Engine
Raylib based game framework
Loading...
Searching...
No Matches
Registry.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Assert.hpp"
4#include "entt/entt.hpp"
5#include <Types.hpp>
6#include <functional>
7#include <typeindex>
8#include <unordered_map>
9#include <unordered_set>
10#include <utility>
11
12using Entity = entt::entity;
13
14constexpr Entity NULL_ENTITY = static_cast<Entity>(0);
15
20
29{
30public:
31
37 Entity CreateEntity();
38
46 void DestroyEntity(const Entity entity);
47
54 bool EntityValid(const Entity entity);
55
67 template <typename Component, typename... Args>
68 const Component* Emplace(const Entity entity, Args&&... args)
69 {
70 Assert(EntityValid(entity));
71 if (HasAny<Component>(entity))
72 {
73 return nullptr;
74 }
75
76 return &m_registry.emplace<Component>(entity, std::forward<Args>(args)...);
77 }
78
90 template <typename Component, typename... Args>
91 const Component& EmplaceOrReplace(const Entity entity, Args&&... args)
92 {
93 Assert(EntityValid(entity));
94 return m_registry.emplace_or_replace<Component>(entity, std::forward<Args>(args)...);
95 }
96
108 template <typename Component>
109 bool Patch(const Entity entity, const std::function<void(Component&)>& func)
110 {
111 Assert(EntityValid(entity));
112 if (!m_registry.any_of<Component>(entity))
113 {
114 return false;
115 }
116
117 m_registry.patch<Component>(entity, func);
118
119 return true;
120 }
121
129 template <typename Component>
130 const Component* Get(const Entity entity)
131 {
132 Assert(EntityValid(entity));
133 Component* ptr = m_registry.try_get<Component>(entity);
134 if (!ptr)
135 {
136 return nullptr;
137 }
138
139 return ptr;
140 }
141
149 template <typename... Components>
150 bool HasAny(const Entity entity)
151 {
152 Assert(EntityValid(entity));
153 return m_registry.any_of<Components...>(entity);
154 }
155
163 template <typename... Components>
164 bool HasAll(const Entity entity)
165 {
166 Assert(EntityValid(entity));
167 return m_registry.all_of<Components...>(entity);
168 }
169
181 template <typename Component, typename... Args>
182 const Component* Replace(const Entity entity, Args&&... args)
183 {
184 Assert(EntityValid(entity));
185 if (!HasAny<Component>(entity))
186 {
187 return nullptr;
188 }
189
190 return &m_registry.replace<Component>(entity, std::forward<Args>(args)...);
191 }
192
201 template <typename Component>
202 void Remove(const Entity entity)
203 {
204 Assert(EntityValid(entity));
205 m_registry.remove<Component>(entity);
206 }
207
213 template <typename Component>
215 {
216 m_registry.clear<Component>();
217 }
218
227 template <typename... Components>
228 auto GetView()
229 {
230 return m_registry.view<const Components...>();
231 }
232
246 template <typename... Owned, typename... Get, typename... Exclude>
247 auto GetGroup([[maybe_unused]] entt::get_t<Get...> get = entt::get_t{},
248 [[maybe_unused]] entt::exclude_t<Exclude...> exclude = entt::exclude_t{})
249 {
250 return m_registry.group<const Owned...>(entt::get_t<const Get...>{}, entt::exclude_t<Exclude...>{});
251 }
252
261 template <typename Component>
262 void Sort(const std::function<bool(const Component& a, const Component& b)>& comparitor)
263 {
264 m_registry.sort<Component>(comparitor);
265 }
266
280 template <typename... Owned, typename... Get, typename... Exclude>
281 void SortGroup(const std::function<bool(const Entity& a, const Entity& b)>& comparitor,
282 entt::get_t<Get...> get = entt::get_t{}, entt::exclude_t<Exclude...> exclude = entt::exclude_t{})
283 {
284 auto group = m_registry.group<Owned...>(get, exclude);
285 group.sort(comparitor);
286 }
287
298 template <typename Component>
299 u32 OnConstruct(const std::function<void(Component& component, const Entity entity)>& callback)
300 {
301 m_callbackId++;
302
303 auto& callbacks = m_constructCallbacks[typeid(Component)];
304 callbacks[m_callbackId] = [callback](void* comp, const Entity entity)
305 {
306 callback(*static_cast<Component*>(comp), entity);
307 };
308
309 if (!m_constructConnected.contains(typeid(Component)))
310 {
311 m_registry.on_construct<Component>().template connect<&Registry::HandleConstruct<Component>>(this);
312 m_constructConnected.insert(typeid(Component));
313 }
314
315 return m_callbackId;
316 };
317
328 template <typename Component>
329 u32 OnUpdate(const std::function<void(Component& component, const Entity entity)>& callback)
330 {
331 m_callbackId++;
332
333 auto& callbacks = m_updateCallbacks[typeid(Component)];
334 callbacks[m_callbackId] = [callback](void* comp, const Entity entity)
335 {
336 callback(*static_cast<Component*>(comp), entity);
337 };
338
339 if (!m_updateConnected.contains(typeid(Component)))
340 {
341 m_registry.on_update<Component>().template connect<&Registry::HandleUpdate<Component>>(this);
342 m_updateConnected.insert(typeid(Component));
343 }
344
345 return m_callbackId;
346 };
347
358 template <typename Component>
359 u32 OnDestroy(const std::function<void(Component& component, const Entity entity)>& callback)
360 {
361 m_callbackId++;
362
363 auto& callbacks = m_destroyCallbacks[typeid(Component)];
364 callbacks[m_callbackId] = [callback](void* comp, const Entity entity)
365 {
366 callback(*static_cast<Component*>(comp), entity);
367 };
368
369 if (!m_destroyConnected.contains(typeid(Component)))
370 {
371 m_registry.on_destroy<Component>().template connect<&Registry::HandleDestroy<Component>>(this);
372 m_destroyConnected.insert(typeid(Component));
373 }
374
375 return m_callbackId;
376 };
377
386 template <typename Component>
387 void RemoveConstructCallback(const u32 callbackId)
388 {
389 auto it = m_constructCallbacks.find(typeid(Component));
390 if (it == m_constructCallbacks.end())
391 {
392 return;
393 }
394
395 auto& map = it->second;
396 map.erase(callbackId);
397
398 if (map.empty())
399 {
400 m_registry.on_construct<Component>().template disconnect<&Registry::HandleConstruct<Component>>(this);
401 m_constructConnected.erase(typeid(Component));
402 }
403 }
404
413 template <typename Component>
414 void RemoveUpdateCallback(const u32 callbackId)
415 {
416 auto it = m_updateCallbacks.find(typeid(Component));
417 if (it == m_updateCallbacks.end())
418 {
419 return;
420 }
421
422 auto& map = it->second;
423 map.erase(callbackId);
424
425 if (map.empty())
426 {
427 m_registry.on_update<Component>().template disconnect<&Registry::HandleUpdate<Component>>(this);
428 m_updateConnected.erase(typeid(Component));
429 }
430 }
431
440 template <typename Component>
441 void RemoveDestroyCallback(const u32 callbackId)
442 {
443 auto it = m_destroyCallbacks.find(typeid(Component));
444 if (it == m_destroyCallbacks.end())
445 {
446 return;
447 }
448
449 auto& map = it->second;
450 map.erase(callbackId);
451
452 if (map.empty())
453 {
454 m_registry.on_destroy<Component>().template disconnect<&Registry::HandleDestroy<Component>>(this);
455 m_destroyConnected.erase(typeid(Component));
456 }
457 }
458
467 entt::registry& GetRegistry();
468
469private:
470
471 template <typename Component>
472 void HandleConstruct(entt::registry& registry, Entity entity)
473 {
474 auto it = m_constructCallbacks.find(typeid(Component));
475 if (it == m_constructCallbacks.end())
476 {
477 return;
478 }
479
480 for (auto& pair : it->second)
481 {
482 pair.second(static_cast<void*>(&registry.get<Component>(entity)), entity);
483 }
484 }
485
486 template <typename Component>
487 void HandleUpdate(entt::registry& registry, Entity entity)
488 {
489 auto it = m_updateCallbacks.find(typeid(Component));
490 if (it == m_updateCallbacks.end())
491 {
492 return;
493 }
494
495 for (auto& pair : it->second)
496 {
497 pair.second(static_cast<void*>(&registry.get<Component>(entity)), entity);
498 }
499 }
500
501 template <typename Component>
502 void HandleDestroy(entt::registry& registry, Entity entity)
503 {
504 auto it = m_destroyCallbacks.find(typeid(Component));
505 if (it == m_destroyCallbacks.end())
506 {
507 return;
508 }
509
510 for (auto& pair : it->second)
511 {
512 pair.second(static_cast<void*>(&registry.get<Component>(entity)), entity);
513 }
514 }
515
516 u32 m_callbackId = 0;
517
518 std::unordered_map<std::type_index, std::unordered_map<u32, std::function<void(void*, const Entity entity)>>>
519 m_constructCallbacks;
520 std::unordered_map<std::type_index, std::unordered_map<u32, std::function<void(void*, const Entity entity)>>>
521 m_updateCallbacks;
522 std::unordered_map<std::type_index, std::unordered_map<u32, std::function<void(void*, const Entity entity)>>>
523 m_destroyCallbacks;
524
525 std::unordered_set<std::type_index> m_constructConnected;
526 std::unordered_set<std::type_index> m_updateConnected;
527 std::unordered_set<std::type_index> m_destroyConnected;
528
529 entt::registry m_registry;
530};
Wraps entt::registry with a safer, callback-aware API.
Definition Registry.hpp:29
const Component * Get(const Entity entity)
Gets a pointer to a component on an entity.
Definition Registry.hpp:130
const Component * Emplace(const Entity entity, Args &&... args)
Adds a component to an entity.
Definition Registry.hpp:68
u32 OnConstruct(const std::function< void(Component &component, const Entity entity)> &callback)
Registers a callback invoked when a component of the given type is constructed.
Definition Registry.hpp:299
bool Patch(const Entity entity, const std::function< void(Component &)> &func)
Applies a function to an existing component in place.
Definition Registry.hpp:109
auto GetView()
Returns a view over all entities that have the given components.
Definition Registry.hpp:228
void RemoveUpdateCallback(const u32 callbackId)
Removes a previously registered update callback.
Definition Registry.hpp:414
void SortGroup(const std::function< bool(const Entity &a, const Entity &b)> &comparitor, entt::get_t< Get... > get=entt::get_t{}, entt::exclude_t< Exclude... > exclude=entt::exclude_t{})
Sorts a group's entities using an entity comparator.
Definition Registry.hpp:281
void ClearComponents()
Removes all instances of a component type from every entity.
Definition Registry.hpp:214
bool HasAll(const Entity entity)
Checks whether an entity has all of the given components.
Definition Registry.hpp:164
entt::registry & GetRegistry()
Returns a reference to the underlying entt registry.
Definition Registry.cpp:21
void Remove(const Entity entity)
Removes a component from an entity.
Definition Registry.hpp:202
bool HasAny(const Entity entity)
Checks whether an entity has at least one of the given components.
Definition Registry.hpp:150
void DestroyEntity(const Entity entity)
Destroys an entity if it is valid.
Definition Registry.cpp:8
auto GetGroup(entt::get_t< Get... > get=entt::get_t{}, entt::exclude_t< Exclude... > exclude=entt::exclude_t{})
Returns a group over entities with the specified owned and non-owned components.
Definition Registry.hpp:247
u32 OnDestroy(const std::function< void(Component &component, const Entity entity)> &callback)
Registers a callback invoked just before a component of the given type is destroyed.
Definition Registry.hpp:359
const Component & EmplaceOrReplace(const Entity entity, Args &&... args)
Adds or replaces a component on an entity.
Definition Registry.hpp:91
u32 OnUpdate(const std::function< void(Component &component, const Entity entity)> &callback)
Registers a callback invoked when a component of the given type is updated.
Definition Registry.hpp:329
const Component * Replace(const Entity entity, Args &&... args)
Replaces an existing component on an entity.
Definition Registry.hpp:182
bool EntityValid(const Entity entity)
Checks whether an entity is alive in the registry.
Definition Registry.cpp:16
void RemoveConstructCallback(const u32 callbackId)
Removes a previously registered construction callback.
Definition Registry.hpp:387
void RemoveDestroyCallback(const u32 callbackId)
Removes a previously registered destruction callback.
Definition Registry.hpp:441
Entity CreateEntity()
Creates a new entity.
Definition Registry.cpp:3
void Sort(const std::function< bool(const Component &a, const Component &b)> &comparitor)
Sorts a component pool using a comparator.
Definition Registry.hpp:262