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(
272 m_entityAppearanceCon.disconnect();
275 auto parentType = ent->
getType();
278 parentType = parentType->getParent();
283 ent->
observe(
"_containers_active",
284 [
this](
const Atlas::Message::Element &elem) { containerActiveChanged(elem); },
297 void Avatar::onTransferRequested(
const TransferInfo &transfer) {
306 WFMath::TimeDiff deltaT = TimeStamp::now() - m_stampAtLastOp;
307 return m_lastOpTime + ((double)deltaT.milliseconds() / 1000.0);
311 m_stampAtLastOp = TimeStamp::now();
312 m_lastOpTime = seconds;
315 void Avatar::logoutResponse(
const RootOperation &op) {
316 if (!op->instanceOf(INFO_NO)) {
317 warning() <<
"received an avatar logout response that is not an INFO";
321 const std::vector<Root> &args(op->getArgs());
323 if (args.empty() || (args.front()->getClassNo() != LOGOUT_NO)) {
324 warning() <<
"argument of avatar logout INFO is not a logout op";
328 RootOperation logout = smart_dynamic_cast<RootOperation>(args.front());
329 const std::vector<Root> &args2(logout->getArgs());
331 warning() <<
"argument of avatar INFO(LOGOUT) is empty";
335 std::string charId = args2.front()->getId();
336 debug() <<
"got logout for character " << charId;
337 if (charId != m_mindId) {
338 error() <<
"got logout for character " << charId
339 <<
" that is not this avatar " << m_mindId;
346 void Avatar::containerActiveChanged(
const Atlas::Message::Element &element) {
347 std::set<std::string> entityIdSet;
348 if (element.isList()) {
349 auto &entityList = element.List();
350 for (
auto &entry: entityList) {
351 if (entry.isString()) {
352 entityIdSet.insert(entry.String());
356 for (
auto I = m_activeContainers.begin(); I != m_activeContainers.end();) {
358 if (entityIdSet.find(entry.first) == entityIdSet.end()) {
360 auto &entityRef = *I->second;
362 ContainerClosed(*entityRef);
365 I = m_activeContainers.erase(I);
367 entityIdSet.erase(I->first);
372 for (
auto &
id : entityIdSet) {
373 auto ref = std::make_unique<EntityRef>(*m_view, id);
374 auto refInstance = ref.get();
376 ContainerOpened(**refInstance);
377 ref->Changed.connect([
this](
Entity *newEntity,
Entity *oldEntity) {
380 ContainerClosed(*oldEntity);
384 ref->Changed.connect([
this](
Entity *newEntity,
Entity *oldEntity) {
386 ContainerOpened(*newEntity);
389 ContainerClosed(*oldEntity);
393 m_activeContainers.emplace(
id, std::move(ref));
403 onTransferRequested(transferInfo);
415 void Avatar::send(
const Atlas::Objects::Operation::RootOperation &op) {
416 op->setFrom(m_mindId);
const std::string & getId() const
Get the Mind id of this Avatar. All interaction with the entity goes through the Mind.
sigc::signal< void, Entity * > GotCharacterEntity
void setIsAdmin(bool isAdmin)
Sets whether the current avatar is an admin character.
Entity * getLocation() const
The containing entity, or null if this is a top-level visible entity.
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.
const std::string & getId() const
returns the account ID if logged in
bool getIsAdmin() const
Gets whether the current avatar is an admin character.
const std::string & getId() const
Retrieve the unique entity ID.
void onAvatarEntityDeleted()
Called when the avatar entity is deleted.
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
Connection & getConnection() const
Access the underlying Connection for this account.
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.
TypeInfo * getType() const
Gets the type of this entity.
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...
sigc::signal< void, const TransferInfo & > TransferRequested
Entity is a concrete (instantiable) class representing one game 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.
void useStop()
Stop the current task, if one is in progress.
sigc::signal< void > CharacterEntityDeleted