neoGFX
Cross-platform C++ app/game engine
i_ecs.hpp
Go to the documentation of this file.
1 // i_ecs.hpp
2 /*
3  neogfx C++ GUI Library
4  Copyright (c) 2018 Leigh Johnston. All Rights Reserved.
5 
6  This program is free software: you can redistribute it and / or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #pragma once
21 
22 #include <neogfx/neogfx.hpp>
23 #include <map>
24 #include <neogfx/core/event.hpp>
25 #include <neogfx/game/ecs_ids.hpp>
28 #include <neogfx/game/system.hpp>
29 #include <neogfx/game/chrono.hpp>
30 
31 namespace neogfx::game
32 {
33  enum class ecs_flags : uint32_t
34  {
35  None = 0x0000,
36  PopulateEntityInfo = 0x0001
37  };
38 
39  inline constexpr ecs_flags operator|(ecs_flags aLhs, ecs_flags aRhs)
40  {
41  return static_cast<ecs_flags>(static_cast<uint32_t>(aLhs) | static_cast<uint32_t>(aRhs));
42  }
43 
44  inline constexpr ecs_flags operator&(ecs_flags aLhs, ecs_flags aRhs)
45  {
46  return static_cast<ecs_flags>(static_cast<uint32_t>(aLhs) & static_cast<uint32_t>(aRhs));
47  }
48 
49  inline constexpr ecs_flags& operator|=(ecs_flags& aLhs, ecs_flags aRhs)
50  {
51  return aLhs = static_cast<ecs_flags>(static_cast<uint32_t>(aLhs) | static_cast<uint32_t>(aRhs));
52  }
53 
54  inline constexpr ecs_flags& operator&=(ecs_flags& aLhs, ecs_flags aRhs)
55  {
56  return aLhs = static_cast<ecs_flags>(static_cast<uint32_t>(aLhs) & static_cast<uint32_t>(aRhs));
57  }
58 
59  class i_ecs
60  {
61  public:
62  declare_event(systems_paused)
63  declare_event(systems_resumed)
64  declare_event(entity_created, entity_id)
65  declare_event(entity_destroyed, entity_id)
66  declare_event(handle_updated, handle_id)
67  public:
68  struct entity_archetype_not_found : std::logic_error { entity_archetype_not_found() : std::logic_error("neogfx::i_ecs::entity_archetype_not_found") {} };
69  struct component_not_found : std::logic_error { component_not_found() : std::logic_error("neogfx::i_ecs::component_not_found") {} };
70  struct system_not_found : std::logic_error { system_not_found() : std::logic_error("neogfx::i_ecs::system_not_found") {} };
71  struct uuid_exists : std::runtime_error { uuid_exists(const std::string& aContext) : std::runtime_error("neogfx::i_ecs::uuid_exists: " + aContext) {} };
72  struct entity_ids_exhausted : std::runtime_error { entity_ids_exhausted() : std::runtime_error("neogfx::i_ecs::entity_ids_exhausted") {} };
73  struct handle_ids_exhausted : std::runtime_error { handle_ids_exhausted() : std::runtime_error("neogfx::i_ecs::handle_ids_exhausted") {} };
74  struct invalid_handle_id : std::logic_error { invalid_handle_id() : std::logic_error("neogfx::i_ecs::invalid_handle_id") {} };
75  public:
76  typedef std::function<std::unique_ptr<i_component>()> component_factory;
77  typedef std::function<std::unique_ptr<i_shared_component>()> shared_component_factory;
78  typedef std::function<std::unique_ptr<i_system>()> system_factory;
79  protected:
80  typedef std::map<entity_archetype_id, std::shared_ptr<const i_entity_archetype>> archetype_registry_t;
81  typedef std::map<component_id, component_factory> component_factories_t;
82  typedef std::map<component_id, std::unique_ptr<i_component>> components_t;
83  typedef std::map<component_id, shared_component_factory> shared_component_factories_t;
84  typedef std::map<component_id, std::unique_ptr<i_shared_component>> shared_components_t;
85  typedef std::map<system_id, system_factory> system_factories_t;
86  typedef std::map<system_id, std::unique_ptr<i_system>> systems_t;
87  public:
88  typedef id_t handle_id;
89  typedef void* handle_t;
90  public:
91  virtual ecs_flags flags() const = 0;
92  virtual entity_id create_entity(const entity_archetype_id& aArchetypeId) = 0;
93  virtual void destroy_entity(entity_id aEntityId) = 0;
94  public:
95  virtual bool all_systems_paused() const = 0;
96  virtual void pause_all_systems() = 0;
97  virtual void resume_all_systems() = 0;
98  public:
99  virtual const archetype_registry_t& archetypes() const = 0;
100  virtual archetype_registry_t& archetypes() = 0;
101  virtual const component_factories_t& component_factories() const = 0;
102  virtual component_factories_t& component_factories() = 0;
103  virtual const components_t& components() const = 0;
104  virtual components_t& components() = 0;
105  virtual const shared_component_factories_t& shared_component_factories() const = 0;
106  virtual shared_component_factories_t& shared_component_factories() = 0;
107  virtual const shared_components_t& shared_components() const = 0;
108  virtual shared_components_t& shared_components() = 0;
109  virtual const system_factories_t& system_factories() const = 0;
110  virtual system_factories_t& system_factories() = 0;
111  virtual const systems_t& systems() const = 0;
112  virtual systems_t& systems() = 0;
113  public:
114  virtual const i_entity_archetype& archetype(entity_archetype_id aArchetypeId) const = 0;
115  virtual i_entity_archetype& archetype(entity_archetype_id aArchetypeId) = 0;
116  virtual bool component_instantiated(component_id aComponentId) const = 0;
117  virtual const i_component& component(component_id aComponentId) const = 0;
118  virtual i_component& component(component_id aComponentId) = 0;
119  virtual bool shared_component_instantiated(component_id aComponentId) const = 0;
120  virtual const i_shared_component& shared_component(component_id aComponentId) const = 0;
121  virtual i_shared_component& shared_component(component_id aComponentId) = 0;
122  virtual bool system_instantiated(system_id aSystemId) const = 0;
123  virtual const i_system& system(system_id aSystemId) const = 0;
124  virtual i_system& system(system_id aSystemId) = 0;
125  public:
126  virtual entity_id next_entity_id() = 0;
127  virtual void free_entity_id(entity_id aId) = 0;
128  public:
129  virtual bool archetype_registered(const i_entity_archetype& aArchetype) const = 0;
130  virtual void register_archetype(const i_entity_archetype& aArchetype) = 0;
131  virtual void register_archetype(std::shared_ptr<const i_entity_archetype> aArchetype) = 0;
132  virtual bool component_registered(component_id aComponentId) const = 0;
133  virtual void register_component(component_id aComponentId, component_factory aFactory) = 0;
134  virtual bool shared_component_registered(component_id aComponentId) const = 0;
135  virtual void register_shared_component(component_id aComponentId, shared_component_factory aFactory) = 0;
136  virtual bool system_registered(system_id aSystemId) const = 0;
137  virtual void register_system(system_id aSystemId, system_factory aFactory) = 0;
138  public:
139  virtual handle_t to_handle(handle_id aId) const = 0;
140  virtual handle_id add_handle(const std::type_info& aTypeInfo, handle_t aHandle) = 0;
141  virtual handle_t update_handle(handle_id aId, const std::type_info& aTypeInfo, handle_t aHandle) = 0;
142  virtual handle_t release_handle(handle_id aId) = 0;
143  // helpers
144  public:
145  template <typename... ComponentData>
146  entity_id create_entity(const entity_archetype_id& aArchetypeId, ComponentData&&... aComponentData)
147  {
148  auto newEntity = create_entity(aArchetypeId);
149  populate(newEntity, std::forward<ComponentData>(aComponentData)...);
150  archetype(aArchetypeId).populate_default_components(*this, newEntity);
151  return newEntity;
152  }
153  template <typename Archetype, typename... ComponentData>
154  entity_id create_entity(const Archetype& aArchetype, ComponentData&&... aComponentData)
155  {
156  if (!archetype_registered(aArchetype))
157  register_archetype(aArchetype);
158  return create_entity(aArchetype.id(), std::forward<ComponentData>(aComponentData)...);
159  }
160  public:
161  template <typename ComponentData, typename... ComponentDataRest>
162  void populate(entity_id aEntity, ComponentData&& aComponentData, ComponentDataRest&&... aComponentDataRest)
163  {
164  populate(aEntity, std::forward<ComponentData>(aComponentData));
165  populate(aEntity, std::forward<ComponentDataRest>(aComponentDataRest)...);
166  }
167  template <typename ComponentData>
168  void populate(entity_id aEntity, ComponentData&& aComponentData)
169  {
170  component<ecs_data_type_t<ComponentData>>().populate(aEntity, std::forward<ComponentData>(aComponentData));
171  }
172  template <typename ComponentData, typename... ComponentDataRest>
173  void populate_shared(const std::string& aName, ComponentData&& aComponentData, ComponentDataRest&&... aComponentDataRest)
174  {
175  populate_shared(aName, std::forward<ComponentData>(aComponentData));
176  populate_shared(aName, std::forward<ComponentDataRest>(aComponentDataRest)...);
177  }
178  template <typename ComponentData>
179  void populate_shared(const std::string& aName, ComponentData&& aComponentData)
180  {
181  shared_component<ecs_data_type_t<ComponentData>>().populate(aName, std::forward<ComponentData>(aComponentData));
182  }
183  template <typename ComponentData>
185  {
186  return component_instantiated(ecs_data_type_t<ComponentData>::meta::id());
187  }
188  template <typename ComponentData>
190  {
192  }
193  template <typename ComponentData>
195  {
196  if (!component_registered<ecs_data_type_t<ComponentData>>())
197  register_component<ecs_data_type_t<ComponentData>>();
199  }
200  template <typename ComponentData>
202  {
203  return shared_component_instantiated(ecs_data_type_t<ComponentData>::meta::id());
204  }
205  template <typename ComponentData>
207  {
208  return static_cast<const static_shared_component<ecs_data_type_t<ComponentData>>&>(shared_component(ComponentData::meta::id()));
209  }
210  template <typename ComponentData>
212  {
213  if (!shared_component_registered<ecs_data_type_t<ComponentData>>())
214  register_shared_component<ecs_data_type_t<ComponentData>>();
216  }
217  template <typename System>
218  bool system_instantiated() const
219  {
220  return system_instantiated(ecs_data_type_t<System>::meta::id());
221  }
222  template <typename System>
224  {
226  }
227  template <typename System>
229  {
230  if (!system_registered<ecs_data_type_t<System>>())
231  register_system<ecs_data_type_t<System>>();
232  return const_cast<ecs_data_type_t<System>&>(to_const(*this).system<ecs_data_type_t<System>>());
233  }
234  public:
235  template <typename ComponentData>
236  bool component_registered() const
237  {
238  return component_registered(ecs_data_type_t<ComponentData>::meta::id());
239  }
240  template <typename ComponentData>
242  {
243  register_component(ecs_data_type_t<ComponentData>::meta::id(), [&]() { return std::unique_ptr<i_component>{std::make_unique<static_component<ecs_data_type_t<ComponentData>>>(*this)}; });
244  }
245  template <typename ComponentData>
247  {
248  return shared_component_registered(ecs_data_type_t<ComponentData>::meta::id());
249  }
250  template <typename ComponentData>
252  {
253  register_shared_component(ecs_data_type_t<ComponentData>::meta::id(), [&]() { return std::unique_ptr<i_shared_component>{std::make_unique<static_shared_component<ecs_data_type_t<ComponentData>>>(*this)}; });
254  }
255  template <typename System>
256  bool system_registered() const
257  {
258  return system_registered(ecs_data_type_t<System>::meta::id());
259  }
260  template <typename System>
262  {
263  register_system(
265  [&]() { return std::unique_ptr<i_system>{std::make_unique<ecs_data_type_t<System>>(*this)}; });
266  }
267  public:
268  template <typename Handle>
269  Handle to_handle(handle_id aId) const
270  {
271  return reinterpret_cast<Handle>(to_handle(aId));
272  }
273  template <typename Context, typename Handle>
274  handle_id add_handle(Handle aHandle)
275  {
276  return add_handle(typeid(Context), reinterpret_cast<handle_t>(aHandle));
277  }
278  template <typename Context, typename Handle>
279  Handle update_handle(handle_id aId, Handle aHandle)
280  {
281  if constexpr(std::is_pointer<Handle>::value)
282  return reinterpret_cast<Handle>(update_handle(aId, typeid(Context), reinterpret_cast<handle_t>(aHandle)));
283  else
284  return static_cast<Handle>(reinterpret_cast<intptr_t>(update_handle(aId, typeid(Context), reinterpret_cast<handle_t>(aHandle))));
285  }
286  template <typename Handle>
287  Handle release_handle(handle_id aId)
288  {
289  if constexpr(std::is_pointer<Handle>::value)
290  return reinterpret_cast<Handle>(release_handle(aId));
291  else
292  return static_cast<Handle>(reinterpret_cast<intptr_t>(release_handle(aId)));
293  }
294  };
295 
296  template <typename Data>
298  {
299  public:
301  iLockGuard{ aEcs.shared_component<Data>().mutex() }
302  {
303  }
304  private:
305  std::scoped_lock<std::recursive_mutex> iLockGuard;
306  };
307 
308  template <typename Data>
310  {
311  public:
313  iLockGuard{ aEcs.component<Data>().mutex() }
314  {
315  }
316  private:
317  std::scoped_lock<std::recursive_mutex> iLockGuard;
318  };
319 }
component_scoped_lock(const i_ecs &aEcs)
Definition: i_ecs.hpp:312
static_shared_component< ComponentData > & shared_component()
Definition: i_ecs.hpp:211
void register_system()
Definition: i_ecs.hpp:261
const static_component< ComponentData > & component() const
Definition: i_ecs.hpp:189
Handle to_handle(handle_id aId) const
Definition: i_ecs.hpp:269
static_component< ComponentData > & component()
Definition: i_ecs.hpp:194
Handle update_handle(handle_id aId, Handle aHandle)
Definition: i_ecs.hpp:279
std::remove_cv_t< std::remove_reference_t< _Ty > > ecs_data_type_t
void populate(entity_id aEntity, ComponentData &&aComponentData)
Definition: i_ecs.hpp:168
std::map< component_id, component_factory > component_factories_t
Definition: i_ecs.hpp:81
bool component_instantiated() const
Definition: i_ecs.hpp:184
ecs_data_type_t< System > & system()
Definition: i_ecs.hpp:228
uint32_t id
Definition: primitives.hpp:31
virtual const i_shared_component & shared_component(component_id aComponentId) const =0
void populate_shared(const std::string &aName, ComponentData &&aComponentData)
Definition: i_ecs.hpp:179
shared_component_scoped_lock(const i_ecs &aEcs)
Definition: i_ecs.hpp:300
std::map< system_id, std::unique_ptr< i_system > > systems_t
Definition: i_ecs.hpp:86
void populate_shared(const std::string &aName, ComponentData &&aComponentData, ComponentDataRest &&... aComponentDataRest)
Definition: i_ecs.hpp:173
constexpr component_data_field_type operator|(component_data_field_type aLhs, component_data_field_type aRhs)
bool system_instantiated() const
Definition: i_ecs.hpp:218
std::function< std::unique_ptr< i_system >)> system_factory
Definition: i_ecs.hpp:78
std::map< component_id, shared_component_factory > shared_component_factories_t
Definition: i_ecs.hpp:83
to_const_reference_t< T > to_const(T &&object)
Definition: neolib.hpp:59
std::map< entity_archetype_id, std::shared_ptr< const i_entity_archetype > > archetype_registry_t
Definition: i_ecs.hpp:80
std::function< std::unique_ptr< i_shared_component >)> shared_component_factory
Definition: i_ecs.hpp:77
void register_component()
Definition: i_ecs.hpp:241
bool shared_component_instantiated() const
Definition: i_ecs.hpp:201
virtual const i_component & component(component_id aComponentId) const =0
std::map< component_id, std::unique_ptr< i_component > > components_t
Definition: i_ecs.hpp:82
entity_id create_entity(const Archetype &aArchetype, ComponentData &&... aComponentData)
Definition: i_ecs.hpp:154
uuid_exists(const std::string &aContext)
Definition: i_ecs.hpp:71
bool shared_component_registered() const
Definition: i_ecs.hpp:246
constexpr component_data_field_type operator &(component_data_field_type aLhs, component_data_field_type aRhs)
void register_shared_component()
Definition: i_ecs.hpp:251
neolib::cookie id_t
Definition: ecs_ids.hpp:31
entity_id create_entity(const entity_archetype_id &aArchetypeId, ComponentData &&... aComponentData)
Definition: i_ecs.hpp:146
id_t entity_id
Definition: ecs_ids.hpp:34
handle_id add_handle(Handle aHandle)
Definition: i_ecs.hpp:274
Handle release_handle(handle_id aId)
Definition: i_ecs.hpp:287
std::map< system_id, system_factory > system_factories_t
Definition: i_ecs.hpp:85
std::function< std::unique_ptr< i_component >)> component_factory
Definition: i_ecs.hpp:76
bool system_registered() const
Definition: i_ecs.hpp:256
bool component_registered() const
Definition: i_ecs.hpp:236
const static_shared_component< ComponentData > & shared_component() const
Definition: i_ecs.hpp:206
void populate(entity_id aEntity, ComponentData &&aComponentData, ComponentDataRest &&... aComponentDataRest)
Definition: i_ecs.hpp:162
#define declare_event(declName,...)
constexpr component_data_field_type & operator|=(component_data_field_type &aLhs, component_data_field_type aRhs)
std::map< component_id, std::unique_ptr< i_shared_component > > shared_components_t
Definition: i_ecs.hpp:84
const ecs_data_type_t< System > & system() const
Definition: i_ecs.hpp:223
constexpr component_data_field_type & operator &=(component_data_field_type &aLhs, component_data_field_type aRhs)