From 24bfcaf7ebb11ea10d79dcb949e2efa0100f4332 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Wed, 10 Apr 2019 02:08:55 +0700 Subject: [PATCH] add entity cloning --- ecs.hpp | 53 +++++++++++++++++++++++++++++++++++++++++---------- ecs_tests.cpp | 43 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/ecs.hpp b/ecs.hpp index ed8d5e5..8f9e4b8 100644 --- a/ecs.hpp +++ b/ecs.hpp @@ -322,7 +322,7 @@ namespace ecs_hpp } bool unordered_erase(const T& v) noexcept( - noexcept(indexer_(std::declval())) && + noexcept(std::declval()(std::declval())) && std::is_nothrow_move_assignable::value) { if ( !has(v) ) { @@ -343,7 +343,7 @@ namespace ecs_hpp } bool has(const T& v) const noexcept( - noexcept(indexer_(std::declval()))) + noexcept(std::declval()(std::declval()))) { const std::size_t vi = indexer_(v); return vi < sparse_.size() @@ -352,7 +352,7 @@ namespace ecs_hpp } const_iterator find(const T& v) const noexcept( - noexcept(indexer_(std::declval()))) + noexcept(std::declval()(std::declval()))) { return has(v) ? begin() + sparse_[indexer_(v)] @@ -368,7 +368,7 @@ namespace ecs_hpp } std::pair find_dense_index(const T& v) const noexcept( - noexcept(indexer_(std::declval()))) + noexcept(std::declval()(std::declval()))) { return has(v) ? std::make_pair(sparse_[indexer_(v)], true) @@ -486,7 +486,7 @@ namespace ecs_hpp } bool unordered_erase(const K& k) noexcept( - noexcept(keys_.find_dense_index(k)) && + noexcept(std::declval>().find_dense_index(k)) && std::is_nothrow_move_assignable::value) { static_assert( @@ -510,7 +510,7 @@ namespace ecs_hpp } bool has(const K& k) const noexcept( - noexcept(keys_.has(k))) + noexcept(std::declval>().has(k))) { return keys_.has(k); } @@ -524,7 +524,7 @@ namespace ecs_hpp } T* find(const K& k) noexcept( - noexcept(keys_.find_dense_index(k))) + noexcept(std::declval>().find_dense_index(k))) { const auto value_index_p = keys_.find_dense_index(k); return value_index_p.second @@ -533,7 +533,7 @@ namespace ecs_hpp } const T* find(const K& k) const noexcept( - noexcept(keys_.find_dense_index(k))) + noexcept(std::declval>().find_dense_index(k))) { const auto value_index_p = keys_.find_dense_index(k); return value_index_p.second @@ -588,6 +588,7 @@ namespace ecs_hpp virtual ~component_storage_base() = default; virtual bool remove(entity_id id) noexcept = 0; virtual bool has(entity_id id) const noexcept = 0; + virtual void clone(entity_id from, entity_id to) = 0; }; template < typename T > @@ -605,6 +606,7 @@ namespace ecs_hpp std::size_t count() const noexcept; bool has(entity_id id) const noexcept override; + void clone(entity_id from, entity_id to) override; template < typename F > void for_each_component(F&& f); @@ -655,10 +657,18 @@ namespace ecs_hpp return components_.has(id); } + template < typename T > + void component_storage::clone(entity_id from, entity_id to) { + const T* c = components_.find(from); + if ( c ) { + components_.insert_or_assign(to, *c); + } + } + template < typename T > template < typename F > void component_storage::for_each_component(F&& f) { - for ( const auto id : components_ ) { + for ( const entity_id id : components_ ) { f(id, components_.get(id)); } } @@ -666,7 +676,7 @@ namespace ecs_hpp template < typename T > template < typename F > void component_storage::for_each_component(F&& f) const { - for ( const auto id : components_ ) { + for ( const entity_id id : components_ ) { f(id, components_.get(id)); } } @@ -699,6 +709,7 @@ namespace ecs_hpp bool destroy(); bool alive() const noexcept; + entity clone() const; template < typename T, typename... Args > bool assign_component(Args&&... args); @@ -1032,6 +1043,7 @@ namespace ecs_hpp const_component wrap_component(const const_uentity& ent) const noexcept; entity create_entity(); + entity create_entity(const const_uentity& prototype); bool destroy_entity(const uentity& ent); bool alive_entity(const const_uentity& ent) const noexcept; @@ -1244,6 +1256,10 @@ namespace ecs_hpp return detail::as_const(*owner_).alive_entity(id_); } + inline entity entity::clone() const { + return (*owner_).create_entity(id_); + } + template < typename T, typename... Args > bool entity::assign_component(Args&&... args) { return (*owner_).assign_component( @@ -1691,6 +1707,23 @@ namespace ecs_hpp throw std::logic_error("ecs_hpp::registry (entity index overlow)"); } + inline entity registry::create_entity(const const_uentity& prototype) { + assert(prototype.check_owner(this)); + entity ent = create_entity(); + if ( !alive_entity(prototype) ) { + return ent; + } + try { + for ( const auto family_id : storages_ ) { + storages_.get(family_id)->clone(prototype, ent.id()); + } + } catch (...) { + destroy_entity(ent); + throw; + } + return ent; + } + inline bool registry::destroy_entity(const uentity& ent) { assert(ent.check_owner(this)); remove_all_components(ent); diff --git a/ecs_tests.cpp b/ecs_tests.cpp index 446256f..072968a 100644 --- a/ecs_tests.cpp +++ b/ecs_tests.cpp @@ -732,6 +732,49 @@ TEST_CASE("registry") { REQUIRE(e1.get_component().y == 40); } } + SECTION("cloning") { + { + ecs::registry w; + + auto e1 = w.create_entity(); + ecs::entity_filler(e1) + .component(1, 2) + .component(3, 4); + + auto e2 = w.create_entity(e1); + REQUIRE(w.component_count() == 2); + REQUIRE(w.component_count() == 2); + REQUIRE(e2.exists_component()); + REQUIRE(e2.exists_component()); + REQUIRE(e2.get_component() == position_c(1, 2)); + REQUIRE(e2.get_component() == velocity_c(3, 4)); + + e2.remove_component(); + auto e3 = e2.clone(); + + REQUIRE(w.component_count() == 3); + REQUIRE(w.component_count() == 1); + + REQUIRE(e3.exists_component()); + REQUIRE_FALSE(e3.exists_component()); + REQUIRE(e3.get_component() == position_c(1, 2)); + } + { + ecs::registry w; + + auto e1 = w.create_entity(); + ecs::entity_filler(e1) + .component(1, 2) + .component(3, 4); + e1.destroy(); + + auto e2 = e1.clone(); + REQUIRE_FALSE(e2.exists_component()); + REQUIRE_FALSE(e2.exists_component()); + REQUIRE(w.component_count() == 0); + REQUIRE(w.component_count() == 0); + } + } SECTION("for_each_entity") { { ecs::registry w;