Core/ObjectHandle: Remade object handle system
This commit is contained in:
parent
3933d5007d
commit
4c4822eef9
|
|
@ -151,6 +151,7 @@ Nazara Engine:
|
|||
- Added TcpClient::PollForConnected
|
||||
- ⚠️ Use of the new Angle class instead of floating point angle
|
||||
- It is now possible to set elasticity/friction/surface bodies of 2D colliders and change it at runtime on RigidBody2D
|
||||
- ObjectHandle were remade and should be way more optimized now
|
||||
|
||||
Nazara Development Kit:
|
||||
- Added ImageWidget (#139)
|
||||
|
|
@ -219,6 +220,7 @@ Nazara Development Kit:
|
|||
- EntityOwner constructor taking a Entity* is no longer explicit
|
||||
- PhysicsComponent2D now allows massless bodies (zero mass)
|
||||
- ⚠️ Use of the new Angle class instead of floating point angle
|
||||
- Added EntityOwner::Release
|
||||
|
||||
# 0.4:
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
#define NDK_ENTITY_HPP
|
||||
|
||||
#include <Nazara/Core/Bitset.hpp>
|
||||
#include <Nazara/Core/HandledObject.hpp>
|
||||
#include <Nazara/Core/MovablePtr.hpp>
|
||||
#include <Nazara/Core/ObjectHandle.hpp>
|
||||
#include <Nazara/Core/Signal.hpp>
|
||||
#include <NDK/Algorithm.hpp>
|
||||
#include <NDK/Prerequisites.hpp>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ namespace Ndk
|
|||
EntityOwner(EntityOwner&& handle) noexcept = default;
|
||||
~EntityOwner();
|
||||
|
||||
void Release();
|
||||
void Reset(Entity* entity = nullptr);
|
||||
void Reset(EntityOwner&& handle);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NDK/EntityOwner.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
|
|
@ -36,16 +37,23 @@ namespace Ndk
|
|||
Reset(nullptr);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Release the ownership of the entity without killing it
|
||||
*/
|
||||
inline void EntityOwner::Release()
|
||||
{
|
||||
EntityHandle::Reset(nullptr);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the ownership of the entity, previous is killed
|
||||
*
|
||||
* \param entity Entity to own
|
||||
*/
|
||||
|
||||
inline void EntityOwner::Reset(Entity* entity)
|
||||
{
|
||||
if (m_object)
|
||||
m_object->Kill();
|
||||
if (IsValid())
|
||||
GetObject()->Kill();
|
||||
|
||||
EntityHandle::Reset(entity);
|
||||
}
|
||||
|
|
@ -55,11 +63,10 @@ namespace Ndk
|
|||
*
|
||||
* \param handle EntityOwner to move into this
|
||||
*/
|
||||
|
||||
inline void EntityOwner::Reset(EntityOwner&& handle)
|
||||
{
|
||||
Reset(handle.GetObject());
|
||||
handle.m_object = nullptr;
|
||||
handle.Release();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -13,6 +13,16 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
struct NAZARA_CORE_API HandleData
|
||||
{
|
||||
void* object;
|
||||
|
||||
static std::shared_ptr<HandleData> GetEmptyObject();
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T> class ObjectHandle;
|
||||
|
||||
template<typename T>
|
||||
|
|
@ -35,11 +45,10 @@ namespace Nz
|
|||
void UnregisterAllHandles() noexcept;
|
||||
|
||||
private:
|
||||
void RegisterHandle(ObjectHandle<T>* handle);
|
||||
void UnregisterHandle(ObjectHandle<T>* handle) noexcept;
|
||||
void UpdateHandle(ObjectHandle<T>* oldHandle, ObjectHandle<T>* newHandle) noexcept;
|
||||
std::shared_ptr<const Detail::HandleData> GetHandleData();
|
||||
void InitHandleData();
|
||||
|
||||
std::vector<ObjectHandle<T>*> m_handles;
|
||||
std::shared_ptr<Detail::HandleData> m_handleData;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Core/HandledObject.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ObjectHandle.hpp>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
|
|
@ -35,10 +36,10 @@ namespace Nz
|
|||
*/
|
||||
template<typename T>
|
||||
HandledObject<T>::HandledObject(HandledObject&& object) noexcept :
|
||||
m_handles(std::move(object.m_handles))
|
||||
m_handleData(std::move(object.m_handleData))
|
||||
{
|
||||
for (ObjectHandle<T>* handle : m_handles)
|
||||
handle->OnObjectMoved(static_cast<T*>(this));
|
||||
if (m_handleData)
|
||||
m_handleData->object = static_cast<T*>(this);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -74,7 +75,7 @@ namespace Nz
|
|||
NazaraUnused(object);
|
||||
|
||||
// Nothing to do
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -88,73 +89,42 @@ namespace Nz
|
|||
{
|
||||
UnregisterAllHandles();
|
||||
|
||||
m_handles = std::move(object.m_handles);
|
||||
for (ObjectHandle<T>* handle : m_handles)
|
||||
handle->OnObjectMoved(static_cast<T*>(this));
|
||||
m_handleData = std::move(object.m_handleData);
|
||||
|
||||
if (m_handleData)
|
||||
m_handleData->object = static_cast<T*>(this);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Registers a handle
|
||||
*
|
||||
* \param handle Handle to register
|
||||
*
|
||||
* \remark One handle can only be registered once, errors can occur if it's more than once
|
||||
*/
|
||||
template<typename T>
|
||||
void HandledObject<T>::RegisterHandle(ObjectHandle<T>* handle)
|
||||
{
|
||||
m_handles.push_back(handle);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Unregisters all handles
|
||||
*/
|
||||
template<typename T>
|
||||
void HandledObject<T>::UnregisterAllHandles() noexcept
|
||||
{
|
||||
// Tell every handle we got destroyed, to null them
|
||||
for (ObjectHandle<T>* handle : m_handles)
|
||||
handle->OnObjectDestroyed();
|
||||
|
||||
m_handles.clear();
|
||||
if (m_handleData)
|
||||
{
|
||||
m_handleData->object = nullptr;
|
||||
m_handleData.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Unregisters a handle
|
||||
*
|
||||
* \param handle Handle to unregister
|
||||
*
|
||||
* \remark One handle can only be unregistered once, crash can occur if it's more than once
|
||||
* \remark Produces a NazaraAssert if handle not registered
|
||||
*/
|
||||
template<typename T>
|
||||
void HandledObject<T>::UnregisterHandle(ObjectHandle<T>* handle) noexcept
|
||||
std::shared_ptr<const Detail::HandleData> HandledObject<T>::GetHandleData()
|
||||
{
|
||||
auto it = std::find(m_handles.begin(), m_handles.end(), handle);
|
||||
NazaraAssert(it != m_handles.end(), "Handle not registered");
|
||||
if (!m_handleData)
|
||||
InitHandleData();
|
||||
|
||||
// Swap and pop idiom, more efficient than vector::erase
|
||||
std::swap(*it, m_handles.back());
|
||||
m_handles.pop_back();
|
||||
return std::shared_ptr<const Detail::HandleData>(m_handleData);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates one handle with another
|
||||
*
|
||||
* \param oldHandle Old handle to replace
|
||||
* \param newHandle New handle to take place
|
||||
*
|
||||
* \remark Produces a NazaraAssert if handle not registered
|
||||
*/
|
||||
template<typename T>
|
||||
void HandledObject<T>::UpdateHandle(ObjectHandle<T>* oldHandle, ObjectHandle<T>* newHandle) noexcept
|
||||
void HandledObject<T>::InitHandleData()
|
||||
{
|
||||
auto it = std::find(m_handles.begin(), m_handles.end(), oldHandle);
|
||||
NazaraAssert(it != m_handles.end(), "Handle not registered");
|
||||
assert(!m_handleData);
|
||||
|
||||
// Simply update the handle
|
||||
*it = newHandle;
|
||||
m_handleData = std::make_shared<Detail::HandleData>();
|
||||
m_handleData->object = static_cast<T*>(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@
|
|||
#define NAZARA_OBJECTHANDLE_HPP
|
||||
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/HandledObject.hpp>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
template<typename T> class HandledObject;
|
||||
|
||||
template<typename T>
|
||||
class ObjectHandle
|
||||
{
|
||||
|
|
@ -22,7 +22,7 @@ namespace Nz
|
|||
public:
|
||||
ObjectHandle();
|
||||
explicit ObjectHandle(T* object);
|
||||
ObjectHandle(const ObjectHandle& handle);
|
||||
ObjectHandle(const ObjectHandle& handle) = default;
|
||||
ObjectHandle(ObjectHandle&& handle) noexcept;
|
||||
~ObjectHandle();
|
||||
|
||||
|
|
@ -43,16 +43,13 @@ namespace Nz
|
|||
T* operator->() const;
|
||||
|
||||
ObjectHandle& operator=(T* object);
|
||||
ObjectHandle& operator=(const ObjectHandle& handle);
|
||||
ObjectHandle& operator=(const ObjectHandle& handle) = default;
|
||||
ObjectHandle& operator=(ObjectHandle&& handle) noexcept;
|
||||
|
||||
static const ObjectHandle InvalidHandle;
|
||||
|
||||
protected:
|
||||
void OnObjectDestroyed() noexcept;
|
||||
void OnObjectMoved(T* newObject) noexcept;
|
||||
|
||||
T* m_object;
|
||||
std::shared_ptr<const Detail::HandleData> m_handleData;
|
||||
};
|
||||
|
||||
template<typename T> std::ostream& operator<<(std::ostream& out, const ObjectHandle<T>& handle);
|
||||
|
|
|
|||
|
|
@ -15,37 +15,15 @@ namespace Nz
|
|||
* \brief Core class that represents a object handle
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a ObjectHandle object by default
|
||||
*/
|
||||
template<typename T>
|
||||
ObjectHandle<T>::ObjectHandle() :
|
||||
m_object(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a ObjectHandle object with a pointer to an object
|
||||
*
|
||||
* \param object Pointer to handle like an object (can be nullptr)
|
||||
*/
|
||||
template<typename T>
|
||||
ObjectHandle<T>::ObjectHandle(T* object) :
|
||||
ObjectHandle()
|
||||
ObjectHandle<T>::ObjectHandle() :
|
||||
m_handleData(Detail::HandleData::GetEmptyObject())
|
||||
{
|
||||
Reset(object);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a ObjectHandle object by assignation
|
||||
*
|
||||
* \param handle ObjectHandle to assign into this
|
||||
*/
|
||||
template<typename T>
|
||||
ObjectHandle<T>::ObjectHandle(const ObjectHandle& handle) :
|
||||
ObjectHandle()
|
||||
{
|
||||
Reset(handle);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -54,12 +32,22 @@ namespace Nz
|
|||
* \param handle ObjectHandle to move into this
|
||||
*/
|
||||
template<typename T>
|
||||
ObjectHandle<T>::ObjectHandle(ObjectHandle&& handle) noexcept :
|
||||
ObjectHandle()
|
||||
ObjectHandle<T>::ObjectHandle(ObjectHandle&& handle) noexcept
|
||||
{
|
||||
Reset(std::move(handle));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a ObjectHandle object with a pointer to an object
|
||||
*
|
||||
* \param object Pointer to handle like an object (can be nullptr)
|
||||
*/
|
||||
template<typename T>
|
||||
ObjectHandle<T>::ObjectHandle(T* object)
|
||||
{
|
||||
Reset(object);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and calls reset with nullptr
|
||||
*
|
||||
|
|
@ -78,7 +66,7 @@ namespace Nz
|
|||
template<typename T>
|
||||
T* ObjectHandle<T>::GetObject() const
|
||||
{
|
||||
return m_object;
|
||||
return static_cast<T*>(m_handleData->object);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -88,7 +76,7 @@ namespace Nz
|
|||
template<typename T>
|
||||
bool ObjectHandle<T>::IsValid() const
|
||||
{
|
||||
return m_object != nullptr;
|
||||
return m_handleData->object != nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -99,14 +87,10 @@ namespace Nz
|
|||
template<typename T>
|
||||
void ObjectHandle<T>::Reset(T* object)
|
||||
{
|
||||
// If we already have an entity, we must alert it that we are not pointing to it anymore
|
||||
if (m_object)
|
||||
m_object->UnregisterHandle(this);
|
||||
|
||||
m_object = object;
|
||||
if (m_object)
|
||||
// We alert the new entity that we are pointing to it
|
||||
m_object->RegisterHandle(this);
|
||||
if (object)
|
||||
m_handleData = object->GetHandleData();
|
||||
else
|
||||
m_handleData = Detail::HandleData::GetEmptyObject();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -117,7 +101,7 @@ namespace Nz
|
|||
template<typename T>
|
||||
void ObjectHandle<T>::Reset(const ObjectHandle& handle)
|
||||
{
|
||||
Reset(handle.GetObject());
|
||||
m_handleData = handle.m_handleData;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -128,20 +112,8 @@ namespace Nz
|
|||
template<typename T>
|
||||
void ObjectHandle<T>::Reset(ObjectHandle&& handle) noexcept
|
||||
{
|
||||
if (this == &handle)
|
||||
return;
|
||||
|
||||
if (m_object)
|
||||
m_object->UnregisterHandle(this);
|
||||
|
||||
if (T* object = handle.GetObject())
|
||||
{
|
||||
m_object = handle.m_object;
|
||||
handle.m_object = nullptr;
|
||||
object->UpdateHandle(&handle, this);
|
||||
}
|
||||
else
|
||||
m_object = nullptr;
|
||||
m_handleData = std::move(handle.m_handleData);
|
||||
handle.m_handleData = Detail::HandleData::GetEmptyObject();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -153,23 +125,8 @@ namespace Nz
|
|||
template<typename T>
|
||||
ObjectHandle<T>& ObjectHandle<T>::Swap(ObjectHandle& handle)
|
||||
{
|
||||
// As we swap the two handles, we must alert the entities
|
||||
// The default version with swap (move) would be working,
|
||||
// but will register handles one more time (due to temporary copy).
|
||||
if (m_object)
|
||||
{
|
||||
m_object->UnregisterHandle(this);
|
||||
m_object->RegisterHandle(&handle);
|
||||
}
|
||||
|
||||
if (handle.m_object)
|
||||
{
|
||||
handle.m_object->UnregisterHandle(&handle);
|
||||
handle.m_object->RegisterHandle(this);
|
||||
}
|
||||
|
||||
// We do the swap
|
||||
std::swap(m_object, handle.m_object);
|
||||
std::swap(m_handleData, handle.m_handleData);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -183,7 +140,7 @@ namespace Nz
|
|||
Nz::StringStream ss;
|
||||
ss << "ObjectHandle(";
|
||||
if (IsValid())
|
||||
ss << m_object->ToString();
|
||||
ss << GetObject()->ToString();
|
||||
else
|
||||
ss << "Null";
|
||||
|
||||
|
|
@ -211,7 +168,7 @@ namespace Nz
|
|||
template<typename T>
|
||||
ObjectHandle<T>::operator T*() const
|
||||
{
|
||||
return m_object;
|
||||
return GetObject();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -221,7 +178,7 @@ namespace Nz
|
|||
template<typename T>
|
||||
T* ObjectHandle<T>::operator->() const
|
||||
{
|
||||
return m_object;
|
||||
return GetObject();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -231,23 +188,9 @@ namespace Nz
|
|||
* \param entity Pointer to handle like an object (can be nullptr)
|
||||
*/
|
||||
template<typename T>
|
||||
ObjectHandle<T>& ObjectHandle<T>::operator=(T* entity)
|
||||
ObjectHandle<T>& ObjectHandle<T>::operator=(T* object)
|
||||
{
|
||||
Reset(entity);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the handle of the ObjectHandle with the handle from another
|
||||
* \return A reference to this
|
||||
*
|
||||
* \param handle The other ObjectHandle
|
||||
*/
|
||||
template<typename T>
|
||||
ObjectHandle<T>& ObjectHandle<T>::operator=(const ObjectHandle& handle)
|
||||
{
|
||||
Reset(handle);
|
||||
Reset(object);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -266,26 +209,6 @@ namespace Nz
|
|||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Action to do on object destruction
|
||||
*/
|
||||
template<typename T>
|
||||
void ObjectHandle<T>::OnObjectDestroyed() noexcept
|
||||
{
|
||||
// Shortcut
|
||||
m_object = nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Action to do on object move
|
||||
*/
|
||||
template<typename T>
|
||||
void ObjectHandle<T>::OnObjectMoved(T* newObject) noexcept
|
||||
{
|
||||
// The object has been moved, update our pointer
|
||||
m_object = newObject;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Output operator
|
||||
* \return The stream
|
||||
|
|
@ -388,7 +311,7 @@ namespace Nz
|
|||
template<typename T>
|
||||
bool operator<(const ObjectHandle<T>& lhs, const ObjectHandle<T>& rhs)
|
||||
{
|
||||
return lhs.m_object < rhs.m_object;
|
||||
return lhs.GetObject() < rhs.GetObject();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -401,7 +324,7 @@ namespace Nz
|
|||
template<typename T>
|
||||
bool operator<(const T& lhs, const ObjectHandle<T>& rhs)
|
||||
{
|
||||
return &lhs < rhs.m_object;
|
||||
return &lhs < rhs.GetObject();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -414,7 +337,7 @@ namespace Nz
|
|||
template<typename T>
|
||||
bool operator<(const ObjectHandle<T>& lhs, const T& rhs)
|
||||
{
|
||||
return lhs.m_object < &rhs;
|
||||
return lhs.GetObject() < &rhs;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/HandledObject.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
std::shared_ptr<HandleData> HandleData::GetEmptyObject()
|
||||
{
|
||||
static std::shared_ptr<HandleData> emptyHandleData = std::make_shared<HandleData>(HandleData{});
|
||||
return emptyHandleData;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue