don’t assign components to dead entities

This commit is contained in:
2018-12-25 20:08:27 +07:00
parent 64b919763d
commit e29aa3d4eb
2 changed files with 43 additions and 17 deletions

33
ecs.hpp
View File

@@ -142,7 +142,7 @@ namespace ecs_hpp
bool is_alive() const noexcept; bool is_alive() const noexcept;
template < typename T, typename... Args > template < typename T, typename... Args >
void assign_component(Args&&... args); bool assign_component(Args&&... args);
template < typename T > template < typename T >
bool remove_component(); bool remove_component();
@@ -190,7 +190,7 @@ namespace ecs_hpp
bool is_entity_alive(const entity& ent) const noexcept; bool is_entity_alive(const entity& ent) const noexcept;
template < typename T, typename... Args > template < typename T, typename... Args >
void assign_component(const entity& ent, Args&&... args); bool assign_component(const entity& ent, Args&&... args);
template < typename T > template < typename T >
bool remove_component(const entity& ent); bool remove_component(const entity& ent);
@@ -206,6 +206,7 @@ namespace ecs_hpp
template < typename T > template < typename T >
detail::component_storage<T>& get_or_create_storage_(); detail::component_storage<T>& get_or_create_storage_();
bool is_entity_alive_impl_(const entity& ent) const noexcept;
std::size_t remove_all_components_impl_(const entity& ent) const noexcept; std::size_t remove_all_components_impl_(const entity& ent) const noexcept;
private: private:
mutable std::mutex mutex_; mutable std::mutex mutex_;
@@ -250,8 +251,8 @@ namespace ecs_hpp
} }
template < typename T, typename... Args > template < typename T, typename... Args >
void entity::assign_component(Args&&... args) { bool entity::assign_component(Args&&... args) {
owner_.assign_component<T>( return owner_.assign_component<T>(
*this, *this,
std::forward<Args>(args)...); std::forward<Args>(args)...);
} }
@@ -271,7 +272,8 @@ namespace ecs_hpp
} }
inline bool operator==(const entity& l, const entity& r) noexcept { inline bool operator==(const entity& l, const entity& r) noexcept {
return l.id() == r.id(); return &l.owner() == &r.owner()
&& l.id() == r.id();
} }
inline bool operator!=(const entity& l, const entity& r) noexcept { inline bool operator!=(const entity& l, const entity& r) noexcept {
@@ -306,20 +308,27 @@ namespace ecs_hpp
inline bool world::is_entity_alive(const entity& ent) const noexcept { inline bool world::is_entity_alive(const entity& ent) const noexcept {
std::lock_guard<std::mutex> guard(mutex_); std::lock_guard<std::mutex> guard(mutex_);
return entities_.count(ent) > 0u; return is_entity_alive_impl_(ent);
} }
template < typename T, typename... Args > template < typename T, typename... Args >
void world::assign_component(const entity& ent, Args&&... args) { bool world::assign_component(const entity& ent, Args&&... args) {
std::lock_guard<std::mutex> guard(mutex_); std::lock_guard<std::mutex> guard(mutex_);
if ( !is_entity_alive_impl_(ent) ) {
return false;
}
get_or_create_storage_<T>().assign( get_or_create_storage_<T>().assign(
ent.id(), ent.id(),
std::forward<Args>(args)...); std::forward<Args>(args)...);
return true;
} }
template < typename T > template < typename T >
bool world::remove_component(const entity& ent) { bool world::remove_component(const entity& ent) {
std::lock_guard<std::mutex> guard(mutex_); std::lock_guard<std::mutex> guard(mutex_);
if ( !is_entity_alive_impl_(ent) ) {
return false;
}
const detail::component_storage<T>* storage = find_storage_<T>(); const detail::component_storage<T>* storage = find_storage_<T>();
return storage return storage
? storage->remove(ent.id()) ? storage->remove(ent.id())
@@ -329,6 +338,9 @@ namespace ecs_hpp
template < typename T > template < typename T >
bool world::exists_component(const entity& ent) const noexcept { bool world::exists_component(const entity& ent) const noexcept {
std::lock_guard<std::mutex> guard(mutex_); std::lock_guard<std::mutex> guard(mutex_);
if ( !is_entity_alive_impl_(ent) ) {
return false;
}
const detail::component_storage<T>* storage = find_storage_<T>(); const detail::component_storage<T>* storage = find_storage_<T>();
return storage return storage
? storage->exists(ent.id()) ? storage->exists(ent.id())
@@ -365,7 +377,14 @@ namespace ecs_hpp
emplace_r.first->second.get()); emplace_r.first->second.get());
} }
inline bool world::is_entity_alive_impl_(const entity& ent) const noexcept {
return entities_.count(ent) > 0u;
}
inline std::size_t world::remove_all_components_impl_(const entity& ent) const noexcept { inline std::size_t world::remove_all_components_impl_(const entity& ent) const noexcept {
if ( !is_entity_alive_impl_(ent) ) {
return 0u;
}
std::size_t removed_components = 0u; std::size_t removed_components = 0u;
for ( auto& storage_p : storages_ ) { for ( auto& storage_p : storages_ ) {
if ( storage_p.second->remove(ent.id()) ) { if ( storage_p.second->remove(ent.id()) ) {

View File

@@ -82,18 +82,18 @@ TEST_CASE("world") {
SECTION("components") { SECTION("components") {
{ {
ecs::world w; ecs::world w;
ecs::entity e1{w}; ecs::entity e1 = w.create_entity();
{ {
REQUIRE_FALSE(w.exists_component<position_c>(e1)); REQUIRE_FALSE(w.exists_component<position_c>(e1));
REQUIRE_FALSE(w.exists_component<velocity_c>(e1)); REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
w.assign_component<position_c>(e1); REQUIRE(w.assign_component<position_c>(e1));
REQUIRE(w.exists_component<position_c>(e1)); REQUIRE(w.exists_component<position_c>(e1));
REQUIRE_FALSE(w.exists_component<velocity_c>(e1)); REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
w.assign_component<velocity_c>(e1); REQUIRE(w.assign_component<velocity_c>(e1));
REQUIRE(w.exists_component<position_c>(e1)); REQUIRE(w.exists_component<position_c>(e1));
REQUIRE(w.exists_component<velocity_c>(e1)); REQUIRE(w.exists_component<velocity_c>(e1));
@@ -108,12 +108,12 @@ TEST_CASE("world") {
REQUIRE_FALSE(e1.exists_component<position_c>()); REQUIRE_FALSE(e1.exists_component<position_c>());
REQUIRE_FALSE(e1.exists_component<velocity_c>()); REQUIRE_FALSE(e1.exists_component<velocity_c>());
e1.assign_component<position_c>(); REQUIRE(e1.assign_component<position_c>());
REQUIRE(e1.exists_component<position_c>()); REQUIRE(e1.exists_component<position_c>());
REQUIRE_FALSE(e1.exists_component<velocity_c>()); REQUIRE_FALSE(e1.exists_component<velocity_c>());
e1.assign_component<velocity_c>(); REQUIRE(e1.assign_component<velocity_c>());
REQUIRE(e1.exists_component<position_c>()); REQUIRE(e1.exists_component<position_c>());
REQUIRE(e1.exists_component<velocity_c>()); REQUIRE(e1.exists_component<velocity_c>());
@@ -125,13 +125,13 @@ TEST_CASE("world") {
auto e1 = w.create_entity(); auto e1 = w.create_entity();
auto e2 = w.create_entity(); auto e2 = w.create_entity();
w.assign_component<position_c>(e1); REQUIRE(w.assign_component<position_c>(e1));
w.assign_component<velocity_c>(e1); REQUIRE(w.assign_component<velocity_c>(e1));
w.assign_component<position_c>(e2); REQUIRE(w.assign_component<position_c>(e2));
w.assign_component<velocity_c>(e2); REQUIRE(w.assign_component<velocity_c>(e2));
w.destroy_entity(e1); REQUIRE(w.destroy_entity(e1));
REQUIRE_FALSE(w.exists_component<position_c>(e1)); REQUIRE_FALSE(w.exists_component<position_c>(e1));
REQUIRE_FALSE(w.exists_component<velocity_c>(e1)); REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
@@ -139,5 +139,12 @@ TEST_CASE("world") {
REQUIRE(w.exists_component<position_c>(e2)); REQUIRE(w.exists_component<position_c>(e2));
REQUIRE(w.exists_component<velocity_c>(e2)); REQUIRE(w.exists_component<velocity_c>(e2));
} }
{
ecs::world w;
auto e1 = w.create_entity();
REQUIRE(e1.destroy());
REQUIRE_FALSE(e1.assign_component<position_c>());
REQUIRE_FALSE(w.exists_component<position_c>(e1));
}
} }
} }