6 #include "ViewEntity.h"
8 #include "Connection.h"
9 #include "Exceptions.h"
12 #include "TypeService.h"
15 #include "EntityRouter.h"
17 #include <Atlas/Objects/Entity.h>
18 #include <Atlas/Objects/Operation.h>
20 using namespace Atlas::Objects::Operation;
21 using Atlas::Objects::Root;
22 using Atlas::Objects::Entity::RootEntity;
23 using Atlas::Objects::smart_dynamic_cast;
27 View::View(Avatar& av) :
30 m_simulationSpeed(1.0),
31 m_maxPendingCount(10) {
36 deleteEntity(m_topLevel->
getId());
41 auto contents = std::move(m_contents);
46 auto E = m_contents.find(eid);
47 if (E == m_contents.end()) {
51 return E->second.entity.get();
55 m_factories.insert(std::move(f));
59 if (m_contents.count(eid)) {
60 error() <<
"notifyWhenEntitySeen: entity " << eid <<
" already in View";
64 sigc::connection c = m_notifySights[eid].connect(slot);
65 getEntityFromServer(eid);
70 return m_owner.getConnection().getTypeService();
74 return m_owner.getConnection().getTypeService();
78 return m_owner.getConnection().getEventService();
82 return m_owner.getConnection().getEventService();
85 double View::getSimulationSpeed()
const {
86 return m_simulationSpeed;
91 auto pruned = pruneAbandonedPendingEntities();
92 for (
size_t i = 0; i < pruned; ++i) {
96 WFMath::TimeStamp t(WFMath::TimeStamp::now());
99 for (
auto& it : m_moving) {
100 it->updatePredictedState(t, m_simulationSpeed);
104 if (!m_lastUpdateTime.isValid()) {
105 m_lastUpdateTime = t;
107 WFMath::TimeDiff dt = t - m_lastUpdateTime;
109 for (
auto& m_progressingTask : m_progressingTasks) {
110 m_progressingTask->updatePredictedProgress(dt);
113 m_lastUpdateTime = t;
117 setTopLevelEntity(topEntity);
119 setTopLevelEntity(
nullptr);
125 assert(m_moving.count(ent) == 0);
126 m_moving.insert(ent);
129 void View::removeFromPrediction(ViewEntity* ent) {
130 assert(m_moving.count(ent) == 1);
135 if (t->m_progressRate > 0.0) {
136 m_progressingTasks.insert(t);
138 m_progressingTasks.erase(t);
144 void View::appear(
const std::string& eid,
double stamp) {
147 getEntityFromServer(eid);
151 if (ent->m_recentlyCreated) {
153 ent->m_recentlyCreated =
false;
156 if (ent->isVisible())
return;
158 if ((stamp == 0) || (stamp > ent->getStamp())) {
160 m_pending[eid].sightAction = SightAction::APPEAR;
163 getEntityFromServer(eid);
166 ent->setVisible(
true);
171 void View::disappear(
const std::string& eid) {
178 m_pending[eid].sightAction = SightAction::DISCARD;
180 warning() <<
"got disappear for unknown entity " << eid;
185 void View::sight(
const RootEntity& gent) {
187 std::string eid = gent->getId();
188 auto pending = m_pending.find(eid);
191 if (pending != m_pending.end()) {
192 switch (pending->second.sightAction) {
193 case SightAction::APPEAR:
197 case SightAction::DISCARD:
198 m_pending.erase(pending);
202 case SightAction::HIDE:
206 case SightAction::QUEUED:
207 error() <<
"got sight of queued entity " << eid <<
" somehow";
208 eraseFromLookQueue(eid);
212 throw InvalidOperation(
"got bad pending action for entity");
215 m_pending.erase(pending);
222 ent->firstSight(gent);
224 ent = initialSight(gent);
228 ent->setVisible(visible);
232 ViewEntity* View::initialSight(
const RootEntity& gent) {
233 assert(m_contents.count(gent->getId()) == 0);
235 auto entity = createEntity(gent);
236 auto router = std::make_unique<EntityRouter>(*entity, *
this);
238 auto entityPtr = entity.get();
240 entity->Moving.connect([
this, entityPtr](
bool startedMoving) {
242 addToPrediction(entityPtr);
244 removeFromPrediction(entityPtr);
248 auto I = m_contents.emplace(gent->getId(), EntityEntry{std::move(entity), std::move(router)});
249 auto& insertedEntry = I.first->second;
250 auto insertedEntity = insertedEntry.entity.get();
251 insertedEntity->init(gent,
false);
255 auto it = m_notifySights.find(gent->getId());
256 if (it != m_notifySights.end()) {
257 it->second.emit(insertedEntity);
258 m_notifySights.erase(it);
261 return insertedEntity;
264 void View::deleteEntity(
const std::string& eid) {
265 auto I = m_contents.find(eid);
266 if (I != m_contents.end()) {
268 auto entity = I->second.entity.get();
269 if (entity->m_moving) {
270 removeFromPrediction(entity);
274 if (entity->isAncestorTo(*m_owner.
getEntity())) {
275 Entity* nearestAncestor = m_owner.
getEntity();
276 while (nearestAncestor->getLocation() != entity) {
282 setTopLevelEntity(nearestAncestor);
284 if (entity->getLocation()) {
285 auto entityLocation = entity->getLocation();
287 entity->setLocation(
nullptr,
true);
289 deleteEntity(entityLocation->getTopEntity()->getId());
296 entity->BeingDeleted.emit();
298 auto children = I->second.entity->getContent();
300 for (
auto& child : children) {
301 deleteEntity(child->getId());
307 m_pending[eid].sightAction = SightAction::DISCARD;
309 warning() <<
"got delete for unknown entity " << eid;
314 std::unique_ptr<ViewEntity> View::createEntity(
const RootEntity& gent) {
315 TypeInfo* type = getConnection().getTypeService().
getTypeForAtlas(gent);
316 assert(type->isBound());
318 auto F = m_factories.begin();
319 for (; F != m_factories.end(); ++F) {
320 if ((*F)->accept(gent, type)) {
321 return (*F)->instantiate(gent, type, *
this);
325 throw std::runtime_error(
"Could not find entity factory suitable for creating new entity.");
328 void View::unseen(
const std::string& eid) {
333 m_pending.erase(eid);
337 return m_pending.find(eid) != m_pending.end();
341 return m_owner.getConnection();
344 void View::getEntityFromServer(
const std::string& eid) {
350 if (!eid.empty() && (m_pending.size() >= m_maxPendingCount)) {
351 m_lookQueue.push_back(eid);
352 m_pending[eid].sightAction = SightAction::QUEUED;
359 size_t View::pruneAbandonedPendingEntities() {
361 auto now = std::chrono::steady_clock::now();
362 for (
auto I = m_pending.begin(); I != m_pending.end();) {
363 if (I->second.sightAction != SightAction::QUEUED && (now - I->second.registrationTime) > std::chrono::seconds(20)) {
364 warning() <<
"Didn't receive any response for entity " << I->first <<
" within 20 seconds, will remove it from pending list.";
365 I = m_pending.erase(I);
378 auto pending = m_pending.find(eid);
379 if (pending != m_pending.end()) {
380 switch (pending->second.sightAction) {
381 case SightAction::QUEUED:
383 pending->second.sightAction = SightAction::APPEAR;
386 case SightAction::DISCARD:
387 case SightAction::HIDE:
388 if (m_notifySights.count(eid) == 0) {
390 m_pending.erase(pending);
398 case SightAction::APPEAR:
411 m_pending.emplace(eid, PendingStatus{SightAction::APPEAR, std::chrono::steady_clock::now()});
417 look->setArgs1(what);
420 look->setFrom(m_owner.
getId());
421 getConnection().
send(look);
424 void View::setTopLevelEntity(
Entity* newTopLevel) {
425 if (newTopLevel == m_topLevel) {
429 m_simulationSpeedConnection.disconnect();
433 m_simulationSpeedConnection = newTopLevel->
observe(
"simulation_speed", sigc::mem_fun(
this, &View::parseSimulationSpeed),
true);
435 m_topLevel = newTopLevel;
440 void View::parseSimulationSpeed(
const Atlas::Message::Element& element) {
441 if (element.isFloat()) {
442 m_simulationSpeed = element.Float();
446 void View::issueQueuedLook() {
447 if (m_lookQueue.empty()) {
450 std::string eid = std::move(m_lookQueue.front());
451 m_lookQueue.pop_front();
455 void View::dumpLookQueue() {
456 debug() <<
"look queue:";
457 for (
const auto& lookOp : m_lookQueue) {
458 debug() <<
"\t" << lookOp;
462 void View::eraseFromLookQueue(
const std::string& eid) {
463 std::deque<std::string>::iterator it;
464 for (it = m_lookQueue.begin(); it != m_lookQueue.end(); ++it) {
466 m_lookQueue.erase(it);
471 error() <<
"entity " << eid <<
" not present in the look queue";