Add generic handlers

Former-commit-id: 8fc343d3a056de8031cf453748b8801d50d3710e
This commit is contained in:
Lynix
2016-03-31 21:14:22 +02:00
parent a2f6e54104
commit a77ad42fcb
16 changed files with 542 additions and 423 deletions

View File

@@ -7,7 +7,7 @@
#ifndef NDK_BASECOMPONENT_HPP
#define NDK_BASECOMPONENT_HPP
#include <NDK/EntityHandle.hpp>
#include <NDK/Entity.hpp>
#include <functional>
#include <unordered_map>
#include <vector>

View File

@@ -8,7 +8,7 @@
#define NDK_BASESYSTEM_HPP
#include <Nazara/Core/Bitset.hpp>
#include <NDK/EntityHandle.hpp>
#include <NDK/Entity.hpp>
#include <vector>
namespace Ndk

View File

@@ -8,6 +8,7 @@
#define NDK_ENTITY_HPP
#include <Nazara/Core/Bitset.hpp>
#include <Nazara/Core/HandledObject.hpp>
#include <NDK/Algorithm.hpp>
#include <memory>
#include <vector>
@@ -15,13 +16,14 @@
namespace Ndk
{
class BaseComponent;
class EntityHandle;
class Entity;
class World;
class NDK_API Entity
using EntityHandle = Nz::ObjectHandle<Entity>;
class NDK_API Entity : public Nz::HandledObject<Entity>
{
friend class BaseSystem;
friend EntityHandle;
friend World;
public:
@@ -32,8 +34,6 @@ namespace Ndk
BaseComponent& AddComponent(std::unique_ptr<BaseComponent>&& component);
template<typename ComponentType, typename... Args> ComponentType& AddComponent(Args&&... args);
EntityHandle CreateHandle();
inline void Enable(bool enable);
inline BaseComponent& GetComponent(ComponentIndex index);
@@ -56,6 +56,8 @@ namespace Ndk
void RemoveComponent(ComponentIndex index);
template<typename ComponentType> void RemoveComponent();
inline Nz::String ToString() const;
Entity& operator=(const Entity&) = delete;
Entity& operator=(Entity&&) = delete;
@@ -65,16 +67,13 @@ namespace Ndk
void Create();
void Destroy();
inline void RegisterHandle(EntityHandle* handle);
inline void RegisterSystem(SystemIndex index);
inline void SetWorld(World* world) noexcept;
inline void UnregisterHandle(EntityHandle* handle);
inline void UnregisterSystem(SystemIndex index);
std::vector<std::unique_ptr<BaseComponent>> m_components;
std::vector<EntityHandle*> m_handles;
Nz::Bitset<> m_componentBits;
Nz::Bitset<> m_systemBits;
EntityId m_id;

View File

@@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <algorithm>
#include <type_traits>
#include <utility>
@@ -102,10 +103,10 @@ namespace Ndk
RemoveComponent(index);
}
inline void Entity::RegisterHandle(EntityHandle* handle)
inline Nz::String Entity::ToString() const
{
///DOC: Un handle ne doit être enregistré qu'une fois, des erreurs se produisent s'il l'est plus d'une fois
m_handles.push_back(handle);
Nz::StringStream ss;
return ss << "Entity(" << GetId() << ')';
}
inline void Entity::RegisterSystem(SystemIndex index)
@@ -120,18 +121,24 @@ namespace Ndk
m_world = world;
}
inline void Entity::UnregisterHandle(EntityHandle* handle)
{
///DOC: Un handle ne doit être libéré qu'une fois, et doit faire partie de la liste, sous peine de crash
auto it = std::find(m_handles.begin(), m_handles.end(), handle);
// On échange cet élément avec le dernier, et on diminue la taille du vector de 1
std::swap(*it, m_handles.back());
m_handles.pop_back();
}
inline void Entity::UnregisterSystem(SystemIndex index)
{
m_systemBits.UnboundedReset(index);
}
}
namespace std
{
template<>
struct hash<Ndk::EntityHandle>
{
size_t operator()(const Ndk::EntityHandle& handle) const
{
// Hasher le pointeur fonctionnerait jusqu'à ce que l'entité soit mise à jour et déplacée
// pour cette raison, nous devons hasher l'ID de l'entité (qui reste constante)
Ndk::EntityId id = (handle.IsValid()) ? handle->GetId() : std::numeric_limits<Ndk::EntityId>::max();
return hash<Ndk::EntityId>()(id);
}
};
}

View File

@@ -1,89 +0,0 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#pragma once
#ifndef NDK_ENTITYHANDLE_HPP
#define NDK_ENTITYHANDLE_HPP
#include <NDK/Entity.hpp>
#include <ostream>
namespace Ndk
{
class EntityHandle
{
friend Entity;
public:
EntityHandle();
explicit EntityHandle(Entity* entity);
EntityHandle(const EntityHandle& handle);
EntityHandle(EntityHandle&& handle);
~EntityHandle();
Entity* GetEntity() const;
bool IsValid() const;
void Reset(Entity* entity = nullptr);
void Reset(const EntityHandle& handle);
void Reset(EntityHandle&& handle);
EntityHandle& Swap(EntityHandle& handle);
Nz::String ToString() const;
operator bool() const;
operator Entity*() const;
Entity* operator->() const;
EntityHandle& operator=(Entity* entity);
EntityHandle& operator=(const EntityHandle& handle);
EntityHandle& operator=(EntityHandle&& handle);
friend std::ostream& operator<<(std::ostream& out, const EntityHandle& handle);
friend bool operator==(const EntityHandle& lhs, const EntityHandle& rhs);
friend bool operator==(const Entity& lhs, const EntityHandle& rhs);
friend bool operator==(const EntityHandle& lhs, const Entity& rhs);
friend bool operator!=(const EntityHandle& lhs, const EntityHandle& rhs);
friend bool operator!=(const Entity& lhs, const EntityHandle& rhs);
friend bool operator!=(const EntityHandle& lhs, const Entity& rhs);
friend bool operator<(const EntityHandle& lhs, const EntityHandle& rhs);
friend bool operator<(const Entity& lhs, const EntityHandle& rhs);
friend bool operator<(const EntityHandle& lhs, const Entity& rhs);
friend bool operator<=(const EntityHandle& lhs, const EntityHandle& rhs);
friend bool operator<=(const Entity& lhs, const EntityHandle& rhs);
friend bool operator<=(const EntityHandle& lhs, const Entity& rhs);
friend bool operator>(const EntityHandle& lhs, const EntityHandle& rhs);
friend bool operator>(const Entity& lhs, const EntityHandle& rhs);
friend bool operator>(const EntityHandle& lhs, const Entity& rhs);
friend bool operator>=(const EntityHandle& lhs, const EntityHandle& rhs);
friend bool operator>=(const Entity& lhs, const EntityHandle& rhs);
friend bool operator>=(const EntityHandle& lhs, const Entity& rhs);
static const EntityHandle InvalidHandle;
protected:
void OnEntityDestroyed();
void OnEntityMoved(Entity* newEntity);
Entity* m_entity;
};
}
namespace std
{
void swap(Ndk::EntityHandle& lhs, Ndk::EntityHandle& rhs);
}
#include <NDK/EntityHandle.inl>
#endif // NDK_ENTITYHANDLE_HPP

View File

@@ -1,280 +0,0 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <Nazara/Core/StringStream.hpp>
#include <functional>
#include <limits>
namespace Ndk
{
inline EntityHandle::EntityHandle() :
m_entity(nullptr)
{
}
inline EntityHandle::EntityHandle(Entity* entity) :
EntityHandle()
{
Reset(entity);
}
inline EntityHandle::EntityHandle(const EntityHandle& handle) :
EntityHandle()
{
Reset(handle);
}
inline EntityHandle::EntityHandle(EntityHandle&& handle) :
EntityHandle()
{
Reset(handle);
}
inline EntityHandle::~EntityHandle()
{
Reset(nullptr);
}
inline Entity* EntityHandle::GetEntity() const
{
return m_entity;
}
inline bool EntityHandle::IsValid() const
{
return m_entity != nullptr;
}
inline void EntityHandle::Reset(Entity* entity)
{
// Si nous avions déjà une entité, nous devons l'informer que nous ne pointons plus sur elle
if (m_entity)
m_entity->UnregisterHandle(this);
m_entity = entity;
if (m_entity)
// On informe la nouvelle entité que nous pointons sur elle
m_entity->RegisterHandle(this);
}
inline void EntityHandle::Reset(const EntityHandle& handle)
{
Reset(handle.GetEntity());
}
inline void EntityHandle::Reset(EntityHandle&& handle)
{
Reset(handle.GetEntity());
}
inline EntityHandle& EntityHandle::Swap(EntityHandle& handle)
{
// Comme nous inversons les handles, nous devons prévenir les entités
// La version par défaut de swap (à base de move) aurait fonctionné,
// mais en enregistrant les handles une fois de plus que nécessaire (à cause de la copie temporaire).
if (m_entity)
{
m_entity->UnregisterHandle(this);
m_entity->RegisterHandle(&handle);
}
if (handle.m_entity)
{
handle.m_entity->UnregisterHandle(&handle);
handle.m_entity->RegisterHandle(this);
}
// On effectue l'échange
std::swap(m_entity, handle.m_entity);
return *this;
}
inline Nz::String EntityHandle::ToString() const
{
Nz::StringStream ss;
ss << "EntityHandle(";
if (IsValid())
ss << "Entity(" << m_entity->GetId() << ')';
else
ss << "Null entity";
ss << ')';
return ss;
}
inline EntityHandle::operator bool() const
{
return IsValid();
}
inline EntityHandle::operator Entity*() const
{
return m_entity;
}
inline Entity* EntityHandle::operator->() const
{
return m_entity;
}
inline EntityHandle& EntityHandle::operator=(Entity* entity)
{
Reset(entity);
return *this;
}
inline EntityHandle& EntityHandle::operator=(const EntityHandle& handle)
{
Reset(handle);
return *this;
}
inline EntityHandle& EntityHandle::operator=(EntityHandle&& handle)
{
Reset(std::move(handle));
return *this;
}
inline void EntityHandle::OnEntityDestroyed()
{
// Un raccourci, un appel à Reset nous enlèverait de la liste des handles que nous ne pouvons pas modifier
// maintenant car elle est actuellement parcourue
m_entity = nullptr;
}
inline void EntityHandle::OnEntityMoved(Entity* newEntity)
{
// L'entité a été déplacée (peut arriver lors d'un changement de taille du conteneur du monde)
// nous mettons à jour notre pointeur
m_entity = newEntity;
}
inline std::ostream& operator<<(std::ostream& out, const EntityHandle& handle)
{
out << "EntityHandle(";
if (handle.IsValid())
out << "Entity(" << handle->GetId() << ')';
else
out << "Null entity";
out << ')';
return out;
}
inline bool operator==(const EntityHandle& lhs, const EntityHandle& rhs)
{
return lhs.m_entity == rhs.m_entity;
}
inline bool operator==(const Entity& lhs, const EntityHandle& rhs)
{
return &lhs == rhs.m_entity;
}
inline bool operator==(const EntityHandle& lhs, const Entity& rhs)
{
return lhs.m_entity == &rhs;
}
inline bool operator!=(const EntityHandle& lhs, const EntityHandle& rhs)
{
return !(lhs == rhs);
}
inline bool operator!=(const Entity& lhs, const EntityHandle& rhs)
{
return !(lhs == rhs);
}
inline bool operator!=(const EntityHandle& lhs, const Entity& rhs)
{
return !(lhs == rhs);
}
inline bool operator<(const EntityHandle& lhs, const EntityHandle& rhs)
{
return lhs.m_entity < rhs.m_entity;
}
inline bool operator<(const Entity& lhs, const EntityHandle& rhs)
{
return &lhs < rhs.m_entity;
}
inline bool operator<(const EntityHandle& lhs, const Entity& rhs)
{
return lhs.m_entity < &rhs;
}
inline bool operator<=(const EntityHandle& lhs, const EntityHandle& rhs)
{
return !(lhs > rhs);
}
inline bool operator<=(const Entity& lhs, const EntityHandle& rhs)
{
return !(lhs > rhs);
}
inline bool operator<=(const EntityHandle& lhs, const Entity& rhs)
{
return !(lhs > rhs);
}
inline bool operator>(const EntityHandle& lhs, const EntityHandle& rhs)
{
return rhs < lhs;
}
inline bool operator>(const Entity& lhs, const EntityHandle& rhs)
{
return rhs < lhs;
}
inline bool operator>(const EntityHandle& lhs, const Entity& rhs)
{
return rhs < lhs;
}
inline bool operator>=(const EntityHandle& lhs, const EntityHandle& rhs)
{
return !(lhs < rhs);
}
inline bool operator>=(const Entity& lhs, const EntityHandle& rhs)
{
return !(lhs < rhs);
}
inline bool operator>=(const EntityHandle& lhs, const Entity& rhs)
{
return !(lhs < rhs);
}
}
namespace std
{
template<>
struct hash<Ndk::EntityHandle>
{
size_t operator()(const Ndk::EntityHandle& handle) const
{
// Hasher le pointeur fonctionnerait jusqu'à ce que l'entité soit mise à jour et déplacée
// pour cette raison, nous devons hasher l'ID de l'entité (qui reste constante)
Ndk::EntityId id = (handle.IsValid()) ? handle->GetId() : std::numeric_limits<Ndk::EntityId>::max();
return hash<Ndk::EntityId>()(id);
}
};
inline void swap(Ndk::EntityHandle& lhs, Ndk::EntityHandle& rhs)
{
lhs.Swap(rhs);
}
}

View File

@@ -9,7 +9,7 @@
#include <Nazara/Core/Bitset.hpp>
#include <NDK/Prerequesites.hpp>
#include <NDK/EntityHandle.hpp>
#include <NDK/Entity.hpp>
namespace Ndk
{

View File

@@ -7,7 +7,7 @@
#ifndef NDK_ENTITYOWNER_HPP
#define NDK_ENTITYOWNER_HPP
#include <NDK/EntityHandle.hpp>
#include <NDK/Entity.hpp>
namespace Ndk
{

View File

@@ -26,16 +26,16 @@ namespace Ndk
inline void EntityOwner::Reset(Entity* entity)
{
if (m_entity)
m_entity->Kill();
if (m_object)
m_object->Kill();
EntityHandle::Reset(entity);
}
inline void EntityOwner::Reset(EntityOwner&& handle)
{
Reset(handle.GetEntity());
handle.m_entity = nullptr;
Reset(handle.GetObject());
handle.m_object = nullptr;
}
inline EntityOwner& EntityOwner::operator=(Entity* entity)

View File

@@ -4,14 +4,13 @@
#include <NDK/Entity.hpp>
#include <NDK/BaseComponent.hpp>
#include <NDK/EntityHandle.hpp>
#include <NDK/World.hpp>
namespace Ndk
{
Entity::Entity(Entity&& entity) :
HandledObject(std::move(entity)),
m_components(std::move(entity.m_components)),
m_handles(std::move(entity.m_handles)),
m_componentBits(std::move(entity.m_componentBits)),
m_systemBits(std::move(entity.m_systemBits)),
m_id(entity.m_id),
@@ -19,8 +18,6 @@ namespace Ndk
m_enabled(entity.m_enabled),
m_valid(entity.m_valid)
{
for (EntityHandle* handle : m_handles)
handle->OnEntityMoved(this);
}
Entity::Entity(World* world, EntityId id) :
@@ -63,11 +60,6 @@ namespace Ndk
return component;
}
EntityHandle Entity::CreateHandle()
{
return EntityHandle(this);
}
void Entity::Kill()
{
m_world->KillEntity(this);
@@ -132,11 +124,7 @@ namespace Ndk
}
m_systemBits.Clear();
// On informe chaque handle de notre destruction pour éviter qu'il ne continue de pointer sur nous
for (EntityHandle* handle : m_handles)
handle->OnEntityDestroyed();
m_handles.clear();
UnregisterAllHandles();
m_valid = false;
}

View File

@@ -1,10 +0,0 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <NDK/EntityHandle.hpp>
namespace Ndk
{
const EntityHandle EntityHandle::InvalidHandle;
}

View File

@@ -61,7 +61,7 @@ namespace Ndk
void World::Clear() noexcept
{
///DOC: Tous les handles sont correctement invalidés
///DOC: Tous les handles sont correctement invalidés, les entités sont immédiatement invalidées
// Destruction des entités d'abord, et des handles ensuite
// ceci pour éviter que les handles n'informent les entités inutilement lors de leur destruction