From 655dd2778fa3c9c74a97ec73bbbf8e3d79cc0991 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sun, 1 Sep 2024 23:59:31 +0300 Subject: [PATCH] Implement string entity description in ecs --- libs/ecs/include/psemek/ecs/accessor.hpp | 4 +-- libs/ecs/include/psemek/ecs/container.hpp | 9 +++++++ libs/ecs/include/psemek/ecs/detail/column.hpp | 19 ++++++++++++++ .../include/psemek/ecs/detail/describe.hpp | 26 +++++++++++++++++++ libs/ecs/include/psemek/ecs/detail/table.hpp | 3 +++ libs/ecs/include/psemek/ecs/exceptions.hpp | 4 +-- libs/ecs/source/container.cpp | 7 +++++ libs/ecs/source/detail/table.cpp | 12 +++++++++ 8 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 libs/ecs/include/psemek/ecs/detail/describe.hpp diff --git a/libs/ecs/include/psemek/ecs/accessor.hpp b/libs/ecs/include/psemek/ecs/accessor.hpp index 333e535b..f998d375 100644 --- a/libs/ecs/include/psemek/ecs/accessor.hpp +++ b/libs/ecs/include/psemek/ecs/accessor.hpp @@ -107,7 +107,7 @@ namespace psemek::ecs { if (auto ptr = get_if()) return *ptr; - throw component_not_found_exception(typeid(std::remove_const_t), table_->entity_handles()[row_]); + throw component_not_found_exception(typeid(std::remove_const_t), table_->entity_handles()[row_], table_->describe(row_)); } template @@ -115,7 +115,7 @@ namespace psemek::ecs { if (auto ptr = get_if()) return *ptr; - throw component_not_found_exception(typeid(std::remove_const_t), table_->entity_handles()[row_]); + throw component_not_found_exception(typeid(std::remove_const_t), table_->entity_handles()[row_], table_->describe(row_)); } template diff --git a/libs/ecs/include/psemek/ecs/container.hpp b/libs/ecs/include/psemek/ecs/container.hpp index 2d5585b3..78c9a4b4 100644 --- a/libs/ecs/include/psemek/ecs/container.hpp +++ b/libs/ecs/include/psemek/ecs/container.hpp @@ -93,6 +93,15 @@ namespace psemek::ecs */ accessor get(handle entity); + /** Compute a string representation of an entity, based on the contained components. + * A component has to implement a to_string() method in order to provide extra info. + * + * @param entity A handle to the entity to describe + * @return A string representation of an entity + * @pre The entity was previously obtained by a `create()` call and is `alive()` + */ + std::string describe(handle entity) const; + /** Check if the entity can be cloned. * * An entity can be cloned if all of its components are copy-constructible. diff --git a/libs/ecs/include/psemek/ecs/detail/column.hpp b/libs/ecs/include/psemek/ecs/detail/column.hpp index 1e1cd358..a3f6dc43 100644 --- a/libs/ecs/include/psemek/ecs/detail/column.hpp +++ b/libs/ecs/include/psemek/ecs/detail/column.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -53,6 +54,8 @@ namespace psemek::ecs::detail virtual std::size_t memory_usage() const = 0; + virtual std::string describe(std::uint32_t row) const = 0; + virtual ~column() = default; protected: @@ -87,6 +90,8 @@ namespace psemek::ecs::detail std::size_t memory_usage() const override; + std::string describe(std::uint32_t row) const override; + ~column_impl() override; private: @@ -113,6 +118,8 @@ namespace psemek::ecs::detail std::size_t memory_usage() const override; + std::string describe(std::uint32_t row) const override; + ~column_impl() override; }; @@ -208,6 +215,12 @@ namespace psemek::ecs::detail return sizeof(Component) * row_count_; } + template + std::string column_impl::describe(std::uint32_t row) const + { + return detail::describe(reinterpret_cast(data_)[row]); + } + template column_impl::~column_impl() { @@ -286,6 +299,12 @@ namespace psemek::ecs::detail return sizeof(Component); } + template + std::string column_impl::describe(std::uint32_t) const + { + return detail::describe(*reinterpret_cast(data_)); + } + template column_impl::~column_impl() { diff --git a/libs/ecs/include/psemek/ecs/detail/describe.hpp b/libs/ecs/include/psemek/ecs/detail/describe.hpp new file mode 100644 index 00000000..19f1b9ee --- /dev/null +++ b/libs/ecs/include/psemek/ecs/detail/describe.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include + +namespace psemek::ecs::detail +{ + + template + std::string describe(Component const & component) + { + if constexpr (requires {component.to_string();}) + { + return component.to_string(); + } + else + { + auto name = util::type_name(); + if (auto pos = name.find_last_of(':'); pos != std::string::npos) + name = name.substr(pos + 1); + return name; + } + } + +} diff --git a/libs/ecs/include/psemek/ecs/detail/table.hpp b/libs/ecs/include/psemek/ecs/detail/table.hpp index a2ba752e..6e4c3ae9 100644 --- a/libs/ecs/include/psemek/ecs/detail/table.hpp +++ b/libs/ecs/include/psemek/ecs/detail/table.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace psemek::ecs::detail { @@ -81,6 +82,8 @@ namespace psemek::ecs::detail std::size_t memory_usage() const; + std::string describe(std::uint32_t row) const; + protected: std::size_t hash_; std::vector> columns_; diff --git a/libs/ecs/include/psemek/ecs/exceptions.hpp b/libs/ecs/include/psemek/ecs/exceptions.hpp index c0bdcf22..3ee59494 100644 --- a/libs/ecs/include/psemek/ecs/exceptions.hpp +++ b/libs/ecs/include/psemek/ecs/exceptions.hpp @@ -13,8 +13,8 @@ namespace psemek::ecs struct component_not_found_exception : util::exception { - component_not_found_exception(std::type_info const & type, handle const & handle, boost::stacktrace::stacktrace stacktrace = {}) - : util::exception(util::to_string("Component ", util::type_name(type), " not found for entity ", handle), std::move(stacktrace)) + component_not_found_exception(std::type_info const & type, handle const & handle, std::string const & description, boost::stacktrace::stacktrace stacktrace = {}) + : util::exception(util::to_string("Component ", util::type_name(type), " not found for entity ", handle, " <", description, ">"), std::move(stacktrace)) , type_(type) , handle_(handle) {} diff --git a/libs/ecs/source/container.cpp b/libs/ecs/source/container.cpp index dd27db1a..302df130 100644 --- a/libs/ecs/source/container.cpp +++ b/libs/ecs/source/container.cpp @@ -27,6 +27,13 @@ namespace psemek::ecs return {data.table, data.row}; } + std::string container::describe(handle entity) const + { + assert(alive(entity)); + auto const data = entity_list_.get_entities()[entity.id]; + return data.table->describe(data.row); + } + bool container::can_clone(handle entity) const { return entity_list_.get_entities()[entity.id].table->non_copyable_components().empty(); diff --git a/libs/ecs/source/detail/table.cpp b/libs/ecs/source/detail/table.cpp index 0e1bafcd..a0b2fd5e 100644 --- a/libs/ecs/source/detail/table.cpp +++ b/libs/ecs/source/detail/table.cpp @@ -186,4 +186,16 @@ namespace psemek::ecs::detail return result; } + std::string table::describe(std::uint32_t row) const + { + std::string result; + for (std::size_t i = 0; i < columns_.size(); ++i) + { + if (i > 0) + result += ";"; + result += columns_[i]->describe(row); + } + return result; + } + }