CmGameObjectHandle.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #pragma once
  2. namespace CamelotFramework
  3. {
  4. struct CM_EXPORT GameObjectHandleData
  5. {
  6. GameObjectHandleData()
  7. :mPtr(nullptr), mDeleter(nullptr)
  8. { }
  9. GameObjectHandleData(GameObject* ptr, void(*deleter)(GameObject*))
  10. {
  11. mPtr = ptr;
  12. mDeleter = deleter;
  13. }
  14. typedef void(*HandleDeleter)(GameObject*);
  15. GameObject* mPtr;
  16. HandleDeleter mDeleter;
  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
  30. {
  31. public:
  32. GameObjectHandleBase(const std::shared_ptr<GameObjectHandleData> data);
  33. /**
  34. * @brief Checks if the object has been destroyed
  35. */
  36. bool isDestroyed() const { return mData->mPtr == nullptr; }
  37. /**
  38. * @brief Internal method only. Not meant to be called directly.
  39. */
  40. std::shared_ptr<GameObjectHandleData> getHandleData() const { return mData; }
  41. GameObject* get() const
  42. {
  43. throwIfDestroyed();
  44. return mData->mPtr;
  45. }
  46. GameObject* operator->() const { return get(); }
  47. GameObject& operator*() const { return *get(); }
  48. protected:
  49. friend SceneObject;
  50. GameObjectHandleBase();
  51. inline void throwIfDestroyed() const;
  52. void destroy()
  53. {
  54. if(mData->mPtr != nullptr)
  55. {
  56. GameObject* toDelete = mData->mPtr;
  57. mData->mPtr = nullptr; // Need to set this to null before deleting, otherwise destructor thinks object isn't destroyed
  58. // and we end up here again
  59. if(mData->mDeleter != nullptr)
  60. mData->mDeleter(toDelete);
  61. else
  62. delete toDelete;
  63. }
  64. }
  65. std::shared_ptr<GameObjectHandleData> mData;
  66. };
  67. // NOTE: It is important this class contains no data since we often value
  68. // cast it to its base
  69. template <typename T>
  70. class GameObjectHandle : public GameObjectHandleBase
  71. {
  72. public:
  73. GameObjectHandle()
  74. :GameObjectHandleBase()
  75. {
  76. mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>();
  77. }
  78. template <typename T1>
  79. GameObjectHandle(const GameObjectHandle<T1>& ptr)
  80. :GameObjectHandleBase()
  81. {
  82. mData = ptr.getHandleData();
  83. }
  84. inline GameObjectHandle<T>& operator=(std::nullptr_t ptr)
  85. {
  86. mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>();
  87. mData->mPtr = nullptr;
  88. return *this;
  89. }
  90. inline operator GameObjectHandleBase()
  91. {
  92. GameObjectHandleBase base(mData);
  93. return base;
  94. }
  95. T* get() const
  96. {
  97. throwIfDestroyed();
  98. return reinterpret_cast<T*>(mData->mPtr);
  99. }
  100. T* operator->() const { return get(); }
  101. T& operator*() const { return *get(); }
  102. template<class _Ty>
  103. struct CM_Bool_struct
  104. {
  105. int _Member;
  106. };
  107. // Conversion to bool
  108. // (Why not just directly convert to bool? Because then we can assign pointer to bool and that's weird)
  109. operator int CM_Bool_struct<T>::*() const
  110. {
  111. return (((mData->mPtr != nullptr)) ? &CM_Bool_struct<T>::_Member : 0);
  112. }
  113. private:
  114. friend SceneObject;
  115. explicit GameObjectHandle(T* ptr, void(*deleter)(GameObject*) = nullptr)
  116. :GameObjectHandleBase()
  117. {
  118. mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>((GameObject*)ptr, deleter);
  119. }
  120. };
  121. template<class _Ty1, class _Ty2>
  122. GameObjectHandle<_Ty1> static_object_cast(const GameObjectHandle<_Ty2>& other)
  123. {
  124. return GameObjectHandle<_Ty1>(other);
  125. }
  126. template<class _Ty1, class _Ty2>
  127. bool operator==(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  128. {
  129. return (_Left.get() == _Right.get());
  130. }
  131. template<class _Ty1, class _Ty2>
  132. bool operator!=(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  133. {
  134. return (!(_Left == _Right));
  135. }
  136. }