BsGameObjectHandle.h 7.5 KB

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