From 9284a063d17dccddcc83ae78bce3c5107f1e7540 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sun, 19 May 2019 04:11:37 +0700 Subject: [PATCH] add the ability to applying prototype to components --- headers/ecs.hpp/ecs.hpp | 103 +++++++++++++++++++++++++--------------- untests/ecs_tests.cpp | 31 ++++++++++++ 2 files changed, 97 insertions(+), 37 deletions(-) diff --git a/headers/ecs.hpp/ecs.hpp b/headers/ecs.hpp/ecs.hpp index c2dfec7..886c5ca 100644 --- a/headers/ecs.hpp/ecs.hpp +++ b/headers/ecs.hpp/ecs.hpp @@ -1099,23 +1099,30 @@ namespace ecs_hpp { namespace detail { - class component_applier_base; - using component_applier_uptr = std::unique_ptr; + class applier_base; + using applier_uptr = std::unique_ptr; - class component_applier_base { + class applier_base { public: - virtual ~component_applier_base() = default; - virtual component_applier_uptr clone() const = 0; - virtual void apply_to(entity& ent, bool override) const = 0; + virtual ~applier_base() = default; + virtual applier_uptr clone() const = 0; + virtual void apply_to_entity(entity& ent, bool override) const = 0; + }; + + template < typename T > + class typed_applier : public applier_base { + public: + virtual void apply_to_component(T& component) const = 0; }; template < typename T, typename... Args > - class component_applier final : public component_applier_base { + class typed_applier_with_args final : public typed_applier { public: - component_applier(std::tuple&& args); - component_applier(const std::tuple& args); - component_applier_uptr clone() const override; - void apply_to(entity& ent, bool override) const override; + typed_applier_with_args(std::tuple&& args); + typed_applier_with_args(const std::tuple& args); + applier_uptr clone() const override; + void apply_to_entity(entity& ent, bool override) const override; + void apply_to_component(T& component) const override; private: std::tuple args_; }; @@ -1147,11 +1154,13 @@ namespace ecs_hpp prototype& merge_with(const prototype& other, bool override) &; prototype&& merge_with(const prototype& other, bool override) &&; - void apply_to(entity& ent, bool override) const; + template < typename T > + bool apply_to_component(T& component) const; + void apply_to_entity(entity& ent, bool override) const; private: detail::sparse_map< family_id, - detail::component_applier_uptr> appliers_; + detail::applier_uptr> appliers_; }; void swap(prototype& l, prototype& r) noexcept; @@ -1840,31 +1849,38 @@ namespace ecs_hpp namespace detail { template < typename T, typename... Args > - component_applier::component_applier(std::tuple&& args) + typed_applier_with_args::typed_applier_with_args(std::tuple&& args) : args_(std::move(args)) {} template < typename T, typename... Args > - component_applier::component_applier(const std::tuple& args) + typed_applier_with_args::typed_applier_with_args(const std::tuple& args) : args_(args) {} template < typename T, typename... Args > - component_applier_uptr component_applier::clone() const { - return std::make_unique(args_); + applier_uptr typed_applier_with_args::clone() const { + return std::make_unique(args_); } template < typename T, typename... Args > - void component_applier::apply_to(entity& ent, bool override) const { + void typed_applier_with_args::apply_to_entity(entity& ent, bool override) const { detail::tiny_tuple_apply([&ent, override](const Args&... args){ if ( override || !ent.exists_component() ) { ent.assign_component(args...); } }, args_); } + + template < typename T, typename... Args > + void typed_applier_with_args::apply_to_component(T& component) const { + detail::tiny_tuple_apply([&component](const Args&... args){ + component = T(args...); + }, args_); + } } inline prototype::prototype(const prototype& other) { - for ( const family_id id : other.appliers_ ) { - appliers_.insert(id, other.appliers_.get(id)->clone()); + for ( const family_id family : other.appliers_ ) { + appliers_.insert(family, other.appliers_.get(family)->clone()); } } @@ -1908,7 +1924,7 @@ namespace ecs_hpp template < typename T, typename... Args > prototype& prototype::component(Args&&... args) & { - using applier_t = detail::component_applier< + using applier_t = detail::typed_applier_with_args< T, std::decay_t...>; auto applier = std::make_unique( @@ -1925,11 +1941,11 @@ namespace ecs_hpp } inline prototype& prototype::merge_with(const prototype& other, bool override) & { - for ( const auto family_id : other.appliers_ ) { - if ( override || !appliers_.has(family_id) ) { + for ( const auto family : other.appliers_ ) { + if ( override || !appliers_.has(family) ) { appliers_.insert_or_assign( - family_id, - other.appliers_.get(family_id)->clone()); + family, + other.appliers_.get(family)->clone()); } } return *this; @@ -1940,9 +1956,22 @@ namespace ecs_hpp return std::move(*this); } - inline void prototype::apply_to(entity& ent, bool override) const { - for ( const auto family_id : appliers_ ) { - appliers_.get(family_id)->apply_to(ent, override); + template < typename T > + bool prototype::apply_to_component(T& component) const { + const auto family = detail::type_family::id(); + const auto applier_base_ptr = appliers_.find(family); + if ( !applier_base_ptr ) { + return false; + } + using applier_t = detail::typed_applier; + const auto applier = static_cast(applier_base_ptr->get()); + applier->apply_to_component(component); + return true; + } + + inline void prototype::apply_to_entity(entity& ent, bool override) const { + for ( const auto family : appliers_ ) { + appliers_.get(family)->apply_to_entity(ent, override); } } @@ -2096,7 +2125,7 @@ namespace ecs_hpp inline entity registry::create_entity(const prototype& proto) { auto ent = create_entity(); try { - proto.apply_to(ent, true); + proto.apply_to_entity(ent, true); } catch (...) { destroy_entity(ent); throw; @@ -2108,8 +2137,8 @@ namespace ecs_hpp assert(valid_entity(proto)); entity ent = create_entity(); try { - for ( const auto family_id : storages_ ) { - storages_.get(family_id)->clone(proto, ent.id()); + for ( const auto family : storages_ ) { + storages_.get(family)->clone(proto, ent.id()); } } catch (...) { destroy_entity(ent); @@ -2161,8 +2190,8 @@ namespace ecs_hpp inline std::size_t registry::remove_all_components(const uentity& ent) noexcept { assert(valid_entity(ent)); std::size_t removed_count = 0u; - for ( const auto family_id : storages_ ) { - if ( storages_.get(family_id)->remove(ent) ) { + for ( const auto family : storages_ ) { + if ( storages_.get(family)->remove(ent) ) { ++removed_count; } } @@ -2246,8 +2275,8 @@ namespace ecs_hpp inline std::size_t registry::entity_component_count(const const_uentity& ent) const noexcept { assert(valid_entity(ent)); std::size_t component_count = 0u; - for ( const auto family_id : storages_ ) { - if ( storages_.get(family_id)->has(ent) ) { + for ( const auto family : storages_ ) { + if ( storages_.get(family)->has(ent) ) { ++component_count; } } @@ -2348,8 +2377,8 @@ namespace ecs_hpp memory_usage_info info; info.entities += free_entity_ids_.capacity() * sizeof(free_entity_ids_[0]); info.entities += entity_ids_.memory_usage(); - for ( const auto family_id : storages_ ) { - info.components += storages_.get(family_id)->memory_usage(); + for ( const auto family : storages_ ) { + info.components += storages_.get(family)->memory_usage(); } return info; } diff --git a/untests/ecs_tests.cpp b/untests/ecs_tests.cpp index 8fd31c5..40240eb 100644 --- a/untests/ecs_tests.cpp +++ b/untests/ecs_tests.cpp @@ -661,6 +661,37 @@ TEST_CASE("registry") { REQUIRE(e4.get_component() == position_c(1,2)); REQUIRE(e4.get_component() == velocity_c(3,4)); } + { + const auto p1 = ecs::prototype() + .component(1,2) + .component(3,4); + + position_c c1; + velocity_c c2; + movable_c c3; + + REQUIRE(p1.apply_to_component(c1)); + REQUIRE(p1.apply_to_component(c2)); + REQUIRE_FALSE(p1.apply_to_component(c3)); + + REQUIRE(c1 == position_c(1,2)); + REQUIRE(c2 == velocity_c(3,4)); + } + { + const auto p1 = ecs::prototype() + .component(1,2); + + position_c c1; + velocity_c c2; + movable_c c3; + + REQUIRE(p1.apply_to_component(c1)); + REQUIRE_FALSE(p1.apply_to_component(c2)); + REQUIRE_FALSE(p1.apply_to_component(c3)); + + REQUIRE(c1 == position_c(1,2)); + REQUIRE(c2 == velocity_c(0,0)); + } } SECTION("component_assigning") { {