From aa304ef2e9fbfa261364b2400d1f34ce31a0fdce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 8 Nov 2016 02:51:25 +0100 Subject: [PATCH] SDK: Allow to set an update order for systems (Closes #106) --- SDK/include/NDK/BaseSystem.hpp | 3 ++ SDK/include/NDK/BaseSystem.inl | 20 +++++++++-- SDK/include/NDK/World.hpp | 5 +++ SDK/include/NDK/World.inl | 62 ++++++++++++++++++---------------- SDK/src/NDK/BaseSystem.cpp | 21 ++++++++++++ SDK/src/NDK/World.cpp | 18 ++++++++++ 6 files changed, 97 insertions(+), 32 deletions(-) diff --git a/SDK/include/NDK/BaseSystem.hpp b/SDK/include/NDK/BaseSystem.hpp index a4ff0bf41..7433f7d04 100644 --- a/SDK/include/NDK/BaseSystem.hpp +++ b/SDK/include/NDK/BaseSystem.hpp @@ -35,6 +35,7 @@ namespace Ndk inline const std::vector& GetEntities() const; inline SystemIndex GetIndex() const; + inline int GetUpdateOrder() const; inline float GetUpdateRate() const; inline World& GetWorld() const; @@ -42,6 +43,7 @@ namespace Ndk inline bool HasEntity(const Entity* entity) const; + void SetUpdateOrder(int updateOrder); inline void SetUpdateRate(float updatePerSecond); inline void Update(float elapsedTime); @@ -93,6 +95,7 @@ namespace Ndk bool m_updateEnabled; float m_updateCounter; float m_updateRate; + int m_updateOrder; static SystemIndex s_nextIndex; }; diff --git a/SDK/include/NDK/BaseSystem.inl b/SDK/include/NDK/BaseSystem.inl index 31a0c314e..79971e3d6 100644 --- a/SDK/include/NDK/BaseSystem.inl +++ b/SDK/include/NDK/BaseSystem.inl @@ -16,7 +16,9 @@ namespace Ndk inline BaseSystem::BaseSystem(SystemIndex systemId) : m_systemIndex(systemId), - m_updateEnabled(true) + m_world(nullptr), + m_updateEnabled(true), + m_updateOrder(0) { SetUpdateRate(30); } @@ -33,7 +35,8 @@ namespace Ndk m_systemIndex(system.m_systemIndex), m_updateEnabled(system.m_updateEnabled), m_updateCounter(0.f), - m_updateRate(system.m_updateRate) + m_updateRate(system.m_updateRate), + m_updateOrder(system.m_updateOrder) { } @@ -69,7 +72,18 @@ namespace Ndk } /*! - * \brief Gets the rate of update for the system + * \brief Gets the update order of the system + * \return Update order + * + * \see SetUpdateOrder + */ + inline int BaseSystem::GetUpdateOrder() const + { + return m_updateOrder; + } + + /*! + * \brief Gets the rate of update of the system * \return Update rate */ diff --git a/SDK/include/NDK/World.hpp b/SDK/include/NDK/World.hpp index 5d1dabb77..ded8c4ff5 100644 --- a/SDK/include/NDK/World.hpp +++ b/SDK/include/NDK/World.hpp @@ -24,6 +24,7 @@ namespace Ndk class NDK_API World : public Nz::HandledObject { + friend BaseSystem; friend Entity; public: @@ -72,6 +73,8 @@ namespace Ndk private: inline void Invalidate(); inline void Invalidate(EntityId id); + inline void InvalidateSystemOrder(); + void ReorderSystems(); struct EntityBlock { @@ -87,11 +90,13 @@ namespace Ndk }; std::vector> m_systems; + std::vector m_orderedSystems; std::vector m_entities; std::vector m_freeIdList; EntityList m_aliveEntities; Nz::Bitset m_dirtyEntities; Nz::Bitset m_killedEntities; + bool m_orderedSystemsUpdated; }; } diff --git a/SDK/include/NDK/World.inl b/SDK/include/NDK/World.inl index 9960aef05..b71df5926 100644 --- a/SDK/include/NDK/World.inl +++ b/SDK/include/NDK/World.inl @@ -53,6 +53,7 @@ namespace Ndk m_systems[index]->SetWorld(this); Invalidate(); // We force an update for every entities + InvalidateSystemOrder(); // And regenerate the system update list return *m_systems[index].get(); } @@ -206,6 +207,8 @@ namespace Ndk inline void World::RemoveAllSystems() { m_systems.clear(); + + InvalidateSystemOrder(); } /*! @@ -219,7 +222,11 @@ namespace Ndk inline void World::RemoveSystem(SystemIndex index) { if (HasSystem(index)) + { m_systems[index].reset(); + + InvalidateSystemOrder(); + } } /*! @@ -246,32 +253,11 @@ namespace Ndk Update(); //< Update entities // And then update systems - for (auto& systemPtr : m_systems) - { - if (systemPtr) - systemPtr->Update(elapsedTime); - } - } + if (!m_orderedSystemsUpdated) + ReorderSystems(); - /*! - * \brief Invalidates each entity in the world - */ - - inline void World::Invalidate() - { - m_dirtyEntities.Resize(m_entities.size(), false); - m_dirtyEntities.Set(true); // Activation of all bits - } - - /*! - * \brief Invalidates an entity in the world - * - * \param id Identifier of the entity - */ - - inline void World::Invalidate(EntityId id) - { - m_dirtyEntities.UnboundedSet(id, true); + for (auto& systemPtr : m_orderedSystems) + systemPtr->Update(elapsedTime); } /*! @@ -281,10 +267,12 @@ namespace Ndk inline World& World::operator=(World&& world) noexcept { - m_aliveEntities = std::move(world.m_aliveEntities); - m_dirtyEntities = std::move(world.m_dirtyEntities); - m_freeIdList = std::move(world.m_freeIdList); - m_killedEntities = std::move(world.m_killedEntities); + m_aliveEntities = std::move(world.m_aliveEntities); + m_dirtyEntities = std::move(world.m_dirtyEntities); + m_freeIdList = std::move(world.m_freeIdList); + m_killedEntities = std::move(world.m_killedEntities); + m_orderedSystems = std::move(world.m_orderedSystems); + m_orderedSystemsUpdated = world.m_orderedSystemsUpdated; m_entities = std::move(world.m_entities); for (EntityBlock& block : m_entities) @@ -296,4 +284,20 @@ namespace Ndk return *this; } + + inline void World::Invalidate() + { + m_dirtyEntities.Resize(m_entities.size(), false); + m_dirtyEntities.Set(true); // Activation of all bits + } + + inline void World::Invalidate(EntityId id) + { + m_dirtyEntities.UnboundedSet(id, true); + } + + inline void World::InvalidateSystemOrder() + { + m_orderedSystemsUpdated = false; + } } diff --git a/SDK/src/NDK/BaseSystem.cpp b/SDK/src/NDK/BaseSystem.cpp index 8a2a9dce5..e4ffd7c8e 100644 --- a/SDK/src/NDK/BaseSystem.cpp +++ b/SDK/src/NDK/BaseSystem.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Prerequesites.hpp #include +#include namespace Ndk { @@ -56,6 +57,26 @@ namespace Ndk return true; } + /*! + * \brief Sets the update order of this system + * + * The system update order is used by the world it belongs to in order to know in which order they should be updated, as some application logic may rely a specific update order. + * A system with a greater update order (ex: 1) is guaranteed to be updated after a system with a lesser update order (ex: -1), otherwise the order is unspecified (and is not guaranteed to be stable). + * + * \param updateOrder The relative update order of the system + * + * \remark The update order is only used by World::Update(float) and does not have any effect regarding a call to BaseSystem::Update(float) + * + * \see GetUpdateOrder + */ + inline void BaseSystem::SetUpdateOrder(int updateOrder) + { + m_updateOrder = updateOrder; + + if (m_world) + m_world->InvalidateSystemOrder(); + } + /*! * \brief Operation to perform when entity is added to the system * diff --git a/SDK/src/NDK/World.cpp b/SDK/src/NDK/World.cpp index 6ba110aee..270bae580 100644 --- a/SDK/src/NDK/World.cpp +++ b/SDK/src/NDK/World.cpp @@ -249,4 +249,22 @@ namespace Ndk } m_dirtyEntities.Reset(); } + + void World::ReorderSystems() + { + m_orderedSystems.clear(); + + for (auto& systemPtr : m_systems) + { + if (systemPtr) + m_orderedSystems.push_back(systemPtr.get()); + } + + std::sort(m_orderedSystems.begin(), m_orderedSystems.end(), [] (BaseSystem* first, BaseSystem* second) + { + return first->GetUpdateOrder() < second->GetUpdateOrder(); + }); + + m_orderedSystemsUpdated = true; + } }