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#if !GAIA_SYSTEMS_ENABLED
4namespace gaia {
5 namespace ecs {
6 struct System_ {};
7 } // namespace ecs
8} // namespace gaia
9#else
10 #include <cinttypes>
11 // TODO: Currently necessary due to std::function. Replace them!
12 #include <functional>
13
14 #include "gaia/ecs/chunk_iterator.h"
15 #include "gaia/ecs/id.h"
16 #include "gaia/ecs/query.h"
17 #include "gaia/mt/jobhandle.h"
18
19namespace gaia {
20 namespace ecs {
21
22 #if GAIA_PROFILER_CPU
23 inline constexpr const char* sc_query_func_str = "System_exec";
24 const char* entity_name(const World& world, Entity entity);
25 #endif
26
27 struct System_ {
28 using TSystemIterFunc = std::function<void(Iter&)>;
29
31 Entity entity = EntityBad;
33 TSystemIterFunc on_each_func;
35 Query query;
37 QueryExecType execType = QueryExecType::Default;
39 mt::JobHandle jobHandle = mt::JobNull;
40
41 System_() = default;
42
43 ~System_() {
44 // If the query contains a job handle we can only
45 // destroy the query once the task associated with the handle is finished.
46 if (jobHandle != (mt::JobHandle)mt::JobNull_t{}) {
47 auto& tp = mt::ThreadPool::get();
48 tp.wait(jobHandle);
49 // Job handles created by queries are MANUAL_DELETE so delete it explicitly.
50 tp.del(jobHandle);
51 }
52 }
53
54 void exec() {
55 auto& queryInfo = query.fetch();
56
57 #if GAIA_PROFILER_CPU
58 const char* pName = entity_name(*queryInfo.world(), entity);
59 const char* pScopeName = pName != nullptr ? pName : sc_query_func_str;
60 GAIA_PROF_SCOPE2(pScopeName);
61 #endif
62
63 switch (execType) {
64 case QueryExecType::Parallel:
65 query.run_query_on_chunks<QueryExecType::Parallel, Iter>(queryInfo, on_each_func);
66 break;
67 case QueryExecType::ParallelPerf:
68 query.run_query_on_chunks<QueryExecType::ParallelPerf, Iter>(queryInfo, on_each_func);
69 break;
70 case QueryExecType::ParallelEff:
71 query.run_query_on_chunks<QueryExecType::ParallelEff, Iter>(queryInfo, on_each_func);
72 break;
73 default:
74 query.run_query_on_chunks<QueryExecType::Default, Iter>(queryInfo, on_each_func);
75 break;
76 }
77 }
78
80 GAIA_NODISCARD mt::JobHandle job_handle() {
81 if (jobHandle == (mt::JobHandle)mt::JobNull_t{}) {
82 auto& tp = mt::ThreadPool::get();
83 mt::Job syncJob;
84 syncJob.func = [&]() {
85 exec();
86 };
87 syncJob.flags = mt::JobCreationFlags::ManualDelete;
88 jobHandle = tp.add(syncJob);
89 }
90 return jobHandle;
91 }
92
94 template <typename Serializer>
95 void save(Serializer& s) const {
96 (void)s;
97 }
99 template <typename Serializer>
100 void load(Serializer& s) {
101 (void)s;
102 }
103 };
104
105 // Usage:
106 // auto s = w.system()
107 // .all<Position&, Velocity>()
108 // .any<Rotation>()
109 // .OnCreated([](ecs::Query& q) {
110 // })
111 // .OnStopped([](ecs::Query& q) {
112 // ...
113 // })
114 // .OnUpdate([](ecs::Query& q) {
115 // q.each([](Position& p, const Velocity& v) {
116 // ...
117 // });
118 // })
119 // .commit();
120 class SystemBuilder {
121 World& m_world;
122 Entity m_entity;
123
124 void validate() {
125 GAIA_ASSERT(m_world.valid(m_entity));
126 }
127
128 System_& data() {
129 auto ss = m_world.acc_mut(m_entity);
130 auto& sys = ss.smut<System_>();
131 return sys;
132 }
133
134 const System_& data() const {
135 auto ss = m_world.acc(m_entity);
136 const auto& sys = ss.get<System_>();
137 return sys;
138 }
139
140 public:
141 SystemBuilder(World& world, Entity entity): m_world(world), m_entity(entity) {}
142
143 //------------------------------------------------
144
145 SystemBuilder& add(QueryInput item) {
146 validate();
147 data().query.add(item);
148 return *this;
149 }
150
151 //------------------------------------------------
152
153 SystemBuilder& all(Entity entity, bool isReadWrite = false) {
154 validate();
155 data().query.all(entity, isReadWrite);
156 return *this;
157 }
158
159 SystemBuilder& all(Entity entity, Entity src, bool isReadWrite = false) {
160 validate();
161 data().query.all(entity, src, isReadWrite);
162 return *this;
163 }
164
165 SystemBuilder& any(Entity entity, bool isReadWrite = false) {
166 validate();
167 data().query.any(entity, isReadWrite);
168 return *this;
169 }
170
171 SystemBuilder& no(Entity entity) {
172 validate();
173 data().query.no(entity);
174 return *this;
175 }
176
177 SystemBuilder& changed(Entity entity) {
178 validate();
179 data().query.changed(entity);
180 return *this;
181 }
182
183 //------------------------------------------------
184
185 #if GAIA_USE_VARIADIC_API
186 template <typename... T>
187 SystemBuilder& all() {
188 validate();
189 data().query.all<T...>();
190 return *this;
191 }
192 template <typename... T>
193 SystemBuilder& any() {
194 validate();
195 data().query.any<T...>();
196 return *this;
197 }
198 template <typename... T>
199 SystemBuilder& no() {
200 validate();
201 data().query.no<T...>();
202 return *this;
203 }
204 template <typename... T>
205 SystemBuilder& changed() {
206 validate();
207 data().query.changed<T...>();
208 return *this;
209 }
210 #else
211 template <typename T>
212 SystemBuilder& all() {
213 validate();
214 data().query.all<T>();
215 return *this;
216 }
217 template <typename T>
218 SystemBuilder& any() {
219 validate();
220 data().query.any<T>();
221 return *this;
222 }
223 template <typename T>
224 SystemBuilder& no() {
225 validate();
226 data().query.no<T>();
227 return *this;
228 }
229 template <typename T>
230 SystemBuilder& changed() {
231 validate();
232 data().query.changed<T>();
233 return *this;
234 }
235 #endif
236
237 //------------------------------------------------
238
239 SystemBuilder& group_by(Entity entity, TGroupByFunc func = group_by_func_default) {
240 data().query.group_by(entity, func);
241 return *this;
242 }
243
244 template <typename T>
245 SystemBuilder& group_by(TGroupByFunc func = group_by_func_default) {
246 data().query.group_by<T>(func);
247 return *this;
248 }
249
250 template <typename Rel, typename Tgt>
251 SystemBuilder& group_by(TGroupByFunc func = group_by_func_default) {
252 data().query.group_by<Rel, Tgt>(func);
253 return *this;
254 }
255
256 //------------------------------------------------
257
258 SystemBuilder& group_id(GroupId groupId) {
259 data().query.group_id(groupId);
260 return *this;
261 }
262
263 SystemBuilder& group_id(Entity entity) {
264 GAIA_ASSERT(!entity.pair());
265 data().query.group_id(entity.id());
266 return *this;
267 }
268
269 template <typename T>
270 SystemBuilder& group_id() {
271 data().query.group_id<T>();
272 return *this;
273 }
274
275 //------------------------------------------------
276
277 SystemBuilder& name(const char* name, uint32_t len = 0) {
278 m_world.name(m_entity, name, len);
279 return *this;
280 }
281
282 SystemBuilder& name_raw(const char* name, uint32_t len = 0) {
283 m_world.name_raw(m_entity, name, len);
284 return *this;
285 }
286
287 //------------------------------------------------
288
289 SystemBuilder& mode(QueryExecType type) {
290 auto& ctx = data();
291 ctx.execType = type;
292 return *this;
293 }
294
295 template <typename Func>
296 SystemBuilder& on_each(Func func) {
297 validate();
298
299 auto& ctx = data();
300 if constexpr (std::is_invocable_v<Func, Iter&>) {
301 ctx.on_each_func = [func](Iter& it) {
302 func(it);
303 };
304 } else {
305 using InputArgs = decltype(core::func_args(&Func::operator()));
306
307 #if GAIA_ASSERT_ENABLED
308 // Make sure we only use components specified in the query.
309 // Constness is respected. Therefore, if a type is const when registered to query,
310 // it has to be const (or immutable) also in each().
311 auto& queryInfo = ctx.query.fetch();
312 GAIA_ASSERT(ctx.query.unpack_args_into_query_has_all(queryInfo, InputArgs{}));
313 #endif
314
315 ctx.on_each_func = [e = m_entity, func](Iter& it) {
316 // NOTE: We can't directly use data().query here because the function relies
317 // on SystemBuilder to be present at all times. If it goes out of scope
318 // the only option left is having a copy of the world pointer and entity.
319 // They are then used to get to the query stored inside System_.
320 auto ss = const_cast<World*>(it.world())->acc_mut(e);
321 auto& sys = ss.smut<System_>();
322 sys.query.run_query_on_chunk(it, func, InputArgs{});
323 };
324 }
325
326 return (SystemBuilder&)*this;
327 }
328
329 GAIA_NODISCARD Entity entity() const {
330 return m_entity;
331 }
332
333 void exec() {
334 auto& ctx = data();
335 ctx.exec();
336 }
337
338 GAIA_NODISCARD mt::JobHandle job_handle() {
339 auto& ctx = data();
340 return ctx.job_handle();
341 }
342 };
343
344 } // namespace ecs
345} // namespace gaia
346
347#endif
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition system.inl:6