You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
7.9 KiB

  1. #pragma once
  2. #include <ecs/config.h>
  3. #include <ecs/core/utils/thread_pool.h>
  4. #include <ecs/core/utils/counter_blocker.h>
  5. #include <ecs/core/component/manager.h>
  6. #define ecs_context_proxy_func(base, name) \
  7. template<typename... T_args> \
  8. inline decltype(auto) name(T_args&&... args) \
  9. noexcept(noexcept(base::name(std::forward<T_args>(args)...))) \
  10. { return base::name(std::forward<T_args>(args)...); }
  11. beg_namespace_ecs_context
  12. {
  13. namespace __impl
  14. {
  15. template<typename T_settings>
  16. struct base_t
  17. {
  18. public:
  19. using settings_type = T_settings;
  20. protected:
  21. using component_manager_type = core::component::manager<settings_type>;
  22. using chunk_meta_data_type = typename component_manager_type::chunk_meta_data_type;
  23. using entity_storage_type = decltype((settings_type { }).entity_storage()(settings_type { }, hana::type_c<chunk_meta_data_type>));
  24. using entity_handle_type = typename entity_storage_type::entity_handle_type;
  25. using system_storage_type = decltype((settings_type { }).system_storage()(settings_type { }, hana::type_c<entity_handle_type>));
  26. using scheduler_type = decltype((settings_type { }).scheduler()(settings_type { }));
  27. public:
  28. using handle_type = entity_handle_type;
  29. private:
  30. using handle_vector_type = std::vector<handle_type>;
  31. protected:
  32. component_manager_type _components;
  33. entity_storage_type _entities;
  34. system_storage_type _systems;
  35. scheduler_type _scheduler;
  36. core::utils::thread_pool _thread_pool;
  37. handle_vector_type _to_match;
  38. handle_vector_type _to_kill;
  39. public:
  40. inline base_t()
  41. : _components ()
  42. , _entities ((settings_type { }).entity_storage()(settings_type { }, hana::type_c<chunk_meta_data_type>))
  43. , _systems ((settings_type { }).system_storage()(settings_type { }, hana::type_c<entity_handle_type>))
  44. , _scheduler ((settings_type { }).scheduler()(settings_type { }))
  45. , _thread_pool (std::thread::hardware_concurrency() != 0
  46. ? std::thread::hardware_concurrency()
  47. : 8 )
  48. { }
  49. protected: /* misc */
  50. template<typename T_func>
  51. inline decltype(auto) post_in_thread_pool(T_func&& func)
  52. {
  53. return _thread_pool.post(std::forward<T_func>(func));
  54. }
  55. protected: /* entity */
  56. template<typename... T_args>
  57. inline handle_type create_entity(T_args&&... args)
  58. {
  59. _to_match.emplace_back(_entities.claim(std::forward<T_args>(args)...));
  60. return _to_match.back();
  61. }
  62. inline void kill_entity(const handle_type& handle)
  63. {
  64. _to_kill.emplace_back(handle);
  65. }
  66. inline bool is_alive(const handle_type& handle) const
  67. {
  68. return _entities.is_valid(handle);
  69. }
  70. protected: /* component */
  71. template<typename T_component_tag>
  72. inline decltype(auto) add_component(const handle_type& handle, T_component_tag ct)
  73. {
  74. _to_match.emplace_back(handle);
  75. auto& meta = _entities.meta_data(handle);
  76. auto& cmd = meta.chunk_meta_data();
  77. auto& c = _components.add(ct, handle, cmd);
  78. auto& bitset = meta.bitset();
  79. bitset.set_component(ct, true);
  80. return c;
  81. }
  82. template<typename T_component_tag>
  83. inline decltype(auto) has_component(const handle_type& handle, T_component_tag ct)
  84. {
  85. auto& meta = _entities.meta_data(handle);
  86. auto& bitset = meta.bitset();
  87. return bitset.has_component(ct);
  88. }
  89. template<typename T_component_tag>
  90. inline decltype(auto) get_component(const handle_type& handle, T_component_tag ct)
  91. {
  92. auto& meta = _entities.meta_data(handle);
  93. auto& bitset = meta.bitset();
  94. auto& cmd = meta.chunk_meta_data();
  95. if (!bitset.has_component(ct))
  96. throw std::invalid_argument("entity does not contain the requested compnent");
  97. return _components.get(ct, handle, cmd);
  98. }
  99. template<typename T_component_tag>
  100. inline decltype(auto) remove_component(const handle_type& handle, T_component_tag ct)
  101. {
  102. _to_match.emplace_back(handle);
  103. auto& meta = _entities.meta_data(handle);
  104. auto& bitset = meta.bitset();
  105. bitset.set_component(ct, false);
  106. }
  107. protected: /* systems */
  108. template<typename T_system_tag>
  109. inline auto& instance(T_system_tag st)
  110. {
  111. return _systems.instance_by_tag(st);
  112. }
  113. template<typename T_system_tag>
  114. inline auto& system(T_system_tag st)
  115. {
  116. return _systems.instance_by_tag(st).system();
  117. }
  118. template<typename T_func>
  119. inline void for_systems_sequential(T_func&& func)
  120. {
  121. _systems.for_each(std::forward<T_func>(func));
  122. }
  123. template<typename T_func>
  124. inline void for_systems_parallel(T_func&& func)
  125. {
  126. core::utils::counter_blocker counter(_systems.size());
  127. counter.execute_and_wait_until_zero([this, &counter, func = std::forward<T_func>(func)]{
  128. _systems.for_each([this, &counter, &func](auto& instance){
  129. this->post_in_thread_pool([&counter, &func, &instance]{
  130. ecs_make_scope_guard([&counter](){
  131. counter.decrement_and_notify_one();
  132. });
  133. func(instance);
  134. });
  135. });
  136. });
  137. }
  138. template<typename T_func>
  139. inline void for_systems_dispatch(T_func&& func)
  140. {
  141. hana::eval_if(
  142. (settings_type { }).refresh_parallelism(),
  143. [this, func=std::forward<T_func>(func)](auto _) {
  144. _(this)->for_systems_parallel(func);
  145. },
  146. [this, func=std::forward<T_func>(func)](auto _) {
  147. _(this)->for_systems_sequential(func);
  148. });
  149. }
  150. private:
  151. template<typename... T_system_tags>
  152. static constexpr decltype(auto) make_system_tag_list(T_system_tags&&... tags) noexcept
  153. {
  154. auto list = core::mp::list::make(std::forward<T_system_tags>(tags)...);
  155. return hana::if_(
  156. hana::equal(hana::size(list), hana::size_c<0>),
  157. (settings_type { }).system_signatures().tags(),
  158. list);
  159. }
  160. protected: /* execute */
  161. template<typename... T_system_tags>
  162. inline decltype(auto) execute_systems(T_system_tags&&... sts) noexcept
  163. {
  164. auto tags = make_system_tag_list(std::forward<T_system_tags>(sts)...);
  165. return [tags, this](auto&&... fns) {
  166. auto os = hana::overload_linearly(std::forward<decltype(fns)>(fns)...);
  167. this->_scheduler.execute(tags, os);
  168. };
  169. }
  170. };
  171. }
  172. }
  173. end_namespace_ecs_context