Compare commits
No commits in common. "1265b816d387c9defe64dd296d38f804bd5d7c9c" and "1f7d9e278fef00c2edf2fb54a7956d549b25604e" have entirely different histories.
1265b816d3
...
1f7d9e278f
14 changed files with 153 additions and 326 deletions
|
|
@ -3,6 +3,8 @@
|
||||||
#include <psemek/ecs/exceptions.hpp>
|
#include <psemek/ecs/exceptions.hpp>
|
||||||
#include <psemek/ecs/detail/table.hpp>
|
#include <psemek/ecs/detail/table.hpp>
|
||||||
|
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
namespace psemek::ecs
|
namespace psemek::ecs
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -53,19 +55,6 @@ namespace psemek::ecs
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
Component const & get() const;
|
Component const & get() const;
|
||||||
|
|
||||||
/** Obtain the component by uuid of the accessed entity.
|
|
||||||
* As the runtime type of the component is unknown,
|
|
||||||
* the function returns pointer-to-void.
|
|
||||||
*
|
|
||||||
* @param uuid The uuid of component to obtain
|
|
||||||
* @return A pointer to the component of the specified type, or a null
|
|
||||||
* pointer if the entity doesn't contain a component of this type
|
|
||||||
* @pre The accessor is valid
|
|
||||||
*/
|
|
||||||
void * get_if(util::uuid const & uuid);
|
|
||||||
|
|
||||||
void const * get_if(util::uuid const & uuid) const;
|
|
||||||
|
|
||||||
/** Check if the entity contains this component type.
|
/** Check if the entity contains this component type.
|
||||||
*
|
*
|
||||||
* @tparam Component The type of component to obtain
|
* @tparam Component The type of component to obtain
|
||||||
|
|
@ -109,7 +98,12 @@ namespace psemek::ecs
|
||||||
Component const * accessor::get_if() const
|
Component const * accessor::get_if() const
|
||||||
{
|
{
|
||||||
util::uuid const uuid = std::remove_const_t<Component>::uuid();
|
util::uuid const uuid = std::remove_const_t<Component>::uuid();
|
||||||
return reinterpret_cast<Component const *>(get_if(uuid));
|
|
||||||
|
auto column = table_->column(uuid);
|
||||||
|
if (!column)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return reinterpret_cast<Component *>(column->data() + detail::stride<std::remove_const_t<Component>>() * row_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
|
|
@ -117,7 +111,7 @@ namespace psemek::ecs
|
||||||
{
|
{
|
||||||
if (auto ptr = get_if<Component>())
|
if (auto ptr = get_if<Component>())
|
||||||
return *ptr;
|
return *ptr;
|
||||||
throw component_not_found_exception(typeid(std::remove_const_t<Component>), table_->entity_handles()[row_], table_->describe_short());
|
throw component_not_found_exception(typeid(std::remove_const_t<Component>), table_->entity_handles()[row_], table_->describe(row_));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
|
|
@ -125,21 +119,7 @@ namespace psemek::ecs
|
||||||
{
|
{
|
||||||
if (auto ptr = get_if<Component const>())
|
if (auto ptr = get_if<Component const>())
|
||||||
return *ptr;
|
return *ptr;
|
||||||
throw component_not_found_exception(typeid(std::remove_const_t<Component>), table_->entity_handles()[row_], table_->describe_short());
|
throw component_not_found_exception(typeid(std::remove_const_t<Component>), table_->entity_handles()[row_], table_->describe(row_));
|
||||||
}
|
|
||||||
|
|
||||||
inline void * accessor::get_if(util::uuid const & uuid)
|
|
||||||
{
|
|
||||||
return const_cast<void *>(static_cast<accessor const *>(this)->get_if(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void const * accessor::get_if(util::uuid const & uuid) const
|
|
||||||
{
|
|
||||||
auto column = table_->column(uuid);
|
|
||||||
if (!column)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return column->data() + column->stride() * row_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,7 @@
|
||||||
#include <psemek/ecs/detail/without.hpp>
|
#include <psemek/ecs/detail/without.hpp>
|
||||||
#include <psemek/ecs/detail/component_registry.hpp>
|
#include <psemek/ecs/detail/component_registry.hpp>
|
||||||
#include <psemek/ecs/detail/index_container.hpp>
|
#include <psemek/ecs/detail/index_container.hpp>
|
||||||
#include <psemek/ecs/detail/recursion_depth_guard.hpp>
|
|
||||||
#include <psemek/ecs/accessor.hpp>
|
#include <psemek/ecs/accessor.hpp>
|
||||||
#include <psemek/ecs/inspect.hpp>
|
|
||||||
#include <psemek/ecs/exceptions.hpp>
|
#include <psemek/ecs/exceptions.hpp>
|
||||||
#include <psemek/ecs/statistics.hpp>
|
#include <psemek/ecs/statistics.hpp>
|
||||||
#include <psemek/util/range.hpp>
|
#include <psemek/util/range.hpp>
|
||||||
|
|
@ -96,33 +94,14 @@ namespace psemek::ecs
|
||||||
*/
|
*/
|
||||||
accessor get(handle entity);
|
accessor get(handle entity);
|
||||||
|
|
||||||
/** Inspect the entity, i.e. enumerate the entitie's components.
|
/** 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 inspect
|
|
||||||
* @return A list of component uuids & metadata
|
|
||||||
* @pre The entity was previously obtained by a `create()` call and is `alive()`
|
|
||||||
*/
|
|
||||||
entity_inspection_info inspect(handle entity) const;
|
|
||||||
|
|
||||||
/** Compute a short string representation of an entity, based on the contained components.
|
|
||||||
* The short version just enumerates the component types, separated by ';'.
|
|
||||||
*
|
*
|
||||||
* @param entity A handle to the entity to describe
|
* @param entity A handle to the entity to describe
|
||||||
* @return A short string representation of an entity
|
* @return A string representation of an entity
|
||||||
* @pre The entity was previously obtained by a `create()` call and is `alive()`
|
* @pre The entity was previously obtained by a `create()` call and is `alive()`
|
||||||
*/
|
*/
|
||||||
std::string describe_short(handle entity) const;
|
std::string describe(handle entity) const;
|
||||||
|
|
||||||
/** Compute a detailed 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.
|
|
||||||
* The detailed version lists all components together with their data (as provided by
|
|
||||||
* component.to_string) in a large multi-line string.
|
|
||||||
*
|
|
||||||
* @param entity A handle to the entity to describe
|
|
||||||
* @return A detailed string representation of an entity
|
|
||||||
* @pre The entity was previously obtained by a `create()` call and is `alive()`
|
|
||||||
*/
|
|
||||||
std::string describe_detailed(handle entity) const;
|
|
||||||
|
|
||||||
/** Check if the entity can be cloned.
|
/** Check if the entity can be cloned.
|
||||||
*
|
*
|
||||||
|
|
@ -444,7 +423,7 @@ namespace psemek::ecs
|
||||||
{
|
{
|
||||||
static_assert(detail::all_different_types_v<std::remove_cvref_t<Components>...>, "all component types must be different");
|
static_assert(detail::all_different_types_v<std::remove_cvref_t<Components>...>, "all component types must be different");
|
||||||
|
|
||||||
detail::recursion_depth_guard guard{method_recursion_depth_};
|
++method_recursion_depth_;
|
||||||
|
|
||||||
(register_component<std::remove_cvref_t<Components>>(), ...);
|
(register_component<std::remove_cvref_t<Components>>(), ...);
|
||||||
|
|
||||||
|
|
@ -482,6 +461,8 @@ namespace psemek::ecs
|
||||||
|
|
||||||
finalize_method();
|
finalize_method();
|
||||||
|
|
||||||
|
--method_recursion_depth_;
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,7 +476,7 @@ namespace psemek::ecs
|
||||||
currently_changing_archetype_.insert(entity);
|
currently_changing_archetype_.insert(entity);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
detail::recursion_depth_guard guard{method_recursion_depth_};
|
++method_recursion_depth_;
|
||||||
|
|
||||||
(register_component<Components>(), ...);
|
(register_component<Components>(), ...);
|
||||||
|
|
||||||
|
|
@ -557,6 +538,8 @@ namespace psemek::ecs
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
finalize_method();
|
finalize_method();
|
||||||
|
|
||||||
|
--method_recursion_depth_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ... Components>
|
template <typename ... Components>
|
||||||
|
|
@ -569,7 +552,7 @@ namespace psemek::ecs
|
||||||
currently_changing_archetype_.insert(entity);
|
currently_changing_archetype_.insert(entity);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
detail::recursion_depth_guard guard{method_recursion_depth_};
|
++method_recursion_depth_;
|
||||||
|
|
||||||
auto detached_uuid_set = uuid_set_pool_.get();
|
auto detached_uuid_set = uuid_set_pool_.get();
|
||||||
(detached_uuid_set.insert(std::remove_const_t<Components>::uuid()), ...);
|
(detached_uuid_set.insert(std::remove_const_t<Components>::uuid()), ...);
|
||||||
|
|
@ -631,6 +614,8 @@ namespace psemek::ecs
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
finalize_method();
|
finalize_method();
|
||||||
|
|
||||||
|
--method_recursion_depth_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ... Components>
|
template <typename ... Components>
|
||||||
|
|
@ -656,7 +641,7 @@ namespace psemek::ecs
|
||||||
{
|
{
|
||||||
static_assert(detail::all_different_types_v<std::remove_const_t<Components>...>, "all component types must be different");
|
static_assert(detail::all_different_types_v<std::remove_const_t<Components>...>, "all component types must be different");
|
||||||
|
|
||||||
detail::recursion_depth_guard guard{method_recursion_depth_};
|
++method_recursion_depth_;
|
||||||
|
|
||||||
using invocable_type = typename detail::filter_with<detail::invocable, std::tuple<Components...>, Function>::type;
|
using invocable_type = typename detail::filter_with<detail::invocable, std::tuple<Components...>, Function>::type;
|
||||||
|
|
||||||
|
|
@ -687,6 +672,8 @@ namespace psemek::ecs
|
||||||
|
|
||||||
finalize_method();
|
finalize_method();
|
||||||
|
|
||||||
|
--method_recursion_depth_;
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -695,7 +682,7 @@ namespace psemek::ecs
|
||||||
{
|
{
|
||||||
static_assert(detail::all_different_types_v<std::remove_const_t<Components>...>, "all component types must be different");
|
static_assert(detail::all_different_types_v<std::remove_const_t<Components>...>, "all component types must be different");
|
||||||
|
|
||||||
detail::recursion_depth_guard guard{method_recursion_depth_};
|
++method_recursion_depth_;
|
||||||
|
|
||||||
using invocable_type = typename detail::filter_with<detail::batch_invocable, std::tuple<Components...>, Function>::type;
|
using invocable_type = typename detail::filter_with<detail::batch_invocable, std::tuple<Components...>, Function>::type;
|
||||||
|
|
||||||
|
|
@ -723,6 +710,8 @@ namespace psemek::ecs
|
||||||
|
|
||||||
finalize_method();
|
finalize_method();
|
||||||
|
|
||||||
|
--method_recursion_depth_;
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/ecs/detail/stride.hpp>
|
#include <psemek/ecs/detail/stride.hpp>
|
||||||
#include <psemek/ecs/detail/to_string.hpp>
|
#include <psemek/ecs/detail/describe.hpp>
|
||||||
#include <psemek/util/uuid.hpp>
|
#include <psemek/util/uuid.hpp>
|
||||||
#include <psemek/util/assert.hpp>
|
#include <psemek/util/assert.hpp>
|
||||||
|
|
||||||
|
|
@ -33,11 +33,6 @@ namespace psemek::ecs::detail
|
||||||
return uuid_;
|
return uuid_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const & name() const
|
|
||||||
{
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::type_index const & type() const
|
std::type_index const & type() const
|
||||||
{
|
{
|
||||||
return type_;
|
return type_;
|
||||||
|
|
@ -59,20 +54,21 @@ namespace psemek::ecs::detail
|
||||||
|
|
||||||
virtual std::size_t memory_usage() const = 0;
|
virtual std::size_t memory_usage() const = 0;
|
||||||
|
|
||||||
|
virtual std::string describe() const = 0;
|
||||||
|
virtual std::string describe(std::uint32_t row) const = 0;
|
||||||
|
|
||||||
virtual ~column() = default;
|
virtual ~column() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::uint8_t * data_ = nullptr;
|
std::uint8_t * data_ = nullptr;
|
||||||
std::size_t stride_;
|
std::size_t stride_;
|
||||||
util::uuid uuid_;
|
util::uuid uuid_;
|
||||||
std::string name_;
|
|
||||||
std::type_index type_;
|
std::type_index type_;
|
||||||
bool copy_constructible_;
|
bool copy_constructible_;
|
||||||
|
|
||||||
column(std::size_t stride, util::uuid const & uuid, std::string name, std::type_index const & type, bool copy_constructible)
|
column(std::size_t stride, util::uuid const & uuid, std::type_index const & type, bool copy_constructible)
|
||||||
: stride_(stride)
|
: stride_(stride)
|
||||||
, uuid_(uuid)
|
, uuid_(uuid)
|
||||||
, name_(std::move(name))
|
|
||||||
, type_(type)
|
, type_(type)
|
||||||
, copy_constructible_(copy_constructible)
|
, copy_constructible_(copy_constructible)
|
||||||
{}
|
{}
|
||||||
|
|
@ -95,6 +91,9 @@ namespace psemek::ecs::detail
|
||||||
|
|
||||||
std::size_t memory_usage() const override;
|
std::size_t memory_usage() const override;
|
||||||
|
|
||||||
|
std::string describe() const override;
|
||||||
|
std::string describe(std::uint32_t row) const override;
|
||||||
|
|
||||||
~column_impl() override;
|
~column_impl() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -121,12 +120,15 @@ namespace psemek::ecs::detail
|
||||||
|
|
||||||
std::size_t memory_usage() const override;
|
std::size_t memory_usage() const override;
|
||||||
|
|
||||||
|
std::string describe() const override;
|
||||||
|
std::string describe(std::uint32_t row) const override;
|
||||||
|
|
||||||
~column_impl() override;
|
~column_impl() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Component, bool Empty>
|
template <typename Component, bool Empty>
|
||||||
column_impl<Component, Empty>::column_impl()
|
column_impl<Component, Empty>::column_impl()
|
||||||
: column(detail::stride<Component>(), Component::uuid(), component_name<Component>(), typeid(Component), std::is_copy_constructible_v<Component>)
|
: column(detail::stride<Component>(), Component::uuid(), typeid(Component), std::is_copy_constructible_v<Component>)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template <typename Component, bool Empty>
|
template <typename Component, bool Empty>
|
||||||
|
|
@ -216,6 +218,18 @@ namespace psemek::ecs::detail
|
||||||
return sizeof(Component) * row_count_;
|
return sizeof(Component) * row_count_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Component, bool Empty>
|
||||||
|
std::string column_impl<Component, Empty>::describe() const
|
||||||
|
{
|
||||||
|
return detail::describe<Component>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Component, bool Empty>
|
||||||
|
std::string column_impl<Component, Empty>::describe(std::uint32_t row) const
|
||||||
|
{
|
||||||
|
return detail::describe(reinterpret_cast<Component const *>(data_)[row]);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Component, bool Empty>
|
template <typename Component, bool Empty>
|
||||||
column_impl<Component, Empty>::~column_impl()
|
column_impl<Component, Empty>::~column_impl()
|
||||||
{
|
{
|
||||||
|
|
@ -253,7 +267,7 @@ namespace psemek::ecs::detail
|
||||||
|
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
column_impl<Component, true>::column_impl()
|
column_impl<Component, true>::column_impl()
|
||||||
: column(detail::stride<Component>(), Component::uuid(), component_name<Component>(), typeid(Component), std::is_copy_constructible_v<Component>)
|
: column(detail::stride<Component>(), Component::uuid(), typeid(Component), std::is_copy_constructible_v<Component>)
|
||||||
{
|
{
|
||||||
data_ = reinterpret_cast<std::uint8_t *>(new Component[1]);
|
data_ = reinterpret_cast<std::uint8_t *>(new Component[1]);
|
||||||
}
|
}
|
||||||
|
|
@ -294,6 +308,18 @@ namespace psemek::ecs::detail
|
||||||
return sizeof(Component);
|
return sizeof(Component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Component>
|
||||||
|
std::string column_impl<Component, true>::describe() const
|
||||||
|
{
|
||||||
|
return detail::describe<Component>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Component>
|
||||||
|
std::string column_impl<Component, true>::describe(std::uint32_t) const
|
||||||
|
{
|
||||||
|
return detail::describe(*reinterpret_cast<Component const *>(data_));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
column_impl<Component, true>::~column_impl()
|
column_impl<Component, true>::~column_impl()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/ecs/detail/column.hpp>
|
#include <psemek/ecs/detail/column.hpp>
|
||||||
#include <psemek/ecs/detail/to_string.hpp>
|
|
||||||
#include <psemek/util/uuid.hpp>
|
#include <psemek/util/uuid.hpp>
|
||||||
#include <psemek/util/hash_table.hpp>
|
#include <psemek/util/hash_table.hpp>
|
||||||
#include <psemek/util/function.hpp>
|
#include <psemek/util/function.hpp>
|
||||||
|
|
@ -33,54 +32,36 @@ namespace psemek::ecs::detail
|
||||||
|
|
||||||
struct component_registry
|
struct component_registry
|
||||||
{
|
{
|
||||||
struct component_info
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::type_info const * type_info;
|
|
||||||
util::function<std::unique_ptr<column>()> column_factory;
|
|
||||||
util::function<std::string(void const *)> to_string;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
void register_component()
|
void register_component()
|
||||||
{
|
{
|
||||||
auto const & uuid = Component::uuid();
|
auto const & uuid = Component::uuid();
|
||||||
|
|
||||||
if (auto it = components_.find(uuid); it != components_.end())
|
if (auto it = types_.find(uuid); it != types_.end())
|
||||||
{
|
{
|
||||||
if (it->second.type_info != &typeid(Component))
|
if (it->second != &typeid(Component))
|
||||||
throw duplicate_uuid_exception(uuid, *(it->second.type_info), typeid(Component));
|
throw duplicate_uuid_exception(uuid, *(it->second), typeid(Component));
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
component_info & info = components_[uuid];
|
types_.insert({uuid, &typeid(Component)});
|
||||||
info.name = component_name<Component>();
|
|
||||||
info.type_info = &typeid(Component);
|
column_factories_.insert({uuid, []{
|
||||||
info.column_factory = []{
|
|
||||||
return std::make_unique<column_impl<Component>>();
|
return std::make_unique<column_impl<Component>>();
|
||||||
};
|
}});
|
||||||
info.to_string = [](void const * data){
|
|
||||||
return component_to_string(*static_cast<Component const *>(data));
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<column> create_column(util::uuid const & uuid) const
|
std::unique_ptr<column> create_column(util::uuid const & uuid) const
|
||||||
{
|
{
|
||||||
if (auto it = components_.find(uuid); it != components_.end())
|
if (auto it = column_factories_.find(uuid); it != column_factories_.end())
|
||||||
return it->second.column_factory();
|
return it->second();
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
component_info const * get_info(util::uuid const & uuid) const
|
|
||||||
{
|
|
||||||
if (auto it = components_.find(uuid); it != components_.end())
|
|
||||||
return &it->second;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
util::hash_map<util::uuid, component_info> components_;
|
util::hash_map<util::uuid, std::type_info const *> types_;
|
||||||
|
util::hash_map<util::uuid, util::function<std::unique_ptr<column>()>> column_factories_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
libs/ecs/include/psemek/ecs/detail/describe.hpp
Normal file
39
libs/ecs/include/psemek/ecs/detail/describe.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <psemek/util/type_name.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace psemek::ecs::detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename Component>
|
||||||
|
std::string describe()
|
||||||
|
{
|
||||||
|
if constexpr (requires {Component::to_string();})
|
||||||
|
{
|
||||||
|
return Component::to_string();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto name = util::type_name<Component>();
|
||||||
|
if (auto pos = name.find_last_of(':'); pos != std::string::npos)
|
||||||
|
name = name.substr(pos + 1);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Component>
|
||||||
|
std::string describe(Component const & component)
|
||||||
|
{
|
||||||
|
if constexpr (requires {component.to_string();})
|
||||||
|
{
|
||||||
|
return component.to_string();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return describe<Component>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace psemek::ecs::detail
|
|
||||||
{
|
|
||||||
|
|
||||||
struct recursion_depth_guard
|
|
||||||
{
|
|
||||||
recursion_depth_guard(std::size_t & value)
|
|
||||||
: depth_(&value)
|
|
||||||
{
|
|
||||||
++value;
|
|
||||||
}
|
|
||||||
|
|
||||||
recursion_depth_guard(recursion_depth_guard && other)
|
|
||||||
: depth_(other.depth_)
|
|
||||||
{
|
|
||||||
other.depth_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
recursion_depth_guard & operator = (recursion_depth_guard && other)
|
|
||||||
{
|
|
||||||
if (this != &other)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
depth_ = other.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~recursion_depth_guard()
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
if (depth_)
|
|
||||||
--*depth_;
|
|
||||||
depth_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t * release()
|
|
||||||
{
|
|
||||||
return std::exchange(depth_, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::size_t * depth_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace psemek::ecs::detail
|
namespace psemek::ecs::detail
|
||||||
{
|
{
|
||||||
|
|
@ -80,7 +81,8 @@ namespace psemek::ecs::detail
|
||||||
|
|
||||||
std::size_t memory_usage() const;
|
std::size_t memory_usage() const;
|
||||||
|
|
||||||
std::string describe_short() const;
|
std::string describe() const;
|
||||||
|
std::string describe(std::uint32_t row) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::uint64_t hash_;
|
std::uint64_t hash_;
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <psemek/util/type_name.hpp>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace psemek::ecs::detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template <typename Component>
|
|
||||||
std::string component_name()
|
|
||||||
{
|
|
||||||
if constexpr (requires {Component::name();})
|
|
||||||
{
|
|
||||||
return Component::name();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static std::string const result = []{
|
|
||||||
std::string name = util::type_name<Component>();
|
|
||||||
if (auto pos = name.find_last_of(':'); pos != std::string::npos)
|
|
||||||
name = name.substr(pos + 1);
|
|
||||||
return name;
|
|
||||||
}();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Component>
|
|
||||||
std::string component_to_string(Component const & component)
|
|
||||||
{
|
|
||||||
if constexpr (requires {component.to_string();})
|
|
||||||
{
|
|
||||||
return component.to_string();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <psemek/ecs/detail/component_registry.hpp>
|
|
||||||
|
|
||||||
namespace psemek::ecs
|
|
||||||
{
|
|
||||||
|
|
||||||
struct entity_inspection_info
|
|
||||||
{
|
|
||||||
struct component_inspection_info
|
|
||||||
{
|
|
||||||
util::uuid uuid;
|
|
||||||
detail::component_registry::component_info const * info;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<component_inspection_info> components;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
#include <psemek/ecs/container.hpp>
|
#include <psemek/ecs/container.hpp>
|
||||||
#include <psemek/util/assert.hpp>
|
#include <psemek/util/assert.hpp>
|
||||||
#include <psemek/util/string.hpp>
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
@ -53,47 +52,11 @@ namespace psemek::ecs
|
||||||
return {data.table, data.row};
|
return {data.table, data.row};
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_inspection_info container::inspect(handle entity) const
|
std::string container::describe(handle entity) const
|
||||||
{
|
{
|
||||||
entity_inspection_info result;
|
assert(alive(entity));
|
||||||
auto const data = entity_list_.get_entities()[entity.id];
|
auto const data = entity_list_.get_entities()[entity.id];
|
||||||
for (auto const & column : data.table->columns())
|
return data.table->describe(data.row);
|
||||||
{
|
|
||||||
auto const uuid = column->uuid();
|
|
||||||
result.components.push_back({uuid, component_registry_.get_info(uuid)});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string container::describe_short(handle entity) const
|
|
||||||
{
|
|
||||||
return entity_list_.get_entities()[entity.id].table->describe_short();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string container::describe_detailed(handle entity) const
|
|
||||||
{
|
|
||||||
static std::string const indent = " ";
|
|
||||||
|
|
||||||
std::string result;
|
|
||||||
|
|
||||||
auto const data = entity_list_.get_entities()[entity.id];
|
|
||||||
for (auto const & column : data.table->columns())
|
|
||||||
{
|
|
||||||
auto const info = component_registry_.get_info(column->uuid());
|
|
||||||
result += info->name;
|
|
||||||
result += "\n";
|
|
||||||
|
|
||||||
auto const ptr = column->data() + column->stride() * data.row;
|
|
||||||
auto value = info->to_string(ptr);
|
|
||||||
if (!value.empty())
|
|
||||||
{
|
|
||||||
result += indent;
|
|
||||||
result += util::replace_all(util::trim(std::move(value)), "\n", "\n" + indent);
|
|
||||||
result += "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return util::trim(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool container::can_clone(handle entity) const
|
bool container::can_clone(handle entity) const
|
||||||
|
|
@ -227,7 +190,7 @@ namespace psemek::ecs
|
||||||
|
|
||||||
table_container_.apply([&](detail::table & table)
|
table_container_.apply([&](detail::table & table)
|
||||||
{
|
{
|
||||||
result.tables.push_back({table.describe_short(), table.row_count()});
|
result.tables.push_back({table.describe(), table.row_count()});
|
||||||
}, {}, {});
|
}, {}, {});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
#include <psemek/ecs/detail/table.hpp>
|
#include <psemek/ecs/detail/table.hpp>
|
||||||
#include <psemek/ecs/detail/unordered_component_hash.hpp>
|
#include <psemek/ecs/detail/unordered_component_hash.hpp>
|
||||||
#include <psemek/ecs/detail/to_string.hpp>
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
@ -191,14 +190,26 @@ namespace psemek::ecs::detail
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string table::describe_short() const
|
std::string table::describe() const
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
for (auto const & column : columns_)
|
for (std::size_t i = 0; i < columns_.size(); ++i)
|
||||||
{
|
{
|
||||||
if (!result.empty())
|
if (i > 0)
|
||||||
result += ";";
|
result += ";";
|
||||||
result += column->name();
|
result += columns_[i]->describe();
|
||||||
|
}
|
||||||
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
#include <psemek/gfx/array.hpp>
|
#include <psemek/gfx/array.hpp>
|
||||||
#include <psemek/gfx/gl.hpp>
|
#include <psemek/gfx/gl.hpp>
|
||||||
|
|
||||||
#include <psemek/util/string.hpp>
|
|
||||||
#include <psemek/util/to_string.hpp>
|
#include <psemek/util/to_string.hpp>
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
@ -68,6 +67,17 @@ void main()
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
static void replace_all(std::string & str, std::string_view old_str, std::string_view new_str)
|
||||||
|
{
|
||||||
|
for (size_t i = 0;;)
|
||||||
|
{
|
||||||
|
i = str.find(old_str, i);
|
||||||
|
if (i == std::string::npos) break;
|
||||||
|
str.replace(i, old_str.size(), new_str);
|
||||||
|
i += new_str.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static std::string generate_blur_fs_source(int size, float sigma, bool horizontal)
|
static std::string generate_blur_fs_source(int size, float sigma, bool horizontal)
|
||||||
{
|
{
|
||||||
std::string size_str = util::to_string(size);
|
std::string size_str = util::to_string(size);
|
||||||
|
|
@ -95,9 +105,9 @@ void main()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string result = blur_fs_template;
|
std::string result = blur_fs_template;
|
||||||
result = util::replace_all(std::move(result), "@BLUR_SIZE@", size_str);
|
replace_all(result, "@BLUR_SIZE@", size_str);
|
||||||
result = util::replace_all(std::move(result), "@BLUR_COEFFS@", coeffs_ss.str());
|
replace_all(result, "@BLUR_COEFFS@", coeffs_ss.str());
|
||||||
result = util::replace_all(std::move(result), "@BLUR_DIRECTION@", direction_str);
|
replace_all(result, "@BLUR_DIRECTION@", direction_str);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
namespace psemek::util
|
|
||||||
{
|
|
||||||
|
|
||||||
std::string replace_all(std::string str, std::string_view old_str, std::string_view new_str);
|
|
||||||
|
|
||||||
std::string trim_front(std::string str);
|
|
||||||
std::string trim_back(std::string str);
|
|
||||||
std::string trim(std::string str);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
#include <psemek/util/string.hpp>
|
|
||||||
|
|
||||||
namespace psemek::util
|
|
||||||
{
|
|
||||||
|
|
||||||
std::string replace_all(std::string str, std::string_view old_str, std::string_view new_str)
|
|
||||||
{
|
|
||||||
for (size_t i = 0;;)
|
|
||||||
{
|
|
||||||
i = str.find(old_str, i);
|
|
||||||
if (i == std::string::npos) break;
|
|
||||||
str.replace(i, old_str.size(), new_str);
|
|
||||||
i += new_str.size();
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string const whitespace_mask = " \t\n\r\f\v";
|
|
||||||
|
|
||||||
std::string trim_front(std::string str)
|
|
||||||
{
|
|
||||||
str.erase(0, str.find_first_not_of(whitespace_mask));
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string trim_back(std::string str)
|
|
||||||
{
|
|
||||||
size_t pos = str.find_last_not_of(whitespace_mask);
|
|
||||||
if (pos != std::string::npos) {
|
|
||||||
str.erase(pos + 1);
|
|
||||||
} else {
|
|
||||||
str.clear();
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string trim(std::string str)
|
|
||||||
{
|
|
||||||
return trim_back(trim_front(std::move(str)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue