Overte C++ Documentation
EntityTree.h
1 //
2 // EntityTree.h
3 // libraries/entities/src
4 //
5 // Created by Brad Hefta-Gaub on 12/4/13.
6 // Copyright 2013 High Fidelity, Inc.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 
12 #ifndef hifi_EntityTree_h
13 #define hifi_EntityTree_h
14 
15 #include <QSet>
16 #include <QVector>
17 
18 #include <HelperScriptEngine.h>
19 #include <Octree.h>
20 #include <SpatialParentFinder.h>
21 
22 #include "AddEntityOperator.h"
23 #include "EntityTreeElement.h"
24 #include "DeleteEntityOperator.h"
25 #include "MovingEntitiesOperator.h"
26 
27 class EntityTree;
28 using EntityTreePointer = std::shared_ptr<EntityTree>;
29 
30 class EntitySimulation;
31 
32 namespace EntityQueryFilterSymbol {
33  static const QString NonDefault = "+";
34 }
35 
36 class NewlyCreatedEntityHook {
37 public:
38  virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) = 0;
39 };
40 
41 class SendEntitiesOperationArgs {
42 public:
43  glm::vec3 root;
44  QString entityHostType;
45  EntityTree* ourTree;
46  EntityTreePointer otherTree;
47  QHash<EntityItemID, EntityItemID>* map;
48 };
49 
50 class EntityTree : public Octree, public SpatialParentTree {
51  Q_OBJECT
52 public:
53  enum FilterType {
54  Add,
55  Edit,
56  Physics,
57  Delete
58  };
59  EntityTree(bool shouldReaverage = false);
60  virtual ~EntityTree();
61 
62  void createRootElement();
63 
64 
65  void setEntityMaxTmpLifetime(float maxTmpEntityLifetime) { _maxTmpEntityLifetime = maxTmpEntityLifetime; }
66  void setEntityScriptSourceAllowlist(const QString& entityScriptSourceAllowlist);
67 
69  virtual OctreeElementPointer createNewElement(unsigned char* octalCode = NULL) override;
70 
72  EntityTreeElementPointer getRoot() {
73  if (!_rootElement) {
74  createRootElement();
75  }
76  return std::static_pointer_cast<EntityTreeElement>(_rootElement);
77  }
78 
79 
80  virtual void eraseDomainAndNonOwnedEntities() override;
81  virtual void eraseAllOctreeElements(bool createNewRoot = true) override;
82 
83  virtual void readBitstreamToTree(const unsigned char* bitstream,
84  uint64_t bufferSizeBytes, ReadBitstreamToTreeParams& args) override;
85  int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
86 
87  // These methods will allow the OctreeServer to send your tree inbound edit packets of your
88  // own definition. Implement these to allow your octree based server to support editing
89  virtual PacketType expectedDataPacketType() const override { return PacketType::EntityData; }
90  virtual bool handlesEditPacketType(PacketType packetType) const override;
91  void fixupTerseEditLogging(EntityItemProperties& properties, QList<QString>& changedProperties);
92  virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
93  const SharedNodePointer& senderNode) override;
94 
95  virtual EntityItemID evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
96  QVector<EntityItemID> entityIdsToInclude, QVector<EntityItemID> entityIdsToDiscard,
97  PickFilter searchFilter, OctreeElementPointer& element, float& distance,
98  BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
99  Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
100 
101  virtual EntityItemID evalParabolaIntersection(const PickParabola& parabola,
102  QVector<EntityItemID> entityIdsToInclude, QVector<EntityItemID> entityIdsToDiscard,
103  PickFilter searchFilter, OctreeElementPointer& element, glm::vec3& intersection,
104  float& distance, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
105  Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
106 
107  virtual bool rootElementHasData() const override { return true; }
108 
109  virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const override;
110 
111  // Why preUpdate() and update()?
112  // Because sometimes we need to do stuff between the two.
113  void preUpdate() override;
114  void update(bool simulate = true) override;
115 
116  // The newer API...
117  void postAddEntity(EntityItemPointer entityItem);
118 
119  EntityItemPointer addEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool isClone = false, const bool isImport = false);
120 
121  // use this method if you only know the entityID
122  bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
123 
124  // check if the avatar is a child of this entity, If so set the avatar parentID to null
125  void unhookChildAvatar(const EntityItemID entityID);
126  void cleanupCloneIDs(const EntityItemID& entityID);
127  void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = true);
128 
129  void deleteEntitiesByID(const std::vector<EntityItemID>& entityIDs, bool force = false, bool ignoreWarnings = true);
130  void deleteEntitiesByPointer(const std::vector<EntityItemPointer>& entities);
131 
132  EntityItemPointer findEntityByID(const QUuid& id) const;
133  EntityItemPointer findEntityByEntityItemID(const EntityItemID& entityID) const;
134  virtual SpatiallyNestablePointer findByID(const QUuid& id) const override { return findEntityByID(id); }
135 
136  EntityItemID assignEntityID(const EntityItemID& entityItemID);
137 
138  QUuid evalClosestEntity(const glm::vec3& position, float targetRadius, PickFilter searchFilter);
139  void evalEntitiesInSphere(const glm::vec3& center, float radius, PickFilter searchFilter, QVector<QUuid>& foundEntities);
140  void evalEntitiesInSphereWithType(const glm::vec3& center, float radius, EntityTypes::EntityType type, PickFilter searchFilter, QVector<QUuid>& foundEntities);
141  void evalEntitiesInSphereWithName(const glm::vec3& center, float radius, const QString& name, bool caseSensitive, PickFilter searchFilter, QVector<QUuid>& foundEntities);
142  void evalEntitiesInSphereWithTags(const glm::vec3& center, float radius, const QVector<QString>& tags, bool caseSensitive, PickFilter searchFilter, QVector<QUuid>& foundEntities);
143  void evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector<QUuid>& foundEntities);
144  void evalEntitiesInBox(const AABox& box, PickFilter searchFilter, QVector<QUuid>& foundEntities);
145  void evalEntitiesInFrustum(const ViewFrustum& frustum, PickFilter searchFilter, QVector<QUuid>& foundEntities);
146 
147  void addNewlyCreatedHook(NewlyCreatedEntityHook* hook);
148  void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook);
149 
150  bool hasAnyDeletedEntities() const {
151  QReadLocker locker(&_recentlyDeletedEntitiesLock);
152  return _recentlyDeletedEntityItemIDs.size() > 0;
153  }
154 
155  bool hasEntitiesDeletedSince(quint64 sinceTime);
156  static quint64 getAdjustedConsiderSince(quint64 sinceTime);
157 
158  QMultiMap<quint64, QUuid> getRecentlyDeletedEntityIDs() const {
159  QReadLocker locker(&_recentlyDeletedEntitiesLock);
160  return _recentlyDeletedEntityItemIDs;
161  }
162 
163  void forgetEntitiesDeletedBefore(quint64 sinceTime);
164 
165  int processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode);
166  int processEraseMessageDetails(const QByteArray& buffer, const SharedNodePointer& sourceNode);
167  bool shouldEraseEntity(EntityItemID entityID, const SharedNodePointer& sourceNode);
168 
169 
170  EntityTreeElementPointer getContainingElement(const EntityItemID& entityItemID) /*const*/;
171  void addEntityMapEntry(EntityItemPointer entity);
172  void clearEntityMapEntry(const EntityItemID& id);
173  void debugDumpMap();
174  virtual void dumpTree() override;
175  virtual void pruneTree() override;
176 
177  static QByteArray remapActionDataIDs(QByteArray actionData, QHash<EntityItemID, EntityItemID>& map);
178 
179  QVector<EntityItemID> sendEntities(EntityEditPacketSender* packetSender, EntityTreePointer localTree,
180  const QString& entityHostType, float x, float y, float z);
181 
182  void entityChanged(EntityItemPointer entity);
183 
184  void emitEntityScriptChanging(const EntityItemID& entityItemID, bool reload);
185  void emitEntityServerScriptChanging(const EntityItemID& entityItemID, bool reload);
186 
187  void setSimulation(EntitySimulationPointer simulation);
188  EntitySimulationPointer getSimulation() const { return _simulation; }
189 
190  bool wantEditLogging() const { return _wantEditLogging; }
191  void setWantEditLogging(bool value) { _wantEditLogging = value; }
192 
193  bool wantTerseEditLogging() const { return _wantTerseEditLogging; }
194  void setWantTerseEditLogging(bool value) { _wantTerseEditLogging = value; }
195 
196  virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues,
197  bool skipThoseWithBadParents) override;
198  virtual bool readFromMap(QVariantMap& entityDescription, const bool isImport = false) override;
199  virtual bool writeToJSON(QString& jsonString, const OctreeElementPointer& element) override;
200 
201 
202  glm::vec3 getContentsDimensions();
203  float getContentsLargestDimension();
204 
205  virtual void resetEditStats() override {
206  _totalEditMessages = 0;
207  _totalUpdates = 0;
208  _totalCreates = 0;
209  _totalDecodeTime = 0;
210  _totalLookupTime = 0;
211  _totalUpdateTime = 0;
212  _totalCreateTime = 0;
213  _totalLoggingTime = 0;
214  }
215 
216  virtual quint64 getAverageDecodeTime() const override { return _totalEditMessages == 0 ? 0 : _totalDecodeTime / _totalEditMessages; }
217  virtual quint64 getAverageLookupTime() const override { return _totalEditMessages == 0 ? 0 : _totalLookupTime / _totalEditMessages; }
218  virtual quint64 getAverageUpdateTime() const override { return _totalUpdates == 0 ? 0 : _totalUpdateTime / _totalUpdates; }
219  virtual quint64 getAverageCreateTime() const override { return _totalCreates == 0 ? 0 : _totalCreateTime / _totalCreates; }
220  virtual quint64 getAverageLoggingTime() const override { return _totalEditMessages == 0 ? 0 : _totalLoggingTime / _totalEditMessages; }
221  virtual quint64 getAverageFilterTime() const override { return _totalEditMessages == 0 ? 0 : _totalFilterTime / _totalEditMessages; }
222 
223  void trackIncomingEntityLastEdited(quint64 lastEditedTime, int bytesRead);
224  quint64 getAverageEditDeltas() const
225  { return _totalTrackedEdits == 0 ? 0 : _totalEditDeltas / _totalTrackedEdits; }
226  quint64 getAverageEditBytes() const
227  { return _totalTrackedEdits == 0 ? 0 : _totalEditBytes / _totalTrackedEdits; }
228  quint64 getMaxEditDelta() const { return _maxEditDelta; }
229  quint64 getTotalTrackedEdits() const { return _totalTrackedEdits; }
230 
231  EntityTreePointer getThisPointer() { return std::static_pointer_cast<EntityTree>(shared_from_this()); }
232 
233  bool isDeletedEntity(const QUuid& id) {
234  QReadLocker locker(&_deletedEntitiesLock);
235  return _deletedEntityItemIDs.contains(id);
236  }
237 
238  // these are used to call through to EntityItems
239  Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name) const;
240  Q_INVOKABLE QStringList getJointNames(const QUuid& entityID) const;
241 
242  void knowAvatarID(const QUuid& avatarID);
243  void forgetAvatarID(const QUuid& avatarID);
244  void deleteDescendantsOfAvatar(const QUuid& avatarID);
245  void removeFromChildrenOfAvatars(EntityItemPointer entity);
246 
247  void addToNeedsParentFixupList(EntityItemPointer entity);
248 
249  void notifyNewCollisionSoundURL(const QString& newCollisionSoundURL, const EntityItemID& entityID);
250 
251  static const float DEFAULT_MAX_TMP_ENTITY_LIFETIME;
252 
253  QUuid getMyAvatarSessionUUID() { return _myAvatar ? _myAvatar->getSessionUUID() : QUuid(); }
254  void setMyAvatar(std::shared_ptr<AvatarData> myAvatar) { _myAvatar = myAvatar; }
255 
256  void swapStaleProxies(std::vector<int>& proxies) { proxies.swap(_staleProxies); }
257 
258  void setIsServerlessMode(bool value) { _serverlessDomain = value; }
259  bool isServerlessMode() const { return _serverlessDomain; }
260 
261  void setIsEntityServer(bool value) { _entityServer = value; }
262  bool isEntityServer() const { return _entityServer; }
263 
264  static void setGetEntityObjectOperator(std::function<QObject*(const QUuid&)> getEntityObjectOperator) { _getEntityObjectOperator = getEntityObjectOperator; }
265  static QObject* getEntityObject(const QUuid& id);
266 
267  static void setTextSizeOperator(std::function<QSizeF(const QUuid&, const QString&)> textSizeOperator) { _textSizeOperator = textSizeOperator; }
268  static QSizeF textSize(const QUuid& id, const QString& text);
269 
270  static void setEntityClicksCapturedOperator(std::function<bool()> areEntityClicksCapturedOperator) { _areEntityClicksCapturedOperator = areEntityClicksCapturedOperator; }
271  static bool areEntityClicksCaptured();
272 
273  static void setEmitScriptEventOperator(std::function<void(const QUuid&, const QVariant&)> emitScriptEventOperator) { _emitScriptEventOperator = emitScriptEventOperator; }
274  static void emitScriptEvent(const QUuid& id, const QVariant& message);
275 
276  static void setGetUnscaledDimensionsForIDOperator(std::function<glm::vec3(const QUuid&)> getUnscaledDimensionsForIDOperator) { _getUnscaledDimensionsForIDOperator = getUnscaledDimensionsForIDOperator; }
277  static glm::vec3 getUnscaledDimensionsForID(const QUuid& id);
278 
279  std::map<QString, QString> getNamedPaths() const { return _namedPaths; }
280 
281  void updateEntityQueryAACube(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,
282  bool force, bool tellServer);
283 
284 signals:
285  void deletingEntity(const EntityItemID& entityID);
286  void deletingEntityPointer(EntityItem* entityID);
287  void addingEntity(const EntityItemID& entityID);
288  void addingEntityPointer(EntityItem* entityID);
289  void editingEntityPointer(const EntityItemPointer& entityID);
290  void entityScriptChanging(const EntityItemID& entityItemID, const bool reload);
291  void entityServerScriptChanging(const EntityItemID& entityItemID, const bool reload);
292  void newCollisionSoundURL(const QUrl& url, const EntityItemID& entityID);
293  void clearingEntities();
294  void killChallengeOwnershipTimeoutTimer(const EntityItemID& certID);
295 
296 protected:
297 
298  void recursivelyFilterAndCollectForDelete(const EntityItemPointer& entity, std::vector<EntityItemPointer>& entitiesToDelete, bool force) const;
299  void processRemovedEntities(const DeleteEntityOperator& theOperator);
300  bool updateEntity(EntityItemPointer entity, const EntityItemProperties& properties,
301  const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
302  static bool sendEntitiesOperation(const OctreeElementPointer& element, void* extraData);
303  static void bumpTimestamp(EntityItemProperties& properties);
304 
305  void notifyNewlyCreatedEntity(const EntityItem& newEntity, const SharedNodePointer& senderNode);
306 
307  bool isScriptInAllowlist(const QString& scriptURL);
308 
309  QReadWriteLock _newlyCreatedHooksLock;
310  QVector<NewlyCreatedEntityHook*> _newlyCreatedHooks;
311 
312  mutable QReadWriteLock _recentlyDeletedEntitiesLock;
313  QMultiMap<quint64, QUuid> _recentlyDeletedEntityItemIDs;
314 
315  mutable QReadWriteLock _deletedEntitiesLock;
316  QSet<QUuid> _deletedEntityItemIDs;
317 
318  void clearDeletedEntities() {
319  QWriteLocker locker(&_deletedEntitiesLock);
320  _deletedEntityItemIDs.clear();
321  }
322 
323  void trackDeletedEntity(const QUuid& id) {
324  QWriteLocker locker(&_deletedEntitiesLock);
325  _deletedEntityItemIDs << id;
326  }
327 
328  mutable QReadWriteLock _entityMapLock;
329  QHash<EntityItemID, EntityItemPointer> _entityMap;
330 
331  EntitySimulationPointer _simulation;
332 
333  bool _wantEditLogging = false;
334  bool _wantTerseEditLogging = false;
335 
336 
337  // some performance tracking properties - only used in server trees
338  int _totalEditMessages = 0;
339  int _totalUpdates = 0;
340  int _totalCreates = 0;
341  mutable quint64 _totalDecodeTime = 0;
342  mutable quint64 _totalLookupTime = 0;
343  mutable quint64 _totalUpdateTime = 0;
344  mutable quint64 _totalCreateTime = 0;
345  mutable quint64 _totalLoggingTime = 0;
346  mutable quint64 _totalFilterTime = 0;
347 
348  // these performance statistics are only used in the client
349  void resetClientEditStats();
350  int _totalTrackedEdits = 0;
351  quint64 _totalEditBytes = 0;
352  quint64 _totalEditDeltas = 0;
353  quint64 _maxEditDelta = 0;
354  quint64 _treeResetTime = 0;
355 
356  void fixupNeedsParentFixups(); // try to hook members of _needsParentFixup to parent instances
357  QVector<EntityItemWeakPointer> _needsParentFixup; // entites with a parentID but no (yet) known parent instance
358  mutable QReadWriteLock _needsParentFixupLock;
359 
360  std::mutex _avatarIDsLock;
361  // we maintain a list of avatarIDs to notice when an entity is a child of one.
362  QSet<QUuid> _avatarIDs; // IDs of avatars connected to entity server
363  std::mutex _childrenOfAvatarsLock;
364  QHash<QUuid, QSet<EntityItemID>> _childrenOfAvatars; // which entities are children of which avatars
365 
366  float _maxTmpEntityLifetime { DEFAULT_MAX_TMP_ENTITY_LIFETIME };
367 
368  bool filterProperties(const EntityItemPointer& existingEntity, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut, bool& wasChanged, FilterType filterType) const;
369  bool _hasEntityEditFilter{ false };
370  QStringList _entityScriptSourceAllowlist;
371 
372  MovingEntitiesOperator _entityMover;
373  QHash<EntityItemID, EntityItemPointer> _entitiesToAdd;
374 
375 private:
376  std::shared_ptr<AvatarData> _myAvatar{ nullptr };
377 
378  static std::function<QObject*(const QUuid&)> _getEntityObjectOperator;
379  static std::function<QSizeF(const QUuid&, const QString&)> _textSizeOperator;
380  static std::function<bool()> _areEntityClicksCapturedOperator;
381  static std::function<void(const QUuid&, const QVariant&)> _emitScriptEventOperator;
382  static std::function<glm::vec3(const QUuid&)> _getUnscaledDimensionsForIDOperator;
383 
384  std::vector<int32_t> _staleProxies;
385 
386  bool _serverlessDomain { false };
387  bool _entityServer { false };
388 
389  std::map<QString, QString> _namedPaths;
390 
391  // Return an AACube containing object and all its entity descendants
392  AACube updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,
393  MovingEntitiesOperator& moveOperator, bool force, bool tellServer);
394 
395  // Script engine for writing entity tree data to and from JSON
396  HelperScriptEngine _helperScriptEngine;
397 };
398 
399 void convertGrabUserDataToProperties(EntityItemProperties& properties);
400 
401 #endif // hifi_EntityTree_h
Utility for processing, packing, queueing and sending of outbound edit voxel messages.
Definition: EntityEditPacketSender.h:25
Abstract ID for editing model items. Used in EntityItem JS API.
Definition: EntityItemID.h:28
Provides a wrapper around script engine that does not have ScriptManager.
Definition: HelperScriptEngine.h:31