CmGameObjectHandle.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. /**
  33. * @brief Checks if the object has been destroyed
  34. */
  35. bool isDestroyed() const { return mData->mPtr == nullptr; }
  36. /**
  37. * @brief Internal method only. Not meant to be called directly.
  38. */
  39. std::shared_ptr<GameObjectHandleData> getHandleData() const { return mData; }
  40. protected:
  41. friend SceneObject;
  42. GameObjectHandleBase();
  43. inline void throwIfDestroyed() const;
  44. void destroy()
  45. {
  46. if(mData->mPtr != nullptr)
  47. {
  48. GameObject* toDelete = mData->mPtr;
  49. mData->mPtr = nullptr; // Need to set this to null before deleting, otherwise destructor thinks object isn't destroyed
  50. // and we end up here again
  51. if(mData->mDeleter != nullptr)
  52. mData->mDeleter(toDelete);
  53. else
  54. delete toDelete;
  55. }
  56. }
  57. std::shared_ptr<GameObjectHandleData> mData;
  58. };
  59. template <typename T>
  60. class GameObjectHandle : public GameObjectHandleBase
  61. {
  62. public:
  63. GameObjectHandle()
  64. :GameObjectHandleBase()
  65. {
  66. mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>();
  67. }
  68. template <typename T1>
  69. GameObjectHandle(const GameObjectHandle<T1>& ptr)
  70. :GameObjectHandleBase()
  71. {
  72. mData = ptr.getHandleData();
  73. }
  74. inline GameObjectHandle<T>& operator=(std::nullptr_t ptr)
  75. {
  76. mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>();
  77. mData->mPtr = nullptr;
  78. return *this;
  79. }
  80. T* get() const
  81. {
  82. throwIfDestroyed();
  83. return reinterpret_cast<T*>(mData->mPtr);
  84. }
  85. T* operator->() const { return get(); }
  86. T& operator*() const { return *get(); }
  87. template<class _Ty>
  88. struct CM_Bool_struct
  89. {
  90. int _Member;
  91. };
  92. // Conversion to bool
  93. // (Why not just directly convert to bool? Because then we can assign pointer to bool and that's weird)
  94. operator int CM_Bool_struct<T>::*() const
  95. {
  96. return (((mData->mPtr != nullptr)) ? &CM_Bool_struct<T>::_Member : 0);
  97. }
  98. private:
  99. friend SceneObject;
  100. explicit GameObjectHandle(T* ptr, void(*deleter)(GameObject*) = nullptr)
  101. :GameObjectHandleBase()
  102. {
  103. mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>((GameObject*)ptr, deleter);
  104. }
  105. };
  106. template<class _Ty1, class _Ty2>
  107. GameObjectHandle<_Ty1> static_object_cast(const GameObjectHandle<_Ty2>& other)
  108. {
  109. return GameObjectHandle<_Ty1>(other);
  110. }
  111. template<class _Ty1, class _Ty2>
  112. bool operator==(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  113. {
  114. return (_Left.get() == _Right.get());
  115. }
  116. template<class _Ty1, class _Ty2>
  117. bool operator!=(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  118. {
  119. return (!(_Left == _Right));
  120. }
  121. }