diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index bdc5b9e75..1d3ecd11e 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -85,6 +85,7 @@ set(CUBOS_CORE_SOURCE "src/cubos/core/ecs/entity/entity.cpp" "src/cubos/core/ecs/entity/hash.cpp" "src/cubos/core/ecs/entity/manager.cpp" + "src/cubos/core/ecs/component/storage.cpp" "src/cubos/core/ecs/component/registry.cpp" "src/cubos/core/ecs/component/manager.cpp" "src/cubos/core/ecs/system/system.cpp" diff --git a/core/include/cubos/core/ecs/component/manager.hpp b/core/include/cubos/core/ecs/component/manager.hpp index a58fc0aa5..469f7e72e 100644 --- a/core/include/cubos/core/ecs/component/manager.hpp +++ b/core/include/cubos/core/ecs/component/manager.hpp @@ -4,73 +4,14 @@ #pragma once -#include #include -#include -#include -#include -#include -#include +#include #include #include namespace cubos::core::ecs { - /// @brief Utility struct used to reference a storage of component type @p T for reading. - /// @tparam T Component type. - /// @ingroup core-ecs-component - template - class ReadStorage - { - public: - /// @brief Move constructor. - /// @param other Other instance to move from. - ReadStorage(ReadStorage&& other) noexcept; - - /// @brief Gets the underlying storage reference. - /// @return Underlying storage reference. - const Storage& get() const; - - private: - friend class ComponentManager; - - /// @brief Constructs. - /// @param storage Storage to reference. - /// @param lock Read lock to hold. - ReadStorage(const Storage& storage, std::shared_lock&& lock); - - const Storage& mStorage; - std::shared_lock mLock; - }; - - /// @brief Utility struct used to reference a storage of component type @p T for writing. - /// @tparam T Component type. - /// @ingroup core-ecs-component - template - class WriteStorage - { - public: - /// @brief Move constructor. - /// @param other Other instance to move from. - WriteStorage(WriteStorage&& other) noexcept; - - /// @brief Gets the underlying storage reference. - /// @return Underlying storage reference. - Storage& get() const; - - private: - friend class ComponentManager; - - /// @brief Constructs. - /// @param storage Storage to reference. - /// @param lock Write lock to hold. - WriteStorage(Storage& storage, std::unique_lock&& lock); - - Storage& mStorage; - std::unique_lock mLock; - }; - /// @brief Holds and manages components. /// /// Used internally by @ref World. @@ -80,182 +21,53 @@ namespace cubos::core::ecs { public: /// @brief Registers a new component type with the component manager. - /// - /// Must be called before any component of this type is used in any way. - /// - /// @tparam T Type of the component. - template - void registerComponent(); - - /// @brief Registers a new component type with the component manager. - /// - /// Must be called before any component of this type is used in any way. - /// /// @param type Type of the component. - void registerComponent(const reflection::Type& type); + void registerType(const reflection::Type& type); /// @brief Gets the identifier of a registered component type. /// @param type Component type. /// @return Component identifier. - std::size_t getID(const reflection::Type& type) const; + uint32_t id(const reflection::Type& type) const; /// @brief Gets the identifier of a registered component type. /// @tparam T Component type. /// @return Component identifier. - template - std::size_t getID() const; + template + uint32_t id() const + { + return this->id(reflection::reflect()); + } /// @brief Gets the type of a component from its identifier. /// @param id Component identifier. /// @return Component type index. - const reflection::Type& getType(std::size_t id) const; - - //// @brief Locks a storage for reading and returns it. - /// @tparam T Component type. - /// @return Storage lock. - template - ReadStorage read() const; - - //// @brief Locks a storage for writing and returns it. - /// @tparam T Component type. - /// @return Storage lock. - template - WriteStorage write() const; + const reflection::Type& type(uint32_t id) const; /// @brief Adds a component to an entity. - /// @param id Entity index. - /// @param type Component type. + /// @param index Entity index. + /// @param id Component identifier. /// @param value Component value to move. - void add(uint32_t id, const reflection::Type& type, void* value); - - /// @brief Adds a component to an entity. - /// @tparam T Component type. - /// @param id Entity index. - /// @param value Initial component value. - template - void add(uint32_t id, T value); + void insert(uint32_t index, uint32_t id, void* value); /// @brief Removes a component from an entity. - /// @tparam T Component type. - /// @param id Entity index. - template - void remove(uint32_t id); - - /// @brief Removes a component from an entity. - /// @param id Entity index. - /// @param componentId Component identifier. - void remove(uint32_t id, std::size_t componentId); + /// @param index Entity index. + /// @param id Component identifier. + void erase(uint32_t index, uint32_t id); /// @brief Removes all components from an entity. - /// @param id Entity index. - void removeAll(uint32_t id); + /// @param index Entity index. + void erase(uint32_t index); /// @brief Gets the storage of the given component type. - /// @param id Component type identifier. + /// @param id Component identifier. /// @return Component storage. - IStorage* storage(std::size_t id); + Storage& storage(uint32_t id); - /// @copydoc storage(std::size_t) - const IStorage* storage(std::size_t id) const; + /// @copydoc storage(uint32_t) + const Storage& storage(uint32_t id) const; private: - struct Entry - { - Entry(std::unique_ptr storage); - - std::unique_ptr storage; ///< Generic component storage. - std::unique_ptr mutex; ///< Read/write lock for the storage. - }; - - memory::TypeMap mTypeToIds; ///< Maps component types to component IDs. - std::vector mEntries; ///< Registered component storages. + memory::TypeMap mTypeToIds; ///< Maps component types to component IDs. + std::vector mStorages; ///< Registered component storages. }; - - // Implementation. - - template - ReadStorage::ReadStorage(ReadStorage&& other) noexcept - : mStorage(other.mStorage) - , mLock(std::move(other.mLock)) - { - // Do nothing. - } - - template - const Storage& ReadStorage::get() const - { - return mStorage; - } - - template - ReadStorage::ReadStorage(const Storage& storage, std::shared_lock&& lock) - : mStorage(storage) - , mLock(std::move(lock)) - { - // Do nothing. - } - - template - WriteStorage::WriteStorage(WriteStorage&& other) noexcept - : mStorage(other.mStorage) - , mLock(std::move(other.mLock)) - { - // Do nothing. - } - - template - Storage& WriteStorage::get() const - { - return mStorage; - } - - template - WriteStorage::WriteStorage(Storage& storage, std::unique_lock&& lock) - : mStorage(storage) - , mLock(std::move(lock)) - { - // Do nothing. - } - - template - void ComponentManager::registerComponent() - { - this->registerComponent(reflection::reflect()); - } - - template - std::size_t ComponentManager::getID() const - { - return this->getID(reflection::reflect()); - } - - template - ReadStorage ComponentManager::read() const - { - const std::size_t componentId = this->getID(); - return ReadStorage(*static_cast*>(mEntries[componentId - 1].storage.get()), - std::shared_lock(*mEntries[componentId - 1].mutex)); - } - - template - WriteStorage ComponentManager::write() const - { - const std::size_t componentId = this->getID(); - return WriteStorage(*static_cast*>(mEntries[componentId - 1].storage.get()), - std::unique_lock(*mEntries[componentId - 1].mutex)); - } - - template - void ComponentManager::add(uint32_t id, T value) - { - this->add(id, reflection::reflect(), &value); - } - - template - void ComponentManager::remove(uint32_t id) - { - const std::size_t componentId = this->getID(); - auto storage = static_cast*>(mEntries[componentId - 1].storage.get()); - storage->erase(id); - } } // namespace cubos::core::ecs diff --git a/core/include/cubos/core/ecs/component/map_storage.hpp b/core/include/cubos/core/ecs/component/map_storage.hpp deleted file mode 100644 index 2626891cf..000000000 --- a/core/include/cubos/core/ecs/component/map_storage.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/// @file -/// @brief Class @ref cubos::core::ecs::MapStorage. -/// @ingroup core-ecs-component - -#pragma once - -#include - -namespace cubos::core::ecs -{ - - /// @brief Storage implementation that uses an `std::unordered_map`. - /// @tparam T Component type. - /// @ingroup core-ecs-component - template - class MapStorage : public Storage - { - public: - void insert(uint32_t index, void* value) override; - void* get(uint32_t index) override; - const void* get(uint32_t index) const override; - void erase(uint32_t index) override; - - private: - std::unordered_map mData; - }; - - template - void MapStorage::insert(uint32_t index, void* value) - { - mData[index] = std::move(*static_cast(value)); - } - - template - void* MapStorage::get(uint32_t index) - { - return &mData.at(index); - } - - template - const void* MapStorage::get(uint32_t index) const - { - return &mData.at(index); - } - - template - void MapStorage::erase(uint32_t index) - { - mData.erase(index); - } - -} // namespace cubos::core::ecs diff --git a/core/include/cubos/core/ecs/component/null_storage.hpp b/core/include/cubos/core/ecs/component/null_storage.hpp deleted file mode 100644 index 42d4edea8..000000000 --- a/core/include/cubos/core/ecs/component/null_storage.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/// @file -/// @brief Class @ref cubos::core::ecs::NullStorage. -/// @ingroup core-ecs-component - -#pragma once - -#include - -namespace cubos::core::ecs -{ - - /// @brief Storage implementation that doesn't keep any data, made for - /// zero-sized components. - /// @tparam T Component type. - /// @ingroup core-ecs-component - template - class NullStorage : public Storage - { - public: - void insert(uint32_t index, void* value) override; - void* get(uint32_t index) override; - const void* get(uint32_t index) const override; - void erase(uint32_t index) override; - - private: - T mData; - }; - - template - void NullStorage::insert(uint32_t /*unused*/, void* /*unused*/) - { - } - - template - void* NullStorage::get(uint32_t /*unused*/) - { - return &mData; - } - - template - const void* NullStorage::get(uint32_t /*unused*/) const - { - return &mData; - } - - template - void NullStorage::erase(uint32_t /*unused*/) - { - } - -} // namespace cubos::core::ecs diff --git a/core/include/cubos/core/ecs/component/registry.hpp b/core/include/cubos/core/ecs/component/registry.hpp index 9e0effb90..acbf2749d 100644 --- a/core/include/cubos/core/ecs/component/registry.hpp +++ b/core/include/cubos/core/ecs/component/registry.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -36,16 +35,10 @@ namespace cubos::core::ecs /// @return Whether the instantiation was successful. static bool create(std::string_view name, data::old::Deserializer& des, Blueprint& blueprint, Entity id); - /// @brief Instantiates a component storage for the given component type. - /// @param type Type of the component. - /// @return Smart pointer to the storage, or nullptr if the component type was not found. - static std::unique_ptr createStorage(const reflection::Type& type); - /// @brief Registers a new component type. /// @tparam T Component type to register. - /// @tparam S Storage type to use for the component. /// @param name Name of the component. - template + template static void add(); /// @brief Gets the type index of a component type. @@ -61,9 +54,6 @@ namespace cubos::core::ecs /// Function for creating the component from a deserializer. bool (*componentCreator)(data::old::Deserializer&, Blueprint&, Entity); - - /// Function for creating the storage for the component. - std::unique_ptr (*storageCreator)(); }; /// @return Global entry registry, indexed by type. @@ -75,34 +65,25 @@ namespace cubos::core::ecs // Implementation. - template + template inline void Registry::add() { - static_assert(std::is_base_of_v, S>, "Component storage for T must be derived from Storage"); - auto& byType = Registry::entriesByType(); auto& byNames = Registry::entriesByName(); - auto entry = std::make_shared(Entry{ - .type = &reflection::reflect(), - .componentCreator = - [](data::old::Deserializer& des, Blueprint& blueprint, Entity id) { - T comp; - des.read(comp); - if (des.failed()) - { - return false; - } - - blueprint.add(id, std::move(comp)); - return true; - }, - .storageCreator = - []() { - auto storage = std::make_unique(); - return std::unique_ptr(storage.release()); - }, - }); + auto entry = std::make_shared( + Entry{.type = &reflection::reflect(), + .componentCreator = [](data::old::Deserializer& des, Blueprint& blueprint, Entity id) { + T comp; + des.read(comp); + if (des.failed()) + { + return false; + } + + blueprint.add(id, std::move(comp)); + return true; + }}); byType.insert(entry); byNames[entry->type->name()] = entry; @@ -115,7 +96,7 @@ namespace cubos::core::ecs /// unit (think of it as a .cpp file) in the executable, otherwise the component type may not be /// registered. E.g.: keeping it hidden in a .cpp file on a library may not work. /// @ingroup core-ecs-component -#define CUBOS_REGISTER_COMPONENT(type, storageType) \ +#define CUBOS_REGISTER_COMPONENT(type) \ namespace cubos::core::ecs::impl \ { \ class ComponentRegister##type \ @@ -123,7 +104,7 @@ namespace cubos::core::ecs private: \ static inline bool registerType() \ { \ - ::cubos::core::ecs::Registry::add(); \ + ::cubos::core::ecs::Registry::add(); \ return true; \ } \ \ diff --git a/core/include/cubos/core/ecs/component/storage.hpp b/core/include/cubos/core/ecs/component/storage.hpp index a243b09fc..e7418388f 100644 --- a/core/include/cubos/core/ecs/component/storage.hpp +++ b/core/include/cubos/core/ecs/component/storage.hpp @@ -4,49 +4,50 @@ #pragma once -#include +#include + +#include namespace cubos::core::ecs { - /// @brief Abstract parent class for all storages. - /// - /// Necessary to provide a type-erased interface for erasing and packaging/unpackaging - /// components. - /// + /// @brief Stores the components of a given type. /// @ingroup core-ecs-component - class IStorage + class Storage final { public: - virtual ~IStorage() = default; + /// @brief Constructs. + /// @param type Component type. + Storage(const reflection::Type& type); + + /// @brief Move constructs. + /// @param other Moved storage. + Storage(Storage&& other) noexcept = default; /// @brief Inserts a value into the storage. /// @param index Index where to insert the value. /// @param value Value to be moved. - virtual void insert(uint32_t index, void* value) = 0; + void insert(uint32_t index, void* value); /// @brief Remove a value from the storage. /// @param index Index of the value to be removed. - virtual void erase(uint32_t index) = 0; + void erase(uint32_t index); /// @brief Gets a value from the storage. /// @param index Index of the value to be retrieved. /// @return Pointer to the value. - virtual void* get(uint32_t index) = 0; + void* get(uint32_t index); /// @brief Gets a value from the storage. /// @param index Index of the value to be retrieved. /// @return Pointer to the value. - virtual const void* get(uint32_t index) const = 0; - }; + const void* get(uint32_t index) const; - /// @brief Abstract container for a component type @p T. - /// @tparam T Component type. - /// @ingroup core-ecs-component - template - class Storage : public IStorage - { - public: - /// @brief Component type. - using Type = T; + /// @brief Gets the component type stored in the storage. + /// @return Component type. + const reflection::Type& type() const; + + private: + memory::AnyVector mData; + const reflection::ConstructibleTrait* mConstructibleTrait{nullptr}; }; } // namespace cubos::core::ecs diff --git a/core/include/cubos/core/ecs/component/vec_storage.hpp b/core/include/cubos/core/ecs/component/vec_storage.hpp deleted file mode 100644 index f1a47cf61..000000000 --- a/core/include/cubos/core/ecs/component/vec_storage.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/// @file -/// @brief Class @ref cubos::core::ecs::VecStorage. -/// @ingroup core-ecs-component - -#pragma once - -#include - -namespace cubos::core::ecs -{ - /// @brief Storage implementation that uses a `std::vector`. - /// @tparam T Component type. - /// @ingroup core-ecs-component - template - class VecStorage : public Storage - { - public: - void insert(uint32_t index, void* value) override; - void* get(uint32_t index) override; - const void* get(uint32_t index) const override; - void erase(uint32_t index) override; - - private: - std::vector mData; - }; - - template - void VecStorage::insert(uint32_t index, void* value) - { - if (mData.size() <= index) - { - mData.resize(index); - mData.emplace_back(std::move(*static_cast(value))); - } - else - { - mData[index].~T(); - new (&mData[index]) T(std::move(*static_cast(value))); - } - } - - template - void* VecStorage::get(uint32_t index) - { - return &mData[index]; - } - - template - const void* VecStorage::get(uint32_t index) const - { - return &mData[index]; - } - - template - void VecStorage::erase(uint32_t index) - { - if (static_cast(index) < mData.size()) - { - mData[index].~T(); - new (&mData[index]) T; - } - } -} // namespace cubos::core::ecs diff --git a/core/include/cubos/core/ecs/resource/manager.hpp b/core/include/cubos/core/ecs/resource/manager.hpp index d9cf2eb35..2c3d8f3b3 100644 --- a/core/include/cubos/core/ecs/resource/manager.hpp +++ b/core/include/cubos/core/ecs/resource/manager.hpp @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include diff --git a/core/include/cubos/core/ecs/system/commands.hpp b/core/include/cubos/core/ecs/system/commands.hpp index fc00616cf..1dc3581a3 100644 --- a/core/include/cubos/core/ecs/system/commands.hpp +++ b/core/include/cubos/core/ecs/system/commands.hpp @@ -308,8 +308,8 @@ namespace cubos::core::ecs mBuffers.insert({}); } - std::size_t componentID = mWorld.mComponentManager.getID(); - mask.set(componentID); + auto componentID = mWorld.mComponentManager.id(); + mask.set(static_cast(componentID)); mBuffers.at().components.erase(entity); mBuffers.at().components.emplace( entity, memory::AnyValue::moveConstruct(reflection::reflect(), &components)); @@ -326,8 +326,8 @@ namespace cubos::core::ecs ( [&]() { - std::size_t componentID = mWorld.mComponentManager.getID(); - mask.set(componentID); + auto componentID = mWorld.mComponentManager.id(); + mask.set(static_cast(componentID)); }(), ...); } @@ -349,8 +349,8 @@ namespace cubos::core::ecs mBuffers.insert({}); } - std::size_t componentID = mWorld.mComponentManager.getID(); - mask.set(componentID); + auto componentID = mWorld.mComponentManager.id(); + mask.set(static_cast(componentID)); mBuffers.at().components.erase(entity); mBuffers.at().components.emplace( entity, memory::AnyValue::moveConstruct(reflection::reflect(), &components)); diff --git a/core/include/cubos/core/ecs/system/query.hpp b/core/include/cubos/core/ecs/system/query.hpp index a3ff086cb..407817d41 100644 --- a/core/include/cubos/core/ecs/system/query.hpp +++ b/core/include/cubos/core/ecs/system/query.hpp @@ -22,7 +22,7 @@ namespace cubos::core::ecs /// @ingroup core-ecs-system struct QueryInfo { - std::unordered_set read; ///< Componenst read. + std::unordered_set read; ///< Components read. std::unordered_set written; ///< Components written. }; @@ -43,49 +43,65 @@ namespace cubos::core::ecs template struct QueryFetcher> { - using Type = WriteStorage; + struct Type + { + Storage& storage; + }; + using InnerType = Component; constexpr static bool IsOptional = false; static void add(QueryInfo& info); - static Type fetch(const World& world); - static Write arg(const World& world, Type& lock, Entity entity); + static Type fetch(World& world); + static Write arg(const World& world, Type& fetched, Entity entity); }; template struct QueryFetcher> { - using Type = ReadStorage; + struct Type + { + const Storage& storage; + }; + using InnerType = Component; constexpr static bool IsOptional = false; static void add(QueryInfo& info); - static Type fetch(const World& world); - static Read arg(const World& world, Type& lock, Entity entity); + static Type fetch(World& world); + static Read arg(const World& world, Type& fetched, Entity entity); }; template struct QueryFetcher> { - using Type = WriteStorage; + struct Type + { + Storage& storage; + }; + using InnerType = Component; constexpr static bool IsOptional = true; static void add(QueryInfo& info); - static Type fetch(const World& world); - static OptWrite arg(const World& world, Type& lock, Entity entity); + static Type fetch(World& world); + static OptWrite arg(const World& world, Type& fetched, Entity entity); }; template struct QueryFetcher> { - using Type = ReadStorage; + struct Type + { + const Storage& storage; + }; + using InnerType = Component; constexpr static bool IsOptional = true; static void add(QueryInfo& info); - static Type fetch(const World& world); - static OptRead arg(const World& world, Type& lock, Entity entity); + static Type fetch(World& world); + static OptRead arg(const World& world, Type& fetched, Entity entity); }; } // namespace impl @@ -137,7 +153,7 @@ namespace cubos::core::ecs /// @brief Constructs a query over the given world. /// @param world World to query. - Query(const World& world); + Query(World& world); /// @brief Gets an iterator to the first entity which matches the query. /// @return Iterator. @@ -159,9 +175,9 @@ namespace cubos::core::ecs private: friend World; - const World& mWorld; ///< World to query. - Fetched mFetched; ///< Fetched data. - Entity::Mask mMask; ///< Mask of the components to query. + World& mWorld; ///< World to query. + Fetched mFetched; ///< Fetched data. + Entity::Mask mMask; ///< Mask of the components to query. }; // Implementation. @@ -169,7 +185,6 @@ namespace cubos::core::ecs template std::tuple Query::Iterator::operator*() const { - // Convert the fetched data into the desired query reference types. return std::forward_as_tuple( *mIt, impl::QueryFetcher::arg( @@ -205,16 +220,17 @@ namespace cubos::core::ecs } template - Query::Query(const World& world) + Query::Query(World& world) : mWorld(world) , mFetched(std::forward_as_tuple(impl::QueryFetcher::fetch(world)...)) { // We must turn the type from Read and similar to T before getting the ID. - std::size_t ids[] = {0, - (impl::QueryFetcher::IsOptional - ? SIZE_MAX - : mWorld.mComponentManager - .template getID::InnerType>())...}; + std::size_t ids[] = { + 0, (impl::QueryFetcher::IsOptional + ? SIZE_MAX + : static_cast( + mWorld.mComponentManager + .template id::InnerType>()))...}; mMask.reset(); for (std::size_t id : ids) { @@ -252,15 +268,15 @@ namespace cubos::core::ecs } template - typename impl::QueryFetcher>::Type impl::QueryFetcher>::fetch(const World& world) + typename impl::QueryFetcher>::Type impl::QueryFetcher>::fetch(World& world) { - return world.mComponentManager.write(); + return {world.mComponentManager.storage(world.mComponentManager.id(reflection::reflect()))}; } template - Write impl::QueryFetcher>::arg(const World& /*unused*/, Type& lock, Entity entity) + Write impl::QueryFetcher>::arg(const World& /*unused*/, Type& fetched, Entity entity) { - return {*static_cast(lock.get().get(entity.index))}; + return {*static_cast(fetched.storage.get(entity.index))}; } template @@ -270,15 +286,15 @@ namespace cubos::core::ecs } template - typename impl::QueryFetcher>::Type impl::QueryFetcher>::fetch(const World& world) + typename impl::QueryFetcher>::Type impl::QueryFetcher>::fetch(World& world) { - return world.mComponentManager.read(); + return {world.mComponentManager.storage(world.mComponentManager.id(reflection::reflect()))}; } template - Read impl::QueryFetcher>::arg(const World& /*unused*/, Type& lock, Entity entity) + Read impl::QueryFetcher>::arg(const World& /*unused*/, Type& fetched, Entity entity) { - return {*static_cast(lock.get().get(entity.index))}; + return {*static_cast(fetched.storage.get(entity.index))}; } template @@ -288,18 +304,17 @@ namespace cubos::core::ecs } template - typename impl::QueryFetcher>::Type impl::QueryFetcher>::fetch( - const World& world) + typename impl::QueryFetcher>::Type impl::QueryFetcher>::fetch(World& world) { - return world.mComponentManager.write(); + return {world.mComponentManager.storage(world.mComponentManager.id(reflection::reflect()))}; } template - OptWrite impl::QueryFetcher>::arg(const World& world, Type& lock, Entity entity) + OptWrite impl::QueryFetcher>::arg(const World& world, Type& fetched, Entity entity) { if (world.components(entity).has()) { - return {static_cast(lock.get().get(entity.index))}; + return {static_cast(fetched.storage.get(entity.index))}; } return {nullptr}; @@ -312,18 +327,17 @@ namespace cubos::core::ecs } template - typename impl::QueryFetcher>::Type impl::QueryFetcher>::fetch( - const World& world) + typename impl::QueryFetcher>::Type impl::QueryFetcher>::fetch(World& world) { - return world.mComponentManager.read(); + return {world.mComponentManager.storage(world.mComponentManager.id(reflection::reflect()))}; } template - OptRead impl::QueryFetcher>::arg(const World& world, Type& lock, Entity entity) + OptRead impl::QueryFetcher>::arg(const World& world, Type& fetched, Entity entity) { if (world.components(entity).has()) { - return {static_cast(lock.get().get(entity.index))}; + return {static_cast(fetched.storage.get(entity.index))}; } return {nullptr}; diff --git a/core/include/cubos/core/ecs/world.hpp b/core/include/cubos/core/ecs/world.hpp index 8a130d199..6d34d372b 100644 --- a/core/include/cubos/core/ecs/world.hpp +++ b/core/include/cubos/core/ecs/world.hpp @@ -318,7 +318,7 @@ namespace cubos::core::ecs private: World::Components& mComponents; - std::size_t mId{1}; + uint32_t mId{1}; mutable Component mComponent; }; @@ -363,7 +363,7 @@ namespace cubos::core::ecs private: const World::ConstComponents& mComponents; - std::size_t mId{1}; + uint32_t mId{1}; mutable Component mComponent; }; @@ -380,7 +380,7 @@ namespace cubos::core::ecs void World::registerComponent() { CUBOS_TRACE("Registered component '{}'", reflection::reflect().name()); - mComponentManager.registerComponent(); + mComponentManager.registerType(reflection::reflect()); } template diff --git a/core/samples/ecs/general/main.cpp b/core/samples/ecs/general/main.cpp index 1d361d04f..f9177187d 100644 --- a/core/samples/ecs/general/main.cpp +++ b/core/samples/ecs/general/main.cpp @@ -1,10 +1,7 @@ #include #include -#include -#include #include -#include #include #include #include @@ -122,10 +119,10 @@ namespace cubos::core::data::old } } // namespace cubos::core::data::old -CUBOS_REGISTER_COMPONENT(Player, ecs::NullStorage) -CUBOS_REGISTER_COMPONENT(Position, ecs::VecStorage) -CUBOS_REGISTER_COMPONENT(Velocity, ecs::MapStorage) -CUBOS_REGISTER_COMPONENT(Parent, ecs::VecStorage) +CUBOS_REGISTER_COMPONENT(Player) +CUBOS_REGISTER_COMPONENT(Position) +CUBOS_REGISTER_COMPONENT(Velocity) +CUBOS_REGISTER_COMPONENT(Parent) void spawner(ecs::Commands cmds) { diff --git a/core/src/cubos/core/ecs/component/manager.cpp b/core/src/cubos/core/ecs/component/manager.cpp index ab93f9ca6..3d8da60e7 100644 --- a/core/src/cubos/core/ecs/component/manager.cpp +++ b/core/src/cubos/core/ecs/component/manager.cpp @@ -1,77 +1,57 @@ #include -#include #include #include #include #include -using namespace cubos::core; +using cubos::core::reflection::Type; + using namespace cubos::core::ecs; -void ComponentManager::registerComponent(const reflection::Type& type) +void ComponentManager::registerType(const Type& type) { if (!mTypeToIds.contains(type)) { - auto storage = Registry::createStorage(type); - CUBOS_ASSERT(storage != nullptr, "Component type '{}' is not registered in the global registry", type.name()); - - mTypeToIds.insert(type, mEntries.size() + 1); // Component ids start at 1. - mEntries.emplace_back(std::move(storage)); + mTypeToIds.insert(type, static_cast(mStorages.size()) + 1); // Component ids start at 1. + mStorages.emplace_back(type); } } -std::size_t ComponentManager::getID(const reflection::Type& type) const +uint32_t ComponentManager::id(const Type& type) const { - CUBOS_ASSERT(mTypeToIds.contains(type), "Component type '{}' is not registered in the component manager", - type.name()); + CUBOS_ASSERT(mTypeToIds.contains(type), "Component type {} was not registered", type.name()); return mTypeToIds.at(type); } -const reflection::Type& ComponentManager::getType(std::size_t id) const +const Type& ComponentManager::type(uint32_t id) const { - for (const auto& pair : mTypeToIds) - { - if (pair.second == id) - { - return *pair.first; - } - } - - CUBOS_FAIL("No component found with ID {}", id); + return mStorages[static_cast(id) - 1].type(); } -void ComponentManager::add(uint32_t id, const reflection::Type& type, void* value) +void ComponentManager::insert(uint32_t index, uint32_t id, void* value) { - const std::size_t componentId = this->getID(type); - auto* storage = static_cast(mEntries[componentId - 1].storage.get()); - storage->insert(id, value); + mStorages[static_cast(id) - 1].insert(index, value); } -void ComponentManager::remove(uint32_t id, std::size_t componentId) +void ComponentManager::erase(uint32_t index, uint32_t id) { - mEntries[componentId - 1].storage->erase(id); + mStorages[static_cast(id) - 1].erase(index); } -void ComponentManager::removeAll(uint32_t id) +void ComponentManager::erase(uint32_t index) { - for (auto& entry : mEntries) + for (auto& storage : mStorages) { - entry.storage->erase(id); + storage.erase(index); } } -IStorage* ComponentManager::storage(std::size_t id) -{ - return mEntries.at(id - 1).storage.get(); -} - -const IStorage* ComponentManager::storage(std::size_t id) const +Storage& ComponentManager::storage(uint32_t id) { - return mEntries.at(id - 1).storage.get(); + return mStorages[static_cast(id) - 1]; } -ComponentManager::Entry::Entry(std::unique_ptr storage) - : storage(std::move(storage)) +const Storage& ComponentManager::storage(uint32_t id) const { - this->mutex = std::make_unique(); + return mStorages[static_cast(id) - 1]; } diff --git a/core/src/cubos/core/ecs/component/registry.cpp b/core/src/cubos/core/ecs/component/registry.cpp index f11403e0f..701209375 100644 --- a/core/src/cubos/core/ecs/component/registry.cpp +++ b/core/src/cubos/core/ecs/component/registry.cpp @@ -14,17 +14,6 @@ bool Registry::create(std::string_view name, data::old::Deserializer& des, Bluep return false; } -std::unique_ptr Registry::createStorage(const reflection::Type& type) -{ - auto& creators = Registry::entriesByType(); - if (creators.contains(type)) - { - return creators.at(type)->storageCreator(); - } - - return nullptr; -} - const reflection::Type* Registry::type(std::string_view name) { auto& entries = Registry::entriesByName(); diff --git a/core/src/cubos/core/ecs/component/storage.cpp b/core/src/cubos/core/ecs/component/storage.cpp new file mode 100644 index 000000000..80c7fba83 --- /dev/null +++ b/core/src/cubos/core/ecs/component/storage.cpp @@ -0,0 +1,48 @@ +#include +#include +#include + +using cubos::core::ecs::Storage; +using cubos::core::reflection::Type; + +Storage::Storage(const Type& type) + : mData{type} +{ + mConstructibleTrait = &type.get(); +} + +void Storage::insert(uint32_t index, void* value) +{ + while (mData.size() <= static_cast(index)) + { + mData.pushDefault(); + } + + mConstructibleTrait->destruct(mData.at(index)); + mConstructibleTrait->moveConstruct(mData.at(index), value); +} + +void Storage::erase(uint32_t index) +{ + if (static_cast(index) < mData.size()) + { + void* value = mData.at(static_cast(index)); + mConstructibleTrait->destruct(value); + mConstructibleTrait->defaultConstruct(value); + } +} + +void* Storage::get(uint32_t index) +{ + return mData.at(static_cast(index)); +} + +const void* Storage::get(uint32_t index) const +{ + return mData.at(static_cast(index)); +} + +const Type& Storage::type() const +{ + return mData.elementType(); +} diff --git a/core/src/cubos/core/ecs/system/commands.cpp b/core/src/cubos/core/ecs/system/commands.cpp index f979ac481..194564e50 100644 --- a/core/src/cubos/core/ecs/system/commands.cpp +++ b/core/src/cubos/core/ecs/system/commands.cpp @@ -74,8 +74,8 @@ void CommandBuffer::add(Entity entity, const reflection::Type& type, void* compo mBuffers.insert(type, {}); } - std::size_t componentID = mWorld.mComponentManager.getID(type); - mask.set(componentID); + auto componentID = mWorld.mComponentManager.id(type); + mask.set(static_cast(componentID)); mBuffers.at(type).components.erase(entity); mBuffers.at(type).components.emplace(entity, memory::AnyValue::moveConstruct(type, component)); } @@ -107,11 +107,11 @@ void CommandBuffer::commit() // 1. Components are removed. for (auto& [entity, removed] : mRemoved) { - for (std::size_t componentId = 1; componentId <= CUBOS_CORE_ECS_MAX_COMPONENTS; ++componentId) + for (uint32_t componentId = 1; componentId <= CUBOS_CORE_ECS_MAX_COMPONENTS; ++componentId) { if (removed.test(componentId)) { - mWorld.mComponentManager.remove(entity.index, componentId); + mWorld.mComponentManager.erase(entity.index, componentId); } } } @@ -119,7 +119,7 @@ void CommandBuffer::commit() // 2. Entities are destroyed. for (auto entity : mDestroyed) { - mWorld.mComponentManager.removeAll(entity.index); + mWorld.mComponentManager.erase(entity.index); mWorld.mEntityManager.destroy(entity); } @@ -182,7 +182,7 @@ void CommandBuffer::Buffer::move(Entity entity, ComponentManager& manager) auto it = this->components.find(entity); if (it != this->components.end()) { - manager.add(entity.index, it->second.type(), it->second.get()); + manager.insert(entity.index, manager.id(it->second.type()), it->second.get()); this->components.erase(it); } } diff --git a/core/src/cubos/core/ecs/world.cpp b/core/src/cubos/core/ecs/world.cpp index 9b78a0ecd..29e672070 100644 --- a/core/src/cubos/core/ecs/world.cpp +++ b/core/src/cubos/core/ecs/world.cpp @@ -26,7 +26,7 @@ Entity World::create() void World::destroy(Entity entity) { mEntityManager.destroy(entity); - mComponentManager.removeAll(entity.index); + mComponentManager.erase(entity.index); CUBOS_DEBUG("Destroyed entity {}", entity); } @@ -64,15 +64,15 @@ World::Components::Components(World& world, Entity entity) bool World::Components::has(const reflection::Type& type) const { - std::size_t componentId = mWorld.mComponentManager.getID(type); - return mWorld.mEntityManager.getMask(mEntity).test(componentId); + auto componentId = mWorld.mComponentManager.id(type); + return mWorld.mEntityManager.getMask(mEntity).test(static_cast(componentId)); } void* World::Components::get(const reflection::Type& type) { CUBOS_ASSERT(this->has(type)); - std::size_t componentId = mWorld.mComponentManager.getID(type); - return mWorld.mComponentManager.storage(componentId)->get(mEntity.index); + auto componentId = mWorld.mComponentManager.id(type); + return mWorld.mComponentManager.storage(componentId).get(mEntity.index); } auto World::Components::begin() -> Iterator @@ -87,11 +87,11 @@ auto World::Components::end() -> Iterator auto World::Components::add(const reflection::Type& type, void* value) -> Components& { - std::size_t componentId = mWorld.mComponentManager.getID(type); + auto componentId = mWorld.mComponentManager.id(type); auto mask = mWorld.mEntityManager.getMask(mEntity); - mask.set(componentId); + mask.set(static_cast(componentId)); mWorld.mEntityManager.setMask(mEntity, mask); - mWorld.mComponentManager.add(mEntity.index, type, value); + mWorld.mComponentManager.insert(mEntity.index, componentId, value); CUBOS_DEBUG("Added component {} to entity {}", type.name(), mEntity, mEntity); return *this; @@ -99,11 +99,11 @@ auto World::Components::add(const reflection::Type& type, void* value) -> Compon auto World::Components::remove(const reflection::Type& type) -> Components& { - std::size_t componentId = mWorld.mComponentManager.getID(type); + auto componentId = mWorld.mComponentManager.id(type); auto mask = mWorld.mEntityManager.getMask(mEntity); - mask.set(componentId, false); + mask.set(static_cast(componentId), false); mWorld.mEntityManager.setMask(mEntity, mask); - mWorld.mComponentManager.remove(mEntity.index, componentId); + mWorld.mComponentManager.erase(mEntity.index, componentId); CUBOS_DEBUG("Removed component {} from entity {}", type.name(), mEntity); return *this; @@ -118,15 +118,15 @@ World::ConstComponents::ConstComponents(const World& world, Entity entity) bool World::ConstComponents::has(const reflection::Type& type) const { - std::size_t componentId = mWorld.mComponentManager.getID(type); - return mWorld.mEntityManager.getMask(mEntity).test(componentId); + auto componentId = mWorld.mComponentManager.id(type); + return mWorld.mEntityManager.getMask(mEntity).test(static_cast(componentId)); } const void* World::ConstComponents::get(const reflection::Type& type) const { CUBOS_ASSERT(this->has(type)); - std::size_t componentId = mWorld.mComponentManager.getID(type); - return mWorld.mComponentManager.storage(componentId)->get(mEntity.index); + auto componentId = mWorld.mComponentManager.id(type); + return mWorld.mComponentManager.storage(componentId).get(mEntity.index); } auto World::ConstComponents::begin() const -> Iterator @@ -146,10 +146,10 @@ World::Components::Iterator::Iterator(Components& components, bool end) if (end) { - mId = mask.size(); + mId = static_cast(mask.size()); } - while (mId < mask.size() && !mask.test(mId)) + while (static_cast(mId) < mask.size() && !mask.test(static_cast(mId))) { mId += 1; } @@ -163,8 +163,8 @@ bool World::Components::Iterator::operator==(const Iterator& other) const auto World::Components::Iterator::operator*() const -> const Component& { const auto& mask = mComponents.mWorld.mEntityManager.getMask(mComponents.mEntity); - CUBOS_ASSERT(mId < mask.size(), "Iterator is out of bounds"); - mComponent.type = &mComponents.mWorld.mComponentManager.getType(mId); + CUBOS_ASSERT(static_cast(mId) < mask.size(), "Iterator is out of bounds"); + mComponent.type = &mComponents.mWorld.mComponentManager.type(mId); mComponent.value = mComponents.get(*mComponent.type); return mComponent; } @@ -193,10 +193,10 @@ World::ConstComponents::Iterator::Iterator(const ConstComponents& components, bo if (end) { - mId = mask.size(); + mId = static_cast(mask.size()); } - while (mId < mask.size() && !mask.test(mId)) + while (static_cast(mId) < mask.size() && !mask.test(static_cast(mId))) { mId += 1; } @@ -210,8 +210,8 @@ bool World::ConstComponents::Iterator::operator==(const Iterator& other) const auto World::ConstComponents::Iterator::operator*() const -> const Component& { const auto& mask = mComponents.mWorld.mEntityManager.getMask(mComponents.mEntity); - CUBOS_ASSERT(mId < mask.size(), "Iterator is out of bounds"); - mComponent.type = &mComponents.mWorld.mComponentManager.getType(mId); + CUBOS_ASSERT(static_cast(mId) < mask.size(), "Iterator is out of bounds"); + mComponent.type = &mComponents.mWorld.mComponentManager.type(mId); mComponent.value = mComponents.get(*mComponent.type); return mComponent; } diff --git a/core/tests/ecs/registry.cpp b/core/tests/ecs/registry.cpp index 63f12df4b..b48e6427b 100644 --- a/core/tests/ecs/registry.cpp +++ b/core/tests/ecs/registry.cpp @@ -1,7 +1,6 @@ #include #include -#include #include #include @@ -10,7 +9,6 @@ using cubos::core::ecs::CommandBuffer; using cubos::core::ecs::Commands; using cubos::core::ecs::Registry; -using cubos::core::ecs::VecStorage; using cubos::core::ecs::World; using cubos::core::reflection::reflect; @@ -24,11 +22,7 @@ TEST_CASE("ecs::Registry") CHECK(Registry::type("int") == nullptr); // After registering, it can now be found. - Registry::add>(); + Registry::add(); REQUIRE(Registry::type("int") != nullptr); CHECK(Registry::type("int") == &reflect()); - - // Create a storage for it and check if its of the correct type. - auto storage = Registry::createStorage(reflect()); - CHECK(dynamic_cast*>(storage.get()) != nullptr); } diff --git a/tools/quadrados-gen/src/main.cpp b/tools/quadrados-gen/src/main.cpp index f62de4d47..f0acc78dd 100644 --- a/tools/quadrados-gen/src/main.cpp +++ b/tools/quadrados-gen/src/main.cpp @@ -793,9 +793,6 @@ static bool generate(const GenerateOptions& options) file << "/// Do not edit this file." << std::endl; file << std::endl; file << "#include " << std::endl; - file << "#include " << std::endl; - file << "#include " << std::endl; - file << "#include " << std::endl; file << std::endl; // Include all the component headers. @@ -819,8 +816,6 @@ static bool generate(const GenerateOptions& options) } id += component.typeStr; - std::string storageId = "::cubos::core::ecs::" + component.storage + "<" + id + ">"; - file << std::endl; file << "template <>" << std::endl; file << "void cubos::core::data::old::serialize<" << id << ">(Serializer& ser, const " << id << "& obj," @@ -881,7 +876,7 @@ static bool generate(const GenerateOptions& options) file << "{" << std::endl; file << " "; } - file << "CUBOS_REGISTER_COMPONENT(" << component.typeStr << ", " << storageId << ")" << std::endl; + file << "CUBOS_REGISTER_COMPONENT(" << component.typeStr << ")" << std::endl; if (!component.namespaceStr.empty()) { file << "} // namespace " << component.namespaceStr << std::endl;