diff --git a/SDK/include/NDK/EntityList.hpp b/SDK/include/NDK/EntityList.hpp index 3b4f1580a..7602b6b21 100644 --- a/SDK/include/NDK/EntityList.hpp +++ b/SDK/include/NDK/EntityList.hpp @@ -16,6 +16,7 @@ namespace Ndk class NDK_API EntityList { friend Entity; + friend World; public: class iterator; @@ -23,16 +24,16 @@ namespace Ndk using size_type = std::size_t; inline EntityList(); - inline EntityList(const EntityList& entityList); - inline EntityList(EntityList&& entityList) noexcept; - inline ~EntityList(); + EntityList(const EntityList& entityList); + EntityList(EntityList&& entityList) noexcept; + ~EntityList(); - inline void Clear(); + void Clear(); inline bool Has(const Entity* entity) const; inline bool Has(EntityId entity) const; - inline void Insert(Entity* entity); + void Insert(Entity* entity); inline void Remove(Entity* entity); inline void Reserve(std::size_t entityCount); @@ -50,6 +51,7 @@ namespace Ndk inline std::size_t FindNext(std::size_t currentId) const; inline World* GetWorld() const; inline void NotifyEntityDestruction(const Entity* entity); + inline void SetWorld(World* world); Nz::Bitset m_entityBits; World* m_world; diff --git a/SDK/include/NDK/EntityList.inl b/SDK/include/NDK/EntityList.inl index a34165a68..27dfbb48d 100644 --- a/SDK/include/NDK/EntityList.inl +++ b/SDK/include/NDK/EntityList.inl @@ -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 #include #include @@ -21,52 +22,6 @@ namespace Ndk { } - /*! - * \brief Construct a new entity list by copying another one - */ - inline EntityList::EntityList(const EntityList& entityList) : - m_entityBits(entityList.m_entityBits), - m_world(entityList.m_world) - { - for (const Ndk::EntityHandle& entity : *this) - entity->RegisterEntityList(this); - } - - /*! - * \brief Construct a new entity list by moving a list into this one - */ - inline EntityList::EntityList(EntityList&& entityList) noexcept : - m_entityBits(std::move(entityList.m_entityBits)), - m_world(entityList.m_world) - { - for (const Ndk::EntityHandle& entity : *this) - { - entity->UnregisterEntityList(&entityList); - entity->RegisterEntityList(this); - } - } - - inline EntityList::~EntityList() - { - for (const Ndk::EntityHandle& entity : *this) - entity->UnregisterEntityList(this); - } - - - /*! - * \brief Clears the set from every entities - * - * \remark This resets the implicit world member, allowing you to insert entities from a different world than previously - */ - inline void EntityList::Clear() - { - for (const Ndk::EntityHandle& entity : *this) - entity->UnregisterEntityList(this); - - m_entityBits.Clear(); - m_world = nullptr; - } - /*! * \brief Checks whether or not the EntityList contains the entity * \return true If it is the case @@ -93,29 +48,6 @@ namespace Ndk return m_entityBits.UnboundedTest(entity); } - /*! - * \brief Inserts the entity into the set - * - * Marks an entity as present in this entity list, it must belongs to the same world as others entities contained in this list. - * - * \param entity Valid pointer to an entity - * - * \remark If entity is already contained, no action is performed - * \remark If any entity has been inserted since construction (or last Clear call), the entity must belong to the same world as the previously inserted entities - */ - inline void EntityList::Insert(Entity* entity) - { - NazaraAssert(entity, "Invalid entity"); - - if (!Has(entity)) - { - entity->RegisterEntityList(this); - - m_entityBits.UnboundedSet(entity->GetId(), true); - m_world = entity->GetWorld(); - } - } - /*! * \brief Removes the entity from the set * @@ -167,40 +99,6 @@ namespace Ndk return m_entityBits.Count(); } - inline EntityList& EntityList::operator=(const EntityList& entityList) - { - for (const Ndk::EntityHandle& entity : *this) - entity->UnregisterEntityList(this); - - m_entityBits = entityList.m_entityBits; - m_world = entityList.m_world; - - for (const Ndk::EntityHandle& entity : *this) - entity->RegisterEntityList(this); - - return *this; - } - - inline EntityList& EntityList::operator=(EntityList&& entityList) noexcept - { - if (this == &entityList) - return *this; - - for (const Ndk::EntityHandle& entity : *this) - entity->UnregisterEntityList(this); - - m_entityBits = std::move(entityList.m_entityBits); - m_world = entityList.m_world; - - for (const Ndk::EntityHandle& entity : *this) - { - entity->UnregisterEntityList(&entityList); - entity->RegisterEntityList(this); - } - - return *this; - } - inline std::size_t EntityList::FindNext(std::size_t currentId) const { return m_entityBits.FindNext(currentId); @@ -218,6 +116,11 @@ namespace Ndk m_entityBits.Reset(entity->GetId()); } + inline void EntityList::SetWorld(World* world) + { + m_world = world; + } + inline EntityList::iterator::iterator(const EntityList* list, std::size_t nextId) : m_nextEntityId(nextId), diff --git a/SDK/include/NDK/World.hpp b/SDK/include/NDK/World.hpp index ca6e917b7..072ce0637 100644 --- a/SDK/include/NDK/World.hpp +++ b/SDK/include/NDK/World.hpp @@ -26,6 +26,7 @@ namespace Ndk { friend BaseSystem; friend Entity; + friend EntityList; public: using EntityVector = std::vector; @@ -97,7 +98,9 @@ namespace Ndk inline void Invalidate(); inline void Invalidate(EntityId id); inline void InvalidateSystemOrder(); + inline void RegisterEntityList(EntityList* list); void ReorderSystems(); + inline void UnregisterEntityList(EntityList* list); struct DoubleBitset { @@ -123,6 +126,7 @@ namespace Ndk std::vector m_orderedSystems; std::vector m_entities; std::vector m_entityBlocks; + std::vector m_referencedByLists; std::vector> m_waitingEntities; EntityList m_aliveEntities; ProfilerData m_profilerData; diff --git a/SDK/include/NDK/World.inl b/SDK/include/NDK/World.inl index 1c3e446e1..85a34c9cc 100644 --- a/SDK/include/NDK/World.inl +++ b/SDK/include/NDK/World.inl @@ -443,25 +443,31 @@ namespace Ndk m_dirtyEntities = std::move(world.m_dirtyEntities); m_entityBlocks = std::move(world.m_entityBlocks); m_freeEntityIds = std::move(world.m_freeEntityIds); + m_isProfilerEnabled = world.m_isProfilerEnabled; m_killedEntities = std::move(world.m_killedEntities); m_orderedSystems = std::move(world.m_orderedSystems); m_orderedSystemsUpdated = world.m_orderedSystemsUpdated; m_profilerData = std::move(world.m_profilerData); - m_isProfilerEnabled = world.m_isProfilerEnabled; + m_referencedByLists = std::move(world.m_referencedByLists); m_entities = std::move(world.m_entities); for (EntityBlock& block : m_entities) block.entity.SetWorld(this); + for (EntityList* list : m_referencedByLists) + list->SetWorld(this); + m_waitingEntities = std::move(world.m_waitingEntities); for (auto& blockPtr : m_waitingEntities) blockPtr->entity.SetWorld(this); m_systems = std::move(world.m_systems); for (const auto& systemPtr : m_systems) + { if (systemPtr) systemPtr->SetWorld(this); - + } + return *this; } @@ -480,4 +486,19 @@ namespace Ndk { m_orderedSystemsUpdated = false; } + + inline void World::RegisterEntityList(EntityList* list) + { + m_referencedByLists.push_back(list); + } + + inline void World::UnregisterEntityList(EntityList* list) + { + auto it = std::find(m_referencedByLists.begin(), m_referencedByLists.end(), list); + assert(it != m_referencedByLists.end()); + + // Swap and pop idiom + *it = m_referencedByLists.back(); + m_referencedByLists.pop_back(); + } } diff --git a/SDK/src/NDK/EntityList.cpp b/SDK/src/NDK/EntityList.cpp index 49841843d..fdae20097 100644 --- a/SDK/src/NDK/EntityList.cpp +++ b/SDK/src/NDK/EntityList.cpp @@ -7,6 +7,149 @@ namespace Ndk { + /*! + * \brief Construct a new entity list by copying another one + */ + EntityList::EntityList(const EntityList& entityList) : + m_entityBits(entityList.m_entityBits), + m_world(entityList.m_world) + { + for (const Ndk::EntityHandle& entity : *this) + entity->RegisterEntityList(this); + + if (m_world) + m_world->RegisterEntityList(this); + } + + /*! + * \brief Construct a new entity list by moving a list into this one + */ + EntityList::EntityList(EntityList&& entityList) noexcept : + m_entityBits(std::move(entityList.m_entityBits)), + m_world(entityList.m_world) + { + for (const Ndk::EntityHandle& entity : *this) + { + entity->UnregisterEntityList(&entityList); + entity->RegisterEntityList(this); + } + + if (m_world) + { + m_world->UnregisterEntityList(&entityList); + m_world->RegisterEntityList(this); + + entityList.m_world = nullptr; + } + } + + EntityList::~EntityList() + { + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + + if (m_world) + m_world->UnregisterEntityList(this); + } + + + /*! + * \brief Clears the set from every entities + * + * \remark This resets the implicit world member, allowing you to insert entities from a different world than previously + */ + void EntityList::Clear() + { + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + + m_entityBits.Clear(); + + if (m_world) + { + m_world->UnregisterEntityList(this); + m_world = nullptr; + } + } + + /*! + * \brief Inserts the entity into the set + * + * Marks an entity as present in this entity list, it must belongs to the same world as others entities contained in this list. + * + * \param entity Valid pointer to an entity + * + * \remark If entity is already contained, no action is performed + * \remark If any entity has been inserted since construction (or last Clear call), the entity must belong to the same world as the previously inserted entities + */ + void EntityList::Insert(Entity* entity) + { + NazaraAssert(entity, "Invalid entity"); + + if (!Has(entity)) + { + entity->RegisterEntityList(this); + + m_entityBits.UnboundedSet(entity->GetId(), true); + if (!m_world) + { + m_world = entity->GetWorld(); + m_world->RegisterEntityList(this); + } + } + } + + EntityList& EntityList::operator=(const EntityList& entityList) + { + if (m_world) + m_world->UnregisterEntityList(this); + + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + + m_entityBits = entityList.m_entityBits; + m_world = entityList.m_world; + + for (const Ndk::EntityHandle& entity : *this) + entity->RegisterEntityList(this); + + if (m_world) + m_world->RegisterEntityList(this); + + return *this; + } + + EntityList& EntityList::operator=(EntityList&& entityList) noexcept + { + if (this == &entityList) + return *this; + + if (m_world) + m_world->UnregisterEntityList(this); + + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + + m_entityBits = std::move(entityList.m_entityBits); + m_world = entityList.m_world; + + if (m_world) + { + m_world->UnregisterEntityList(&entityList); + m_world->RegisterEntityList(this); + + entityList.m_world = nullptr; + } + + for (const Ndk::EntityHandle& entity : *this) + { + entity->UnregisterEntityList(&entityList); + entity->RegisterEntityList(this); + } + + return *this; + } + const EntityHandle& EntityList::iterator::operator*() const { return m_list->GetWorld()->GetEntity(static_cast(m_nextEntityId)); diff --git a/SDK/src/NDK/World.cpp b/SDK/src/NDK/World.cpp index ef59463bc..9b255c71e 100644 --- a/SDK/src/NDK/World.cpp +++ b/SDK/src/NDK/World.cpp @@ -131,6 +131,11 @@ namespace Ndk } m_entityBlocks.clear(); + // Reset world for entity lists + for (EntityList* list : m_referencedByLists) + list->SetWorld(nullptr); + m_referencedByLists.clear(); + m_entities.clear(); m_waitingEntities.clear();