BsGameObjectHandle.h 7.8 KB

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