瀏覽代碼

* implemented entity creation and matching

* added dummy system processing
wip
bergmann 5 年之前
父節點
當前提交
a21d5daf59
共有 13 個檔案被更改,包括 278 行新增72 行删除
  1. +20
    -3
      include/ecs/context/base.h
  2. +19
    -4
      include/ecs/context/base.inl
  3. +76
    -1
      include/ecs/context/context.h
  4. +1
    -0
      include/ecs/context/defer_proxy.h
  5. +7
    -0
      include/ecs/core/entity/storage/base.h
  6. +8
    -1
      include/ecs/core/entity/storage/base.inl
  7. +23
    -7
      include/ecs/core/system/instance.h
  8. +4
    -5
      include/ecs/core/system/scheduler/atomic_counter.inl
  9. +2
    -2
      include/ecs/core/system/storage/tuple.h
  10. +20
    -1
      include/ecs/core/utils/bitset.h
  11. +22
    -3
      include/ecs/core/utils/bitset.inl
  12. +4
    -1
      include/ecs/core/utils/ordered_vector.h
  13. +72
    -44
      test/dummy.cpp

+ 20
- 3
include/ecs/context/base.h 查看文件

@@ -3,6 +3,7 @@
#include <ecs/config.h>
#include <ecs/core/utils/thread_pool.h>
#include <ecs/core/utils/counter_blocker.h>
#include <ecs/core/utils/ordered_vector.h>
#include <ecs/core/component/manager.h>

#include "./context.fwd.h"
@@ -44,7 +45,7 @@ namespace context {
using handle_type = entity_handle_type;

private:
using handle_vector_type = std::vector<handle_type>;
using handle_set_type = core::utils::ordered_vector<handle_type>;

protected:
context_type& _context; //!< reference to its own child class
@@ -56,8 +57,8 @@ namespace context {

core::utils::thread_pool _thread_pool; //!< thread pool to execute tasks parallel

handle_vector_type _to_match; //!< handles of entities that were created in the last tick
handle_vector_type _to_kill; //!< handles of entities that were destroyed in the last tick
handle_set_type _to_match; //!< handles of entities that were created in the last tick
handle_set_type _to_kill; //!< handles of entities that were destroyed in the last tick

public:

@@ -111,6 +112,22 @@ namespace context {
*/
inline bool _is_alive(const handle_type& handle) const;

/**
* destroy the passed entity
*
* @param handle handle of the entity to destroy
*/
inline void _destroy_entity(const handle_type& handle);

/**
* get the meta data for the passed entity
*
* @param handle handle to get meta data for
*
* @return meta data of the passed entity
*/
inline const auto& _entity_meta_data(const handle_type& handle);

protected: /* component */

/**


+ 19
- 4
include/ecs/context/base.inl 查看文件

@@ -38,15 +38,16 @@ namespace detail {
inline decltype(auto) base_t<T_settings>
::_create_entity(T_args&&... args)
{
_to_match.emplace_back(_entities.claim(std::forward<T_args>(args)...));
return _to_match.back();
auto handle = _entities.claim(std::forward<T_args>(args)...);
_to_match.insert(handle);
return handle;
}

template<typename T_settings>
inline void base_t<T_settings>
::_kill_entity(const handle_type& handle)
{
_to_kill.emplace_back(handle);
_to_kill.insert(handle);
}

template<typename T_settings>
@@ -56,6 +57,20 @@ namespace detail {
return _entities.is_valid(handle);
}

template<typename T_settings>
inline void base_t<T_settings>
::_destroy_entity(const handle_type& handle)
{
_entities.reclaim(handle);
}

template<typename T_settings>
inline const auto& base_t<T_settings>
::_entity_meta_data(const handle_type& handle)
{
return _entities.meta_data(handle);
}

/* components */

template<typename T_settings>
@@ -63,7 +78,7 @@ namespace detail {
inline decltype(auto) base_t<T_settings>
::_add_component(const handle_type& handle, T_component_tag ct)
{
_to_match.emplace_back(handle);
_to_match.insert(handle);
auto& meta = _entities.meta_data(handle);
auto& cmd = meta.storage_meta_data();
auto& c = _components.add(ct, handle, cmd);


+ 76
- 1
include/ecs/context/context.h 查看文件

@@ -18,16 +18,91 @@ namespace context {
private:
using settings_type = T_settings;
using this_type = context_t<settings_type>;
using base_type = step_proxy_t<settings_type>;
using step_proxy = step_proxy_t<settings_type>;
using defer_proxy = defer_proxy_t<settings_type>;
using base_type = step_proxy;

private:
inline void refresh()
{
refresh_execute_deferred();
refresh_kill_entities();
refresh_match_entities();
}

inline void refresh_match_entities()
{
/* match new/changed entities to system instances */
for_systems_dispatch([this](auto& instance){
auto& system_bitset = instance.bitset();
for (const auto& handle : this->_to_match)
{
auto& entity_bitset = this->entity_meta_data(handle).bitset();
if (entity_bitset.contains(system_bitset))
{
if (instance.subscribe(handle))
{
// TODO send event
}
}
else if (instance.unsubscribe(handle))
{
// TODO send event
}
}
});

this->_to_match.clear();
}

inline void refresh_kill_entities()
{
/* copy entities to kill to the main vector */
for_systems_sequential([this](auto& instance){
instance.for_states([this](auto& state){
for (auto& handle : state.to_kill)
{
this->_to_kill.insert(handle);
}
});
});

/* unsubscribe dead entities */
for_systems_dispatch([this](auto& instance){
for (const auto& handle : this->_to_kill)
{
if (instance.unsubscribe(handle))
{
// TODO send event
}
}
});

/* reclaim all killed entities */
for (const auto& handle : this->_to_kill)
{
destroy_entity(handle);
}

this->_to_kill.clear();
}

inline void refresh_execute_deferred()
{
defer_proxy& proxy = *this;
for_systems_sequential([&proxy](auto& instance){
instance.for_states([&proxy](auto& state){
state.deferred_functions.execute_all(proxy);
});
});
}

public:
ecs_context_proxy_func(this_type, destroy_entity)
ecs_context_proxy_func(this_type, post_in_thread_pool)
ecs_context_proxy_func(this_type, for_systems_sequential)
ecs_context_proxy_func(this_type, for_systems_parallel)
ecs_context_proxy_func(this_type, for_systems_dispatch)

public:
inline context_t()


+ 1
- 0
include/ecs/context/defer_proxy.h 查看文件

@@ -33,6 +33,7 @@ namespace context {
ecs_context_proxy_func(this_type, create_entity)
ecs_context_proxy_func(this_type, kill_entity)
ecs_context_proxy_func(this_type, is_alive)
ecs_context_proxy_func(this_type, entity_meta_data)

public: /* component */
ecs_context_proxy_func(this_type, add_component)


+ 7
- 0
include/ecs/core/entity/storage/base.h 查看文件

@@ -105,6 +105,13 @@ namespace storage {
*/
inline auto& bitset();

/**
* get the bitset of components stored for this entity
*
* @return component bitset
*/
inline const auto& bitset() const;

/**
* get the current reusage counter of the entity
*


+ 8
- 1
include/ecs/core/entity/storage/base.inl 查看文件

@@ -58,6 +58,13 @@ namespace storage {
return _bitset;
}

template <typename T_settings, typename T_storage_meta_data>
inline const auto& entity_meta_data<T_settings, T_storage_meta_data>
::bitset() const
{
return _bitset;
}

template <typename T_settings, typename T_storage_meta_data>
inline auto entity_meta_data<T_settings, T_storage_meta_data>
::counter() const
@@ -120,7 +127,7 @@ namespace storage {
grow(grow_size);
}
assert(!_free_ids.empty());
auto index = _free_ids.back();
auto index = _free_ids.front();
auto& item = _container.at(index);
_free_ids.pop();
return entity_handle(index, item.counter());


+ 23
- 7
include/ecs/core/system/instance.h 查看文件

@@ -2,6 +2,7 @@

#include <ecs/config.h>
#include <ecs/signature/system.h>
#include <ecs/context/defer_proxy.h>
#include <ecs/core/utils/bitset.h>
#include <ecs/core/utils/fixed_function.h>
#include <ecs/core/utils/ordered_vector.h>
@@ -14,7 +15,8 @@ namespace system {
struct deferred_function_vector
{
private:
using deferred_proxy_type = int;
using settings_type = T_settings;
using deferred_proxy_type = context::detail::defer_proxy_t<settings_type>;
using function_type = utils::fixed_function<void(deferred_proxy_type&)>;
using function_vector_type = std::vector<function_type>;

@@ -92,7 +94,7 @@ namespace system {

public:
instance()
: _bitset ()
: _bitset (bitset_type::from_system_signature(mp::unwrap(system_signature_type { })))
, _system ()
, _executor (mp::unwrap(system_signature_type { }).parallelism()())
, _subscribed()
@@ -149,7 +151,10 @@ namespace system {
inline void execute(T_context& context, T_func&& func)
{ _executor(context, *this, std::forward<T_func>(func)); }

public: /* bitset */
public: /* misc */
constexpr decltype(auto) signature() const noexcept
{ return mp::unwrap(system_signature_type { }); }

inline const auto& bitset() const noexcept
{ return _bitset; }

@@ -173,11 +178,22 @@ namespace system {
inline bool is_subscribed(const entity_handle_type& handle) const
{ return (_subscribed.find(handle) != _subscribed.end()); }

inline void subscribe(const entity_handle_type& handle)
{ _subscribed.insert(handle); }
inline bool subscribe(const entity_handle_type& handle)
{ return _subscribed.insert(handle).second; }

inline void unsubscribe(const entity_handle_type& handle)
{ _subscribed.erase(handle); }
inline bool unsubscribe(const entity_handle_type& handle)
{
auto it = _subscribed.find(handle);
if (it != _subscribed.end())
{
_subscribed.erase(it);
return true;
}
else
{
return false;
}
}

public: /* states */
template<typename T_func>


+ 4
- 5
include/ecs/core/system/scheduler/atomic_counter.inl 查看文件

@@ -1,5 +1,7 @@
#pragma once

// #define ECS_DEBUG_ATOMIC_COUNTER

#include <ecs/core/system/scheduler/atomic_counter.h>

namespace ecs {
@@ -106,7 +108,6 @@ namespace scheduler {
inline void task_group_t<T_context, T_dependency_items>
::post_task_in_thread_pool(T_task_id, T_func&& func)
{
std::cout << "post_task_in_thread_pool (current=" << std::this_thread::get_id() << ", task=" << T_task_id::value << ")" << std::endl;
_context.post_in_thread_pool([this, &func]{
execute_task(T_task_id { }, func);
});
@@ -117,7 +118,6 @@ namespace scheduler {
inline void task_group_t<T_context, T_dependency_items>
::execute_task(T_task_id, T_func&& func)
{
std::cout << "execute_task (current=" << std::this_thread::get_id() << ", task=" << T_task_id::value << ")" << std::endl;
auto& task = hana::at(_tasks, T_task_id { });
auto& instance = _context.instance_by_tag(task.dependency_item.tag);
instance.execute(_context, func);
@@ -129,7 +129,6 @@ namespace scheduler {
inline void task_group_t<T_context, T_dependency_items>
::check_and_start_dependencies(T_task_id, T_func&& func)
{
std::cout << "check_and_start_dependencies (current=" << std::this_thread::get_id() << ", task=" << T_task_id::value << ")" << std::endl;
auto& task = hana::at(_tasks, T_task_id { });
task.for_dependent_ids([this, &func](auto id){
auto& other = hana::at(_tasks, id);
@@ -250,7 +249,7 @@ namespace scheduler {
using independent_item_ids_type = mp::decay_t<decltype(detail::get_independent_item_ids(
dependency_list_type { }))>;;

/* TODO debug beg! */
#ifdef ECS_DEBUG_ATOMIC_COUNTER
size_t i = 0;
std::cout << "dependency_list" << std::endl;
hana::for_each(dependency_list_type { }, [&i](auto item){
@@ -260,7 +259,7 @@ namespace scheduler {
std::cout << " " << hana::value(id) << std::endl;
});
});
/* TODO debug end! */
#endif

using task_group_type = detail::task_group_t<context_type, dependency_list_type>;



+ 2
- 2
include/ecs/core/system/storage/tuple.h 查看文件

@@ -53,14 +53,14 @@ namespace storage {
make_tuple { }))>;

private:
storage_type _storage;
storage_type _storage;

public:
constexpr decltype(auto) size() const noexcept
{ return (ssl_type { }).size(); }

template<typename T_func>
constexpr void for_each(T_func&& f) const noexcept
constexpr void for_each(T_func&& f) noexcept
{ hana::for_each(_storage, std::forward<T_func>(f)); }

template<typename T_system>


+ 20
- 1
include/ecs/core/utils/bitset.h 查看文件

@@ -52,7 +52,19 @@ namespace utils {
* @return integral constant with the ID of the requested component tag
*/
template<typename T_component_tag>
static constexpr decltype(auto) component_id(T_component_tag ct) noexcept;
static constexpr decltype(auto) component_id(T_component_tag&& ct) noexcept;

/**
* get the bitset from the given system signature
*
* @tparam T_system_signature system signature type to get bitmask for
*
* @param ssig system signature to get bitmask for
*
* @return bitmask for the passed system signature
*/
template<typename T_system_signature>
static constexpr decltype(auto) from_system_signature(T_system_signature&& ssig) noexcept;

/**
* internal bitset type that contains all components
@@ -63,6 +75,13 @@ namespace utils {
bitset_type _bitset;

public:
/**
* return a string representation of the bitset
*
* @return string representation of the bitset
*/
inline decltype(auto) to_string() const;

/**
* clear all bits of the bitset
*/


+ 22
- 3
include/ecs/core/utils/bitset.inl 查看文件

@@ -9,9 +9,28 @@ namespace utils {
template<typename T_settings>
template<typename T_component_tag>
constexpr decltype(auto) bitset<T_settings>
::component_id(T_component_tag ct) noexcept
::component_id(T_component_tag&& ct) noexcept
{
return mp::list::index_of(all_components(), ct);
return mp::list::index_of(all_components(), std::forward<T_component_tag>(ct));
}

template<typename T_settings>
template<typename T_system_signature>
constexpr decltype(auto) bitset<T_settings>
::from_system_signature(T_system_signature&& ssig) noexcept
{
bitset ret;
hana::for_each(hana::concat(ssig.read(), ssig.write()), [&ret](auto ct){
ret.set_component(ct, true);
});
return ret;
}

template<typename T_settings>
inline decltype(auto) bitset<T_settings>
::to_string() const
{
return _bitset.to_string();
}

template<typename T_settings>
@@ -26,7 +45,7 @@ namespace utils {
inline bool bitset<T_settings>
::contains(const T_other& other) const noexcept
{
return (_bitset & other._bitset) == _bitset;
return (_bitset & other._bitset) == other._bitset;
}

template<typename T_settings>


+ 4
- 1
include/ecs/core/utils/ordered_vector.h 查看文件

@@ -152,7 +152,7 @@ namespace utils {
inline decltype(auto) insert(const value_type& value)
{
auto it = std::lower_bound(begin(), end(), value);
auto is_new = _compare(value, *it);
auto is_new = (it != end() && _compare(value, *it));
if (it == end() || is_new)
_items.insert(it, value);
return std::make_pair(it, is_new);
@@ -181,6 +181,9 @@ namespace utils {
template<typename... T_args>
constexpr decltype(auto) erase(T_args&&... args)
{ return _items.erase(std::forward<T_args>(args)...); }

void clear()
{ _items.clear(); }
};

} } }

+ 72
- 44
test/dummy.cpp 查看文件

@@ -40,13 +40,9 @@ namespace test
double y;
};

struct test
{ };

MAKE_COMPONENT_TAG(position)
MAKE_COMPONENT_TAG(velocity)
MAKE_COMPONENT_TAG(acceleration)
MAKE_COMPONENT_TAG(test)
}

namespace system
@@ -60,13 +56,9 @@ namespace test
struct render
{ };

struct foo
{ };

MAKE_SYSTEM_TAG(accelerate)
MAKE_SYSTEM_TAG(move)
MAKE_SYSTEM_TAG(render)
MAKE_SYSTEM_TAG(foo)
}
}

@@ -96,19 +88,10 @@ constexpr decltype(auto) cs_acceleration =
cs::make(ct::acceleration)
.storage(cs::storage::dynamic<storage_size>);

constexpr decltype(auto) cs_test =
cs::make(ct::test)
.storage(cs::storage::dynamic<storage_size>);

constexpr decltype(auto) cs_list = csl::make(
cs_position,
cs_velocity,
cs_acceleration,
cs_test);

constexpr decltype(auto) ss_foo =
ss::make(st::foo)
.write(ct::test);
cs_acceleration);

constexpr decltype(auto) ss_accelerate =
ss::make(st::accelerate)
@@ -122,45 +105,90 @@ constexpr decltype(auto) ss_move =

constexpr decltype(auto) ss_render =
ss::make(st::render)
.read(ct::velocity, ct::position, ct::acceleration, ct::test);
.read(ct::velocity, ct::position, ct::acceleration);

constexpr decltype(auto) ss_list = ssl::make(
ss_foo,
ss_accelerate,
ss_move,
ss_render);

constexpr decltype(auto) settings = ::ecs::settings::make()
.component_signatures(cs_list)
.system_signatures (ss_list);
.system_signatures (ss_list)
.refresh_parallelism (ecs::settings::refresh_parallelism::disable);

namespace sea = ::ecs::system_execution_adapter;

double frand(double min, double max)
{
double f = (double)rand() / RAND_MAX;
return min + f * (max - min);
}

TEST(DummyTest, fuu)
{
srand(static_cast<unsigned int>(time(nullptr)));

auto context = ::ecs::context::make(settings);
context.step([](auto& step_proxy){
step_proxy.execute_systems()(
sea::tags(st::foo)
.for_subtasks([](auto& s, auto& data){
std::cout << "foo" << std::endl
<< " " << type_helper<decltype(data)>::name() << std::endl;
}),
sea::tags(st::accelerate)
.for_subtasks([](auto& s, auto& data){
std::cout << "accelerate" << std::endl
<< " " << type_helper<decltype(data)>::name() << std::endl;
}),
sea::tags(st::move)
.for_subtasks([](auto& s, auto& data){
std::cout << "move" << std::endl
<< " " << type_helper<decltype(data)>::name() << std::endl;
}),
sea::tags(st::render)
.for_subtasks([](auto& s, auto& data){
std::cout << "render" << std::endl
<< " " << type_helper<decltype(data)>::name() << std::endl;
})
);

context.step([](auto& proxy){
for (auto i = 0; i < 10; ++i) {
auto handle = proxy.create_entity();

auto& position = proxy.add_component(handle, ct::position);
position.x = frand(-100, 100);
position.y = frand(-100, 100);

auto& velocity = proxy.add_component(handle, ct::velocity);
velocity.x = frand(-1, 1);
velocity.y = frand(-1, 1);

auto& acceleration = proxy.add_component(handle, ct::acceleration);
acceleration.x = frand(-1, 1);
acceleration.y = frand(-1, 1);
}
});

for (int i = 0; i < 10; ++i) {
context.step([](auto& proxy){
proxy.execute_systems()(
sea::tags(st::accelerate)
.for_subtasks([](auto& s, auto& data){
data.for_entities([&data](auto& handle) {
auto& velocity = data.get_component(ct::velocity, handle);
auto& acceleration = data.get_component(ct::acceleration, handle);

velocity.x += acceleration.x;
velocity.y += acceleration.y;
});
}),
sea::tags(st::move)
.for_subtasks([](auto& s, auto& data){
data.for_entities([&data](auto& handle) {
auto& position = data.get_component(ct::position, handle);
auto& velocity = data.get_component(ct::velocity, handle);

position.x += velocity.x;
position.y += velocity.y;
});
}),
sea::tags(st::render)
.for_subtasks([](auto& s, auto& data){
std::cout << "render" << std::endl;
data.for_entities([&data](auto& handle) {
auto& position = data.get_component(ct::position, handle);
auto& velocity = data.get_component(ct::velocity, handle);
auto& acceleration = data.get_component(ct::acceleration, handle);

std::cout << std::fixed
<< " " << handle.index() << ": "
<< "pos(" << position.x << ";" << position.y << ") "
<< "vel(" << velocity.x << ";" << velocity.y << ") "
<< "acc(" << acceleration.x << ";" << acceleration.y << ")"
<< std::endl;
});
})
);
});
}
}

Loading…
取消
儲存