mirror of
https://github.com/BlackMATov/ecs.hpp.git
synced 2026-01-04 07:06:51 +07:00
add entity cloning
This commit is contained in:
53
ecs.hpp
53
ecs.hpp
@@ -322,7 +322,7 @@ namespace ecs_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool unordered_erase(const T& v) noexcept(
|
bool unordered_erase(const T& v) noexcept(
|
||||||
noexcept(indexer_(std::declval<T>())) &&
|
noexcept(std::declval<Indexer>()(std::declval<T>())) &&
|
||||||
std::is_nothrow_move_assignable<T>::value)
|
std::is_nothrow_move_assignable<T>::value)
|
||||||
{
|
{
|
||||||
if ( !has(v) ) {
|
if ( !has(v) ) {
|
||||||
@@ -343,7 +343,7 @@ namespace ecs_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool has(const T& v) const noexcept(
|
bool has(const T& v) const noexcept(
|
||||||
noexcept(indexer_(std::declval<T>())))
|
noexcept(std::declval<Indexer>()(std::declval<T>())))
|
||||||
{
|
{
|
||||||
const std::size_t vi = indexer_(v);
|
const std::size_t vi = indexer_(v);
|
||||||
return vi < sparse_.size()
|
return vi < sparse_.size()
|
||||||
@@ -352,7 +352,7 @@ namespace ecs_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
const_iterator find(const T& v) const noexcept(
|
const_iterator find(const T& v) const noexcept(
|
||||||
noexcept(indexer_(std::declval<T>())))
|
noexcept(std::declval<Indexer>()(std::declval<T>())))
|
||||||
{
|
{
|
||||||
return has(v)
|
return has(v)
|
||||||
? begin() + sparse_[indexer_(v)]
|
? begin() + sparse_[indexer_(v)]
|
||||||
@@ -368,7 +368,7 @@ namespace ecs_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::size_t,bool> find_dense_index(const T& v) const noexcept(
|
std::pair<std::size_t,bool> find_dense_index(const T& v) const noexcept(
|
||||||
noexcept(indexer_(std::declval<T>())))
|
noexcept(std::declval<Indexer>()(std::declval<T>())))
|
||||||
{
|
{
|
||||||
return has(v)
|
return has(v)
|
||||||
? std::make_pair(sparse_[indexer_(v)], true)
|
? std::make_pair(sparse_[indexer_(v)], true)
|
||||||
@@ -486,7 +486,7 @@ namespace ecs_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool unordered_erase(const K& k) noexcept(
|
bool unordered_erase(const K& k) noexcept(
|
||||||
noexcept(keys_.find_dense_index(k)) &&
|
noexcept(std::declval<sparse_set<K, Indexer>>().find_dense_index(k)) &&
|
||||||
std::is_nothrow_move_assignable<T>::value)
|
std::is_nothrow_move_assignable<T>::value)
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -510,7 +510,7 @@ namespace ecs_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool has(const K& k) const noexcept(
|
bool has(const K& k) const noexcept(
|
||||||
noexcept(keys_.has(k)))
|
noexcept(std::declval<sparse_set<K, Indexer>>().has(k)))
|
||||||
{
|
{
|
||||||
return keys_.has(k);
|
return keys_.has(k);
|
||||||
}
|
}
|
||||||
@@ -524,7 +524,7 @@ namespace ecs_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
T* find(const K& k) noexcept(
|
T* find(const K& k) noexcept(
|
||||||
noexcept(keys_.find_dense_index(k)))
|
noexcept(std::declval<sparse_set<K, Indexer>>().find_dense_index(k)))
|
||||||
{
|
{
|
||||||
const auto value_index_p = keys_.find_dense_index(k);
|
const auto value_index_p = keys_.find_dense_index(k);
|
||||||
return value_index_p.second
|
return value_index_p.second
|
||||||
@@ -533,7 +533,7 @@ namespace ecs_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
const T* find(const K& k) const noexcept(
|
const T* find(const K& k) const noexcept(
|
||||||
noexcept(keys_.find_dense_index(k)))
|
noexcept(std::declval<sparse_set<K, Indexer>>().find_dense_index(k)))
|
||||||
{
|
{
|
||||||
const auto value_index_p = keys_.find_dense_index(k);
|
const auto value_index_p = keys_.find_dense_index(k);
|
||||||
return value_index_p.second
|
return value_index_p.second
|
||||||
@@ -588,6 +588,7 @@ namespace ecs_hpp
|
|||||||
virtual ~component_storage_base() = default;
|
virtual ~component_storage_base() = default;
|
||||||
virtual bool remove(entity_id id) noexcept = 0;
|
virtual bool remove(entity_id id) noexcept = 0;
|
||||||
virtual bool has(entity_id id) const noexcept = 0;
|
virtual bool has(entity_id id) const noexcept = 0;
|
||||||
|
virtual void clone(entity_id from, entity_id to) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
@@ -605,6 +606,7 @@ namespace ecs_hpp
|
|||||||
|
|
||||||
std::size_t count() const noexcept;
|
std::size_t count() const noexcept;
|
||||||
bool has(entity_id id) const noexcept override;
|
bool has(entity_id id) const noexcept override;
|
||||||
|
void clone(entity_id from, entity_id to) override;
|
||||||
|
|
||||||
template < typename F >
|
template < typename F >
|
||||||
void for_each_component(F&& f);
|
void for_each_component(F&& f);
|
||||||
@@ -655,10 +657,18 @@ namespace ecs_hpp
|
|||||||
return components_.has(id);
|
return components_.has(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
void component_storage<T>::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 T >
|
||||||
template < typename F >
|
template < typename F >
|
||||||
void component_storage<T>::for_each_component(F&& f) {
|
void component_storage<T>::for_each_component(F&& f) {
|
||||||
for ( const auto id : components_ ) {
|
for ( const entity_id id : components_ ) {
|
||||||
f(id, components_.get(id));
|
f(id, components_.get(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -666,7 +676,7 @@ namespace ecs_hpp
|
|||||||
template < typename T >
|
template < typename T >
|
||||||
template < typename F >
|
template < typename F >
|
||||||
void component_storage<T>::for_each_component(F&& f) const {
|
void component_storage<T>::for_each_component(F&& f) const {
|
||||||
for ( const auto id : components_ ) {
|
for ( const entity_id id : components_ ) {
|
||||||
f(id, components_.get(id));
|
f(id, components_.get(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -699,6 +709,7 @@ namespace ecs_hpp
|
|||||||
|
|
||||||
bool destroy();
|
bool destroy();
|
||||||
bool alive() const noexcept;
|
bool alive() const noexcept;
|
||||||
|
entity clone() const;
|
||||||
|
|
||||||
template < typename T, typename... Args >
|
template < typename T, typename... Args >
|
||||||
bool assign_component(Args&&... args);
|
bool assign_component(Args&&... args);
|
||||||
@@ -1032,6 +1043,7 @@ namespace ecs_hpp
|
|||||||
const_component<T> wrap_component(const const_uentity& ent) const noexcept;
|
const_component<T> wrap_component(const const_uentity& ent) const noexcept;
|
||||||
|
|
||||||
entity create_entity();
|
entity create_entity();
|
||||||
|
entity create_entity(const const_uentity& prototype);
|
||||||
|
|
||||||
bool destroy_entity(const uentity& ent);
|
bool destroy_entity(const uentity& ent);
|
||||||
bool alive_entity(const const_uentity& ent) const noexcept;
|
bool alive_entity(const const_uentity& ent) const noexcept;
|
||||||
@@ -1244,6 +1256,10 @@ namespace ecs_hpp
|
|||||||
return detail::as_const(*owner_).alive_entity(id_);
|
return detail::as_const(*owner_).alive_entity(id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline entity entity::clone() const {
|
||||||
|
return (*owner_).create_entity(id_);
|
||||||
|
}
|
||||||
|
|
||||||
template < typename T, typename... Args >
|
template < typename T, typename... Args >
|
||||||
bool entity::assign_component(Args&&... args) {
|
bool entity::assign_component(Args&&... args) {
|
||||||
return (*owner_).assign_component<T>(
|
return (*owner_).assign_component<T>(
|
||||||
@@ -1691,6 +1707,23 @@ namespace ecs_hpp
|
|||||||
throw std::logic_error("ecs_hpp::registry (entity index overlow)");
|
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) {
|
inline bool registry::destroy_entity(const uentity& ent) {
|
||||||
assert(ent.check_owner(this));
|
assert(ent.check_owner(this));
|
||||||
remove_all_components(ent);
|
remove_all_components(ent);
|
||||||
|
|||||||
@@ -732,6 +732,49 @@ TEST_CASE("registry") {
|
|||||||
REQUIRE(e1.get_component<velocity_c>().y == 40);
|
REQUIRE(e1.get_component<velocity_c>().y == 40);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SECTION("cloning") {
|
||||||
|
{
|
||||||
|
ecs::registry w;
|
||||||
|
|
||||||
|
auto e1 = w.create_entity();
|
||||||
|
ecs::entity_filler(e1)
|
||||||
|
.component<position_c>(1, 2)
|
||||||
|
.component<velocity_c>(3, 4);
|
||||||
|
|
||||||
|
auto e2 = w.create_entity(e1);
|
||||||
|
REQUIRE(w.component_count<position_c>() == 2);
|
||||||
|
REQUIRE(w.component_count<velocity_c>() == 2);
|
||||||
|
REQUIRE(e2.exists_component<position_c>());
|
||||||
|
REQUIRE(e2.exists_component<velocity_c>());
|
||||||
|
REQUIRE(e2.get_component<position_c>() == position_c(1, 2));
|
||||||
|
REQUIRE(e2.get_component<velocity_c>() == velocity_c(3, 4));
|
||||||
|
|
||||||
|
e2.remove_component<velocity_c>();
|
||||||
|
auto e3 = e2.clone();
|
||||||
|
|
||||||
|
REQUIRE(w.component_count<position_c>() == 3);
|
||||||
|
REQUIRE(w.component_count<velocity_c>() == 1);
|
||||||
|
|
||||||
|
REQUIRE(e3.exists_component<position_c>());
|
||||||
|
REQUIRE_FALSE(e3.exists_component<velocity_c>());
|
||||||
|
REQUIRE(e3.get_component<position_c>() == position_c(1, 2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ecs::registry w;
|
||||||
|
|
||||||
|
auto e1 = w.create_entity();
|
||||||
|
ecs::entity_filler(e1)
|
||||||
|
.component<position_c>(1, 2)
|
||||||
|
.component<velocity_c>(3, 4);
|
||||||
|
e1.destroy();
|
||||||
|
|
||||||
|
auto e2 = e1.clone();
|
||||||
|
REQUIRE_FALSE(e2.exists_component<position_c>());
|
||||||
|
REQUIRE_FALSE(e2.exists_component<velocity_c>());
|
||||||
|
REQUIRE(w.component_count<position_c>() == 0);
|
||||||
|
REQUIRE(w.component_count<velocity_c>() == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
SECTION("for_each_entity") {
|
SECTION("for_each_entity") {
|
||||||
{
|
{
|
||||||
ecs::registry w;
|
ecs::registry w;
|
||||||
|
|||||||
Reference in New Issue
Block a user