7 #include "Connection.h" 12 #include "Exceptions.h" 13 #include "TypeService.h" 15 #include "EventService.h" 18 #include <wfmath/atlasconv.h> 19 #include <sigc++/slot.h> 21 #include <Atlas/Objects/Operation.h> 22 #include <Atlas/Objects/Entity.h> 23 #include <Atlas/Objects/Anonymous.h> 26 using Atlas::Objects::Root;
27 using Atlas::Objects::Entity::Anonymous;
28 using WFMath::CoordType;
29 using WFMath::TimeStamp;
30 using WFMath::numeric_constants;
31 using WFMath::TimeStamp;
33 using Atlas::Objects::smart_dynamic_cast;
37 Avatar::Avatar(
Account &pl, std::string mindId, std::string entityId) :
39 m_mindId(
std::move(mindId)),
40 m_entityId(
std::move(entityId)),
42 m_stampAtLastOp(TimeStamp::now()),
44 m_view(new
View(*this)),
45 m_router(new
IGRouter(*this, *m_view)),
47 m_logoutTimer(nullptr) {
49 m_entityAppearanceCon= m_view->notifyWhenEntitySeen(m_entityId, sigc::mem_fun(
this, &Avatar::onEntityAppear));
52 m_view->getEntityFromServer(
"");
54 m_view->getEntityFromServer(m_entityId);
58 m_entityParentDeletedConnection.disconnect();
59 m_avatarEntityDeletedConnection.disconnect();
61 for (
auto &entry : m_activeContainers) {
63 auto entityRef = *entry.second;
65 ContainerClosed(*entityRef);
71 void Avatar::deactivate() {
78 l->setFrom(m_account.
getId());
80 getConnection().getResponder().await(l->getSerialno(),
this, &Avatar::logoutResponse);
81 getConnection().
send(l);
82 m_logoutTimer = std::make_unique<TimedEvent>(getConnection().getEventService(), std::chrono::seconds(5),
85 <<
"Did not receive logout response after five seconds; forcing Avatar logout.";
92 touchOp->setFrom(m_mindId);
95 what->setId(e->
getId());
97 what->setPosAsList(Atlas::Message::Element(pos.toAtlas()).asList());
99 touchOp->setArgs1(what);
101 getConnection().
send(touchOp);
104 void Avatar::wield(
Eris::Entity *entity, std::string attachPoint)
const {
107 Atlas::Objects::Entity::Anonymous arguments;
109 arguments->setId(entity->
getId());
111 arguments->setAttr(
"attachment", std::move(attachPoint));
112 Atlas::Objects::Operation::Wield wield;
113 wield->setFrom(
getId());
114 wield->setArgs1(arguments);
116 getConnection().
send(wield);
124 what->setAttr(
"say", msg);
126 t->setFrom(m_mindId);
128 getConnection().
send(t);
131 void Avatar::sayTo(
const std::string &message,
const std::vector<std::string> &entities) {
135 what->setAttr(
"say", message);
136 Atlas::Message::ListType addressList;
137 for (
const auto &entity : entities) {
138 addressList.emplace_back(entity);
140 what->setAttr(
"address", addressList);
142 t->setFrom(m_mindId);
144 getConnection().
send(t);
152 emote->setId(
"emote");
153 emote->setAttr(
"description", em);
156 im->setFrom(m_mindId);
159 getConnection().
send(im);
165 what->setId(m_entityId);
167 what->setAttr(
"pos", pos.toAtlas());
169 if (orient.isValid()) {
170 what->setAttr(
"orientation", orient.toAtlas());
174 moveOp->setFrom(m_mindId);
175 moveOp->setArgs1(what);
177 getConnection().
send(moveOp);
184 arg->setAttr(
"_propel", vel.toAtlas());
186 if (orient.isValid()) {
187 arg->setAttr(
"_direction", orient.toAtlas());
189 arg->setId(m_entityId);
192 setOp->setFrom(m_mindId);
193 setOp->setArgs1(arg);
195 getConnection().
send(setOp);
200 const WFMath::Point<3> &pos,
201 const WFMath::Quaternion &orientation,
202 boost::optional<float> offset,
205 what->setLoc(container->
getId());
207 what->setPosAsList(Atlas::Message::Element(pos.toAtlas()).asList());
209 if (orientation.isValid()) {
210 what->setAttr(
"orientation", orientation.toAtlas());
213 what->setAttr(
"planted-offset", offset.get());
216 what->setAttr(
"amount", amount);
219 what->setId(entity->
getId());
222 moveOp->setFrom(m_mindId);
223 moveOp->setArgs1(what);
229 moveOp->setTo(entity->
getId());
232 getConnection().
send(moveOp);
238 use->setFrom(m_mindId);
239 getConnection().
send(use);
242 void Avatar::onEntityAppear(
Entity *ent) {
243 if (ent->
getId() == m_entityId) {
244 assert(m_entity ==
nullptr);
252 auto entityParentDeletedFn = [
this, ent](){
255 m_entityParentDeletedConnection.disconnect();
259 m_entityParentDeletedConnection.disconnect();
268 m_avatarEntityDeletedConnection = ent->
BeingDeleted.connect(
273 [
this](
const Atlas::Message::Element &elem) {
274 if (elem.isInt() && elem.asInt() != 0) {
283 m_entityAppearanceCon.disconnect();
286 auto parentType = ent->
getType();
289 parentType = parentType->getParent();
294 ent->
observe(
"_containers_active",
295 [
this](
const Atlas::Message::Element &elem) { containerActiveChanged(elem); },
308 void Avatar::onTransferRequested(
const TransferInfo &transfer) {
317 WFMath::TimeDiff deltaT = TimeStamp::now() - m_stampAtLastOp;
318 return m_lastOpTime + ((double)deltaT.milliseconds() / 1000.0);
322 m_stampAtLastOp = TimeStamp::now();
323 m_lastOpTime = seconds;
326 void Avatar::logoutResponse(
const RootOperation &op) {
327 if (!op->instanceOf(INFO_NO)) {
328 warning() <<
"received an avatar logout response that is not an INFO";
332 const std::vector<Root> &args(op->getArgs());
334 if (args.empty() || (args.front()->getClassNo() != LOGOUT_NO)) {
335 warning() <<
"argument of avatar logout INFO is not a logout op";
339 RootOperation logout = smart_dynamic_cast<RootOperation>(args.front());
340 const std::vector<Root> &args2(logout->getArgs());
342 warning() <<
"argument of avatar INFO(LOGOUT) is empty";
346 std::string charId = args2.front()->getId();
347 debug() <<
"got logout for character " << charId;
348 if (charId != m_mindId) {
349 error() <<
"got logout for character " << charId
350 <<
" that is not this avatar " << m_mindId;
357 void Avatar::containerActiveChanged(
const Atlas::Message::Element &element) {
358 std::set<std::string> entityIdSet;
359 if (element.isList()) {
360 auto &entityList = element.List();
361 for (
auto &entry: entityList) {
362 if (entry.isString()) {
363 entityIdSet.insert(entry.String());
367 for (
auto I = m_activeContainers.begin(); I != m_activeContainers.end();) {
369 if (entityIdSet.find(entry.first) == entityIdSet.end()) {
371 auto &entityRef = *I->second;
373 ContainerClosed(*entityRef);
376 I = m_activeContainers.erase(I);
378 entityIdSet.erase(I->first);
383 for (
auto &
id : entityIdSet) {
384 auto ref = std::make_unique<EntityRef>(*m_view, id);
385 auto refInstance = ref.get();
387 ContainerOpened(**refInstance);
388 ref->Changed.connect([
this](
Entity *newEntity,
Entity *oldEntity) {
391 ContainerClosed(*oldEntity);
395 ref->Changed.connect([
this](
Entity *newEntity,
Entity *oldEntity) {
397 ContainerOpened(*newEntity);
400 ContainerClosed(*oldEntity);
404 m_activeContainers.emplace(
id, std::move(ref));
414 onTransferRequested(transferInfo);
426 void Avatar::send(
const Atlas::Objects::Operation::RootOperation &op) {
427 op->setFrom(m_mindId);
sigc::signal< void, Entity * > GotCharacterEntity
void setIsAdmin(bool isAdmin)
Sets whether the current avatar is an admin character.
void place(const Entity *entity, const Entity *container, const WFMath::Point< 3 > &pos=WFMath::Point< 3 >(), const WFMath::Quaternion &orientation=WFMath::Quaternion(), boost::optional< float > offset=boost::none, int amount=1)
Place an entity inside another one.
void logoutRequested()
Called when a logout of the avatar has been requested by the server.
void touch(Entity *, const WFMath::Point< 3 > &pos)
Touch an entity.
void onAvatarEntityDeleted()
Called when the avatar entity is deleted.
Connection & getConnection() const
Access the underlying Connection for this account.
void sayTo(const std::string &message, const std::vector< std::string > &entities)
sigc::signal< void > BeingDeleted
void destroyAvatar(const std::string &avatarId)
Destroys the avatar with the specified id, if available.
void setLocation(Entity *newLocation, bool removeFromOldLocation=true)
void emote(const std::string &)
Emote something (in-game)
sigc::signal< void, Entity * > LocationChanged
Signal that the entity's container changed.
void updateWorldTime(double t)
void say(const std::string &)
Say something (in-game)
void setTypeProviderId(std::string id)
Set another provider of type data than the connection.
virtual void send(const Atlas::Objects::Root &obj)
Transmit an Atlas::Objects instance to the server.
std::int64_t getNewSerialno()
operation serial number sequencing
const std::string & getId() const
Get the Mind id of this Avatar. All interaction with the entity goes through the Mind.
sigc::connection observe(const std::string &propertyName, const PropertyChangedSlot &aslot, bool evaluateNow)
Setup an observer so that the specified slot is fired when the named property's value changes...
void send(const Atlas::Objects::Operation::RootOperation &op)
Sends an operation from this Avatar.
void refresh()
Request update to the type info from the server.
bool getIsAdmin() const
Gets whether the current avatar is an admin character.
void moveToPoint(const WFMath::Point< 3 > &, const WFMath::Quaternion &orient)
Have the character move towards a position. Any non-valid data will not be sent.
Encapsulates all the state of an Atlas Account, and methods that operation on that state...
const std::string & getId() const
Retrieve the unique entity ID.
sigc::signal< void, const TransferInfo & > TransferRequested
Entity is a concrete (instantiable) class representing one game entity.
TypeInfo * getType() const
Gets the type of this entity.
void moveInDirection(const WFMath::Vector< 3 > &, const WFMath::Quaternion &)
Set the character's velocity and orientation. Any non-valid data will not be sent.
Entity * getLocation() const
The containing entity, or null if this is a top-level visible entity.
const std::string & getId() const
returns the account ID if logged in
void useStop()
Stop the current task, if one is in progress.
sigc::signal< void > CharacterEntityDeleted