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>
25 using namespace Atlas::Objects::Operation;
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;
32 using namespace Atlas::Message;
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();
258 ent->
LocationChanged.connect([
this, ent, entityParentDeletedFn](Entity* oldParent){
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) {
312 Connection &Avatar::getConnection()
const {
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);