mirror of
https://github.com/BlackMATov/ecs.hpp.git
synced 2025-12-16 22:19:21 +07:00
dummy component storage
This commit is contained in:
169
ecs.hpp
169
ecs.hpp
@@ -11,11 +11,13 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <memory>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
@@ -42,7 +44,7 @@ namespace ecs_hpp
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// detail
|
// detail::type_family
|
||||||
//
|
//
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -74,6 +76,52 @@ namespace ecs_hpp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// detail::component_storage
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace ecs_hpp
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
class component_storage_base {
|
||||||
|
public:
|
||||||
|
virtual ~component_storage_base() = default;
|
||||||
|
virtual bool remove(entity_id id) noexcept = 0;
|
||||||
|
virtual bool exists(entity_id id) const noexcept = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
class component_storage : public component_storage_base {
|
||||||
|
public:
|
||||||
|
template < typename... Args >
|
||||||
|
void assign(entity_id id, Args&&... args);
|
||||||
|
bool remove(entity_id id) noexcept override;
|
||||||
|
bool exists(entity_id id) const noexcept override;
|
||||||
|
private:
|
||||||
|
std::unordered_map<entity_id, T> components_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
template < typename... Args >
|
||||||
|
void component_storage<T>::assign(entity_id id, Args&&... args) {
|
||||||
|
components_[id] = T(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool component_storage<T>::remove(entity_id id) noexcept {
|
||||||
|
return components_.erase(id) > 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool component_storage<T>::exists(entity_id id) const noexcept {
|
||||||
|
return components_.find(id) != components_.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// entity
|
// entity
|
||||||
@@ -91,6 +139,18 @@ namespace ecs_hpp
|
|||||||
entity_id id() const noexcept;
|
entity_id id() const noexcept;
|
||||||
|
|
||||||
bool destroy();
|
bool destroy();
|
||||||
|
bool is_alive() const noexcept;
|
||||||
|
|
||||||
|
template < typename T, typename... Args >
|
||||||
|
void assign_component(Args&&... args);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool remove_component();
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool exists_component() const noexcept;
|
||||||
|
|
||||||
|
std::size_t remove_all_components() noexcept;
|
||||||
private:
|
private:
|
||||||
world& owner_;
|
world& owner_;
|
||||||
entity_id id_{0u};
|
entity_id id_{0u};
|
||||||
@@ -128,10 +188,30 @@ namespace ecs_hpp
|
|||||||
entity create_entity();
|
entity create_entity();
|
||||||
bool destroy_entity(const entity& ent);
|
bool destroy_entity(const entity& ent);
|
||||||
bool is_entity_alive(const entity& ent) const noexcept;
|
bool is_entity_alive(const entity& ent) const noexcept;
|
||||||
|
|
||||||
|
template < typename T, typename... Args >
|
||||||
|
void assign_component(const entity& ent, Args&&... args);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool remove_component(const entity& ent);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool exists_component(const entity& ent) const noexcept;
|
||||||
|
|
||||||
|
std::size_t remove_all_components(const entity& ent) const noexcept;
|
||||||
|
private:
|
||||||
|
template < typename T >
|
||||||
|
detail::component_storage<T>* find_storage_() const;
|
||||||
|
template < typename T >
|
||||||
|
detail::component_storage<T>& get_or_create_storage_();
|
||||||
private:
|
private:
|
||||||
mutable std::mutex mutex_;
|
mutable std::mutex mutex_;
|
||||||
|
|
||||||
entity_id last_entity_id_{0u};
|
entity_id last_entity_id_{0u};
|
||||||
std::unordered_set<entity> entities_;
|
std::unordered_set<entity> entities_;
|
||||||
|
|
||||||
|
using storage_uptr = std::unique_ptr<detail::component_storage_base>;
|
||||||
|
std::unordered_map<family_id, storage_uptr> storages_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +242,31 @@ namespace ecs_hpp
|
|||||||
return owner_.destroy_entity(*this);
|
return owner_.destroy_entity(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool entity::is_alive() const noexcept {
|
||||||
|
return owner_.is_entity_alive(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T, typename... Args >
|
||||||
|
void entity::assign_component(Args&&... args) {
|
||||||
|
owner_.assign_component<T>(
|
||||||
|
*this,
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool entity::remove_component() {
|
||||||
|
return owner_.remove_component<T>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool entity::exists_component() const noexcept {
|
||||||
|
return owner_.exists_component<T>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t entity::remove_all_components() noexcept {
|
||||||
|
return owner_.remove_all_components(*this);
|
||||||
|
}
|
||||||
|
|
||||||
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.id() == r.id();
|
||||||
}
|
}
|
||||||
@@ -199,4 +304,66 @@ namespace ecs_hpp
|
|||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
return entities_.count(ent) > 0u;
|
return entities_.count(ent) > 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename T, typename... Args >
|
||||||
|
void world::assign_component(const entity& ent, Args&&... args) {
|
||||||
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
|
get_or_create_storage_<T>().assign(
|
||||||
|
ent.id(),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool world::remove_component(const entity& ent) {
|
||||||
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
|
const detail::component_storage<T>* storage = find_storage_<T>();
|
||||||
|
return storage
|
||||||
|
? storage->remove(ent.id())
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool world::exists_component(const entity& ent) const noexcept {
|
||||||
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
|
const detail::component_storage<T>* storage = find_storage_<T>();
|
||||||
|
return storage
|
||||||
|
? storage->exists(ent.id())
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t world::remove_all_components(const entity& ent) const noexcept {
|
||||||
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
|
std::size_t removed_components = 0u;
|
||||||
|
for ( auto& storage_p : storages_ ) {
|
||||||
|
if ( storage_p.second->remove(ent.id()) ) {
|
||||||
|
++removed_components;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return removed_components;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
detail::component_storage<T>* world::find_storage_() const {
|
||||||
|
const auto family = detail::type_family<T>::id();
|
||||||
|
const auto iter = storages_.find(family);
|
||||||
|
if ( iter != storages_.end() ) {
|
||||||
|
return static_cast<detail::component_storage<T>*>(iter->second.get());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
detail::component_storage<T>& world::get_or_create_storage_() {
|
||||||
|
detail::component_storage<T>* storage = find_storage_<T>();
|
||||||
|
if ( storage ) {
|
||||||
|
return *storage;
|
||||||
|
}
|
||||||
|
const auto family = detail::type_family<T>::id();
|
||||||
|
const auto emplace_r = storages_.emplace(std::make_pair(
|
||||||
|
family,
|
||||||
|
std::make_unique<detail::component_storage<T>>()));
|
||||||
|
assert(emplace_r.second && "unexpected internal error");
|
||||||
|
return *static_cast<detail::component_storage<T>*>(
|
||||||
|
emplace_r.first->second.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,5 +80,44 @@ TEST_CASE("world") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SECTION("components") {
|
SECTION("components") {
|
||||||
|
{
|
||||||
|
ecs::world w;
|
||||||
|
ecs::entity e1{w};
|
||||||
|
|
||||||
|
{
|
||||||
|
REQUIRE_FALSE(w.exists_component<position_c>(e1));
|
||||||
|
REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
|
||||||
|
|
||||||
|
w.assign_component<position_c>(e1);
|
||||||
|
|
||||||
|
REQUIRE(w.exists_component<position_c>(e1));
|
||||||
|
REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
|
||||||
|
|
||||||
|
w.assign_component<velocity_c>(e1);
|
||||||
|
|
||||||
|
REQUIRE(w.exists_component<position_c>(e1));
|
||||||
|
REQUIRE(w.exists_component<velocity_c>(e1));
|
||||||
|
|
||||||
|
REQUIRE(w.remove_all_components(e1) == 2u);
|
||||||
|
|
||||||
|
REQUIRE_FALSE(w.exists_component<position_c>(e1));
|
||||||
|
REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
REQUIRE_FALSE(e1.exists_component<position_c>());
|
||||||
|
REQUIRE_FALSE(e1.exists_component<velocity_c>());
|
||||||
|
|
||||||
|
e1.assign_component<position_c>();
|
||||||
|
|
||||||
|
REQUIRE(e1.exists_component<position_c>());
|
||||||
|
REQUIRE_FALSE(e1.exists_component<velocity_c>());
|
||||||
|
|
||||||
|
e1.assign_component<velocity_c>();
|
||||||
|
|
||||||
|
REQUIRE(e1.exists_component<position_c>());
|
||||||
|
REQUIRE(e1.exists_component<velocity_c>());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user