CmGameObjectHandle.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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 = std::shared_ptr<GameObjectHandleData>(CM_NEW(GameObjectHandleData, PoolAlloc) GameObjectHandleData(),
  67. &MemAllocDeleter<GameObjectHandleData, PoolAlloc>::deleter);
  68. }
  69. template <typename T1>
  70. GameObjectHandle(const GameObjectHandle<T1>& ptr)
  71. :GameObjectHandleBase()
  72. {
  73. mData = ptr.getHandleData();
  74. }
  75. T* get() const
  76. {
  77. throwIfDestroyed();
  78. return reinterpret_cast<T*>(mData->mPtr);
  79. }
  80. T* operator->() const { return get(); }
  81. T& operator*() const { return *get(); }
  82. template<class _Ty>
  83. struct CM_Bool_struct
  84. {
  85. int _Member;
  86. };
  87. // Conversion to bool
  88. // (Why not just directly convert to bool? Because then we can assign pointer to bool and that's weird)
  89. operator int CM_Bool_struct<T>::*() const
  90. {
  91. return (((mData->mPtr != nullptr)) ? &CM_Bool_struct<T>::_Member : 0);
  92. }
  93. private:
  94. friend SceneObject;
  95. explicit GameObjectHandle(T* ptr, void(*deleter)(GameObject*) = nullptr)
  96. :GameObjectHandleBase()
  97. {
  98. mData = std::shared_ptr<GameObjectHandleData>(CM_NEW(GameObjectHandleData, PoolAlloc) GameObjectHandleData((GameObject*)ptr, deleter),
  99. &MemAllocDeleter<GameObjectHandleData, PoolAlloc>::deleter);
  100. }
  101. };
  102. template<class _Ty1, class _Ty2>
  103. GameObjectHandle<_Ty1> static_object_cast(const GameObjectHandle<_Ty2>& other)
  104. {
  105. return GameObjectHandle<_Ty1>(other);
  106. }
  107. template<class _Ty1, class _Ty2>
  108. bool operator==(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  109. {
  110. return (_Left.get() == _Right.get());
  111. }
  112. template<class _Ty1, class _Ty2>
  113. bool operator!=(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  114. {
  115. return (!(_Left == _Right));
  116. }
  117. }