Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
id.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstdint>
5#include <type_traits>
6
7#include "gaia/cnt/sparse_storage.h"
8#include "gaia/core/hashing_policy.h"
9#include "gaia/core/utility.h"
10#include "gaia/ecs/id_fwd.h"
11
12namespace gaia {
13 namespace ecs {
14#define GAIA_ID(type) GAIA_ID_##type
15
16 using Identifier = uint64_t;
17 inline constexpr Identifier IdentifierBad = (Identifier)-1;
18 inline constexpr Identifier EntityCompMask = IdentifierBad << 1;
19 inline constexpr IdentifierId IdentifierIdBad = (IdentifierId)-1;
20
21 // ------------------------------------------------------------------------------------
22 // Component
23 // ------------------------------------------------------------------------------------
24
25 struct GAIA_API Component final {
26 static constexpr uint32_t IdMask = IdentifierIdBad;
27 static constexpr uint32_t MaxAlignment_Bits = 10;
28 static constexpr uint32_t MaxAlignment = (1U << MaxAlignment_Bits) - 1;
29 static constexpr uint32_t MaxComponentSize_Bits = 12;
30 static constexpr uint32_t MaxComponentSizeInBytes = (1 << MaxComponentSize_Bits) - 1;
31
32 struct InternalData {
34 // detail::ComponentDescId id;
35 uint32_t id;
37 IdentifierData soa : meta::StructToTupleMaxTypes_Bits;
39 IdentifierData size : MaxComponentSize_Bits;
41 IdentifierData alig : MaxAlignment_Bits;
43 IdentifierData unused : 6;
44 };
45 static_assert(sizeof(InternalData) == sizeof(Identifier));
46
47 union {
48 InternalData data;
49 Identifier val;
50 };
51
52 Component() noexcept = default;
53
54 Component(uint32_t id, uint32_t soa, uint32_t size, uint32_t alig) noexcept {
55 data.id = id;
56 data.soa = soa;
57 data.size = size;
58 data.alig = alig;
59 data.unused = 0;
60 }
61
62 GAIA_NODISCARD constexpr auto id() const noexcept {
63 return (uint32_t)data.id;
64 }
65
66 GAIA_NODISCARD constexpr auto soa() const noexcept {
67 return (uint32_t)data.soa;
68 }
69
70 GAIA_NODISCARD constexpr auto size() const noexcept {
71 return (uint32_t)data.size;
72 }
73
74 GAIA_NODISCARD constexpr auto alig() const noexcept {
75 return (uint32_t)data.alig;
76 }
77
78 GAIA_NODISCARD constexpr auto value() const noexcept {
79 return val;
80 }
81
82 GAIA_NODISCARD constexpr bool operator==(Component other) const noexcept {
83 return value() == other.value();
84 }
85
86 GAIA_NODISCARD constexpr bool operator!=(Component other) const noexcept {
87 return value() != other.value();
88 }
89
90 GAIA_NODISCARD constexpr bool operator<(Component other) const noexcept {
91 return id() < other.id();
92 }
93 };
94
95 //----------------------------------------------------------------------
96 // Entity kind
97 //----------------------------------------------------------------------
98
99 enum EntityKind : uint8_t {
100 // Generic entity, one per entity
101 EK_Gen = 0,
102 // Unique entity, one per chunk
103 EK_Uni
104 };
105
106 inline constexpr const char* EntityKindString[] = {"Gen", "Uni"};
107
108 //----------------------------------------------------------------------
109 // Id type deduction
110 //----------------------------------------------------------------------
111
112 template <typename T>
113 struct uni {
114 static_assert(core::is_raw_v<T>);
115 static_assert(
116 std::is_trivial_v<T> ||
117 // For non-trivial T the comparison operator must be implemented because
118 // defragmentation needs it to figure out if entities can be moved around.
120 "Non-trivial Uni component must implement operator==");
121
123 static constexpr EntityKind Kind = EntityKind::EK_Uni;
124
126 using TType = T;
130 using TTypeOriginal = T;
131 };
132
133 namespace detail {
134 template <typename, typename = void>
135 struct has_entity_kind: std::false_type {};
136 template <typename T>
137 struct has_entity_kind<T, std::void_t<decltype(T::Kind)>>: std::true_type {};
138
139 template <typename T>
142 static constexpr EntityKind Kind = EntityKind::EK_Gen;
143
145 using Type = core::raw_t<T>;
147 using TypeFull = Type;
149 using TypeOriginal = T;
150 };
151
152 template <typename T>
155 static constexpr EntityKind Kind = T::Kind;
156
158 using Type = typename T::TType;
160 using TypeFull = std::conditional_t<Kind == EntityKind::EK_Gen, Type, uni<Type>>;
162 using TypeOriginal = typename T::TTypeOriginal;
163 };
164
165 template <typename, typename = void>
166 struct is_gen_component: std::true_type {};
167 template <typename T>
168 struct is_gen_component<T, std::void_t<decltype(T::Kind)>>: std::bool_constant<T::Kind == EntityKind::EK_Gen> {};
169
170 template <typename T, typename = void>
173 };
174 template <typename T>
175 struct component_type<T, std::void_t<decltype(T::Kind)>> {
177 };
178 } // namespace detail
179
180 template <typename T>
181 using component_type_t = typename detail::component_type<T>::type;
182
183 template <typename T>
184 inline constexpr EntityKind entity_kind_v = component_type_t<T>::Kind;
185
186 //----------------------------------------------------------------------
187 // Pair helpers
188 //----------------------------------------------------------------------
189
190 namespace detail {
191 struct pair_base {};
192 } // namespace detail
193
201 template <typename Rel, typename Tgt>
202 class pair: public detail::pair_base {
203 using rel_comp_type = component_type_t<Rel>;
204 using tgt_comp_type = component_type_t<Tgt>;
205
206 public:
207 using rel = typename rel_comp_type::TypeFull;
208 using tgt = typename tgt_comp_type::TypeFull;
209 using rel_type = typename rel_comp_type::Type;
210 using tgt_type = typename tgt_comp_type::Type;
211 using rel_original = typename rel_comp_type::TypeOriginal;
212 using tgt_original = typename tgt_comp_type::TypeOriginal;
213 using type = std::conditional_t<!std::is_empty_v<rel_type> || std::is_empty_v<tgt_type>, rel, tgt>;
214 };
215
216 template <typename T>
217 struct is_pair {
218 static constexpr bool value = std::is_base_of<detail::pair_base, core::raw_t<T>>::value;
219 };
220
221 // ------------------------------------------------------------------------------------
222 // Entity
223 // ------------------------------------------------------------------------------------
224
225 struct GAIA_API Entity final {
226 static constexpr uint32_t IdMask = IdentifierIdBad;
227
230 EntityId id;
231
233 // Bits in this section need to be 1:1 with EntityContainer data.
234 // Note, the order of these bits is important because entities
235 // are sorted by their "val" member and many behaviors rely on this.
237
239 IdentifierData gen : 28;
241 IdentifierData ent : 1;
243 IdentifierData pair : 1;
245 IdentifierData kind : 1;
247 IdentifierData tmp : 1;
248
250 };
251 static_assert(sizeof(InternalData) == sizeof(Identifier));
252
253 union {
254 InternalData data;
255 Identifier val;
256 };
257
258 constexpr Entity() noexcept: val(IdentifierBad) {};
259
263 template <typename T, typename = std::enable_if_t<std::is_same_v<T, Identifier>>>
264 constexpr Entity(T value) noexcept: val(value) {}
265
267 Entity(EntityId id, IdentifierData gen) noexcept {
268 val = 0;
269 data.id = id;
270 data.gen = gen;
271 }
272
273 Entity(EntityId id, IdentifierData gen, bool isEntity, bool isPair, EntityKind kind) noexcept {
274 data.id = id;
275 data.gen = gen;
276 data.ent = isEntity;
277 data.pair = isPair;
278 data.kind = kind;
279 data.tmp = 0;
280 }
281
282 GAIA_NODISCARD constexpr auto id() const noexcept {
283 return (uint32_t)data.id;
284 }
285
286 GAIA_NODISCARD constexpr auto gen() const noexcept {
287 return (uint32_t)data.gen;
288 }
289
290 GAIA_NODISCARD constexpr bool entity() const noexcept {
291 return data.ent != 0;
292 }
293
294 GAIA_NODISCARD constexpr bool pair() const noexcept {
295 return data.pair != 0;
296 }
297
298 GAIA_NODISCARD constexpr bool comp() const noexcept {
299 return (data.pair | data.ent) == 0;
300 }
301
302 GAIA_NODISCARD constexpr auto kind() const noexcept {
303 return (EntityKind)data.kind;
304 }
305
306 GAIA_NODISCARD constexpr auto value() const noexcept {
307 return val;
308 }
309
310 GAIA_NODISCARD constexpr bool operator==(Entity other) const noexcept {
311 return value() == other.value();
312 }
313
314 GAIA_NODISCARD constexpr bool operator!=(Entity other) const noexcept {
315 return value() != other.value();
316 }
317
318 GAIA_NODISCARD constexpr bool operator<(Entity other) const noexcept {
319 return value() < other.value();
320 }
321 GAIA_NODISCARD constexpr bool operator<=(Entity other) const noexcept {
322 return value() <= other.value();
323 }
324
325 GAIA_NODISCARD constexpr bool operator>(Entity other) const noexcept {
326 return value() > other.value();
327 }
328 GAIA_NODISCARD constexpr bool operator>=(Entity other) const noexcept {
329 return value() >= other.value();
330 }
331 };
332
333 inline static const Entity EntityBad = Entity(IdentifierBad);
334
336 struct GAIA_API EntityLookupKey {
338
339 private:
341 Entity m_entity;
343 LookupHash m_hash;
344
345 static LookupHash calc(Entity entity) {
346 return {core::calculate_hash64(entity.value())};
347 }
348
349 public:
350 static constexpr bool IsDirectHashKey = true;
351
352 EntityLookupKey() = default;
353 explicit EntityLookupKey(Entity entity): m_entity(entity), m_hash(calc(entity)) {}
354 ~EntityLookupKey() = default;
355
356 EntityLookupKey(const EntityLookupKey&) = default;
357 EntityLookupKey(EntityLookupKey&&) noexcept = default;
358 EntityLookupKey& operator=(const EntityLookupKey&) = default;
359 EntityLookupKey& operator=(EntityLookupKey&&) noexcept = default;
360
361 Entity entity() const {
362 return m_entity;
363 }
364
365 size_t hash() const {
366 return (size_t)m_hash.hash;
367 }
368
369 bool operator==(const EntityLookupKey& other) const {
370 if GAIA_LIKELY (m_hash != other.m_hash)
371 return false;
372
373 return m_entity == other.m_entity;
374 }
375
376 bool operator!=(const EntityLookupKey& other) const {
377 return !operator==(other);
378 }
379 };
380
381 inline static const EntityLookupKey EntityBadLookupKey = EntityLookupKey(EntityBad);
382
384 struct GAIA_API EntityDesc {
385 const char* name{};
386 uint32_t len{};
387 };
388
389 //----------------------------------------------------------------------
390 // Pair
391 //----------------------------------------------------------------------
392
394 template <>
396 Entity m_first;
397 Entity m_second;
398
399 public:
400 pair(Entity a, Entity b) noexcept: m_first(a), m_second(b) {}
401
402 operator Entity() const noexcept {
403 return Entity(
404 m_first.id(), m_second.id(),
405 // Pairs have no way of telling gen and uni entities apart.
406 // Therefore, for first, we use the entity bit as Gen/Uni...
407 (bool)m_first.kind(),
408 // Always true for pairs
409 true,
410 // ... and for second, we use the kind bit.
411 m_second.kind());
412 }
413
414 Entity first() const noexcept {
415 return m_first;
416 }
417
418 Entity second() const noexcept {
419 return m_second;
420 }
421
422 bool operator==(const pair& other) const {
423 return m_first == other.m_first && m_second == other.m_second;
424 }
425 bool operator!=(const pair& other) const {
426 return !operator==(other);
427 }
428 };
429
431
432 //----------------------------------------------------------------------
433 // Core components
434 //----------------------------------------------------------------------
435
436 namespace detail {
437 template <typename T, typename U = void>
438 struct actual_type {
439 using type = typename component_type<T>::type;
440 };
441
442 template <typename T>
443 struct actual_type<T, std::enable_if_t<is_pair<T>::value>> {
444 using storage_type = typename T::type;
445 using type = typename component_type<storage_type>::type;
446 };
447 } // namespace detail
448
449 template <typename T>
450 using actual_type_t = typename detail::actual_type<T>::type;
451
452 //----------------------------------------------------------------------
453 // Core components
454 //----------------------------------------------------------------------
455
456 // Core component. The entity it is attached to is ignored by queries
457 struct GAIA_API Core_ {};
458 // struct EntityDesc;
459 // struct Component;
460 struct GAIA_API OnDelete_ {};
461 struct GAIA_API OnDeleteTarget_ {};
462 struct GAIA_API Remove_ {};
463 struct GAIA_API Delete_ {};
464 struct GAIA_API Error_ {};
465 struct GAIA_API Requires_ {};
466 struct GAIA_API CantCombine_ {};
467 struct GAIA_API Exclusive_ {};
468 struct GAIA_API Acyclic_ {};
469 struct GAIA_API All_ {};
470 struct GAIA_API ChildOf_ {};
471 struct GAIA_API Is_ {};
472 struct GAIA_API Traversable_ {};
473 // struct System_;
474 struct GAIA_API DependsOn_ {};
475
476 // Query variables
477 struct GAIA_API _Var0 {};
478 struct GAIA_API _Var1 {};
479 struct GAIA_API _Var2 {};
480 struct GAIA_API _Var3 {};
481 struct GAIA_API _Var4 {};
482 struct GAIA_API _Var5 {};
483 struct GAIA_API _Var6 {};
484 struct GAIA_API _Var7 {};
485
486 //----------------------------------------------------------------------
487 // Core component entities
488 //----------------------------------------------------------------------
489
490 // Core component. The entity it is attached to is ignored by queries
491 inline Entity Core = Entity(0, 0, false, false, EntityKind::EK_Gen);
492 inline Entity GAIA_ID(EntityDesc) = Entity(1, 0, false, false, EntityKind::EK_Gen);
493 inline Entity GAIA_ID(Component) = Entity(2, 0, false, false, EntityKind::EK_Gen);
494 // Cleanup rules
495 inline Entity OnDelete = Entity(3, 0, false, false, EntityKind::EK_Gen);
496 inline Entity OnDeleteTarget = Entity(4, 0, false, false, EntityKind::EK_Gen);
497 inline Entity Remove = Entity(5, 0, false, false, EntityKind::EK_Gen);
498 inline Entity Delete = Entity(6, 0, false, false, EntityKind::EK_Gen);
499 inline Entity Error = Entity(7, 0, false, false, EntityKind::EK_Gen);
500 // Entity dependencies
501 inline Entity Requires = Entity(8, 0, false, false, EntityKind::EK_Gen);
502 inline Entity CantCombine = Entity(9, 0, false, false, EntityKind::EK_Gen);
503 inline Entity Exclusive = Entity(10, 0, false, false, EntityKind::EK_Gen);
504 // Graph properties
505 inline Entity Acyclic = Entity(11, 0, false, false, EntityKind::EK_Gen);
506 inline Entity Traversable = Entity(12, 0, false, false, EntityKind::EK_Gen);
507 // Wildcard query entity
508 inline Entity All = Entity(13, 0, false, false, EntityKind::EK_Gen);
509 // Entity representing a physical hierarchy.
510 // When the relationship target is deleted all children are deleted as well.
511 inline Entity ChildOf = Entity(14, 0, false, false, EntityKind::EK_Gen);
512 // Alias for a base entity/inheritance
513 inline Entity Is = Entity(15, 0, false, false, EntityKind::EK_Gen);
514 // Systems
515 inline Entity System = Entity(16, 0, false, false, EntityKind::EK_Gen);
516 inline Entity DependsOn = Entity(17, 0, false, false, EntityKind::EK_Gen);
517 // Query variables
518 inline Entity Var0 = Entity(18, 0, false, false, EntityKind::EK_Gen);
519 inline Entity Var1 = Entity(19, 0, false, false, EntityKind::EK_Gen);
520 inline Entity Var2 = Entity(20, 0, false, false, EntityKind::EK_Gen);
521 inline Entity Var3 = Entity(21, 0, false, false, EntityKind::EK_Gen);
522 inline Entity Var4 = Entity(22, 0, false, false, EntityKind::EK_Gen);
523 inline Entity Var5 = Entity(23, 0, false, false, EntityKind::EK_Gen);
524 inline Entity Var6 = Entity(24, 0, false, false, EntityKind::EK_Gen);
525 inline Entity Var7 = Entity(25, 0, false, false, EntityKind::EK_Gen);
526
527 // Always has to match the last internal entity
528 inline Entity GAIA_ID(LastCoreComponent) = Var7;
529
530 //----------------------------------------------------------------------
531 // Helper functions
532 //----------------------------------------------------------------------
533
534 GAIA_NODISCARD inline bool is_wildcard(EntityId entityId) {
535 return entityId == All.id();
536 }
537
538 GAIA_NODISCARD inline bool is_wildcard(Entity entity) {
539 return entity.pair() && (is_wildcard(entity.id()) || is_wildcard(entity.gen()));
540 }
541
542 GAIA_NODISCARD inline bool is_wildcard(Pair pair) {
543 return pair.first() == All || pair.second() == All;
544 }
545
546 GAIA_NODISCARD inline bool is_variable(EntityId entityId) {
547 return entityId <= Var7.id() && entityId >= Var0.id();
548 }
549
550 GAIA_NODISCARD inline bool is_variable(Entity entity) {
551 return entity.id() <= Var7.id() && entity.id() >= Var0.id();
552 }
553
554 GAIA_NODISCARD inline bool is_variable(Pair pair) {
555 return is_variable(pair.first()) || is_variable(pair.second());
556 }
557
558 } // namespace ecs
559
560 namespace cnt {
561 template <>
562 struct to_sparse_id<ecs::Entity> {
563 static sparse_id get(const ecs::Entity& item) noexcept {
564 // Cut off the flags
565 return item.id();
566 }
567 };
568 } // namespace cnt
569} // namespace gaia
Wrapper for two Entities forming a relationship pair.
Definition id.h:395
Wrapper for two types forming a relationship pair. Depending on what types are used to form a pair it...
Definition id.h:202
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition sparse_storage.h:31
Definition utility.h:527
Definition utility.h:522
Definition id.h:468
Definition id.h:469
Definition id.h:466
Definition id.h:470
IdentifierData soa
Component is SoA.
Definition id.h:37
IdentifierData alig
Component alignment.
Definition id.h:41
IdentifierData size
Component size.
Definition id.h:39
uint32_t id
Index in the entity array.
Definition id.h:35
IdentifierData unused
Unused part.
Definition id.h:43
Definition id.h:25
Definition id.h:457
Definition id.h:463
Definition id.h:474
Component used to describe the entity name.
Definition id.h:384
Hashmap lookup structure used for Entity.
Definition id.h:336
EntityId id
Index in the entity array.
Definition id.h:230
IdentifierData tmp
0-real entity, 1-temporary entity
Definition id.h:247
IdentifierData kind
0-EntityKind::CT_Gen, 1-EntityKind::CT_Uni
Definition id.h:245
IdentifierData gen
Generation index. Incremented every time an entity is deleted.
Definition id.h:239
IdentifierData pair
0-ordinary, 1-pair
Definition id.h:243
IdentifierData ent
0-component, 1-entity
Definition id.h:241
Definition id.h:225
Entity(EntityId id, IdentifierData gen) noexcept
Special constructor for cnt::ilist.
Definition id.h:267
constexpr Entity(T value) noexcept
We need the entity to be braces-constructible and at the same type prevent it from getting constructe...
Definition id.h:264
Definition id.h:464
Definition id.h:467
Definition id.h:471
Definition id.h:461
Definition id.h:460
Definition id.h:462
Definition id.h:465
Definition id.h:472
Definition id.h:477
Definition id.h:478
Definition id.h:479
Definition id.h:480
Definition id.h:481
Definition id.h:482
Definition id.h:483
Definition id.h:484
Type TypeFull
Same as Type.
Definition id.h:147
T TypeOriginal
Original template type.
Definition id.h:149
core::raw_t< T > Type
Raw type with no additional sugar.
Definition id.h:145
static constexpr EntityKind Kind
Component kind.
Definition id.h:142
static constexpr EntityKind Kind
Component kind.
Definition id.h:155
std::conditional_t< Kind==EntityKind::EK_Gen, Type, uni< Type > > TypeFull
T or uni<T> depending on entity kind specified.
Definition id.h:160
typename T::TType Type
Raw type with no additional sugar.
Definition id.h:158
typename T::TTypeOriginal TypeOriginal
Original template type.
Definition id.h:162
Definition id.h:191
Definition id.h:217
Definition id.h:113
static constexpr EntityKind Kind
Component kind.
Definition id.h:123
T TTypeOriginal
Original template type.
Definition id.h:130
T TType
Raw type with no additional sugar.
Definition id.h:126