2
0

BsGameObjectHandle.h 7.8 KB

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