8 #include "Connection.h"
10 #include "LogStream.h"
11 #include "Exceptions.h"
15 #include <wfmath/atlasconv.h>
16 #include <Atlas/Objects/Entity.h>
17 #include <Atlas/Objects/Operation.h>
18 #include <Atlas/Objects/BaseObject.h>
24 using namespace Atlas::Objects::Operation;
25 using Atlas::Objects::Root;
26 using Atlas::Objects::Entity::RootEntity;
27 using Atlas::Message::Element;
28 using Atlas::Message::ListType;
29 using Atlas::Message::MapType;
30 using Atlas::Objects::smart_static_cast;
31 using Atlas::Objects::smart_dynamic_cast;
33 using WFMath::TimeStamp;
34 using WFMath::TimeDiff;
38 Entity::Entity(std::string
id, TypeInfo* ty) :
44 m_waitingForParentBind(false),
49 m_recentlyCreated(false)
51 assert(!m_id.empty());
52 m_orientation.identity();
56 m_type->PropertyChanges.connect(sigc::mem_fun(
this, &Entity::typeInfo_PropertyChanges));
65 void Entity::shutdown() {
68 for (
auto& child: m_contents) {
70 child->setLocation(
nullptr,
false);
75 for (
auto& entry : m_tasks) {
76 TaskRemoved(entry.first, entry.second.get());
80 void Entity::init(
const RootEntity& ge,
bool fromCreateOp)
87 m_recentlyCreated =
true;
94 if (m_waitingForParentBind) {
115 const Element& Entity::valueOfProperty(
const std::string& name)
const
118 auto A = m_properties.find(name);
119 if (A == m_properties.end())
123 const Element* element = m_type->getProperty(name);
128 error() <<
"did valueOfProperty(" << name <<
") on entity " << m_id <<
" which has no such name";
135 bool Entity::hasProperty(
const std::string& p)
const
138 if (m_properties.find(p) != m_properties.end()) {
142 if (m_type->getProperty(p) !=
nullptr) {
149 const Element* Entity::ptrOfProperty(
const std::string& name)
const
152 auto A = m_properties.find(name);
153 if (A == m_properties.end())
157 const Element* element = m_type->getProperty(name);
169 Entity::PropertyMap Entity::getProperties()
const
172 PropertyMap properties;
173 properties.insert(m_properties.begin(), m_properties.end());
175 fillPropertiesFromType(properties, *m_type);
180 const Entity::PropertyMap& Entity::getInstanceProperties()
const
185 void Entity::fillPropertiesFromType(Entity::PropertyMap& properties,
const TypeInfo& typeInfo)
const
191 fillPropertiesFromType(properties, *typeInfo.
getParent());
196 sigc::connection Entity::observe(
const std::string& propertyName,
const PropertyChangedSlot& slot,
bool evaluateNow)
199 auto connection = m_observers[propertyName].connect(slot);
201 auto prop = ptrOfProperty(propertyName);
209 const WFMath::Point<3>& Entity::getPredictedPos()
const
211 return (m_moving ? m_predicted.position : m_position);
214 const WFMath::Vector<3>& Entity::getPredictedVelocity()
const
216 return (m_moving ? m_predicted.velocity : m_velocity);
219 const WFMath::Quaternion& Entity::getPredictedOrientation()
const
221 return (m_moving ? m_predicted.orientation : m_orientation);
224 bool Entity::isMoving()
const
229 void Entity::updatePredictedState(
const WFMath::TimeStamp& t,
double simulationSpeed)
233 if (m_acc.isValid() && m_acc != WFMath::Vector<3>::ZERO()) {
234 double posDeltaTime =
static_cast<double>((t - m_lastPosTime).milliseconds()) / 1000.0;
235 m_predicted.velocity = m_velocity + (m_acc * posDeltaTime * simulationSpeed);
236 m_predicted.position = m_position + (m_velocity * posDeltaTime * simulationSpeed) + (m_acc * 0.5 * posDeltaTime * posDeltaTime * simulationSpeed);
238 m_predicted.velocity = m_velocity;
239 if (m_predicted.velocity != WFMath::Vector<3>::ZERO()) {
240 double posDeltaTime =
static_cast<double>((t - m_lastPosTime).milliseconds()) / 1000.0;
241 m_predicted.position = m_position + (m_velocity * posDeltaTime * simulationSpeed);
243 m_predicted.position = m_position;
246 if (m_angularVelocity.isValid() && m_angularMag != .0) {
247 double orientationDeltaTime =
static_cast<double>((t - m_lastOrientationTime).milliseconds()) / 1000.0;
248 m_predicted.orientation = m_orientation * WFMath::Quaternion(m_angularVelocity, m_angularMag * orientationDeltaTime * simulationSpeed);
250 m_predicted.orientation = m_orientation;
254 void Entity::firstSight(
const RootEntity &gent)
256 if (!gent->isDefaultLoc()) {
257 setLocationFromAtlas(gent->getLoc());
259 setLocation(
nullptr);
262 setContentsFromAtlas(gent->getContains());
264 setFromRoot(gent,
true);
267 void Entity::setFromRoot(
const Root& obj,
bool includeTypeInfoProperties)
271 Atlas::Message::MapType properties;
272 obj->addToMessage(properties);
274 properties.erase(
"id");
275 properties.erase(
"contains");
277 for (
auto& entry : properties) {
279 auto I = m_properties.find(entry.first);
280 if ((I != m_properties.end()) && (I->second == entry.second)) {
284 setProperty(entry.first, entry.second);
285 }
catch (
const std::exception& ex) {
286 warning() <<
"Error when setting property '" << entry.first <<
"'. Message: " << ex.what();
291 if (includeTypeInfoProperties && m_type) {
292 Atlas::Message::MapType typeProperties;
293 fillPropertiesFromType(typeProperties, *m_type);
294 for (
auto& entry : typeProperties) {
295 propertyChangedFromTypeInfo(entry.first, entry.second);
303 void Entity::onTalk(
const Atlas::Objects::Operation::RootOperation& talk)
305 const std::vector<Root>& talkArgs = talk->getArgs();
306 if (talkArgs.empty())
308 warning() <<
"entity " << getId() <<
" got sound(talk) with no args";
312 for (
const auto& arg: talkArgs) {
318 void Entity::onLocationChanged(
Entity* oldLoc)
320 LocationChanged.emit(oldLoc);
323 void Entity::onMoved(
const WFMath::TimeStamp& timeStamp)
327 updatePredictedState(timeStamp, 1.0);
332 void Entity::onAction(
const Atlas::Objects::Operation::RootOperation& arg,
const TypeInfo& typeInfo)
334 Acted.emit(arg, typeInfo);
337 void Entity::onHit(
const Atlas::Objects::Operation::Hit& arg,
const TypeInfo& typeInfo)
339 Hit.emit(arg, typeInfo);
342 void Entity::onSoundAction(
const Atlas::Objects::Operation::RootOperation& op,
const TypeInfo& typeInfo)
344 Noise.emit(op, typeInfo);
347 void Entity::onImaginary(
const Atlas::Objects::Root& arg)
349 Atlas::Message::Element attr;
350 if (arg->copyAttr(
"description", attr) == 0 && attr.isString()) {
351 Emote.emit(attr.asString());
355 void Entity::setMoving(
bool inMotion)
357 assert(m_moving != inMotion);
360 Moving.emit(inMotion);
366 ChildAdded.emit(child);
369 void Entity::onChildRemoved(
Entity* child)
374 void Entity::onTaskAdded(
const std::string&
id,
Task* task)
380 void Entity::setProperty(
const std::string &p,
const Element &v)
386 nativePropertyChanged(p, v);
387 onPropertyChanged(p, v);
391 auto obs = m_observers.find(p);
392 if (obs != m_observers.end()) {
400 bool Entity::nativePropertyChanged(
const std::string& p,
const Element& v)
407 m_name = v.asString();
409 }
else if (p ==
"stamp") {
410 m_stamp = v.asFloat();
412 }
else if (p ==
"pos") {
413 m_position.fromAtlas(v);
415 }
else if (p ==
"velocity") {
416 m_velocity.fromAtlas(v);
418 }
else if (p ==
"angular") {
419 m_angularVelocity.fromAtlas(v);
420 m_angularMag = m_angularVelocity.mag();
422 }
else if (p ==
"accel") {
425 }
else if (p ==
"orientation") {
426 m_orientation.fromAtlas(v);
428 }
else if (p ==
"bbox") {
429 m_bboxUnscaled.fromAtlas(v);
430 m_bbox = m_bboxUnscaled;
431 if (m_scale.isValid() && m_bbox.isValid()) {
432 m_bbox.lowCorner().x() *= m_scale.x();
433 m_bbox.lowCorner().y() *= m_scale.y();
434 m_bbox.lowCorner().z() *= m_scale.z();
435 m_bbox.highCorner().x() *= m_scale.x();
436 m_bbox.highCorner().y() *= m_scale.y();
437 m_bbox.highCorner().z() *= m_scale.z();
439 m_hasBBox = m_bbox.isValid();
441 }
else if (p ==
"loc") {
442 setLocationFromAtlas(v.asString());
444 }
else if (p ==
"contains") {
446 }
else if (p ==
"tasks") {
449 }
else if (p ==
"scale") {
451 if (v.List().size() == 1) {
452 if (v.List().front().isNum()) {
453 auto num =
static_cast<WFMath::CoordType
>(v.List().front().asNum());
454 m_scale = WFMath::Vector<3>(num, num, num);
457 m_scale.fromAtlas(v.List());
460 m_scale = WFMath::Vector<3>();
462 m_bbox = m_bboxUnscaled;
463 if (m_scale.isValid() && m_bbox.isValid()) {
464 m_bbox.lowCorner().x() *= m_scale.x();
465 m_bbox.lowCorner().y() *= m_scale.y();
466 m_bbox.lowCorner().z() *= m_scale.z();
467 m_bbox.highCorner().x() *= m_scale.x();
468 m_bbox.highCorner().y() *= m_scale.y();
469 m_bbox.highCorner().z() *= m_scale.z();
477 void Entity::onPropertyChanged(
const std::string& propertyName,
const Element& v)
483 void Entity::typeInfo_PropertyChanges(
const std::string& propertyName,
const Atlas::Message::Element& element)
485 propertyChangedFromTypeInfo(propertyName, element);
488 void Entity::propertyChangedFromTypeInfo(
const std::string& propertyName,
const Atlas::Message::Element& element)
491 if (m_properties.find(propertyName) == m_properties.end()) {
493 nativePropertyChanged(propertyName, element);
494 onPropertyChanged(propertyName, element);
498 ObserverMap::const_iterator obs = m_observers.find(propertyName);
499 if (obs != m_observers.end()) {
500 obs->second.emit(element);
503 addToUpdate(propertyName);
509 void Entity::beginUpdate()
514 void Entity::addToUpdate(
const std::string& propertyName)
516 assert(m_updateLevel > 0);
517 m_modifiedProperties.insert(propertyName);
520 void Entity::endUpdate()
522 if (m_updateLevel < 1)
524 error() <<
"mismatched begin/end update pair on entity";
528 if (--m_updateLevel == 0)
530 Changed.emit(m_modifiedProperties);
532 if (m_modifiedProperties.find(
"pos") != m_modifiedProperties.end() ||
533 m_modifiedProperties.find(
"velocity") != m_modifiedProperties.end() ||
534 m_modifiedProperties.find(
"orientation") != m_modifiedProperties.end() ||
535 m_modifiedProperties.find(
"angular") != m_modifiedProperties.end())
537 auto now = TimeStamp::now();
538 if (m_modifiedProperties.find(
"pos") != m_modifiedProperties.end()) {
541 if (m_modifiedProperties.find(
"orientation") != m_modifiedProperties.end()) {
542 m_lastOrientationTime = now;
545 const WFMath::Vector<3> & velocity = getVelocity();
546 bool nowMoving = (velocity.isValid() && (velocity.sqrMag() > 1e-3)) || (m_angularVelocity.isValid() && m_angularVelocity != WFMath::Vector<3>::ZERO());
547 if (nowMoving != m_moving) {
548 setMoving(nowMoving);
554 m_modifiedProperties.clear();
559 void Entity::updateTasks(
const Element& e)
562 for (
auto& entry : m_tasks) {
563 TaskRemoved(entry.first, entry.second.get());
571 auto& taskMap = e.Map();
573 auto previousTasks = std::move(m_tasks);
576 for (
auto& entry : taskMap) {
577 auto& taskElement = entry.second;
578 if (!taskElement.isMap()) {
581 const MapType& tkmap(taskElement.Map());
582 auto it = tkmap.find(
"name");
583 if (it == tkmap.end())
585 error() <<
"task without name";
588 if (!it->second.isString())
590 error() <<
"task with invalid name";
594 auto tasksI = previousTasks.find(entry.first);
595 std::unique_ptr<Task> task;
597 bool newTask =
false;
598 if (tasksI == previousTasks.end())
600 task = std::make_unique<Task>(*
this, it->second.asString());
603 task = std::move(tasksI->second);
604 previousTasks.erase(entry.first);
607 task->updateFromAtlas(tkmap);
609 onTaskAdded(entry.first, task.get());
611 m_tasks.emplace(entry.first, std::move(task));
614 for (
auto& entry : previousTasks) {
617 TaskRemoved(entry.first, entry.second.get());
622 void Entity::setLocationFromAtlas(
const std::string& locId) {
627 Entity* newLocation = getEntity(locId);
630 m_waitingForParentBind =
true;
634 removeFromLocation();
636 m_location =
nullptr;
641 setLocation(newLocation);
644 void Entity::setLocation(
Entity* newLocation,
bool removeFromOldLocation)
646 if (newLocation == m_location)
return;
653 bool wasVisible = isVisible();
654 if (m_location && removeFromOldLocation) {
655 removeFromLocation();
658 Entity* oldLocation = m_location;
659 m_location = newLocation;
661 onLocationChanged(oldLocation);
664 updateCalculatedVisibility(wasVisible);
671 void Entity::addToLocation()
673 assert(!m_location->hasChild(m_id));
674 m_location->addChild(
this);
677 void Entity::removeFromLocation()
679 assert(m_location->hasChild(m_id));
680 m_location->removeChild(
this);
683 void Entity::buildEntityDictFromContents(IdEntityMap& dict)
685 for (
auto& child : m_contents) {
686 dict[child->getId()] = child;
690 void Entity::setContentsFromAtlas(
const std::vector<std::string>& contents)
693 IdEntityMap oldContents;
694 buildEntityDictFromContents(oldContents);
697 for (
auto& content : contents) {
700 auto J = oldContents.find(content);
701 if (J != oldContents.end()) {
704 oldContents.erase(J);
706 child = getEntity(content);
712 assert(!child->m_visible);
724 for (
auto& entry : oldContents) {
725 entry.second->setVisible(
false);
729 bool Entity::hasChild(
const std::string& eid)
const
731 for (
auto& m_content : m_contents) {
732 if (m_content->getId() == eid) {
740 void Entity::addChild(Entity* e)
742 m_contents.push_back(e);
744 assert(e->getLocation() ==
this);
747 void Entity::removeChild(Entity* e)
749 assert(e->getLocation() ==
this);
751 auto I = std::find(m_contents.begin(), m_contents.end(), e);
752 if (I != m_contents.end()) {
757 error() <<
"child " << e->getId() <<
" of entity " << m_id <<
" not found doing remove";
762 void Entity::setVisible(
bool vis)
766 if (m_waitingForParentBind) vis =
false;
768 bool wasVisible = isVisible();
771 updateCalculatedVisibility(wasVisible);
774 bool Entity::isVisible()
const
776 if (m_waitingForParentBind)
return false;
779 return m_visible && m_location->isVisible();
785 void Entity::updateCalculatedVisibility(
bool wasVisible)
787 bool nowVisible = isVisible();
788 if (nowVisible == wasVisible)
return;
795 onVisibilityChanged(
true);
798 for (
auto& item : m_contents) {
802 bool childWasVisible = wasVisible && item->m_visible;
803 item->updateCalculatedVisibility(childWasVisible);
807 onVisibilityChanged(
false);
811 void Entity::onVisibilityChanged(
bool vis)
813 VisibilityChanged.emit(vis);
816 boost::optional<std::string> Entity::extractEntityId(
const Atlas::Message::Element& element)
818 if (element.isString()) {
819 return element.String();
820 }
else if (element.isMap()) {
821 auto I = element.asMap().find(
"$eid");
822 if (I != element.asMap().end() && I->second.isString()) {
823 return I->second.String();
Entity is a concrete (instantiable) class representing one game entity.
void setVisible(bool vis)
void setLocation(Entity *newLocation, bool removeFromOldLocation=true)
Entity * getTopEntity()
Gets the top level entity for this entity, i.e. the parent location which has no parent....
bool m_waitingForParentBind
waiting for parent bind
Entity * getLocation() const
The containing entity, or null if this is a top-level visible entity.
sigc::slot< void, const Atlas::Message::Element & > PropertyChangedSlot
A slot which can be used for receiving property update signals.
The representation of an Atlas type (i.e a class or operation definition). This class supports effice...
const Atlas::Message::MapType & getProperties() const
Gets the default properties for this entity type. Note that the map returned does not include inherit...
const TypeInfo * getParent() const
Gets the currently resolved parent TypeInfo instances.