| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- #pragma once
- namespace CamelotFramework
- {
- struct CM_EXPORT GameObjectHandleData
- {
- GameObjectHandleData()
- :mPtr(nullptr), mDeleter(nullptr)
- { }
- GameObjectHandleData(GameObject* ptr, void(*deleter)(GameObject*))
- {
- mPtr = ptr;
- mDeleter = deleter;
- }
- typedef void(*HandleDeleter)(GameObject*);
- GameObject* mPtr;
- HandleDeleter mDeleter;
- };
- /**
- * @brief A handle that can point to various types of game objects.
- * It primarily keeps track if the object is still alive, so anything
- * still referencing it doesn't accidentally use it.
- *
- * @note This class exists because I want the references between game objects be quite loose.
- * For example one game object should be able to reference another one without the other
- * one knowing. But if that is the case I also need to handle the case when the other
- * object we're referencing has been deleted, and that is the main purpose of this class.
- *
- */
- class CM_EXPORT GameObjectHandleBase
- {
- public:
- /**
- * @brief Checks if the object has been destroyed
- */
- bool isDestroyed() const { return mData->mPtr == nullptr; }
- /**
- * @brief Internal method only. Not meant to be called directly.
- */
- std::shared_ptr<GameObjectHandleData> getHandleData() const { return mData; }
- protected:
- friend SceneObject;
- GameObjectHandleBase();
- inline void throwIfDestroyed() const;
-
- void destroy()
- {
- if(mData->mPtr != nullptr)
- {
- GameObject* toDelete = mData->mPtr;
- mData->mPtr = nullptr; // Need to set this to null before deleting, otherwise destructor thinks object isn't destroyed
- // and we end up here again
- if(mData->mDeleter != nullptr)
- mData->mDeleter(toDelete);
- else
- delete toDelete;
- }
- }
- std::shared_ptr<GameObjectHandleData> mData;
- };
- template <typename T>
- class GameObjectHandle : public GameObjectHandleBase
- {
- public:
- GameObjectHandle()
- :GameObjectHandleBase()
- {
- mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>();
- }
- template <typename T1>
- GameObjectHandle(const GameObjectHandle<T1>& ptr)
- :GameObjectHandleBase()
- {
- mData = ptr.getHandleData();
- }
- T* get() const
- {
- throwIfDestroyed();
- return reinterpret_cast<T*>(mData->mPtr);
- }
- T* operator->() const { return get(); }
- T& operator*() const { return *get(); }
- template<class _Ty>
- struct CM_Bool_struct
- {
- int _Member;
- };
- // Conversion to bool
- // (Why not just directly convert to bool? Because then we can assign pointer to bool and that's weird)
- operator int CM_Bool_struct<T>::*() const
- {
- return (((mData->mPtr != nullptr)) ? &CM_Bool_struct<T>::_Member : 0);
- }
- private:
- friend SceneObject;
- explicit GameObjectHandle(T* ptr, void(*deleter)(GameObject*) = nullptr)
- :GameObjectHandleBase()
- {
- mData = cm_shared_ptr<GameObjectHandleData, PoolAlloc>((GameObject*)ptr, deleter);
- }
- };
- template<class _Ty1, class _Ty2>
- GameObjectHandle<_Ty1> static_object_cast(const GameObjectHandle<_Ty2>& other)
- {
- return GameObjectHandle<_Ty1>(other);
- }
- template<class _Ty1, class _Ty2>
- bool operator==(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
- {
- return (_Left.get() == _Right.get());
- }
- template<class _Ty1, class _Ty2>
- bool operator!=(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
- {
- return (!(_Left == _Right));
- }
- }
|