CmGameObjectHandle.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #pragma once
  2. namespace CamelotEngine
  3. {
  4. struct CM_EXPORT GameObjectHandleData
  5. {
  6. GameObjectHandleData()
  7. { }
  8. GameObjectHandleData(void* ptr)
  9. :mPtr(ptr)
  10. { }
  11. std::shared_ptr<void> mPtr;
  12. };
  13. /**
  14. * @brief A handle that can point to various types of game objects.
  15. * It primarily keeps track if the object is still alive, so anything
  16. * still referencing it doesn't accidentally use it.
  17. *
  18. * @note This class exists because I want the references between game objects be quite loose.
  19. * For example one game object should be able to reference another one without the other
  20. * one knowing. But if that is the case I also need to handle the case when the other
  21. * object we're referencing has been deleted, and that is the main purpose of this class.
  22. *
  23. */
  24. class CM_EXPORT GameObjectHandleBase
  25. {
  26. public:
  27. /**
  28. * @brief Checks if the object has been destroyed
  29. */
  30. bool isDestroyed() const { return mData->mPtr == nullptr; }
  31. /**
  32. * @brief Internal method only. Not meant to be called directly.
  33. */
  34. std::shared_ptr<GameObjectHandleData> getHandleData() const { return mData; }
  35. protected:
  36. GameObjectHandleBase();
  37. inline void throwIfDestroyed() const;
  38. std::shared_ptr<GameObjectHandleData> mData;
  39. };
  40. template <typename T>
  41. class GameObjectHandle : public GameObjectHandleBase
  42. {
  43. public:
  44. GameObjectHandle()
  45. :GameObjectHandleBase()
  46. {
  47. mData = std::shared_ptr<GameObjectHandleData>(new GameObjectHandleData());
  48. }
  49. template <typename T1>
  50. GameObjectHandle(const GameObjectHandle<T1>& ptr)
  51. :GameObjectHandleBase()
  52. {
  53. mData = ptr.getHandleData();
  54. }
  55. /**
  56. * @brief Creates a new handle. Internal use only. Don't call this manually.
  57. */
  58. static GameObjectHandle<T> _create(T* ptr)
  59. {
  60. return GameObjectHandle<T>(ptr);
  61. }
  62. T* get() const
  63. {
  64. throwIfDestroyed();
  65. return reinterpret_cast<T*>(mData->mPtr.get());
  66. }
  67. T* operator->() const { return get(); }
  68. T& operator*() const { return *get(); }
  69. std::shared_ptr<T> getInternalPtr() const
  70. {
  71. throwIfDestroyed();
  72. return std::static_pointer_cast<T>(mData->mPtr);
  73. }
  74. template<class _Ty>
  75. struct CM_Bool_struct
  76. {
  77. int _Member;
  78. };
  79. // Conversion to bool
  80. // (Why not just directly convert to bool? Because then we can assign pointer to bool and that's weird)
  81. operator int CM_Bool_struct<T>::*() const
  82. {
  83. return (((mData->mPtr != nullptr)) ? &CM_Bool_struct<T>::_Member : 0);
  84. }
  85. private:
  86. friend T;
  87. explicit GameObjectHandle(T* ptr)
  88. :GameObjectHandleBase()
  89. {
  90. mData = std::shared_ptr<GameObjectHandleData>(new GameObjectHandleData(ptr));
  91. }
  92. void releaseHeldObject()
  93. {
  94. mData->mPtr = nullptr;
  95. }
  96. };
  97. template<class _Ty1, class _Ty2>
  98. GameObjectHandle<_Ty1> static_object_cast(const GameObjectHandle<_Ty2>& other)
  99. {
  100. return GameObjectHandle<_Ty1>(other);
  101. }
  102. template<class _Ty1, class _Ty2>
  103. bool operator==(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  104. {
  105. return (_Left.get() == _Right.get());
  106. }
  107. template<class _Ty1, class _Ty2>
  108. bool operator!=(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
  109. {
  110. return (!(_Left == _Right));
  111. }
  112. }