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);
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