BsGameObjectHandle.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. #pragma once
  2. namespace BansheeEngine
  3. {
  4. class GameObjectManager;
  5. template <typename T>
  6. class GameObjectHandle;
  7. /**
  8. * @brief Internal data shared between GameObject handles.
  9. */
  10. struct BS_CORE_EXPORT GameObjectHandleData
  11. {
  12. GameObjectHandleData()
  13. :mPtr(nullptr), mInstanceId(0)
  14. { }
  15. GameObjectHandleData(const std::shared_ptr<GameObjectInstanceData>& ptr)
  16. {
  17. mPtr = ptr;
  18. if(ptr != nullptr)
  19. mInstanceId = ptr->object->getInstanceId();
  20. else
  21. mInstanceId = 0;
  22. }
  23. std::shared_ptr<GameObjectInstanceData> mPtr;
  24. UINT64 mInstanceId;
  25. };
  26. /**
  27. * @brief A handle that can point to various types of game objects.
  28. * It primarily keeps track if the object is still alive, so anything
  29. * still referencing it doesn't accidentally use it.
  30. *
  31. * @note This class exists because references between game objects should be quite loose.
  32. * For example one game object should be able to reference another one without the other
  33. * one knowing. But if that is the case I also need to handle the case when the other
  34. * object we're referencing has been deleted, and that is the main purpose of this class.
  35. *
  36. */
  37. class BS_CORE_EXPORT GameObjectHandleBase : public IReflectable
  38. {
  39. public:
  40. GameObjectHandleBase();
  41. /**
  42. * @brief Returns true if the object the handle is pointing to has been destroyed.
  43. *
  44. * @param checkQueued Game objects can be queued for destruction but not actually destroyed yet, and still accessible.
  45. * If this is false this method will return true only if the object is completely inaccessible (fully destroyed).
  46. * If this is true this method will return true if object is completely inaccessible or if it is just queued for destruction.
  47. */
  48. bool isDestroyed(bool checkQueued = false) const
  49. { return mData->mPtr == nullptr || mData->mPtr->object == nullptr || (checkQueued && mData->mPtr->object->_getIsDestroyed()); }
  50. /**
  51. * @brief Returns the instance ID of the object the handle is referencing.
  52. */
  53. UINT64 getInstanceId() const { return mData->mInstanceId; }
  54. /**
  55. * @brief Returns pointer to the referenced GameObject.
  56. *
  57. * @note Throws exception if the GameObject was destroyed.
  58. */
  59. GameObject* get() const
  60. {
  61. throwIfDestroyed();
  62. return mData->mPtr->object.get();
  63. }
  64. /**
  65. * @brief Returns a smart pointer to the referenced GameObject.
  66. *
  67. * @note Throws exception if the GameObject was destroyed.
  68. */
  69. std::shared_ptr<GameObject> getInternalPtr() const
  70. {
  71. throwIfDestroyed();
  72. return mData->mPtr->object;
  73. }
  74. /**
  75. * @brief Returns pointer to the referenced GameObject.
  76. *
  77. * @note Throws exception if the GameObject was destroyed.
  78. */
  79. GameObject* operator->() const { return get(); }
  80. /**
  81. * @brief Returns reference to the referenced GameObject.
  82. *
  83. * @note Throws exception if the GameObject was destroyed.
  84. */
  85. GameObject& operator*() const { return *get(); }
  86. /**
  87. * @brief Returns internal handle data.
  88. *
  89. * @note Internal method.
  90. */
  91. std::shared_ptr<GameObjectHandleData> _getHandleData() const { return mData; }
  92. /**
  93. * @brief Resolves a handle to a proper GameObject in case it was created uninitialized.
  94. *
  95. * @note Internal method.
  96. */
  97. void _resolve(const GameObjectHandleBase& object);
  98. /**
  99. * @brief Changes the GameObject instance the handle is pointing to.
  100. *
  101. * @note Internal method.
  102. */
  103. void _setHandleData(const GameObjectPtr& object);
  104. protected:
  105. friend class SceneObject;
  106. friend class Component;
  107. friend class SceneObjectRTTI;
  108. friend class GameObjectManager;
  109. template<class _Ty1, class _Ty2>
  110. friend bool operator==(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right);
  111. GameObjectHandleBase(const std::shared_ptr<GameObject> ptr);
  112. GameObjectHandleBase(const std::shared_ptr<GameObjectHandleData>& data);
  113. GameObjectHandleBase(std::nullptr_t ptr);
  114. /**
  115. * @brief Throws an exception if the referenced GameObject has been destroyed.
  116. */
  117. inline void throwIfDestroyed() const;
  118. /**
  119. * @brief Invalidates the handle signifying the referenced object was destroyed.
  120. */
  121. void destroy()
  122. {
  123. // It's important not to clear mData->mPtr as some code might rely
  124. // on it. (e.g. for restoring lost handles)
  125. if (mData->mPtr != nullptr)
  126. mData->mPtr->object = nullptr;
  127. }
  128. std::shared_ptr<GameObjectHandleData> mData;
  129. /************************************************************************/
  130. /* RTTI */
  131. /************************************************************************/
  132. public:
  133. friend class GameObjectHandleRTTI;
  134. static RTTITypeBase* getRTTIStatic();
  135. virtual RTTITypeBase* getRTTI() const override;
  136. };
  137. /**
  138. * @copydoc GameObjectHandleBase
  139. *
  140. * @note It is important this class contains no data since we often
  141. * value cast it to its base.
  142. */
  143. template <typename T>
  144. class GameObjectHandle : public GameObjectHandleBase
  145. {
  146. public:
  147. /**
  148. * @brief Constructs a new empty handle.
  149. */
  150. GameObjectHandle()
  151. :GameObjectHandleBase()
  152. {
  153. mData = bs_shared_ptr_new<GameObjectHandleData>();
  154. }
  155. /**
  156. * @brief Copy constructor from another handle of the same type.
  157. */
  158. template <typename T1>
  159. GameObjectHandle(const GameObjectHandle<T1>& ptr)
  160. :GameObjectHandleBase()
  161. {
  162. mData = ptr._getHandleData();
  163. }
  164. /**
  165. * @brief Copy constructor from another handle of the base type.
  166. */
  167. GameObjectHandle(const GameObjectHandleBase& ptr)
  168. :GameObjectHandleBase()
  169. {
  170. mData = ptr._getHandleData();
  171. }
  172. /**
  173. * @brief Invalidates the handle.
  174. */
  175. inline GameObjectHandle<T>& operator=(std::nullptr_t ptr)
  176. {
  177. mData = bs_shared_ptr_new<GameObjectHandleData>();
  178. return *this;
  179. }
  180. /**
  181. * @brief Casts a specific handle to the base handle.
  182. */
  183. inline operator GameObjectHandleBase()
  184. {
  185. GameObjectHandleBase base(mData);
  186. return base;
  187. }
  188. /**
  189. * @brief Returns a pointer to the referenced GameObject.
  190. *
  191. * @note Throws exception if the GameObject was destroyed.
  192. */
  193. T* get() const
  194. {
  195. throwIfDestroyed();
  196. return reinterpret_cast<T*>(mData->mPtr->object.get());
  197. }
  198. /**
  199. * @brief Returns a smart pointer to the referenced GameObject.
  200. *
  201. * @note Throws exception if the GameObject was destroyed.
  202. */
  203. std::shared_ptr<T> getInternalPtr() const
  204. {
  205. throwIfDestroyed();
  206. return std::static_pointer_cast<T>(mData->mPtr->object);
  207. }
  208. /**
  209. * @brief Returns pointer to the referenced GameObject.
  210. *
  211. * @note Throws exception if the GameObject was destroyed.
  212. */
  213. T* operator->() const { return get(); }
  214. /**
  215. * @brief Returns reference to the referenced GameObject.
  216. *
  217. * @note Throws exception if the GameObject was destroyed.
  218. */
  219. T& operator*() const { return *get(); }
  220. template<class _Ty>
  221. struct Bool_struct
  222. {
  223. int _Member;
  224. };
  225. /**
  226. * @brief Allows direct conversion of handle to bool.
  227. *
  228. * @note This is needed because we can't directly convert to bool
  229. * since then we can assign pointer to bool and that's weird.
  230. */
  231. operator int Bool_struct<T>::*() const
  232. {
  233. return (((mData->mPtr != nullptr) && (mData->mPtr->object != nullptr)) ? &Bool_struct<T>::_Member : 0);
  234. }
  235. private:
  236. friend class SceneObject;
  237. friend class SceneObjectRTTI;
  238. friend class GameObjectManager;
  239. /**
  240. * @brief Creates a GameObject handle from a smart pointer.
  241. */
  242. explicit GameObjectHandle(const std::shared_ptr<T> ptr)
  243. :GameObjectHandleBase(ptr)
  244. { }
  245. };
  246. /**
  247. * @brief Casts one GameObject handle type to another.
  248. */
  249. template<class _Ty1, class _Ty2>
  250. GameObjectHandle<_Ty1> static_object_cast(const GameObjectHandle<_Ty2>& other)
  251. {
  252. return GameObjectHandle<_Ty1>(other);
  253. }
  254. /**
  255. * @brief Compares if two handles point to the same GameObject.
  256. */
  257. template<class _Ty1, class _Ty2>
  258. bool operator==(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  259. {
  260. return (_Left.mData == nullptr && _Right.mData == nullptr) ||
  261. (_Left.mData != nullptr && _Right.mData != nullptr && _Left.mData->mInstanceId == _Right.mData->mInstanceId);
  262. }
  263. /**
  264. * @brief Compares if two handles point to different GameObjects.
  265. */
  266. template<class _Ty1, class _Ty2>
  267. bool operator!=(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  268. {
  269. return (!(_Left == _Right));
  270. }
  271. }