Gaia-ECS v1.0.0
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
35 System_() = default;
36
41 ~System_() {
42 // If the query contains a job handle we can only
43 // destroy the query once the task associated with the handle is finished.
44 if (jobHandle != (mt::JobHandle)mt::JobNull_t{}) {
45 auto& tp = mt::ThreadPool::get();
46 tp.wait(jobHandle);
47 // Job handles created by queries are MANUAL_DELETE so delete it explicitly.
48 tp.del(jobHandle);
49 }
50 }
51
59 void exec(World& world) {
60 [[maybe_unused]] auto& queryInfo = query.fetch();
61
62 #if GAIA_PROFILER_CPU
63 const auto name = entity_name(*queryInfo.world(), entity);
64 const char* pScopeName = !name.empty() ? name.data() : sc_system_query_func_str;
65 GAIA_PROF_SCOPE2(pScopeName);
66 #endif
67
68 auto* pRuntime = world.systems().data_try(entity);
69 GAIA_ASSERT(pRuntime != nullptr);
70 if (pRuntime == nullptr || !pRuntime->on_each_func)
71 return;
72
73 static_cast<void>(pRuntime->on_each_func(query, execType, SystemRuntimeData::RunMode::Immediate));
74 }
75
83 GAIA_NODISCARD mt::JobHandle job_handle(World& world) {
84 if (jobHandle == (mt::JobHandle)mt::JobNull_t{}) {
85 auto& tp = mt::ThreadPool::get();
86 auto func = [this, &world]() {
87 exec(world);
88 };
89 static_assert(mt::JobFunc::stores_inline<decltype(func)>(), "System jobs must not allocate");
90
91 mt::Job syncJob;
92 syncJob.func = GAIA_MOV(func);
93 syncJob.flags = mt::JobCreationFlags::ManualDelete;
94 jobHandle = tp.add(GAIA_MOV(syncJob));
95 }
96 return jobHandle;
97 }
98
108 GAIA_NODISCARD SchedJob job(World& world) {
109 auto* pRuntime = world.systems().data_try(entity);
110 GAIA_ASSERT(pRuntime != nullptr);
111 if (pRuntime == nullptr || !pRuntime->on_each_func)
112 return {};
113
114 return pRuntime->on_each_func(query, execType, SystemRuntimeData::RunMode::DeferredJob);
115 }
116
120 template <typename Serializer>
121 void save(Serializer& s) const {
122 (void)s;
123 }
127 template <typename Serializer>
128 void load(Serializer& s) {
129 (void)s;
130 }
131 };
132
140 class SystemBuilder {
141 World& m_world;
142 Entity m_entity;
143
147 void validate() const {
148 GAIA_ASSERT(m_world.valid(m_entity));
149 }
150
153 System_& data() {
154 auto ss = m_world.acc_mut(m_entity);
155 auto& sys = ss.smut<System_>();
156 return sys;
157 }
158
161 const System_& data() const {
162 auto ss = m_world.acc(m_entity);
163 const auto& sys = ss.get<System_>();
164 return sys;
165 }
166
169 SystemRuntimeData& runtime_data() {
170 return m_world.systems().data(m_entity);
171 }
172
175 const SystemRuntimeData& runtime_data() const {
176 return m_world.systems().data(m_entity);
177 }
178
179 public:
183 SystemBuilder(World& world, Entity entity): m_world(world), m_entity(entity) {}
184
185 //------------------------------------------------
186
189
194 SystemBuilder& kind(QueryCacheKind kind) {
195 validate();
196 data().query.kind(kind);
197 return *this;
198 }
199
204 SystemBuilder& scope(QueryCacheScope scope) {
205 validate();
206 data().query.scope(scope);
207 return *this;
208 }
210
211 //------------------------------------------------
212
215
220 SystemBuilder& add(QueryInput item) {
221 validate();
222 data().query.add(item);
223 return *this;
224 }
225
226 //------------------------------------------------
227
232 SystemBuilder& is(Entity entity, const QueryTermOptions& options = {}) {
233 return all(Pair(Is, entity), options);
234 }
235
236 //------------------------------------------------
237
242 SystemBuilder& in(Entity entity, QueryTermOptions options = {}) {
243 options.in();
244 return all(Pair(Is, entity), options);
245 }
246
247 //------------------------------------------------
248
253 SystemBuilder& all(Entity entity, const QueryTermOptions& options = {}) {
254 validate();
255 data().query.all(entity, options);
256 return *this;
257 }
258
263 SystemBuilder& any(Entity entity, const QueryTermOptions& options = {}) {
264 validate();
265 data().query.any(entity, options);
266 return *this;
267 }
268
273 SystemBuilder& or_(Entity entity, const QueryTermOptions& options = {}) {
274 validate();
275 data().query.or_(entity, options);
276 return *this;
277 }
278
283 SystemBuilder& no(Entity entity, const QueryTermOptions& options = {}) {
284 validate();
285 data().query.no(entity, options);
286 return *this;
287 }
288
291 SystemBuilder& match_prefab() {
292 validate();
293 data().query.match_prefab();
294 return *this;
295 }
296
300 SystemBuilder& changed(Entity entity) {
301 validate();
302 data().query.changed(entity);
303 return *this;
304 }
305
310 template <typename T>
311 SystemBuilder& all(const QueryTermOptions& options);
312
317 template <typename T>
318 SystemBuilder& any(const QueryTermOptions& options);
319
324 template <typename T>
325 SystemBuilder& or_(const QueryTermOptions& options);
326
331 template <typename T>
332 SystemBuilder& no(const QueryTermOptions& options);
333
334 //------------------------------------------------
335
339 template <typename T>
340 SystemBuilder& all();
341
345 template <typename T>
346 SystemBuilder& any();
347
351 template <typename T>
352 SystemBuilder& or_();
353
357 template <typename T>
358 SystemBuilder& no();
359
363 template <typename T>
364 SystemBuilder& changed();
366
367 //------------------------------------------------
368
371
376 SystemBuilder& depth_order(Entity relation = ChildOf) {
377 data().query.depth_order(relation);
378 return *this;
379 }
380
384 template <typename Rel>
385 SystemBuilder& depth_order();
386
387 //------------------------------------------------
388
394 SystemBuilder& group_by(Entity entity, TGroupByFunc func = group_by_func_default) {
395 data().query.group_by(entity, func);
396 return *this;
397 }
398
403 template <typename T>
404 SystemBuilder& group_by(TGroupByFunc func = group_by_func_default);
405
411 template <typename Rel, typename Tgt>
412 SystemBuilder& group_by(TGroupByFunc func = group_by_func_default);
413
414 //------------------------------------------------
415
420 SystemBuilder& group_dep(Entity relation) {
421 data().query.group_dep(relation);
422 return *this;
423 }
424
429 template <typename Rel>
430 SystemBuilder& group_dep();
431
432 //------------------------------------------------
433
437 SystemBuilder& group_id(GroupId groupId) {
438 data().query.group_id(groupId);
439 return *this;
440 }
441
445 SystemBuilder& group_id(Entity entity) {
446 GAIA_ASSERT(!entity.pair());
447 data().query.group_id(entity.id());
448 return *this;
449 }
450
454 template <typename T>
455 SystemBuilder& group_id();
457
458 //------------------------------------------------
459
462
467 SystemBuilder& name(const char* name, uint32_t len = 0) {
468 m_world.name(m_entity, name, len);
469 return *this;
470 }
471
476 SystemBuilder& name_raw(const char* name, uint32_t len = 0) {
477 m_world.name_raw(m_entity, name, len);
478 return *this;
479 }
480
496 SystemBuilder& phase(Entity phaseEntity) {
497 validate();
498 GAIA_ASSERT(m_world.valid(phaseEntity));
499 GAIA_ASSERT(!phaseEntity.pair());
500 m_world.add(m_entity, {ChildOf, phaseEntity});
501 m_world.add(m_entity, {DependsOn, phaseEntity});
502 return *this;
503 }
505
506 //------------------------------------------------
507
510
514 SystemBuilder& mode(QueryExecType type) {
515 auto& ctx = data();
516 ctx.execType = type;
517 return *this;
518 }
519
525
537 SystemBuilder& ctx(void* pCtx) {
538 validate();
539 data().query.ctx(pCtx);
540 return *this;
541 }
542
545 GAIA_NODISCARD void* ctx() const {
546 validate();
547 return data().query.ctx();
548 }
550
557 SystemBuilder& main_thread(bool required = true) {
558 validate();
559 data().query.main_thread(required);
560 return *this;
561 }
563
569 SystemBuilder& no_access() {
570 validate();
571 data().query.no_access();
572 return *this;
573 }
574
580 SystemBuilder& reads(Entity entity) {
581 validate();
582 data().query.reads(entity);
583 return *this;
584 }
585
590 template <typename T>
591 SystemBuilder& reads() {
592 validate();
593 data().query.template reads<T>();
594 return *this;
595 }
596
602 SystemBuilder& writes(Entity entity) {
603 validate();
604 data().query.writes(entity);
605 return *this;
606 }
607
612 template <typename T>
613 SystemBuilder& writes() {
614 validate();
615 data().query.template writes<T>();
616 return *this;
617 }
619
625 template <typename Func, std::enable_if_t<detail::is_query_iter_callback_v<Func>, int> = 0>
626 SystemBuilder& on_each(Func func) {
627 validate();
628
629 auto& runtime = runtime_data();
630 runtime.on_each_func = [func](Query& query, QueryExecType execType, SystemRuntimeData::RunMode mode) mutable {
631 if (mode == SystemRuntimeData::RunMode::DeferredJob)
632 return query.job(func, execType);
633
634 query.each_runtime_erased(
635 execType, static_cast<void*>(&func), &detail::QueryImpl::template invoke_runtime_iter<Func, Iter>,
636 Constraints::EnabledOnly);
637 return SchedJob{};
638 };
639
640 return (SystemBuilder&)*this;
641 }
642
649 template <typename Func, std::enable_if_t<!detail::is_query_iter_callback_v<Func>, int> = 0>
650 SystemBuilder& on_each(Func func);
651
654 GAIA_NODISCARD Entity entity() const {
655 return m_entity;
656 }
657
661 void exec() {
662 auto& ctx = data();
663 ctx.exec(m_world);
664 }
665
674 GAIA_NODISCARD SchedJob job() {
675 auto& ctx = data();
676 return ctx.job(m_world);
677 }
678
681 GAIA_NODISCARD mt::JobHandle job_handle() {
682 auto& ctx = data();
683 return ctx.job_handle(m_world);
684 }
686 };
687
688 } // namespace ecs
689} // namespace gaia
690
691 #include "gaia/ecs/system_typed.inl"
692#else
693namespace gaia {
694 namespace ecs {
695 struct System_ {};
696 } // namespace ecs
697} // namespace gaia
698#endif
static ThreadPool & get()
Returns the process-wide thread-pool instance.
Definition threadpool.h:168
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 system.inl:695