diff --git a/headers/Systems/ECS.hpp b/headers/Systems/ECS.hpp index 794db3e..e97fa91 100644 --- a/headers/Systems/ECS.hpp +++ b/headers/Systems/ECS.hpp @@ -6,15 +6,16 @@ * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. */ + #ifndef GUARD_TOURMALINE_ECS_H #define GUARD_TOURMALINE_ECS_H #include #include #include #include -#include #include +#include "../Containers/DualkeyMap.hpp" #include "../Types.hpp" #include "Logging.hpp" @@ -42,105 +43,48 @@ public: Entity CreateEntity(); bool EntityExists(const Entity &entity) noexcept; [[nodiscard("It is not guaranteed that an entity can always be destroyed, " - "please make " - "sure by checking the returned bool")]] + "please make sure by checking the returned bool")]] bool DestroyEntity(Entity entity); // Components - template - T &AddComponent(const Entity &entity, Args &&...constructionArguments) { - auto entityIter = GetEntityIterator( - entity, - std::format( - "Cannot add component \"{}\"! Entity \"{}\" does not exist!", - typeid(T).name(), entity.asString()), - "AddComponent", Systems::Logging::LogLevel::Error); + template + component &AddComponent(const Entity &entity, + Args &&...constructionArguments) { + auto newComponent = entityComponentMap.insert( + entity, typeid(component), component(constructionArguments...)); - auto [componentIter, success] = entityIter->second.try_emplace( - typeid(T), T(std::forward(constructionArguments)...)); - Systems::Logging::Log( - std::format("Cannot add component! Component \"{}\" already exists " - "in entity \"{}\" ", - typeid(T).name(), entity.asString()), - "AddComponent", Systems::Logging::LogLevel::Error, !success); - - T &component = std::any_cast(componentIter->second); - component.owner = &entity; - return component; + return std::any_cast(std::get<2>(newComponent)); } - template + template [[nodiscard("Discarding an expensive operation's result!")]] - T &GetComponent(const Entity &entity) { - auto iter = GetEntityIterator( - entity, - std::format("Can't get entity \"{}\"'s component \"{}\", since " - "entity does not exist!", - entity.asString(), typeid(T).name()), - "GetComponent", Systems::Logging::LogLevel::Error); - - auto component = iter->second.find(typeid(T)); - Systems::Logging::Log( - std::format( - "Entity \"{}\" does not have component \"{}\", cannot get it!", - entity.asString(), typeid(T).name()), - "GetComponent", Systems::Logging::LogLevel::Error, - component == iter->second.end()); - - return std::any_cast(component->second); + component &GetComponent(const Entity &entity) { + auto result = entityComponentMap.query(entity, typeid(component)); + if (result.empty()) { + Logging::Log(std::format("Entity {} does not have component {}!", + entity.asString(), typeid(component).name()), + "ECS/GetComponent", Logging::LogLevel::Error); + } + return std::any_cast(result.begin()->second); } - template + template [[nodiscard("Discarding an expensive operation's result!")]] bool HasComponent(const Entity &entity) { - auto iter = GetEntityIterator( - entity, - std::format("Can't find if entity \"{}\" has component \"{}\", since " - "entity does not exist!", - entity.asString(), typeid(T).name())); - - return iter != entityComponentList.end() && - (iter->second.find(typeid(T)) != iter->second.end()); - } - - template - [[nodiscard("It is not guaranteed that a component can always be removed, " - "please make " - "sure by checking the returned bool")]] - bool RemoveComponent(const Entity &entity) { - auto entityIter = GetEntityIterator( - entity, - std::format("Cannot remove component {} from entity {}, since entity " - "does not exist!", - typeid(T).name(), entity.asString()), - "RemoveComponent", Systems::Logging::LogLevel::Warning); - if (entityIter == entityComponentList.end()) { - return false; - } - - auto componentIter = entityIter->second.find(typeid(T)); - if (componentIter == entityIter->second.end()) { - Systems::Logging::Log( - std::format("Cannot remove component {} from entity {}, since entity " - "does not have that component", - typeid(T).name(), entity.asString()), - "RemoveComponent", Systems::Logging::LogLevel::Warning); - return false; - } - - entityIter->second.erase(componentIter); + // TO BE IMPLEMENTED return true; } -private: - std::unordered_map> - entityComponentList{}; + template + [[nodiscard("It is not guaranteed that a component can always be removed, " + "please make sure by checking the returned bool")]] + bool RemoveComponent(const Entity &entity) { + return entityComponentMap.remove(entity, typeid(component)); + } - decltype(entityComponentList)::iterator - GetEntityIterator(const Entity &entity, const std::string &errorMessage = "", - const std::string &position = "", - Tourmaline::Systems::Logging::LogLevel severity = - Systems::Logging::LogLevel::Warning); +private: + Tourmaline::Containers::DualkeyMap + entityComponentMap{}; }; } // namespace Tourmaline::Systems::ECS #endif diff --git a/source/Systems/ECS/World.cpp b/source/Systems/ECS/World.cpp index 67ebdef..394bcfe 100644 --- a/source/Systems/ECS/World.cpp +++ b/source/Systems/ECS/World.cpp @@ -8,48 +8,27 @@ */ #include +#include #include +#include using namespace Tourmaline::Systems::ECS; +// It is preferable to send a copy of the UUID instead of reference since +// the entity itself may be destroyed in the memory Entity World::CreateEntity() { - auto [iterator, success] = - entityComponentList.try_emplace(Systems::Random::GenerateUUID()); + auto newEntity = entityComponentMap.insert( + Random::GenerateUUID(), typeid(Tourmaline::Systems::Components::Position), + Tourmaline::Systems::Components::Position()); - Systems::Logging::Log("Failed to create an entity! Possibly by incredible " - "luck generated already existing UUID?", - "CreateEntity", Systems::Logging::LogLevel::Critical, - !success); - return iterator->first; + return Entity(std::get<0>(newEntity)); } bool World::EntityExists(const Entity &entity) noexcept { - return entityComponentList.find(entity) != entityComponentList.end(); -} - -bool World::DestroyEntity(Entity entity) { - auto entityIter = GetEntityIterator( - entity, - std::format("Cannot delete entity \"{}\", it does not exist!", - entity.asString()), - "DestroyEntity"); - - if (entityIter == entityComponentList.end()) { - return false; - } - - entityComponentList.erase(entityIter); + // TO BE IMPLEMENTED return true; } -// Very repetitive code -decltype(World::entityComponentList)::iterator -World::GetEntityIterator(const Entity &entity, const std::string &errorMessage, - const std::string &position, - Tourmaline::Systems::Logging::LogLevel severity) { - auto iter = entityComponentList.find(entity); - - Systems::Logging::Log(errorMessage, "GetEntityIterator/" + position, severity, - iter == entityComponentList.end()); - return iter; +bool World::DestroyEntity(Entity entity) { + return entityComponentMap.remove(entity, std::nullopt); }