CmGameObjectHandle.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #pragma once
  2. namespace BansheeEngine
  3. {
  4. class GameObjectManager;
  5. struct CM_EXPORT GameObjectHandleData
  6. {
  7. GameObjectHandleData()
  8. :mPtr(nullptr), mInstanceId(0)
  9. { }
  10. GameObjectHandleData(const std::shared_ptr<GameObjectInstanceData>& ptr)
  11. {
  12. mPtr = ptr;
  13. if(ptr != nullptr)
  14. mInstanceId = ptr->object->getInstanceId();
  15. else
  16. mInstanceId = 0;
  17. }
  18. std::shared_ptr<GameObjectInstanceData> mPtr;
  19. UINT64 mInstanceId;
  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 I want the references between game objects 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 CM_EXPORT GameObjectHandleBase : public IReflectable
  33. {
  34. public:
  35. GameObjectHandleBase();
  36. /**
  37. * @brief Checks if the object has been destroyed
  38. */
  39. bool isDestroyed() const { return mData->mPtr == nullptr || mData->mPtr->object == nullptr; }
  40. /**
  41. * @brief Internal method only. Not meant to be called directly.
  42. */
  43. std::shared_ptr<GameObjectHandleData> getHandleData() const { return mData; }
  44. UINT64 getInstanceId() const { return mData->mInstanceId; }
  45. void resolve(const GameObjectHandleBase& object);
  46. GameObject* get() const
  47. {
  48. throwIfDestroyed();
  49. return mData->mPtr->object.get();
  50. }
  51. std::shared_ptr<GameObject> getInternalPtr() const
  52. {
  53. throwIfDestroyed();
  54. return mData->mPtr->object;
  55. }
  56. GameObject* operator->() const { return get(); }
  57. GameObject& operator*() const { return *get(); }
  58. protected:
  59. friend class SceneObject;
  60. friend class SceneObjectRTTI;
  61. friend class GameObjectManager;
  62. GameObjectHandleBase(const std::shared_ptr<GameObject> ptr);
  63. GameObjectHandleBase(const std::shared_ptr<GameObjectHandleData>& data);
  64. GameObjectHandleBase(std::nullptr_t ptr);
  65. inline void throwIfDestroyed() const;
  66. void destroy()
  67. {
  68. // We need to clear mData->mPtr before we clear mData->mPtr->object,
  69. // as this handle could be stored within the "object" and destroyed when
  70. // we set it to null
  71. std::shared_ptr<GameObjectInstanceData> instanceData = mData->mPtr;
  72. mData->mPtr = nullptr;
  73. if(instanceData != nullptr)
  74. instanceData->object = nullptr;
  75. }
  76. std::shared_ptr<GameObjectHandleData> mData;
  77. /************************************************************************/
  78. /* RTTI */
  79. /************************************************************************/
  80. public:
  81. friend class GameObjectHandleRTTI;
  82. static RTTITypeBase* getRTTIStatic();
  83. virtual RTTITypeBase* getRTTI() const;
  84. };
  85. // NOTE: It is important this class contains no data since we often value
  86. // cast it to its base
  87. template <typename T>
  88. class GameObjectHandle : public GameObjectHandleBase
  89. {
  90. public:
  91. GameObjectHandle()
  92. :GameObjectHandleBase()
  93. {
  94. mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>();
  95. }
  96. template <typename T1>
  97. GameObjectHandle(const GameObjectHandle<T1>& ptr)
  98. :GameObjectHandleBase()
  99. {
  100. mData = ptr.getHandleData();
  101. }
  102. GameObjectHandle(const GameObjectHandleBase& ptr)
  103. :GameObjectHandleBase()
  104. {
  105. mData = ptr.getHandleData();
  106. }
  107. inline GameObjectHandle<T>& operator=(std::nullptr_t ptr)
  108. {
  109. mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>();
  110. return *this;
  111. }
  112. inline operator GameObjectHandleBase()
  113. {
  114. GameObjectHandleBase base(mData);
  115. return base;
  116. }
  117. T* get() const
  118. {
  119. throwIfDestroyed();
  120. return reinterpret_cast<T*>(mData->mPtr->object.get());
  121. }
  122. std::shared_ptr<T> getInternalPtr() const
  123. {
  124. throwIfDestroyed();
  125. return std::static_pointer_cast<T>(mData->mPtr->object);
  126. }
  127. T* operator->() const { return get(); }
  128. T& operator*() const { return *get(); }
  129. template<class _Ty>
  130. struct CM_Bool_struct
  131. {
  132. int _Member;
  133. };
  134. // Conversion to bool
  135. // (Why not just directly convert to bool? Because then we can assign pointer to bool and that's weird)
  136. operator int CM_Bool_struct<T>::*() const
  137. {
  138. return (((mData->mPtr != nullptr) && (mData->mPtr->object != nullptr)) ? &CM_Bool_struct<T>::_Member : 0);
  139. }
  140. private:
  141. friend class SceneObject;
  142. friend class SceneObjectRTTI;
  143. friend class GameObjectManager;
  144. explicit GameObjectHandle(const std::shared_ptr<T> ptr)
  145. :GameObjectHandleBase(ptr)
  146. { }
  147. };
  148. template<class _Ty1, class _Ty2>
  149. GameObjectHandle<_Ty1> static_object_cast(const GameObjectHandle<_Ty2>& other)
  150. {
  151. return GameObjectHandle<_Ty1>(other);
  152. }
  153. template<class _Ty1, class _Ty2>
  154. bool operator==(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  155. {
  156. return (_Left == nullptr && _Right == nullptr) || (_Left != nullptr && _Right != nullptr && _Left.get() == _Right.get());
  157. }
  158. template<class _Ty1, class _Ty2>
  159. bool operator!=(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  160. {
  161. return (!(_Left == _Right));
  162. }
  163. }