CmGameObjectHandle.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #pragma once
  2. namespace CamelotFramework
  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. mInstanceId = ptr->object->getInstanceId();
  14. }
  15. std::shared_ptr<GameObjectInstanceData> mPtr;
  16. UINT64 mInstanceId;
  17. };
  18. /**
  19. * @brief A handle that can point to various types of game objects.
  20. * It primarily keeps track if the object is still alive, so anything
  21. * still referencing it doesn't accidentally use it.
  22. *
  23. * @note This class exists because I want the references between game objects be quite loose.
  24. * For example one game object should be able to reference another one without the other
  25. * one knowing. But if that is the case I also need to handle the case when the other
  26. * object we're referencing has been deleted, and that is the main purpose of this class.
  27. *
  28. */
  29. class CM_EXPORT GameObjectHandleBase : public IReflectable
  30. {
  31. public:
  32. GameObjectHandleBase();
  33. /**
  34. * @brief Checks if the object has been destroyed
  35. */
  36. bool isDestroyed() const { return mData->mPtr == nullptr || mData->mPtr->object == nullptr; }
  37. /**
  38. * @brief Internal method only. Not meant to be called directly.
  39. */
  40. std::shared_ptr<GameObjectHandleData> getHandleData() const { return mData; }
  41. UINT64 getInstanceId() const { return mData->mInstanceId; }
  42. void resolve(const GameObjectHandleBase& object);
  43. GameObject* get() const
  44. {
  45. throwIfDestroyed();
  46. return mData->mPtr->object.get();
  47. }
  48. std::shared_ptr<GameObject> getInternalPtr() const
  49. {
  50. throwIfDestroyed();
  51. return mData->mPtr->object;
  52. }
  53. GameObject* operator->() const { return get(); }
  54. GameObject& operator*() const { return *get(); }
  55. protected:
  56. friend class SceneObject;
  57. friend class SceneObjectRTTI;
  58. friend class GameObjectManager;
  59. GameObjectHandleBase(const std::shared_ptr<GameObject> ptr);
  60. GameObjectHandleBase(const std::shared_ptr<GameObjectHandleData>& data);
  61. GameObjectHandleBase(std::nullptr_t ptr);
  62. inline void throwIfDestroyed() const;
  63. void destroy()
  64. {
  65. if(mData->mPtr != nullptr)
  66. mData->mPtr->object = nullptr;
  67. mData->mPtr = nullptr;
  68. }
  69. std::shared_ptr<GameObjectHandleData> mData;
  70. /************************************************************************/
  71. /* RTTI */
  72. /************************************************************************/
  73. public:
  74. friend class GameObjectHandleRTTI;
  75. static RTTITypeBase* getRTTIStatic();
  76. virtual RTTITypeBase* getRTTI() const;
  77. };
  78. // NOTE: It is important this class contains no data since we often value
  79. // cast it to its base
  80. template <typename T>
  81. class GameObjectHandle : public GameObjectHandleBase
  82. {
  83. public:
  84. GameObjectHandle()
  85. :GameObjectHandleBase()
  86. {
  87. mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>();
  88. }
  89. template <typename T1>
  90. GameObjectHandle(const GameObjectHandle<T1>& ptr)
  91. :GameObjectHandleBase()
  92. {
  93. mData = ptr.getHandleData();
  94. }
  95. GameObjectHandle(const GameObjectHandleBase& ptr)
  96. :GameObjectHandleBase()
  97. {
  98. mData = ptr.getHandleData();
  99. }
  100. inline GameObjectHandle<T>& operator=(std::nullptr_t ptr)
  101. {
  102. mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>();
  103. return *this;
  104. }
  105. inline operator GameObjectHandleBase()
  106. {
  107. GameObjectHandleBase base(mData);
  108. return base;
  109. }
  110. T* get() const
  111. {
  112. throwIfDestroyed();
  113. return reinterpret_cast<T*>(mData->mPtr->object.get());
  114. }
  115. std::shared_ptr<T> getInternalPtr() const
  116. {
  117. throwIfDestroyed();
  118. return std::static_pointer_cast<T>(mData->mPtr->object);
  119. }
  120. T* operator->() const { return get(); }
  121. T& operator*() const { return *get(); }
  122. template<class _Ty>
  123. struct CM_Bool_struct
  124. {
  125. int _Member;
  126. };
  127. // Conversion to bool
  128. // (Why not just directly convert to bool? Because then we can assign pointer to bool and that's weird)
  129. operator int CM_Bool_struct<T>::*() const
  130. {
  131. return (((mData->mPtr != nullptr) && (mData->mPtr->object != nullptr)) ? &CM_Bool_struct<T>::_Member : 0);
  132. }
  133. private:
  134. friend class SceneObject;
  135. friend class SceneObjectRTTI;
  136. friend class GameObjectManager;
  137. explicit GameObjectHandle(const std::shared_ptr<T> ptr)
  138. :GameObjectHandleBase(ptr)
  139. { }
  140. };
  141. template<class _Ty1, class _Ty2>
  142. GameObjectHandle<_Ty1> static_object_cast(const GameObjectHandle<_Ty2>& other)
  143. {
  144. return GameObjectHandle<_Ty1>(other);
  145. }
  146. template<class _Ty1, class _Ty2>
  147. bool operator==(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  148. {
  149. return (_Left == nullptr && _Right == nullptr) || (_Left != nullptr && _Right != nullptr && _Left.get() == _Right.get());
  150. }
  151. template<class _Ty1, class _Ty2>
  152. bool operator!=(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  153. {
  154. return (!(_Left == _Right));
  155. }
  156. }