Gaia-ECS v1.0.0
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/observer_event.h"
9#include "gaia/ecs/query.h"
10#include "gaia/util/move_func.h"
11
12#if GAIA_OBSERVERS_ENABLED
13namespace gaia {
14 namespace ecs {
15 class World;
16 class Archetype;
17
18 #if GAIA_PROFILER_CPU
19 inline constexpr const char* sc_observer_query_func_str = "Observer_exec";
20 util::str_view entity_name(const World& world, Entity entity);
21 #endif
22
25 struct ObserverContext {
26 World* world;
27 Entity entity;
28 ObserverEvent event;
29 Archetype* archetype; // Current archetype
30 Archetype* archetype_prev; // Previous archetype (for OnAdd/OnDel)
31 uint32_t index_in_chunk;
32 Chunk* chunk;
33 const void* old_ptr; // Previous component value (OnSet only)
34 };
35
37 struct ObserverPlan {
38 enum class ExecKind : uint8_t { DirectQuery, DirectFast, DiffLocal, DiffPropagated, DiffFallback };
39 enum class FastPath : uint8_t { None, SinglePositiveTerm, SingleNegativeTerm, Disabled };
40 using TObserverIterFunc = util::MoveFunc<void(Iter&)>;
41
42 struct DiffPlan {
43 enum class DispatchKind : uint8_t { LocalTargets, PropagatedTraversal, GlobalFallback };
44
46 Entity bindingVar = EntityBad;
48 Entity bindingRelation = EntityBad;
50 Entity traversalRelation = EntityBad;
51
53 DispatchKind dispatchKind = DispatchKind::LocalTargets;
55 QueryTravKind travKind = QueryTravKind::None;
57 bool enabled = false;
59 uint8_t travDepth = QueryTermOptions::TravDepthUnlimited;
61 QueryEntityArray traversalTriggerTerms{};
63 uint8_t traversalTriggerTermCount = 0;
65 QueryEntityArray traversalRelations{};
67 uint8_t traversalRelationCount = 0;
68 };
69
71 FastPath fastPath = FastPath::None;
73 uint8_t termCount = 0;
75 bool hasNegativeTerm = false;
77 bool monitorsQuery = false;
79 ExecKind execKind = ExecKind::DirectQuery;
81 DiffPlan diff;
82
83 void refresh_exec_kind() {
84 if (monitorsQuery || diff.enabled) {
85 switch (diff.dispatchKind) {
86 case DiffPlan::DispatchKind::LocalTargets:
87 execKind = ExecKind::DiffLocal;
88 break;
89 case DiffPlan::DispatchKind::PropagatedTraversal:
90 execKind = ExecKind::DiffPropagated;
91 break;
92 case DiffPlan::DispatchKind::GlobalFallback:
93 execKind = ExecKind::DiffFallback;
94 break;
95 }
96 } else if (fastPath == FastPath::SinglePositiveTerm || fastPath == FastPath::SingleNegativeTerm)
97 execKind = ExecKind::DirectFast;
98 else
99 execKind = ExecKind::DirectQuery;
100 }
101
102 GAIA_NODISCARD ExecKind exec_kind() const {
103 return execKind;
104 }
105
106 GAIA_NODISCARD bool uses_diff_dispatch() const {
107 switch (exec_kind()) {
108 case ExecKind::DiffLocal:
109 case ExecKind::DiffPropagated:
110 case ExecKind::DiffFallback:
111 return true;
112 case ExecKind::DirectQuery:
113 case ExecKind::DirectFast:
114 return false;
115 }
116
117 return false;
118 }
119
120 GAIA_NODISCARD bool uses_direct_dispatch() const {
121 return !uses_diff_dispatch();
122 }
123
124 GAIA_NODISCARD bool uses_local_diff_targets() const {
125 return exec_kind() == ExecKind::DiffLocal;
126 }
127
128 GAIA_NODISCARD bool uses_propagated_diff_targets() const {
129 return exec_kind() == ExecKind::DiffPropagated;
130 }
131
132 GAIA_NODISCARD bool uses_fallback_diff_dispatch() const {
133 return exec_kind() == ExecKind::DiffFallback;
134 }
135
136 GAIA_NODISCARD bool is_fast_positive() const {
137 return fastPath == FastPath::SinglePositiveTerm;
138 }
139
140 GAIA_NODISCARD bool is_fast_negative() const {
141 return fastPath == FastPath::SingleNegativeTerm;
142 }
143
147 void add_term_desc(QueryOpKind op, bool allowFastPath) {
148 ++termCount;
149 hasNegativeTerm |= op == QueryOpKind::Not;
150
151 if (!allowFastPath) {
152 fastPath = FastPath::Disabled;
153 return;
154 }
155
156 if (fastPath == FastPath::Disabled)
157 return;
158
159 if (termCount != 1) {
160 fastPath = FastPath::Disabled;
161 return;
162 }
163
164 switch (op) {
165 case QueryOpKind::All:
166 case QueryOpKind::Any:
167 case QueryOpKind::Or:
168 fastPath = FastPath::SinglePositiveTerm;
169 break;
170 case QueryOpKind::Not:
171 fastPath = FastPath::SingleNegativeTerm;
172 break;
173 default:
174 fastPath = FastPath::Disabled;
175 break;
176 }
177
178 refresh_exec_kind();
179 }
180 };
181
183 struct ObserverRuntimeData {
184 using TObserverIterFunc = util::MoveFunc<void(Iter&)>;
185
186 ObserverRuntimeData() {
187 GAIA_FOR(MAX_ITEMS_IN_QUERY) {
188 queryTermIds[i] = EntityBad;
189 }
190 }
191
193 Entity entity = EntityBad;
195 TObserverIterFunc on_each_func;
197 Query query;
199 ObserverPlan plan;
201 QueryEntityArray queryTermIds{};
203 QueryOpKind queryTermOps[MAX_ITEMS_IN_QUERY]{};
205 QueryMatchKind queryTermMatchKinds[MAX_ITEMS_IN_QUERY]{};
207 uint64_t lastMatchStamp = 0;
208
213 void exec(Iter& iter, EntitySpan targets, ObserverEvent reportedEvent);
214 };
215
217 struct Observer_ {
219 Entity entity = EntityBad;
221 ObserverEvent event = ObserverEvent::OnAdd;
223 bool monitorsQuery = false;
224
226 template <typename Serializer>
227 void save(Serializer& s) const {
228 (void)s;
229 }
231 template <typename Serializer>
232 void load(Serializer& s) {
233 (void)s;
234 }
235 };
236
237 } // namespace ecs
238} // namespace gaia
239#else
240namespace gaia {
241 namespace ecs {
242 struct Observer_ {};
243 } // namespace ecs
244} // namespace gaia
245#endif
void load(Reader &reader, T &data)
Read data using Reader at compile-time.
Definition ser_ct.h:112
void save(Writer &writer, const T &data)
Write data using Writer at compile-time.
Definition ser_ct.h:101
Definition observer.h:242