Skip to content

Commit

Permalink
refactor(ecs): replace type idx by Type if needed
Browse files Browse the repository at this point in the history
  • Loading branch information
RiscadoA committed Oct 9, 2023
1 parent 3e46322 commit 2b3021b
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 72 deletions.
9 changes: 4 additions & 5 deletions core/include/cubos/core/ecs/blueprint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,15 @@ namespace cubos::core::ecs

(
[&]() {
auto ptr = mBuffers.at<ComponentTypes>();
IBuffer* buf;
if (ptr == nullptr)
if (mBuffers.contains<ComponentTypes>())
{
buf = new Buffer<ComponentTypes>();
mBuffers.set<ComponentTypes>(buf);
buf = mBuffers.at<ComponentTypes>();
}
else
{
buf = *ptr;
buf = new Buffer<ComponentTypes>();
mBuffers.insert<ComponentTypes>(buf);
}

auto ser = data::old::BinarySerializer(buf->stream);
Expand Down
21 changes: 10 additions & 11 deletions core/include/cubos/core/ecs/component/manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <typeindex>

#include <cubos/core/ecs/component/storage.hpp>
#include <cubos/core/memory/type_map.hpp>

namespace cubos::core::ecs
{
Expand All @@ -33,7 +34,7 @@ namespace cubos::core::ecs
/// @param type Component type.
/// @return Registered name of the component type.
/// @ingroup core-ecs-component
std::optional<std::string_view> getComponentName(std::type_index type);
std::optional<std::string_view> getComponentName(const reflection::Type& type);

/// @brief Utility struct used to reference a storage of component type @p T for reading.
/// @tparam T Component type.
Expand Down Expand Up @@ -110,12 +111,12 @@ namespace cubos::core::ecs
/// Must be called before any component of this type is used in any way.
///
/// @param type Type of the component.
void registerComponent(std::type_index type);
void registerComponent(const reflection::Type& type);

/// @brief Gets the identifier of a registered component type.
/// @param type Component type.
/// @return Component identifier.
std::size_t getIDFromIndex(std::type_index type) const;
std::size_t getID(const reflection::Type& type) const;

/// @brief Gets the identifier of a registered component type.
/// @tparam T Component type.
Expand All @@ -126,7 +127,7 @@ namespace cubos::core::ecs
/// @brief Gets the type of a component from its identifier.
/// @param id Component identifier.
/// @return Component type index.
std::type_index getType(std::size_t id) const;
const reflection::Type& getType(std::size_t id) const;

//// @brief Locks a storage for reading and returns it.
/// @tparam T Component type.
Expand Down Expand Up @@ -187,18 +188,16 @@ namespace cubos::core::ecs
std::unique_ptr<std::shared_mutex> mutex; ///< Read/write lock for the storage.
};

/// @brief Maps component types to component IDs.
std::unordered_map<std::type_index, std::size_t> mTypeToIds;

std::vector<Entry> mEntries; ///< Registered component storages.
memory::TypeMap<std::size_t> mTypeToIds; ///< Maps component types to component IDs.
std::vector<Entry> mEntries; ///< Registered component storages.
};

// Implementation.

template <typename T>
std::optional<std::string_view> getComponentName()
{
return getComponentName(typeid(T));
return getComponentName(reflection::reflect<T>());
}

template <typename T>
Expand Down Expand Up @@ -248,13 +247,13 @@ namespace cubos::core::ecs
template <typename T>
void ComponentManager::registerComponent()
{
this->registerComponent(typeid(T));
this->registerComponent(reflection::reflect<T>());
}

template <typename T>
std::size_t ComponentManager::getID() const
{
return this->getIDFromIndex(typeid(T));
return this->getID(reflection::reflect<T>());
}

template <typename T>
Expand Down
21 changes: 10 additions & 11 deletions core/include/cubos/core/ecs/component/registry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ namespace cubos::core::ecs
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 index of the component.
/// @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<IStorage> createStorage(std::type_index type);
static std::unique_ptr<IStorage> createStorage(const reflection::Type& type);

/// @brief Registers a new component type.
/// @tparam T Component type to register.
Expand All @@ -45,22 +45,21 @@ namespace cubos::core::ecs
static void add(std::string_view name);

/// @brief Gets the name of a component type.
/// @param type Type index of the component.
/// @param type Type of the component.
/// @return Name of the component, or std::nullopt if the component type was not found.
static std::optional<std::string_view> name(std::type_index type);
static std::optional<std::string_view> name(const reflection::Type& type);

/// @brief Gets the type index of a component type.
/// @param name Name of the component.
/// @return Type index of the component, or std::nullopt if the component type was not
/// found.
static std::optional<std::type_index> type(std::string_view name);
/// @return Type of the component, or nullptr if the component type was not found.
static const reflection::Type* type(std::string_view name);

private:
/// @brief Entry in the component registry.
struct Entry
{
std::type_index type; ///< Type index of the component.
std::string name; ///< Name of the component.
const reflection::Type* type; ///< Type of the component.
std::string name; ///< Name of the component.

/// Function for creating the component from a deserializer.
bool (*componentCreator)(data::old::Deserializer&, Blueprint&, Entity);
Expand Down Expand Up @@ -88,7 +87,7 @@ namespace cubos::core::ecs
assert(byNames.find(std::string(name)) == byNames.end());

auto entry = std::make_shared<Entry>(Entry{
.type = typeid(T),
.type = &reflection::reflect<T>(),
.name = std::string(name),
.componentCreator =
[](data::old::Deserializer& des, Blueprint& blueprint, Entity id) {
Expand All @@ -109,7 +108,7 @@ namespace cubos::core::ecs
},
});

byType.set<T>(entry);
byType.insert<T>(entry);
byNames[std::string(name)] = entry;
}
} // namespace cubos::core::ecs
Expand Down
2 changes: 1 addition & 1 deletion core/include/cubos/core/memory/type_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace cubos::core::memory
/// @param value Value.
void insert(const reflection::Type& type, V value)
{
mMap.emplace(&type, std::move(value));
mMap.insert_or_assign(&type, std::move(value));
}

/// @brief Sets the value associated to the given type.
Expand Down
9 changes: 4 additions & 5 deletions core/src/cubos/core/ecs/blueprint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,15 @@ void Blueprint::merge(const std::string& prefix, const Blueprint& other)
/// Then, merge the buffers.
for (const auto& buffer : other.mBuffers)
{
auto* ptr = mBuffers.at(buffer.first);
IBuffer* buf;
if (ptr == nullptr)
if (mBuffers.contains(*buffer.first))
{
buf = buffer.second->create();
mBuffers.set(buffer.first, buf);
buf = mBuffers.at(*buffer.first);
}
else
{
buf = *ptr;
buf = buffer.second->create();
mBuffers.insert(*buffer.first, buf);
}

buf->merge(buffer.second, prefix, src, dst);
Expand Down
34 changes: 13 additions & 21 deletions core/src/cubos/core/ecs/component/manager.cpp
Original file line number Diff line number Diff line change
@@ -1,53 +1,45 @@
#include <cubos/core/ecs/component/manager.hpp>
#include <cubos/core/ecs/component/registry.hpp>
#include <cubos/core/reflection/type.hpp>

using namespace cubos::core;
using namespace cubos::core::ecs;

std::optional<std::string_view> cubos::core::ecs::getComponentName(std::type_index type)
std::optional<std::string_view> cubos::core::ecs::getComponentName(const reflection::Type& type)
{
return Registry::name(type);
}

void ComponentManager::registerComponent(std::type_index type)
void ComponentManager::registerComponent(const reflection::Type& type)
{
if (mTypeToIds.find(type) == mTypeToIds.end())
if (!mTypeToIds.contains(type))
{
auto storage = Registry::createStorage(type);
if (storage == nullptr)
{
CUBOS_CRITICAL("Component type '{}' is not registered in the global registry", type.name());
abort();
}
CUBOS_ASSERT(storage != nullptr, "Component type '{}' is not registered in the global registry", type.name());

mTypeToIds[type] = mEntries.size() + 1; // Component ids start at 1.
mTypeToIds.insert(type, mEntries.size() + 1); // Component ids start at 1.
mEntries.emplace_back(std::move(storage));
}
}

std::size_t ComponentManager::getIDFromIndex(std::type_index type) const
std::size_t ComponentManager::getID(const reflection::Type& type) const
{
if (auto it = mTypeToIds.find(type); it != mTypeToIds.end())
{
return it->second;
}

CUBOS_CRITICAL("Component type '{}' is not registered in the component manager", type.name());
abort();
CUBOS_ASSERT(mTypeToIds.contains(type), "Component type '{}' is not registered in the component manager",
type.name());
return mTypeToIds.at(type);
}

std::type_index ComponentManager::getType(std::size_t id) const
const reflection::Type& ComponentManager::getType(std::size_t id) const
{
for (const auto& pair : mTypeToIds)
{
if (pair.second == id)
{
return pair.first;
return *pair.first;
}
}

CUBOS_CRITICAL("No component found with ID {}", id);
abort();
CUBOS_FAIL("No component found with ID {}", id);
}

void ComponentManager::remove(uint32_t id, std::size_t componentId)
Expand Down
16 changes: 8 additions & 8 deletions core/src/cubos/core/ecs/component/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,37 @@ bool Registry::create(std::string_view name, data::old::Deserializer& des, Bluep
return false;
}

std::unique_ptr<IStorage> Registry::createStorage(std::type_index type)
std::unique_ptr<IStorage> Registry::createStorage(const reflection::Type& type)
{
auto& creators = Registry::entriesByType();
if (auto* it = creators.at(type))
if (creators.contains(type))
{
return (*it)->storageCreator();
return creators.at(type)->storageCreator();
}

return nullptr;
}

std::optional<std::string_view> Registry::name(std::type_index type)
std::optional<std::string_view> Registry::name(const reflection::Type& type)
{
auto& entries = Registry::entriesByType();
if (auto* it = entries.at(type))
if (entries.contains(type))
{
return (*it)->name;
return entries.at(type)->name;
}

return std::nullopt;
}

std::optional<std::type_index> Registry::type(std::string_view name)
const reflection::Type* Registry::type(std::string_view name)
{
auto& entries = Registry::entriesByName();
if (auto it = entries.find(std::string(name)); it != entries.end())
{
return it->second->type;
}

return std::nullopt;
return nullptr;
}

memory::TypeMap<std::shared_ptr<Registry::Entry>>& Registry::entriesByType()
Expand Down
6 changes: 3 additions & 3 deletions core/src/cubos/core/ecs/world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ bool World::unpack(Entity entity, const data::old::Package& package, data::old::

for (const auto& field : package.fields())
{
auto type = Registry::type(field.first);
if (!type.has_value())
const auto* type = Registry::type(field.first);
if (type == nullptr)
{
CUBOS_ERROR("Unknown component type '{}'", field.first);
success = false;
continue;
}

auto id = mComponentManager.getIDFromIndex(*type);
auto id = mComponentManager.getID(*type);
if (mComponentManager.unpack(entity.index, id, field.second, context))
{
mask.set(id);
Expand Down
16 changes: 9 additions & 7 deletions core/tests/ecs/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cubos/core/ecs/component/registry.hpp>
#include <cubos/core/ecs/component/vec_storage.hpp>
#include <cubos/core/reflection/external/primitives.hpp>

#include "utils.hpp"

Expand All @@ -13,6 +14,7 @@ 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;

TEST_CASE("ecs::Registry")
{
Expand All @@ -23,18 +25,18 @@ TEST_CASE("ecs::Registry")
auto entity = blueprint.create("entity");

// Initially "foo" of type int isn't registered.
CHECK_FALSE(Registry::type("foo").has_value());
CHECK_FALSE(Registry::name(typeid(int)).has_value());
CHECK(Registry::type("foo") == nullptr);
CHECK_FALSE(Registry::name(reflect<int>()).has_value());

// After registering, it can now be found.
Registry::add<int, VecStorage<int>>("foo");
REQUIRE(Registry::type("foo").has_value());
CHECK(*Registry::type("foo") == typeid(int));
REQUIRE(Registry::name(typeid(int)).has_value());
CHECK(*Registry::name(typeid(int)) == "foo");
REQUIRE(Registry::type("foo") != nullptr);
CHECK(Registry::type("foo") == &reflect<int>());
REQUIRE(Registry::name(reflect<int>()).has_value());
CHECK(*Registry::name(reflect<int>()) == "foo");

// Create a storage for it and check if its of the correct type.
auto storage = Registry::createStorage(typeid(int));
auto storage = Registry::createStorage(reflect<int>());
CHECK(dynamic_cast<VecStorage<int>*>(storage.get()) != nullptr);

// Instantiate the component into a blueprint, from a package.
Expand Down
1 change: 1 addition & 0 deletions core/tests/ecs/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <doctest/doctest.h>

#include <cubos/core/ecs/system/system.hpp>
#include <cubos/core/reflection/external/primitives.hpp>

#include "utils.hpp"

Expand Down

0 comments on commit 2b3021b

Please sign in to comment.