Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
system.inl
1#include "gaia/config/config.h"
2
3#include <cinttypes>
4// TODO: Currently necessary due to std::function. Replace them!
5#include <functional>
6
7#include "gaia/ecs/chunk_iterator.h"
8#include "gaia/ecs/id.h"
9#include "gaia/ecs/query.h"
10#include "gaia/mt/jobhandle.h"
11
12#if GAIA_SYSTEMS_ENABLED
13namespace gaia {
14 namespace ecs {
15
16 #if GAIA_PROFILER_CPU
17 inline constexpr const char* sc_system_query_func_str = "System_exec";
18 util::str_view entity_name(const World& world, Entity entity);
19 #endif
20
21 struct System_ {
22 using TSystemExecFunc = std::function<void(Query&, QueryExecType)>;
23
25 Entity entity = EntityBad;
27 TSystemExecFunc on_each_func;
29 Query query;
31 QueryExecType execType = QueryExecType::Default;
33 mt::JobHandle jobHandle = mt::JobNull;
34
35 System_() = default;
36
37 ~System_() {
38 // If the query contains a job handle we can only
39 // destroy the query once the task associated with the handle is finished.
40 if (jobHandle != (mt::JobHandle)mt::JobNull_t{}) {
41 auto& tp = mt::ThreadPool::get();
42 tp.wait(jobHandle);
43 // Job handles created by queries are MANUAL_DELETE so delete it explicitly.
44 tp.del(jobHandle);
45 }
46 }
47
48 void exec() {
49 [[maybe_unused]] auto& queryInfo = query.fetch();
50
51 #if GAIA_PROFILER_CPU
52 const auto name = entity_name(*queryInfo.world(), entity);
53 const char* pScopeName = !name.empty() ? name.data() : sc_system_query_func_str;
54 GAIA_PROF_SCOPE2(pScopeName);
55 #endif
56
57 on_each_func(query, execType);
58 }
59
61 GAIA_NODISCARD mt::JobHandle job_handle() {
62 if (jobHandle == (mt::JobHandle)mt::JobNull_t{}) {
63 auto& tp = mt::ThreadPool::get();
64 mt::Job syncJob;
65 syncJob.func = [&]() {
66 exec();
67 };
68 syncJob.flags = mt::JobCreationFlags::ManualDelete;
69 jobHandle = tp.add(syncJob);
70 }
71 return jobHandle;
72 }
73
75 template <typename Serializer>
76 void save(Serializer& s) const {
77 (void)s;
78 }
80 template <typename Serializer>
81 void load(Serializer& s) {
82 (void)s;
83 }
84 };
85
86 class SystemBuilder {
87 World& m_world;
88 Entity m_entity;
89
90 void validate() {
91 GAIA_ASSERT(m_world.valid(m_entity));
92 }
93
94 System_& data() {
95 auto ss = m_world.acc_mut(m_entity);
96 auto& sys = ss.smut<System_>();
97 return sys;
98 }
99
100 const System_& data() const {
101 auto ss = m_world.acc(m_entity);
102 const auto& sys = ss.get<System_>();
103 return sys;
104 }
105
106 public:
107 SystemBuilder(World& world, Entity entity): m_world(world), m_entity(entity) {}
108
109 //------------------------------------------------
110
114 SystemBuilder& kind(QueryCacheKind kind) {
115 validate();
116 data().query.kind(kind);
117 return *this;
118 }
119
123 SystemBuilder& scope(QueryCacheScope scope) {
124 validate();
125 data().query.scope(scope);
126 return *this;
127 }
128
129 //------------------------------------------------
130
131 SystemBuilder& add(QueryInput item) {
132 validate();
133 data().query.add(item);
134 return *this;
135 }
136
137 //------------------------------------------------
138
139 SystemBuilder& is(Entity entity, const QueryTermOptions& options = {}) {
140 return all(Pair(Is, entity), options);
141 }
142
143 //------------------------------------------------
144
145 SystemBuilder& in(Entity entity, QueryTermOptions options = {}) {
146 options.in();
147 return all(Pair(Is, entity), options);
148 }
149
150 //------------------------------------------------
151
152 SystemBuilder& all(Entity entity, const QueryTermOptions& options = {}) {
153 validate();
154 data().query.all(entity, options);
155 return *this;
156 }
157
158 SystemBuilder& any(Entity entity, const QueryTermOptions& options = {}) {
159 validate();
160 data().query.any(entity, options);
161 return *this;
162 }
163
164 SystemBuilder& or_(Entity entity, const QueryTermOptions& options = {}) {
165 validate();
166 data().query.or_(entity, options);
167 return *this;
168 }
169
170 SystemBuilder& no(Entity entity, const QueryTermOptions& options = {}) {
171 validate();
172 data().query.no(entity, options);
173 return *this;
174 }
175
176 SystemBuilder& match_prefab() {
177 validate();
178 data().query.match_prefab();
179 return *this;
180 }
181
182 SystemBuilder& changed(Entity entity) {
183 validate();
184 data().query.changed(entity);
185 return *this;
186 }
187
188 template <typename T>
189 SystemBuilder& all(const QueryTermOptions& options) {
190 validate();
191 data().query.template all<T>(options);
192 return *this;
193 }
194
195 template <typename T>
196 SystemBuilder& any(const QueryTermOptions& options) {
197 validate();
198 data().query.template any<T>(options);
199 return *this;
200 }
201
202 template <typename T>
203 SystemBuilder& or_(const QueryTermOptions& options) {
204 validate();
205 data().query.template or_<T>(options);
206 return *this;
207 }
208
209 template <typename T>
210 SystemBuilder& no(const QueryTermOptions& options) {
211 validate();
212 data().query.template no<T>(options);
213 return *this;
214 }
215
216 //------------------------------------------------
217
218 template <typename T>
219 SystemBuilder& all() {
220 validate();
221 data().query.all<T>();
222 return *this;
223 }
224
225 template <typename T>
226 SystemBuilder& any() {
227 validate();
228 data().query.any<T>();
229 return *this;
230 }
231
232 template <typename T>
233 SystemBuilder& or_() {
234 validate();
235 data().query.or_<T>();
236 return *this;
237 }
238
239 template <typename T>
240 SystemBuilder& no() {
241 validate();
242 data().query.no<T>();
243 return *this;
244 }
245
246 template <typename T>
247 SystemBuilder& changed() {
248 validate();
249 data().query.changed<T>();
250 return *this;
251 }
252
253 //------------------------------------------------
254
257 SystemBuilder& depth_order(Entity relation = ChildOf) {
258 data().query.depth_order(relation);
259 return *this;
260 }
261
264 template <typename Rel>
265 SystemBuilder& depth_order() {
266 data().query.template depth_order<Rel>();
267 return *this;
268 }
269
270 //------------------------------------------------
271
275 SystemBuilder& group_by(Entity entity, TGroupByFunc func = group_by_func_default) {
276 data().query.group_by(entity, func);
277 return *this;
278 }
279
283 template <typename T>
284 SystemBuilder& group_by(TGroupByFunc func = group_by_func_default) {
285 data().query.group_by<T>(func);
286 return *this;
287 }
288
293 template <typename Rel, typename Tgt>
294 SystemBuilder& group_by(TGroupByFunc func = group_by_func_default) {
295 data().query.group_by<Rel, Tgt>(func);
296 return *this;
297 }
298
299 //------------------------------------------------
300
304 SystemBuilder& group_dep(Entity relation) {
305 data().query.group_dep(relation);
306 return *this;
307 }
308
312 template <typename Rel>
313 SystemBuilder& group_dep() {
314 data().query.template group_dep<Rel>();
315 return *this;
316 }
317
318 //------------------------------------------------
319
322 SystemBuilder& group_id(GroupId groupId) {
323 data().query.group_id(groupId);
324 return *this;
325 }
326
329 SystemBuilder& group_id(Entity entity) {
330 GAIA_ASSERT(!entity.pair());
331 data().query.group_id(entity.id());
332 return *this;
333 }
334
337 template <typename T>
338 SystemBuilder& group_id() {
339 data().query.template group_id<T>();
340 return *this;
341 }
342
343 //------------------------------------------------
344
345 SystemBuilder& name(const char* name, uint32_t len = 0) {
346 m_world.name(m_entity, name, len);
347 return *this;
348 }
349
350 SystemBuilder& name_raw(const char* name, uint32_t len = 0) {
351 m_world.name_raw(m_entity, name, len);
352 return *this;
353 }
354
355 //------------------------------------------------
356
357 SystemBuilder& mode(QueryExecType type) {
358 auto& ctx = data();
359 ctx.execType = type;
360 return *this;
361 }
362
363 template <typename Func>
364 SystemBuilder& on_each(Func func) {
365 validate();
366
367 auto& ctx = data();
368 using InputArgs = decltype(core::func_args(&Func::operator()));
369
370 #if GAIA_ASSERT_ENABLED
371 // Make sure we only use components specified in the query.
372 // Constness is respected. Therefore, if a type is const when registered to query,
373 // it has to be const (or immutable) also in each().
374 if constexpr (
375 !std::is_invocable_v<Func, IterAll&> && //
376 !std::is_invocable_v<Func, Iter&> && //
377 !std::is_invocable_v<Func, IterDisabled&> //
378 ) {
379 auto& queryInfo = ctx.query.fetch();
380 GAIA_ASSERT(ctx.query.unpack_args_into_query_has_all(queryInfo, InputArgs{}));
381 }
382 #endif
383
384 ctx.on_each_func = [func](Query& query, QueryExecType execType) {
385 query.each(func, execType);
386 };
387
388 return (SystemBuilder&)*this;
389 }
390
391 GAIA_NODISCARD Entity entity() const {
392 return m_entity;
393 }
394
395 void exec() {
396 auto& ctx = data();
397 ctx.exec();
398 }
399
400 GAIA_NODISCARD mt::JobHandle job_handle() {
401 auto& ctx = data();
402 return ctx.job_handle();
403 }
404 };
405
406 } // namespace ecs
407} // namespace gaia
408
409#endif
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9