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
5#include "gaia/ecs/chunk_iterator.h"
6#include "gaia/ecs/id.h"
7#include "gaia/ecs/query.h"
8#include "gaia/mt/jobhandle.h"
9
10#if GAIA_SYSTEMS_ENABLED
11namespace gaia {
12 namespace ecs {
13
14 #if GAIA_PROFILER_CPU
15 inline constexpr const char* sc_system_query_func_str = "System_exec";
16 util::str_view entity_name(const World& world, Entity entity);
17 #endif
18
25 struct System_ {
27 Entity entity = EntityBad;
29 Query query;
31 QueryExecType execType = QueryExecType::Default;
33 mt::JobHandle jobHandle = mt::JobNull;
34
36 System_() = default;
37
42 ~System_() {
43 // If the query contains a job handle we can only
44 // destroy the query once the task associated with the handle is finished.
45 if (jobHandle != (mt::JobHandle)mt::JobNull_t{}) {
46 auto& tp = mt::ThreadPool::get();
47 tp.wait(jobHandle);
48 // Job handles created by queries are MANUAL_DELETE so delete it explicitly.
49 tp.del(jobHandle);
50 }
51 }
52
60 void exec(World& world) {
61 [[maybe_unused]] auto& queryInfo = query.fetch();
62
63 #if GAIA_PROFILER_CPU
64 const auto name = entity_name(*queryInfo.world(), entity);
65 const char* pScopeName = !name.empty() ? name.data() : sc_system_query_func_str;
66 GAIA_PROF_SCOPE2(pScopeName);
67 #endif
68
69 auto* pRuntime = world.systems().data_try(entity);
70 GAIA_ASSERT(pRuntime != nullptr);
71 if (pRuntime == nullptr || !pRuntime->on_each_func)
72 return;
73
74 static_cast<void>(pRuntime->on_each_func(query, execType, SystemRuntimeData::RunMode::Immediate));
75 }
76
84 GAIA_NODISCARD mt::JobHandle job_handle(World& world) {
85 if (jobHandle == (mt::JobHandle)mt::JobNull_t{}) {
86 auto& tp = mt::ThreadPool::get();
87 mt::Job syncJob;
88 syncJob.func = [this, &world]() {
89 exec(world);
90 };
91 syncJob.flags = mt::JobCreationFlags::ManualDelete;
92 jobHandle = tp.add(GAIA_MOV(syncJob));
93 }
94 return jobHandle;
95 }
96
106 GAIA_NODISCARD SchedJob job(World& world) {
107 auto* pRuntime = world.systems().data_try(entity);
108 GAIA_ASSERT(pRuntime != nullptr);
109 if (pRuntime == nullptr || !pRuntime->on_each_func)
110 return {};
111
112 return pRuntime->on_each_func(query, execType, SystemRuntimeData::RunMode::DeferredJob);
113 }
114
118 template <typename Serializer>
119 void save(Serializer& s) const {
120 (void)s;
121 }
125 template <typename Serializer>
126 void load(Serializer& s) {
127 (void)s;
128 }
129 };
130
138 class SystemBuilder {
139 World& m_world;
140 Entity m_entity;
141
145 void validate() const {
146 GAIA_ASSERT(m_world.valid(m_entity));
147 }
148
151 System_& data() {
152 auto ss = m_world.acc_mut(m_entity);
153 auto& sys = ss.smut<System_>();
154 return sys;
155 }
156
159 const System_& data() const {
160 auto ss = m_world.acc(m_entity);
161 const auto& sys = ss.get<System_>();
162 return sys;
163 }
164
167 SystemRuntimeData& runtime_data() {
168 return m_world.systems().data(m_entity);
169 }
170
173 const SystemRuntimeData& runtime_data() const {
174 return m_world.systems().data(m_entity);
175 }
176
177 public:
181 SystemBuilder(World& world, Entity entity): m_world(world), m_entity(entity) {}
182
183 //------------------------------------------------
184
187
192 SystemBuilder& kind(QueryCacheKind kind) {
193 validate();
194 data().query.kind(kind);
195 return *this;
196 }
197
202 SystemBuilder& scope(QueryCacheScope scope) {
203 validate();
204 data().query.scope(scope);
205 return *this;
206 }
208
209 //------------------------------------------------
210
213
218 SystemBuilder& add(QueryInput item) {
219 validate();
220 data().query.add(item);
221 return *this;
222 }
223
224 //------------------------------------------------
225
230 SystemBuilder& is(Entity entity, const QueryTermOptions& options = {}) {
231 return all(Pair(Is, entity), options);
232 }
233
234 //------------------------------------------------
235
240 SystemBuilder& in(Entity entity, QueryTermOptions options = {}) {
241 options.in();
242 return all(Pair(Is, entity), options);
243 }
244
245 //------------------------------------------------
246
251 SystemBuilder& all(Entity entity, const QueryTermOptions& options = {}) {
252 validate();
253 data().query.all(entity, options);
254 return *this;
255 }
256
261 SystemBuilder& any(Entity entity, const QueryTermOptions& options = {}) {
262 validate();
263 data().query.any(entity, options);
264 return *this;
265 }
266
271 SystemBuilder& or_(Entity entity, const QueryTermOptions& options = {}) {
272 validate();
273 data().query.or_(entity, options);
274 return *this;
275 }
276
281 SystemBuilder& no(Entity entity, const QueryTermOptions& options = {}) {
282 validate();
283 data().query.no(entity, options);
284 return *this;
285 }
286
289 SystemBuilder& match_prefab() {
290 validate();
291 data().query.match_prefab();
292 return *this;
293 }
294
298 SystemBuilder& changed(Entity entity) {
299 validate();
300 data().query.changed(entity);
301 return *this;
302 }
303
308 template <typename T>
309 SystemBuilder& all(const QueryTermOptions& options);
310
315 template <typename T>
316 SystemBuilder& any(const QueryTermOptions& options);
317
322 template <typename T>
323 SystemBuilder& or_(const QueryTermOptions& options);
324
329 template <typename T>
330 SystemBuilder& no(const QueryTermOptions& options);
331
332 //------------------------------------------------
333
337 template <typename T>
338 SystemBuilder& all();
339
343 template <typename T>
344 SystemBuilder& any();
345
349 template <typename T>
350 SystemBuilder& or_();
351
355 template <typename T>
356 SystemBuilder& no();
357
361 template <typename T>
362 SystemBuilder& changed();
364
365 //------------------------------------------------
366
369
374 SystemBuilder& depth_order(Entity relation = ChildOf) {
375 data().query.depth_order(relation);
376 return *this;
377 }
378
382 template <typename Rel>
383 SystemBuilder& depth_order();
384
385 //------------------------------------------------
386
392 SystemBuilder& group_by(Entity entity, TGroupByFunc func = group_by_func_default) {
393 data().query.group_by(entity, func);
394 return *this;
395 }
396
401 template <typename T>
402 SystemBuilder& group_by(TGroupByFunc func = group_by_func_default);
403
409 template <typename Rel, typename Tgt>
410 SystemBuilder& group_by(TGroupByFunc func = group_by_func_default);
411
412 //------------------------------------------------
413
418 SystemBuilder& group_dep(Entity relation) {
419 data().query.group_dep(relation);
420 return *this;
421 }
422
427 template <typename Rel>
428 SystemBuilder& group_dep();
429
430 //------------------------------------------------
431
435 SystemBuilder& group_id(GroupId groupId) {
436 data().query.group_id(groupId);
437 return *this;
438 }
439
443 SystemBuilder& group_id(Entity entity) {
444 GAIA_ASSERT(!entity.pair());
445 data().query.group_id(entity.id());
446 return *this;
447 }
448
452 template <typename T>
453 SystemBuilder& group_id();
455
456 //------------------------------------------------
457
460
465 SystemBuilder& name(const char* name, uint32_t len = 0) {
466 m_world.name(m_entity, name, len);
467 return *this;
468 }
469
474 SystemBuilder& name_raw(const char* name, uint32_t len = 0) {
475 m_world.name_raw(m_entity, name, len);
476 return *this;
477 }
478
493 SystemBuilder& phase(Entity phaseEntity) {
494 validate();
495 GAIA_ASSERT(m_world.valid(phaseEntity));
496 GAIA_ASSERT(!phaseEntity.pair());
497 m_world.add(m_entity, {ChildOf, phaseEntity});
498 m_world.add(m_entity, {DependsOn, phaseEntity});
499 return *this;
500 }
502
503 //------------------------------------------------
504
507
511 SystemBuilder& mode(QueryExecType type) {
512 auto& ctx = data();
513 ctx.execType = type;
514 return *this;
515 }
516
522
530 SystemBuilder& ctx(void* pCtx) {
531 validate();
532 data().query.ctx(pCtx);
533 return *this;
534 }
535
538 GAIA_NODISCARD void* ctx() const {
539 validate();
540 return data().query.ctx();
541 }
543
550 SystemBuilder& main_thread(bool required = true) {
551 validate();
552 data().query.main_thread(required);
553 return *this;
554 }
556
563 SystemBuilder& reads(Entity entity) {
564 validate();
565 data().query.reads(entity);
566 return *this;
567 }
568
573 template <typename T>
574 SystemBuilder& reads() {
575 validate();
576 data().query.template reads<T>();
577 return *this;
578 }
579
584 SystemBuilder& writes(Entity entity) {
585 validate();
586 data().query.writes(entity);
587 return *this;
588 }
589
594 template <typename T>
595 SystemBuilder& writes() {
596 validate();
597 data().query.template writes<T>();
598 return *this;
599 }
601
607 template <typename Func, std::enable_if_t<detail::is_query_iter_callback_v<Func>, int> = 0>
608 SystemBuilder& on_each(Func func) {
609 validate();
610
611 auto& runtime = runtime_data();
612 runtime.on_each_func = [func](Query& query, QueryExecType execType, SystemRuntimeData::RunMode mode) mutable {
613 if (mode == SystemRuntimeData::RunMode::DeferredJob)
614 return query.job(func, execType);
615
616 query.each_runtime_erased(
617 execType, static_cast<void*>(&func), &detail::QueryImpl::template invoke_runtime_iter<Func, Iter>,
618 Constraints::EnabledOnly);
619 return SchedJob{};
620 };
621
622 return (SystemBuilder&)*this;
623 }
624
631 template <typename Func, std::enable_if_t<!detail::is_query_iter_callback_v<Func>, int> = 0>
632 SystemBuilder& on_each(Func func);
633
636 GAIA_NODISCARD Entity entity() const {
637 return m_entity;
638 }
639
643 void exec() {
644 auto& ctx = data();
645 ctx.exec(m_world);
646 }
647
656 GAIA_NODISCARD SchedJob job() {
657 auto& ctx = data();
658 return ctx.job(m_world);
659 }
660
663 GAIA_NODISCARD mt::JobHandle job_handle() {
664 auto& ctx = data();
665 return ctx.job_handle(m_world);
666 }
668 };
669
670 } // namespace ecs
671} // namespace gaia
672
673 #include "gaia/ecs/system_typed.inl"
674
675#endif
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9