// // Created by Daniu // #ifndef EU07_ECWORLD_H #define EU07_ECWORLD_H #pragma once #include #include #include #include #include // Forward declaration so the name-index branch in AddComponent compiles in // translation units that include ECWorld.h without BasicComponents.h. // if constexpr discards the branch for non-Identification T, but the name must // still resolve at parse time. namespace ECSComponent { struct Identification; } class ECWorld { public: ECWorld() = default; ~ECWorld() = default; entt::entity CreateEntity(); void DestroyEntity(entt::entity entity); void Clear(); // Updates the name→entity index after an Identification component's Name is changed at runtime. void UpdateNameIndex(entt::entity entity, const std::string &name); bool IsAlive(entt::entity entity) const; entt::registry& Registry(); const entt::registry& Registry() const; template T& AddComponent(entt::entity entity, Args&&... args); template bool HasComponent(entt::entity entity) const; template T* GetComponent(entt::entity entity); template const T* GetComponent(entt::entity entity) const; template void RemoveComponent(entt::entity entity); entt::entity FindEntityByName(const std::string& name) const; template auto View() { return m_registry.view(); } template void Each(Func&& func) { auto view = m_registry.view(); for (auto entity : view) { auto components = std::forward_as_tuple(view.get(entity)...); std::apply([&](Components&... comps) { func(entity, comps...); }, components); } } // Same as Each but skips entities that have any of the Excluded components. // Usage: world.Each(entt::exclude, lambda) template void Each(entt::exclude_t, Func&& func) { auto view = m_registry.view(entt::exclude); for (auto entity : view) { auto components = std::forward_as_tuple(view.get(entity)...); std::apply([&](Components&... comps) { func(entity, comps...); }, components); } } std::vector GetEntities() const { std::vector entities; auto *storage = m_registry.storage(); for (auto entity : *storage) { entities.push_back(entity); } return entities; } std::size_t GetEntityCount() const { return m_registry.storage()->size(); } private: entt::registry m_registry; std::unordered_map m_nameIndex; }; template T& ECWorld::AddComponent(entt::entity entity, Args&&... args) { static_assert(std::is_constructible_v, "Component must be constructible with provided arguments"); if (m_registry.all_of(entity)) m_registry.replace(entity, std::forward(args)...); else m_registry.emplace(entity, std::forward(args)...); if constexpr (std::is_empty_v) { static T dummy{}; return dummy; } else { auto &comp = m_registry.get(entity); if constexpr (std::is_same_v) m_nameIndex[comp.Name.ToString()] = entity; return comp; } } template bool ECWorld::HasComponent(entt::entity entity) const { return m_registry.all_of(entity); } template T* ECWorld::GetComponent(entt::entity entity) { return m_registry.try_get(entity); } template const T* ECWorld::GetComponent(entt::entity entity) const { return m_registry.try_get(entity); } template void ECWorld::RemoveComponent(entt::entity entity) { if (m_registry.all_of(entity)) m_registry.remove(entity); } extern ECWorld& GetComponentSystem(); #define ECS GetComponentSystem() #endif //EU07_ECWORLD_H