Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
observer.h
1#pragma once
2
3#include "gaia/config/config.h"
4
5#include <cinttypes>
6
7#include "gaia/ecs/id.h"
8#include "gaia/ecs/query.h"
9#include "gaia/util/move_func.h"
10
11#if GAIA_OBSERVERS_ENABLED
12namespace gaia {
13 namespace ecs {
14 class World;
15 class Archetype;
16
17 #if GAIA_PROFILER_CPU
18 inline constexpr const char* sc_observer_query_func_str = "Observer_exec";
19 util::str_view entity_name(const World& world, Entity entity);
20 #endif
21
30 enum class ObserverEvent : uint8_t {
31 OnAdd, // Entity enters matching archetype
32 OnDel, // Entity leaves matching archetype
33 OnSet, // Component value changed on an already present component
34 };
35
38 struct ObserverContext {
39 World* world;
40 Entity entity;
41 ObserverEvent event;
42 Archetype* archetype; // Current archetype
43 Archetype* archetype_prev; // Previous archetype (for OnAdd/OnDel)
44 uint32_t index_in_chunk;
45 Chunk* chunk;
46 const void* old_ptr; // Previous component value (OnSet only)
47 };
48
50 struct ObserverPlan {
51 enum class ExecKind : uint8_t { DirectQuery, DirectFast, DiffLocal, DiffPropagated, DiffFallback };
52 enum class FastPath : uint8_t { None, SinglePositiveTerm, SingleNegativeTerm, Disabled };
53 using TObserverIterFunc = util::MoveFunc<void(Iter&)>;
54
55 struct DiffPlan {
56 enum class DispatchKind : uint8_t { LocalTargets, PropagatedTraversal, GlobalFallback };
57
59 Entity bindingVar = EntityBad;
61 Entity bindingRelation = EntityBad;
63 Entity traversalRelation = EntityBad;
64
66 DispatchKind dispatchKind = DispatchKind::LocalTargets;
68 QueryTravKind travKind = QueryTravKind::None;
70 bool enabled = false;
72 uint8_t travDepth = QueryTermOptions::TravDepthUnlimited;
74 QueryEntityArray traversalTriggerTerms{};
76 uint8_t traversalTriggerTermCount = 0;
78 QueryEntityArray traversalRelations{};
80 uint8_t traversalRelationCount = 0;
81 };
82
84 FastPath fastPath = FastPath::None;
86 uint8_t termCount = 0;
88 ExecKind execKind = ExecKind::DirectQuery;
90 DiffPlan diff;
91
92 void refresh_exec_kind() {
93 if (diff.enabled) {
94 switch (diff.dispatchKind) {
95 case DiffPlan::DispatchKind::LocalTargets:
96 execKind = ExecKind::DiffLocal;
97 break;
98 case DiffPlan::DispatchKind::PropagatedTraversal:
99 execKind = ExecKind::DiffPropagated;
100 break;
101 case DiffPlan::DispatchKind::GlobalFallback:
102 execKind = ExecKind::DiffFallback;
103 break;
104 }
105 } else if (fastPath == FastPath::SinglePositiveTerm || fastPath == FastPath::SingleNegativeTerm)
106 execKind = ExecKind::DirectFast;
107 else
108 execKind = ExecKind::DirectQuery;
109 }
110
111 GAIA_NODISCARD ExecKind exec_kind() const {
112 return execKind;
113 }
114
115 GAIA_NODISCARD bool uses_diff_dispatch() const {
116 switch (exec_kind()) {
117 case ExecKind::DiffLocal:
118 case ExecKind::DiffPropagated:
119 case ExecKind::DiffFallback:
120 return true;
121 case ExecKind::DirectQuery:
122 case ExecKind::DirectFast:
123 return false;
124 }
125
126 return false;
127 }
128
129 GAIA_NODISCARD bool uses_direct_dispatch() const {
130 return !uses_diff_dispatch();
131 }
132
133 GAIA_NODISCARD bool uses_local_diff_targets() const {
134 return exec_kind() == ExecKind::DiffLocal;
135 }
136
137 GAIA_NODISCARD bool uses_propagated_diff_targets() const {
138 return exec_kind() == ExecKind::DiffPropagated;
139 }
140
141 GAIA_NODISCARD bool uses_fallback_diff_dispatch() const {
142 return exec_kind() == ExecKind::DiffFallback;
143 }
144
145 GAIA_NODISCARD bool is_fast_positive() const {
146 return fastPath == FastPath::SinglePositiveTerm;
147 }
148
149 GAIA_NODISCARD bool is_fast_negative() const {
150 return fastPath == FastPath::SingleNegativeTerm;
151 }
152
153 void add_term_descriptor(QueryOpKind op, bool allowFastPath) {
154 ++termCount;
155
156 if (!allowFastPath) {
157 fastPath = FastPath::Disabled;
158 return;
159 }
160
161 if (fastPath == FastPath::Disabled)
162 return;
163
164 if (termCount != 1) {
165 fastPath = FastPath::Disabled;
166 return;
167 }
168
169 switch (op) {
170 case QueryOpKind::All:
171 case QueryOpKind::Any:
172 case QueryOpKind::Or:
173 fastPath = FastPath::SinglePositiveTerm;
174 break;
175 case QueryOpKind::Not:
176 fastPath = FastPath::SingleNegativeTerm;
177 break;
178 default:
179 fastPath = FastPath::Disabled;
180 break;
181 }
182
183 refresh_exec_kind();
184 }
185 };
186
188 struct ObserverRuntimeData {
189 using TObserverIterFunc = util::MoveFunc<void(Iter&)>;
190
191 ObserverRuntimeData() {
192 GAIA_FOR(MAX_ITEMS_IN_QUERY) {
193 queryTermIds[i] = EntityBad;
194 }
195 }
196
198 Entity entity = EntityBad;
200 TObserverIterFunc on_each_func;
202 Query query;
204 ObserverPlan plan;
206 QueryEntityArray queryTermIds{};
208 uint64_t lastMatchStamp = 0;
209
210 void exec(Iter& iter, EntitySpan targets);
211 };
212
214 struct Observer_ {
216 Entity entity = EntityBad;
218 ObserverEvent event = ObserverEvent::OnAdd;
219
221 template <typename Serializer>
222 void save(Serializer& s) const {
223 (void)s;
224 }
226 template <typename Serializer>
227 void load(Serializer& s) {
228 (void)s;
229 }
230 };
231
232 } // namespace ecs
233} // namespace gaia
234#else
235namespace gaia {
236 namespace ecs {
237 struct Observer_ {};
238 } // namespace ecs
239} // namespace gaia
240#endif
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition observer.h:237