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// TODO: Currently necessary due to std::function. Replace them!
7#include <functional>
8
9#include "gaia/ecs/id.h"
10#include "gaia/ecs/query.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
31 enum class ObserverEvent : uint8_t {
32 OnAdd, // Entity enters matching archetype
33 OnDel, // Entity leaves matching archetype
34 OnSet, // Component value changed on an already present component
35 };
36
39 struct ObserverContext {
40 World* world;
41 Entity entity;
42 ObserverEvent event;
43 Archetype* archetype; // Current archetype
44 Archetype* archetype_prev; // Previous archetype (for OnAdd/OnDel)
45 uint32_t index_in_chunk;
46 Chunk* chunk;
47 const void* old_ptr; // Previous component value (OnSet only)
48 };
49
51 struct ObserverPlan {
52 enum class ExecKind : uint8_t { DirectQuery, DirectFast, DiffLocal, DiffPropagated, DiffFallback };
53 enum class FastPath : uint8_t { None, SinglePositiveTerm, SingleNegativeTerm, Disabled };
54 using TObserverIterFunc = std::function<void(Iter&)>;
55
56 struct DiffPlan {
57 enum class DispatchKind : uint8_t { LocalTargets, PropagatedTraversal, GlobalFallback };
58
60 Entity bindingVar = EntityBad;
62 Entity bindingRelation = EntityBad;
64 Entity traversalRelation = EntityBad;
65
67 DispatchKind dispatchKind = DispatchKind::LocalTargets;
69 QueryTravKind travKind = QueryTravKind::None;
71 bool enabled = false;
73 uint8_t travDepth = QueryTermOptions::TravDepthUnlimited;
75 QueryEntityArray traversalTriggerTerms{};
77 uint8_t traversalTriggerTermCount = 0;
79 QueryEntityArray traversalRelations{};
81 uint8_t traversalRelationCount = 0;
82 };
83
85 FastPath fastPath = FastPath::None;
87 uint8_t termCount = 0;
89 ExecKind execKind = ExecKind::DirectQuery;
91 DiffPlan diff;
92
93 void refresh_exec_kind() {
94 if (diff.enabled) {
95 switch (diff.dispatchKind) {
96 case DiffPlan::DispatchKind::LocalTargets:
97 execKind = ExecKind::DiffLocal;
98 break;
99 case DiffPlan::DispatchKind::PropagatedTraversal:
100 execKind = ExecKind::DiffPropagated;
101 break;
102 case DiffPlan::DispatchKind::GlobalFallback:
103 execKind = ExecKind::DiffFallback;
104 break;
105 }
106 } else if (fastPath == FastPath::SinglePositiveTerm || fastPath == FastPath::SingleNegativeTerm)
107 execKind = ExecKind::DirectFast;
108 else
109 execKind = ExecKind::DirectQuery;
110 }
111
112 GAIA_NODISCARD ExecKind exec_kind() const {
113 return execKind;
114 }
115
116 GAIA_NODISCARD bool uses_diff_dispatch() const {
117 switch (exec_kind()) {
118 case ExecKind::DiffLocal:
119 case ExecKind::DiffPropagated:
120 case ExecKind::DiffFallback:
121 return true;
122 case ExecKind::DirectQuery:
123 case ExecKind::DirectFast:
124 return false;
125 }
126
127 return false;
128 }
129
130 GAIA_NODISCARD bool uses_direct_dispatch() const {
131 return !uses_diff_dispatch();
132 }
133
134 GAIA_NODISCARD bool uses_local_diff_targets() const {
135 return exec_kind() == ExecKind::DiffLocal;
136 }
137
138 GAIA_NODISCARD bool uses_propagated_diff_targets() const {
139 return exec_kind() == ExecKind::DiffPropagated;
140 }
141
142 GAIA_NODISCARD bool uses_fallback_diff_dispatch() const {
143 return exec_kind() == ExecKind::DiffFallback;
144 }
145
146 GAIA_NODISCARD bool is_fast_positive() const {
147 return fastPath == FastPath::SinglePositiveTerm;
148 }
149
150 GAIA_NODISCARD bool is_fast_negative() const {
151 return fastPath == FastPath::SingleNegativeTerm;
152 }
153
154 void add_term_descriptor(QueryOpKind op, bool allowFastPath) {
155 ++termCount;
156
157 if (!allowFastPath) {
158 fastPath = FastPath::Disabled;
159 return;
160 }
161
162 if (fastPath == FastPath::Disabled)
163 return;
164
165 if (termCount != 1) {
166 fastPath = FastPath::Disabled;
167 return;
168 }
169
170 switch (op) {
171 case QueryOpKind::All:
172 case QueryOpKind::Any:
173 case QueryOpKind::Or:
174 fastPath = FastPath::SinglePositiveTerm;
175 break;
176 case QueryOpKind::Not:
177 fastPath = FastPath::SingleNegativeTerm;
178 break;
179 default:
180 fastPath = FastPath::Disabled;
181 break;
182 }
183
184 refresh_exec_kind();
185 }
186 };
187
189 struct ObserverRuntimeData {
190 using TObserverIterFunc = std::function<void(Iter&)>;
191
192 ObserverRuntimeData() {
193 GAIA_FOR(MAX_ITEMS_IN_QUERY) {
194 queryTermIds[i] = EntityBad;
195 }
196 }
197
199 Entity entity = EntityBad;
201 TObserverIterFunc on_each_func;
203 Query query;
205 ObserverPlan plan;
207 QueryEntityArray queryTermIds{};
209 uint64_t lastMatchStamp = 0;
210
211 void exec(Iter& iter, EntitySpan targets);
212 };
213
215 struct Observer_ {
217 Entity entity = EntityBad;
219 ObserverEvent event = ObserverEvent::OnAdd;
220
222 template <typename Serializer>
223 void save(Serializer& s) const {
224 (void)s;
225 }
227 template <typename Serializer>
228 void load(Serializer& s) {
229 (void)s;
230 }
231 };
232
233 } // namespace ecs
234} // namespace gaia
235#else
236namespace gaia {
237 namespace ecs {
238 struct Observer_ {};
239 } // namespace ecs
240} // namespace gaia
241#endif
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition observer.h:238