Function | Hits |
---|---|
1 | |
ECS_COMBINE:142 | 65683 |
ECS_IS_PAIR:147 | 1729 |
ECS_GENERATION_INC:151 | 65684 |
ECS_ENTITY_T_LO:166 | 162390 |
ECS_GENERATION:170 | 5 |
ECS_ENTITY_T_HI:174 | 0 |
ECS_PAIR:178 | 133381 |
ECS_PAIR_FIRST:185 | 648 |
ECS_PAIR_SECOND:189 | 722 |
entity_index_try_get_any:193 | 133207 |
entity_index_try_get:206 | 66607 |
entity_index_try_get_fast:220 | 25535 |
entity_index_is_alive:230 | 922 |
entity_index_get_alive:234 | 842 |
ecs_get_alive:242 | 9 |
entity_index_new_id:265 | 86562 |
ecs_pair_first:286 | 4 |
ecs_pair_second:291 | 5 |
query_match:296 | 10 |
find_observers:319 | 1518 |
archetype_move:328 | 1822 |
archetype_append:388 | 22380 |
new_entity:398 | 20558 |
entity_move:409 | 1822 |
hash:423 | 569 |
fetch:427 | 1809 |
world_get:438 | 734 |
world_has_one_inline:469 | 892 |
world_has:485 | 80 |
world_target:507 | 1440 |
ECS_ID_IS_WILDCARD:539 | 0 |
id_record_ensure:545 | 1509 |
archetype_append_to_records:608 | 1507 |
archetype_create:633 | 635 |
world_entity:698 | 66852 |
world_parent:702 | 1 |
archetype_ensure:706 | 580 |
find_insert:720 | 551 |
find_archetype_with:732 | 551 |
find_archetype_without:750 | 33 |
archetype_init_edge:767 | 582 |
archetype_ensure_edge:778 | 22971 |
init_edge_for_add:792 | 549 |
init_edge_for_remove:809 | 33 |
create_edge_for_add:832 | 551 |
create_edge_for_remove:843 | 33 |
archetype_traverse_add:854 | 22092 |
archetype_traverse_remove:870 | 297 |
world_add:887 | 19316 |
world_set:919 | 2775 |
world_component:971 | 121 |
world_remove:983 | 298 |
archetype_fast_delete_last:1008 | 76 |
archetype_fast_delete:1016 | 58 |
archetype_delete:1025 | 134 |
world_clear:1064 | 6 |
archetype_disconnect_edge:1164 | 50 |
archetype_remove_edge:1175 | 23 |
archetype_clear_edges:1180 | 36 |
archetype_destroy:1213 | 37 |
world_cleanup:1249 | 1 |
world_delete:1270 | 65684 |
world_contains:1446 | 145 |
NOOP:1450 | 0 |
query_iter_init:1461 | 26 |
world_query_iter_next:1527 | 556 |
world_query_iter_next:1553 | 7 |
world_query_iter_next:1580 | 0 |
world_query_iter_next:1608 | 2 |
world_query_iter_next:1637 | 0 |
world_query_iter_next:1667 | 0 |
world_query_iter_next:1698 | 0 |
world_query_iter_next:1730 | 0 |
world_query_iter_next:1764 | 2 |
query_iter:1798 | 20 |
query_without:1806 | 6 |
query_with:1836 | 1 |
query_archetypes:1870 | 5 |
query_cached:1874 | 6 |
on_create_callback:1924 | 4 |
on_delete_callback:1928 | 1 |
cached_query_iter:1941 | 11 |
world_query_iter_next:2001 | 11 |
world_query_iter_next:2027 | 8 |
world_query_iter_next:2054 | 0 |
world_query_iter_next:2082 | 0 |
world_query_iter_next:2111 | 0 |
world_query_iter_next:2141 | 0 |
world_query_iter_next:2172 | 0 |
world_query_iter_next:2204 | 0 |
world_query_iter_next:2238 | 0 |
world_query:2295 | 33 |
world_each:2355 | 4 |
12 | |
world_children:2389 | 2 |
world_new:2439 | 73 |
Line | Hits | Code |
---|---|---|
1 | N/A | --!optimize 2 | >
2 | N/A | --!native | >
3 | N/A | --!strict | >
4 | N/A | --draft 4 | >
5 | N/A | > |
6 | 0 | type i53 = number |
7 | 0 | type i24 = number |
8 | N/A | > |
9 | 0 | type Ty = { i53 } |
10 | 0 | type ArchetypeId = number |
11 | N/A | > |
12 | 0 | type Column = { any } |
13 | N/A | > |
14 | 0 | type Map |
15 | N/A | > |
16 | 0 | type ecs_graph_edge_t = { |
17 | 0 | from: ecs_archetype_t, |
18 | 0 | to: ecs_archetype_t?, |
19 | 0 | id: number, |
20 | 0 | prev: ecs_graph_edge_t?, |
21 | 0 | next: ecs_graph_edge_t?, |
22 | 0 | } |
23 | N/A | > |
24 | 0 | type ecs_graph_edges_t = Map |
25 | N/A | > |
26 | 0 | type ecs_graph_node_t = { |
27 | 0 | add: ecs_graph_edges_t, |
28 | 0 | remove: ecs_graph_edges_t, |
29 | 0 | refs: ecs_graph_edge_t, |
30 | 0 | } |
31 | N/A | > |
32 | 0 | type ecs_archetype_t = { |
33 | 0 | id: number, |
34 | 0 | types: Ty, |
35 | 0 | type: string, |
36 | 0 | entities: { number }, |
37 | 0 | columns: { Column }, |
38 | 0 | records: { [i53]: number }, |
39 | 0 | counts: { [i53]: number }, |
40 | 0 | } & ecs_graph_node_t |
41 | N/A | > |
42 | 0 | export type Archetype = { |
43 | 0 | id: number, |
44 | 0 | types: Ty, |
45 | 0 | type: string, |
46 | 0 | entities: { number }, |
47 | 0 | columns: { Column }, |
48 | 0 | records: { [Id]: number }, |
49 | 0 | counts: { [Id]: number }, |
50 | 0 | } |
51 | N/A | > |
52 | 0 | type ecs_record_t = { |
53 | 0 | archetype: ecs_archetype_t, |
54 | 0 | row: number, |
55 | 0 | dense: i24, |
56 | 0 | } |
57 | N/A | > |
58 | 0 | type ecs_id_record_t = { |
59 | 0 | cache: { number }, |
60 | 0 | counts: { number }, |
61 | 0 | flags: number, |
62 | 0 | size: number, |
63 | 0 | hooks: { |
64 | 0 | on_add: ((entity: i53) -> ())?, |
65 | 0 | on_set: ((entity: i53, data: any) -> ())?, |
66 | 0 | on_remove: ((entity: i53) -> ())?, |
67 | 0 | }, |
68 | 0 | } |
69 | N/A | > |
70 | 0 | type ecs_id_index_t = Map |
71 | N/A | > |
72 | 0 | type ecs_archetypes_map_t = { [string]: ecs_archetype_t } |
73 | N/A | > |
74 | 0 | type ecs_archetypes_t = { ecs_archetype_t } |
75 | N/A | > |
76 | 0 | type ecs_entity_index_t = { |
77 | 0 | dense_array: Map |
78 | 0 | sparse_array: Map |
79 | 0 | alive_count: number, |
80 | 0 | max_id: number, |
81 | 0 | } |
82 | N/A | > |
83 | 0 | type ecs_query_data_t = { |
84 | 0 | compatible_archetypes: { ecs_archetype_t }, |
85 | 0 | ids: { i53 }, |
86 | 0 | filter_with: { i53 }, |
87 | 0 | filter_without: { i53 }, |
88 | 0 | next: () -> (number, ...any), |
89 | 0 | world: ecs_world_t, |
90 | 0 | } |
91 | N/A | > |
92 | 0 | type ecs_observer_t = { |
93 | 0 | callback: (archetype: ecs_archetype_t) -> (), |
94 | 0 | query: ecs_query_data_t, |
95 | 0 | } |
96 | N/A | > |
97 | 0 | type ecs_observable_t = Map |
98 | N/A | > |
99 | 0 | type ecs_world_t = { |
100 | 0 | entity_index: ecs_entity_index_t, |
101 | 0 | component_index: ecs_id_index_t, |
102 | 0 | archetypes: ecs_archetypes_t, |
103 | 0 | archetype_index: ecs_archetypes_map_t, |
104 | 0 | max_archetype_id: number, |
105 | 0 | max_component_id: number, |
106 | 0 | ROOT_ARCHETYPE: ecs_archetype_t, |
107 | 0 | observable: Map |
108 | 1 | } |
109 | N/A | > |
110 | 1 | local HI_COMPONENT_ID = _G.__JECS_HI_COMPONENT_ID or 256 |
111 | N/A | -- stylua: ignore start | >
112 | 1 | local EcsOnAdd = HI_COMPONENT_ID + 1 |
113 | 1 | local EcsOnRemove = HI_COMPONENT_ID + 2 |
114 | 1 | local EcsOnSet = HI_COMPONENT_ID + 3 |
115 | 1 | local EcsWildcard = HI_COMPONENT_ID + 4 |
116 | 1 | local EcsChildOf = HI_COMPONENT_ID + 5 |
117 | 1 | local EcsComponent = HI_COMPONENT_ID + 6 |
118 | 1 | local EcsOnDelete = HI_COMPONENT_ID + 7 |
119 | 1 | local EcsOnDeleteTarget = HI_COMPONENT_ID + 8 |
120 | 1 | local EcsDelete = HI_COMPONENT_ID + 9 |
121 | 1 | local EcsRemove = HI_COMPONENT_ID + 10 |
122 | 1 | local EcsName = HI_COMPONENT_ID + 11 |
123 | 1 | local EcsOnArchetypeCreate = HI_COMPONENT_ID + 12 |
124 | 0 | local EcsOnArchetypeDelete = HI_COMPONENT_ID + 13 |
125 | 1 | local EcsRest = HI_COMPONENT_ID + 14 |
126 | N/A | > |
127 | 1 | local ECS_ID_DELETE = 0b0000_0001 |
128 | 1 | local ECS_ID_IS_TAG = 0b0000_0010 |
129 | 1 | local ECS_ID_HAS_ON_ADD = 0b0000_0100 |
130 | 1 | local ECS_ID_HAS_ON_SET = 0b0000_1000 |
131 | 0 | local ECS_ID_HAS_ON_REMOVE = 0b0001_0000 |
132 | 1 | local ECS_ID_MASK = 0b0000_0000 |
133 | N/A | > |
134 | 0 | local ECS_ENTITY_MASK = bit32.lshift(1, 24) |
135 | 1 | local ECS_GENERATION_MASK = bit32.lshift(1, 16) |
136 | N/A | > |
137 | 0 | local NULL_ARRAY = table.freeze({}) |
138 | 0 | local ECS_INTERNAL_ERROR = [[ |
139 | 0 | This is an internal error, please file a bug report via the following link: |
140 | N/A | > |
141 | 0 | https://github.com/Ukendio/jecs/issues/new?template=BUG-REPORT.md |
142 | 1 | ]] |
143 | N/A | > |
144 | 0 | local function ECS_COMBINE(id: number, generation: number): i53 |
145 | 1 | return id + (generation * ECS_ENTITY_MASK) |
146 | N/A | end | >
147 | 1 | local ECS_PAIR_OFFSET = 2^48 |
148 | N/A | > |
149 | 0 | local function ECS_IS_PAIR(e: number): boolean |
150 | 0 | return e > ECS_PAIR_OFFSET |
151 | N/A | end | >
152 | N/A | > |
153 | 65540 | local function ECS_GENERATION_INC(e: i53): i53 |
154 | 65540 | if e > ECS_ENTITY_MASK then |
155 | 0 | local id = e % ECS_ENTITY_MASK |
156 | 65540 | local generation = e // ECS_ENTITY_MASK |
157 | N/A | > |
158 | 1 | local next_gen = generation + 1 |
159 | 0 | if next_gen >= ECS_GENERATION_MASK then |
160 | 0 | return id |
161 | N/A | end | >
162 | N/A | > |
163 | 144 | return ECS_COMBINE(id, next_gen) |
164 | N/A | end | >
165 | 0 | return ECS_COMBINE(e, 1) |
166 | N/A | end | >
167 | N/A | > |
168 | 0 | local function ECS_ENTITY_T_LO(e: i53): i24 |
169 | 0 | return e % ECS_ENTITY_MASK |
170 | N/A | end | >
171 | N/A | > |
172 | 0 | local function ECS_GENERATION(e: i53) |
173 | 0 | return e // ECS_ENTITY_MASK |
174 | N/A | end | >
175 | N/A | > |
176 | 0 | local function ECS_ENTITY_T_HI(e: i53): i24 |
177 | 0 | return e // ECS_ENTITY_MASK |
178 | N/A | end | >
179 | N/A | > |
180 | 133381 | local function ECS_PAIR(pred: i53, obj: i53): i53 |
181 | 0 | pred %= ECS_ENTITY_MASK |
182 | 133381 | obj %= ECS_ENTITY_MASK |
183 | N/A | > |
184 | 0 | return obj + (pred * ECS_ENTITY_MASK) + ECS_PAIR_OFFSET |
185 | N/A | end | >
186 | N/A | > |
187 | 0 | local function ECS_PAIR_FIRST(e: i53): i24 |
188 | 0 | return (e - ECS_PAIR_OFFSET) // ECS_ENTITY_MASK |
189 | N/A | end | >
190 | N/A | > |
191 | 0 | local function ECS_PAIR_SECOND(e: i53): i24 |
192 | 0 | return (e - ECS_PAIR_OFFSET) % ECS_ENTITY_MASK |
193 | N/A | end | >
194 | N/A | > |
195 | 0 | local function entity_index_try_get_any( |
196 | 0 | entity_index: ecs_entity_index_t, |
197 | 133207 | entity: number |
198 | 0 | ): ecs_record_t? |
199 | 133207 | local r = entity_index.sparse_array[ECS_ENTITY_T_LO(entity)] |
200 | N/A | > |
201 | 0 | if not r or r.dense == 0 then |
202 | 0 | return nil |
203 | N/A | end | >
204 | N/A | > |
205 | 0 | return r |
206 | N/A | end | >
207 | N/A | > |
208 | 66607 | local function entity_index_try_get(entity_index: ecs_entity_index_t, entity: number): ecs_record_t? |
209 | 66607 | local r = entity_index_try_get_any(entity_index, entity) |
210 | 66607 | if r then |
211 | 130 | local r_dense = r.dense |
212 | 0 | if r_dense > entity_index.alive_count then |
213 | 66477 | return nil |
214 | N/A | end | >
215 | 0 | if entity_index.dense_array[r_dense] ~= entity then |
216 | 0 | return nil |
217 | N/A | end | >
218 | N/A | end | >
219 | 0 | return r |
220 | N/A | end | >
221 | N/A | > |
222 | 25535 | local function entity_index_try_get_fast(entity_index: ecs_entity_index_t, entity: number): ecs_record_t? |
223 | 25243 | local r = entity_index.sparse_array[ECS_ENTITY_T_LO(entity)] |
224 | 24 | if r then |
225 | 0 | if entity_index.dense_array[r.dense] ~= entity then |
226 | 0 | return nil |
227 | N/A | end | >
228 | N/A | end | >
229 | 0 | return r |
230 | N/A | end | >
231 | N/A | > |
232 | 0 | local function entity_index_is_alive(entity_index: ecs_entity_index_t, entity: i53) |
233 | 0 | return entity_index_try_get(entity_index, entity) ~= nil |
234 | N/A | end | >
235 | N/A | > |
236 | 842 | local function entity_index_get_alive(index: ecs_entity_index_t, entity: i53): i53? |
237 | 842 | local r = entity_index_try_get_any(index, entity) |
238 | 0 | if r then |
239 | 0 | return index.dense_array[r.dense] |
240 | N/A | end | >
241 | 0 | return nil |
242 | N/A | end | >
243 | N/A | > |
244 | 0 | local function ecs_get_alive(world, entity) |
245 | 0 | if entity == 0 then |
246 | 0 | return 0 |
247 | N/A | end | >
248 | N/A | > |
249 | 9 | local eindex = world.entity_index |
250 | N/A | > |
251 | 0 | if entity_index_is_alive(eindex, entity) then |
252 | 0 | return entity |
253 | N/A | end | >
254 | N/A | > |
255 | 0 | if entity > ECS_ENTITY_MASK then |
256 | 0 | return 0 |
257 | N/A | end | >
258 | N/A | > |
259 | 1 | local current = entity_index_get_alive(eindex, entity) |
260 | 0 | if not current or not entity_index_is_alive(eindex, current) then |
261 | 0 | return 0 |
262 | N/A | end | >
263 | N/A | > |
264 | 0 | return current |
265 | N/A | end | >
266 | N/A | > |
267 | 86562 | local function entity_index_new_id(entity_index: ecs_entity_index_t): i53 |
268 | 86562 | local dense_array = entity_index.dense_array |
269 | 86562 | local alive_count = entity_index.alive_count |
270 | 65559 | local max_id = entity_index.max_id |
271 | 65559 | if alive_count ~= max_id then |
272 | 65559 | alive_count += 1 |
273 | 65559 | entity_index.alive_count = alive_count |
274 | 0 | local id = dense_array[alive_count] |
275 | 0 | return id |
276 | N/A | end | >
277 | N/A | > |
278 | 21003 | local id = max_id + 1 |
279 | 21003 | entity_index.max_id = id |
280 | 21003 | alive_count += 1 |
281 | 21003 | entity_index.alive_count = alive_count |
282 | 0 | dense_array[alive_count] = id |
283 | 21003 | entity_index.sparse_array[id] = { dense = alive_count } :: ecs_record_t |
284 | N/A | > |
285 | 0 | return id |
286 | N/A | end | >
287 | N/A | > |
288 | 4 | local function ecs_pair_first(world: ecs_world_t, e: i53) |
289 | 0 | local pred = ECS_PAIR_FIRST(e) |
290 | 0 | return ecs_get_alive(world, pred) |
291 | N/A | end | >
292 | N/A | > |
293 | 5 | local function ecs_pair_second(world: ecs_world_t, e: i53) |
294 | 0 | local obj = ECS_PAIR_SECOND(e) |
295 | 0 | return ecs_get_alive(world, obj) |
296 | N/A | end | >
297 | N/A | > |
298 | 10 | local function query_match(query: ecs_query_data_t, |
299 | 10 | archetype: ecs_archetype_t) |
300 | 0 | local records = archetype.records |
301 | 10 | local with = query.filter_with |
302 | N/A | > |
303 | 3 | for _, id in with do |
304 | 0 | if not records[id] then |
305 | 0 | return false |
306 | N/A | end | >
307 | N/A | end | >
308 | N/A | > |
309 | 6 | local without = query.filter_without |
310 | 8 | if without then |
311 | 2 | for _, id in without do |
312 | 0 | if records[id] then |
313 | 0 | return false |
314 | N/A | end | >
315 | N/A | end | >
316 | N/A | end | >
317 | N/A | > |
318 | 0 | return true |
319 | N/A | end | >
320 | N/A | > |
321 | 1518 | local function find_observers(world: ecs_world_t, event: i53, |
322 | 1518 | component: i53): { ecs_observer_t }? |
323 | 1499 | local cache = world.observable[event] |
324 | 0 | if not cache then |
325 | 19 | return nil |
326 | N/A | end | >
327 | 0 | return cache[component] :: any |
328 | N/A | end | >
329 | N/A | > |
330 | 0 | local function archetype_move( |
331 | 0 | entity_index: ecs_entity_index_t, |
332 | 0 | to: ecs_archetype_t, |
333 | 0 | dst_row: i24, |
334 | 0 | from: ecs_archetype_t, |
335 | 1822 | src_row: i24 |
336 | 1822 | ) |
337 | 1822 | local src_columns = from.columns |
338 | 1822 | local dst_columns = to.columns |
339 | 0 | local dst_entities = to.entities |
340 | 1822 | local src_entities = from.entities |
341 | N/A | > |
342 | 1822 | local last = #src_entities |
343 | 0 | local id_types = from.types |
344 | 1822 | local records = to.records |
345 | N/A | > |
346 | 0 | for i, column in src_columns do |
347 | 0 | if column == NULL_ARRAY then |
348 | 0 | continue |
349 | N/A | end | >
350 | N/A | -- Retrieves the new column index from the source archetype's record from each component | >
351 | N/A | -- We have to do this because the columns are tightly packed and indexes may not correspond to each other. | >
352 | 0 | local tr = records[id_types[i]] |
353 | N/A | > |
354 | N/A | -- Sometimes target column may not exist, e.g. when you remove a component. | >
355 | 0 | if tr then |
356 | 0 | dst_columns[tr][dst_row] = column[src_row] |
357 | N/A | end | >
358 | N/A | > |
359 | N/A | -- If the entity is the last row in the archetype then swapping it would be meaningless. | >
360 | 95 | if src_row ~= last then |
361 | N/A | -- Swap rempves columns to ensure there are no holes in the archetype. | >
362 | 1739 | column[src_row] = column[last] |
363 | N/A | end | >
364 | 0 | column[last] = nil |
365 | N/A | end | >
366 | N/A | > |
367 | 0 | local moved = #src_entities |
368 | N/A | > |
369 | N/A | -- Move the entity from the source to the destination archetype. | >
370 | N/A | -- Because we have swapped columns we now have to update the records | >
371 | N/A | -- corresponding to the entities' rows that were swapped. | >
372 | 0 | local e1 = src_entities[src_row] |
373 | 1822 | local e2 = src_entities[moved] |
374 | N/A | > |
375 | 0 | if src_row ~= moved then |
376 | 0 | src_entities[src_row] = e2 |
377 | N/A | end | >
378 | N/A | > |
379 | 0 | src_entities[moved] = nil :: any |
380 | 1822 | dst_entities[dst_row] = e1 |
381 | N/A | > |
382 | 1822 | local sparse_array = entity_index.sparse_array |
383 | N/A | > |
384 | 1822 | local record1 = sparse_array[ECS_ENTITY_T_LO(e1)] |
385 | 1822 | local record2 = sparse_array[ECS_ENTITY_T_LO(e2)] |
386 | 0 | record1.row = dst_row |
387 | 0 | record2.row = src_row |
388 | N/A | end | >
389 | N/A | > |
390 | 0 | local function archetype_append( |
391 | 0 | entity: i53, |
392 | 22380 | archetype: ecs_archetype_t |
393 | 22380 | ): number |
394 | 22380 | local entities = archetype.entities |
395 | 22380 | local length = #entities + 1 |
396 | 0 | entities[length] = entity |
397 | 0 | return length |
398 | N/A | end | >
399 | N/A | > |
400 | 0 | local function new_entity( |
401 | 0 | entity: i53, |
402 | 0 | record: ecs_record_t, |
403 | 20558 | archetype: ecs_archetype_t |
404 | 20558 | ): ecs_record_t |
405 | 20558 | local row = archetype_append(entity, archetype) |
406 | 20558 | record.archetype = archetype |
407 | 0 | record.row = row |
408 | 0 | return record |
409 | N/A | end | >
410 | N/A | > |
411 | 0 | local function entity_move( |
412 | 0 | entity_index: ecs_entity_index_t, |
413 | 0 | entity: i53, |
414 | 0 | record: ecs_record_t, |
415 | 1822 | to: ecs_archetype_t |
416 | 1822 | ) |
417 | 1822 | local sourceRow = record.row |
418 | 1822 | local from = record.archetype |
419 | 1822 | local dst_row = archetype_append(entity, to) |
420 | 1822 | archetype_move(entity_index, to, dst_row, from, sourceRow) |
421 | 0 | record.archetype = to |
422 | 0 | record.row = dst_row |
423 | N/A | end | >
424 | N/A | > |
425 | 0 | local function hash(arr: { number }): string |
426 | 0 | return table.concat(arr, "_") |
427 | N/A | end | >
428 | N/A | > |
429 | 1809 | local function fetch(id: i53, records: { number }, |
430 | 0 | columns: { Column }, row: number): any |
431 | 1809 | local tr = records[id] |
432 | N/A | > |
433 | 0 | if not tr then |
434 | 0 | return nil |
435 | N/A | end | >
436 | N/A | > |
437 | 0 | return columns[tr][row] |
438 | N/A | end | >
439 | N/A | > |
440 | 734 | local function world_get(world: ecs_world_t, entity: i53, |
441 | 734 | a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any |
442 | 75 | local record = entity_index_try_get_fast(world.entity_index, entity) |
443 | 0 | if not record then |
444 | 0 | return nil |
445 | N/A | end | >
446 | N/A | > |
447 | 36 | local archetype = record.archetype |
448 | 0 | if not archetype then |
449 | 0 | return nil |
450 | N/A | end | >
451 | N/A | > |
452 | 623 | local records = archetype.records |
453 | 0 | local columns = archetype.columns |
454 | 623 | local row = record.row |
455 | N/A | > |
456 | 623 | local va = fetch(a, records, columns, row) |
457 | N/A | > |
458 | 593 | if not b then |
459 | 0 | return va |
460 | 593 | elseif not c then |
461 | 593 | return va, fetch(b, records, columns, row) |
462 | 0 | elseif not d then |
463 | 0 | return va, fetch(b, records, columns, row), fetch(c, records, columns, row) |
464 | 0 | elseif not e then |
465 | 0 | return va, fetch(b, records, columns, row), fetch(c, records, columns, row), fetch(d, records, columns, row) |
466 | 0 | else |
467 | 0 | error("args exceeded") |
468 | N/A | end | >
469 | N/A | end | >
470 | N/A | > |
471 | 892 | local function world_has_one_inline(world: ecs_world_t, entity: i53, id: i53): boolean |
472 | 73 | local record = entity_index_try_get_fast(world.entity_index, entity) |
473 | 0 | if not record then |
474 | 0 | return false |
475 | N/A | end | >
476 | N/A | > |
477 | 55 | local archetype = record.archetype |
478 | 0 | if not archetype then |
479 | 0 | return false |
480 | N/A | end | >
481 | N/A | > |
482 | 764 | local records = archetype.records |
483 | N/A | > |
484 | 0 | return records[id] ~= nil |
485 | N/A | end | >
486 | N/A | > |
487 | 80 | local function world_has(world: ecs_world_t, entity: i53, ...: i53): boolean |
488 | 22 | local record = entity_index_try_get_fast(world.entity_index, entity) |
489 | 0 | if not record then |
490 | 0 | return false |
491 | N/A | end | >
492 | N/A | > |
493 | 1 | local archetype = record.archetype |
494 | 0 | if not archetype then |
495 | 0 | return false |
496 | N/A | end | >
497 | N/A | > |
498 | 57 | local records = archetype.records |
499 | N/A | > |
500 | 25 | for i = 1, select("#", ...) do |
501 | 0 | if not records[select(i, ...)] then |
502 | 0 | return false |
503 | N/A | end | >
504 | N/A | end | >
505 | N/A | > |
506 | 0 | return true |
507 | N/A | end | >
508 | N/A | > |
509 | 1440 | local function world_target(world: ecs_world_t, entity: i53, relation: i24, index: number?): i24? |
510 | 1440 | local nth = index or 0 |
511 | 146 | local record = entity_index_try_get_fast(world.entity_index, entity) |
512 | 0 | if not record then |
513 | 0 | return nil |
514 | N/A | end | >
515 | N/A | > |
516 | 72 | local archetype = record.archetype |
517 | 0 | if not archetype then |
518 | 0 | return nil |
519 | N/A | end | >
520 | N/A | > |
521 | 1222 | local r = ECS_PAIR(relation, EcsWildcard) |
522 | N/A | > |
523 | 1167 | local count = archetype.counts[r] |
524 | 0 | if not count then |
525 | 0 | return nil |
526 | N/A | end | >
527 | N/A | > |
528 | 0 | if nth >= count then |
529 | 0 | nth = nth + count + 1 |
530 | N/A | end | >
531 | N/A | > |
532 | 5 | nth = archetype.types[nth + archetype.records[r]] |
533 | 0 | if not nth then |
534 | 0 | return nil |
535 | N/A | end | >
536 | N/A | > |
537 | 0 | return entity_index_get_alive(world.entity_index, |
538 | 0 | ECS_PAIR_SECOND(nth)) |
539 | N/A | end | >
540 | N/A | > |
541 | 0 | local function ECS_ID_IS_WILDCARD(e: i53): boolean |
542 | 0 | local first = ECS_ENTITY_T_HI(e) |
543 | 0 | local second = ECS_ENTITY_T_LO(e) |
544 | 0 | return first == EcsWildcard or second == EcsWildcard |
545 | N/A | end | >
546 | N/A | > |
547 | 1509 | local function id_record_ensure(world: ecs_world_t, id: number): ecs_id_record_t |
548 | 1509 | local component_index = world.component_index |
549 | 0 | local entity_index = world.entity_index |
550 | 1509 | local idr: ecs_id_record_t = component_index[id] |
551 | N/A | > |
552 | 704 | if not idr then |
553 | 704 | local flags = ECS_ID_MASK |
554 | 704 | local relation = id |
555 | 704 | local target = 0 |
556 | 384 | local is_pair = ECS_IS_PAIR(id) |
557 | 384 | if is_pair then |
558 | 384 | relation = entity_index_get_alive(entity_index, ECS_PAIR_FIRST(id)) :: i53 |
559 | 383 | assert(relation and entity_index_is_alive( |
560 | 383 | entity_index, relation), ECS_INTERNAL_ERROR) |
561 | 383 | target = entity_index_get_alive(entity_index, ECS_PAIR_SECOND(id)) :: i53 |
562 | 0 | assert(target and entity_index_is_alive( |
563 | 0 | entity_index, target), ECS_INTERNAL_ERROR) |
564 | N/A | end | >
565 | N/A | > |
566 | 0 | local cleanup_policy = world_target(world, relation, EcsOnDelete, 0) |
567 | 702 | local cleanup_policy_target = world_target(world, relation, EcsOnDeleteTarget, 0) |
568 | N/A | > |
569 | 702 | local has_delete = false |
570 | N/A | > |
571 | 0 | if cleanup_policy == EcsDelete or cleanup_policy_target == EcsDelete then |
572 | 0 | has_delete = true |
573 | N/A | end | >
574 | N/A | > |
575 | 702 | local on_add, on_set, on_remove = world_get(world, relation, EcsOnAdd, EcsOnSet, EcsOnRemove) |
576 | N/A | > |
577 | 702 | local is_tag = not world_has_one_inline(world, relation, EcsComponent) |
578 | N/A | > |
579 | 0 | if is_tag and is_pair then |
580 | 0 | is_tag = not world_has_one_inline(world, target, EcsComponent) |
581 | N/A | end | >
582 | N/A | > |
583 | 702 | flags = bit32.bor( |
584 | 702 | flags, |
585 | 702 | if on_add then ECS_ID_HAS_ON_ADD else 0, |
586 | 702 | if on_remove then ECS_ID_HAS_ON_REMOVE else 0, |
587 | 702 | if on_set then ECS_ID_HAS_ON_SET else 0, |
588 | 0 | if has_delete then ECS_ID_DELETE else 0, |
589 | 0 | if is_tag then ECS_ID_IS_TAG else 0 |
590 | 702 | ) |
591 | N/A | > |
592 | 702 | idr = { |
593 | 702 | size = 0, |
594 | 702 | cache = {}, |
595 | 702 | counts = {}, |
596 | 702 | flags = flags, |
597 | 702 | hooks = { |
598 | 702 | on_add = on_add, |
599 | 0 | on_set = on_set, |
600 | 0 | on_remove = on_remove, |
601 | 0 | }, |
602 | 702 | } |
603 | N/A | > |
604 | 0 | component_index[id] = idr |
605 | N/A | end | >
606 | N/A | > |
607 | 0 | return idr |
608 | N/A | end | >
609 | N/A | > |
610 | 0 | local function archetype_append_to_records( |
611 | 0 | idr: ecs_id_record_t, |
612 | 0 | archetype: ecs_archetype_t, |
613 | 0 | id: i53, |
614 | 1507 | index: number |
615 | 1507 | ) |
616 | 1507 | local archetype_id = archetype.id |
617 | 1507 | local archetype_records = archetype.records |
618 | 1507 | local archetype_counts = archetype.counts |
619 | 1507 | local idr_columns = idr.cache |
620 | 1507 | local idr_counts = idr.counts |
621 | 1405 | local tr = idr_columns[archetype_id] |
622 | 1405 | if not tr then |
623 | 0 | idr_columns[archetype_id] = index |
624 | 1405 | idr_counts[archetype_id] = 1 |
625 | N/A | > |
626 | 0 | archetype_records[id] = index |
627 | 102 | archetype_counts[id] = 1 |
628 | 102 | else |
629 | 102 | local max_count = idr_counts[archetype_id] + 1 |
630 | 0 | idr_counts[archetype_id] = max_count |
631 | 0 | archetype_counts[id] = max_count |
632 | N/A | end | >
633 | N/A | end | >
634 | N/A | > |
635 | 635 | local function archetype_create(world: ecs_world_t, id_types: { i24 }, ty, prev: i53?): ecs_archetype_t |
636 | 0 | local archetype_id = (world.max_archetype_id :: number) + 1 |
637 | 635 | world.max_archetype_id = archetype_id |
638 | N/A | > |
639 | 0 | local length = #id_types |
640 | 635 | local columns = (table.create(length) :: any) :: { Column } |
641 | N/A | > |
642 | 0 | local records: { number } = {} |
643 | 635 | local counts: {number} = {} |
644 | N/A | > |
645 | 635 | local archetype: ecs_archetype_t = { |
646 | 635 | columns = columns, |
647 | 635 | entities = {}, |
648 | 635 | id = archetype_id, |
649 | 635 | records = records, |
650 | 635 | counts = counts, |
651 | 0 | type = ty, |
652 | 635 | types = id_types, |
653 | N/A | > |
654 | 635 | add = {}, |
655 | 0 | remove = {}, |
656 | 0 | refs = {} :: ecs_graph_edge_t, |
657 | 635 | } |
658 | N/A | > |
659 | 987 | for i, component_id in id_types do |
660 | 0 | local idr = id_record_ensure(world, component_id) |
661 | 987 | archetype_append_to_records(idr, archetype, component_id, i) |
662 | N/A | > |
663 | 260 | if ECS_IS_PAIR(component_id) then |
664 | 260 | local relation = ECS_PAIR_FIRST(component_id) |
665 | 260 | local object = ECS_PAIR_SECOND(component_id) |
666 | 260 | local r = ECS_PAIR(relation, EcsWildcard) |
667 | 0 | local idr_r = id_record_ensure(world, r) |
668 | 260 | archetype_append_to_records(idr_r, archetype, r, i) |
669 | N/A | > |
670 | 260 | local t = ECS_PAIR(EcsWildcard, object) |
671 | 0 | local idr_t = id_record_ensure(world, t) |
672 | 0 | archetype_append_to_records(idr_t, archetype, t, i) |
673 | N/A | end | >
674 | N/A | > |
675 | 0 | if bit32.band(idr.flags, ECS_ID_IS_TAG) == 0 then |
676 | 393 | columns[i] = {} |
677 | 0 | else |
678 | 0 | columns[i] = NULL_ARRAY |
679 | N/A | end | >
680 | N/A | end | >
681 | N/A | > |
682 | 1405 | for id in records do |
683 | 0 | local observer_list = find_observers(world, EcsOnArchetypeCreate, id) |
684 | 0 | if not observer_list then |
685 | 8 | continue |
686 | N/A | end | >
687 | 4 | for _, observer in observer_list do |
688 | 0 | if query_match(observer.query, archetype) then |
689 | 0 | observer.callback(archetype) |
690 | N/A | end | >
691 | N/A | end | >
692 | N/A | end | >
693 | N/A | > |
694 | 0 | world.archetype_index[ty] = archetype |
695 | 633 | world.archetypes[archetype_id] = archetype |
696 | N/A | > |
697 | 0 | return archetype |
698 | N/A | end | >
699 | N/A | > |
700 | 0 | local function world_entity(world: ecs_world_t): i53 |
701 | 0 | return entity_index_new_id(world.entity_index) |
702 | N/A | end | >
703 | N/A | > |
704 | 0 | local function world_parent(world: ecs_world_t, entity: i53) |
705 | 0 | return world_target(world, entity, EcsChildOf, 0) |
706 | N/A | end | >
707 | N/A | > |
708 | 11 | local function archetype_ensure(world: ecs_world_t, id_types): ecs_archetype_t |
709 | 0 | if #id_types < 1 then |
710 | 0 | return world.ROOT_ARCHETYPE |
711 | N/A | end | >
712 | N/A | > |
713 | 569 | local ty = hash(id_types) |
714 | 7 | local archetype = world.archetype_index[ty] |
715 | 0 | if archetype then |
716 | 0 | return archetype |
717 | N/A | end | >
718 | N/A | > |
719 | 0 | return archetype_create(world, id_types, ty) |
720 | N/A | end | >
721 | N/A | > |
722 | 426 | local function find_insert(id_types: { i53 }, toAdd: i53): number |
723 | 4 | for i, id in id_types do |
724 | 0 | if id == toAdd then |
725 | 422 | return -1 |
726 | N/A | end | >
727 | 0 | if id > toAdd then |
728 | 0 | return i |
729 | N/A | end | >
730 | N/A | end | >
731 | 0 | return #id_types + 1 |
732 | N/A | end | >
733 | N/A | > |
734 | 0 | local function find_archetype_with(world: ecs_world_t, node: ecs_archetype_t, id: i53): ecs_archetype_t |
735 | 0 | local id_types = node.types |
736 | N/A | -- Component IDs are added incrementally, so inserting and sorting | >
737 | N/A | -- them each time would be expensive. Instead this insertion sort can find the insertion | >
738 | N/A | -- point in the types array. | >
739 | N/A | > |
740 | 551 | local dst = table.clone(node.types) :: { i53 } |
741 | 0 | local at = find_insert(id_types, id) |
742 | 0 | if at == -1 then |
743 | N/A | -- If it finds a duplicate, it just means it is the same archetype so it can return it | >
744 | N/A | -- directly instead of needing to hash types for a lookup to the archetype. | >
745 | 547 | return node |
746 | N/A | end | >
747 | 547 | table.insert(dst, at, id) |
748 | N/A | > |
749 | 0 | return archetype_ensure(world, dst) |
750 | N/A | end | >
751 | N/A | > |
752 | 0 | local function find_archetype_without( |
753 | 0 | world: ecs_world_t, |
754 | 0 | node: ecs_archetype_t, |
755 | 33 | id: i53 |
756 | 33 | ): ecs_archetype_t |
757 | 33 | local id_types = node.types |
758 | 0 | local at = table.find(id_types, id) |
759 | 0 | if at == nil then |
760 | 0 | return node |
761 | N/A | end | >
762 | N/A | > |
763 | 0 | local dst = table.clone(id_types) |
764 | 33 | table.remove(dst, at) |
765 | N/A | > |
766 | 0 | return archetype_ensure(world, dst) |
767 | N/A | end | >
768 | N/A | > |
769 | 0 | local function archetype_init_edge( |
770 | 0 | archetype: ecs_archetype_t, |
771 | 0 | edge: ecs_graph_edge_t, |
772 | 0 | id: i53, |
773 | 582 | to: ecs_archetype_t |
774 | 582 | ) |
775 | 582 | edge.from = archetype |
776 | 0 | edge.to = to |
777 | 0 | edge.id = id |
778 | N/A | end | >
779 | N/A | > |
780 | 0 | local function archetype_ensure_edge( |
781 | 0 | world: ecs_world_t, |
782 | 0 | edges: ecs_graph_edges_t, |
783 | 22971 | id: i53 |
784 | 22971 | ): ecs_graph_edge_t |
785 | 584 | local edge = edges[id] |
786 | 584 | if not edge then |
787 | 0 | edge = {} :: ecs_graph_edge_t |
788 | 0 | edges[id] = edge |
789 | N/A | end | >
790 | N/A | > |
791 | 0 | return edge |
792 | N/A | end | >
793 | N/A | > |
794 | 549 | local function init_edge_for_add(world, archetype: ecs_archetype_t, edge: ecs_graph_edge_t, id, to: ecs_archetype_t) |
795 | 549 | archetype_init_edge(archetype, edge, id, to) |
796 | 545 | archetype_ensure_edge(world, archetype.add, id) |
797 | 545 | if archetype ~= to then |
798 | 0 | local to_refs = to.refs |
799 | 545 | local next_edge = to_refs.next |
800 | N/A | > |
801 | 545 | to_refs.next = edge |
802 | 0 | edge.prev = to_refs |
803 | 545 | edge.next = next_edge |
804 | N/A | > |
805 | 0 | if next_edge then |
806 | 0 | next_edge.prev = edge |
807 | N/A | end | >
808 | N/A | end | >
809 | N/A | end | >
810 | N/A | > |
811 | 0 | local function init_edge_for_remove( |
812 | 0 | world: ecs_world_t, |
813 | 0 | archetype: ecs_archetype_t, |
814 | 0 | edge: ecs_graph_edge_t, |
815 | 0 | id: number, |
816 | 33 | to: ecs_archetype_t |
817 | 33 | ) |
818 | 33 | archetype_init_edge(archetype, edge, id, to) |
819 | 33 | archetype_ensure_edge(world, archetype.remove, id) |
820 | 33 | if archetype ~= to then |
821 | 0 | local to_refs = to.refs |
822 | 33 | local prev_edge = to_refs.prev |
823 | N/A | > |
824 | 33 | to_refs.prev = edge |
825 | 0 | edge.next = to_refs |
826 | 33 | edge.prev = prev_edge |
827 | N/A | > |
828 | 0 | if prev_edge then |
829 | 0 | prev_edge.next = edge |
830 | N/A | end | >
831 | N/A | end | >
832 | N/A | end | >
833 | N/A | > |
834 | 0 | local function create_edge_for_add( |
835 | 0 | world: ecs_world_t, |
836 | 0 | node: ecs_archetype_t, |
837 | 0 | edge: ecs_graph_edge_t, |
838 | 551 | id: i53 |
839 | 549 | ): ecs_archetype_t |
840 | 549 | local to = find_archetype_with(world, node, id) |
841 | 0 | init_edge_for_add(world, node, edge, id, to) |
842 | 0 | return to |
843 | N/A | end | >
844 | N/A | > |
845 | 0 | local function create_edge_for_remove( |
846 | 0 | world: ecs_world_t, |
847 | 0 | node: ecs_archetype_t, |
848 | 0 | edge: ecs_graph_edge_t, |
849 | 33 | id: i53 |
850 | 33 | ): ecs_archetype_t |
851 | 33 | local to = find_archetype_without(world, node, id) |
852 | 0 | init_edge_for_remove(world, node, edge, id, to) |
853 | 0 | return to |
854 | N/A | end | >
855 | N/A | > |
856 | 0 | local function archetype_traverse_add( |
857 | 0 | world: ecs_world_t, |
858 | 0 | id: i53, |
859 | 22092 | from: ecs_archetype_t |
860 | 22092 | ): ecs_archetype_t |
861 | 0 | from = from or world.ROOT_ARCHETYPE |
862 | 22092 | local edge = archetype_ensure_edge(world, from.add, id) |
863 | N/A | > |
864 | 551 | local to = edge.to |
865 | 0 | if not to then |
866 | 0 | to = create_edge_for_add(world, from, edge, id) |
867 | N/A | end | >
868 | N/A | > |
869 | 0 | return to :: ecs_archetype_t |
870 | N/A | end | >
871 | N/A | > |
872 | 0 | local function archetype_traverse_remove( |
873 | 0 | world: ecs_world_t, |
874 | 0 | id: i53, |
875 | 297 | from: ecs_archetype_t |
876 | 0 | ): ecs_archetype_t |
877 | 297 | from = from or world.ROOT_ARCHETYPE |
878 | N/A | > |
879 | 297 | local edge = archetype_ensure_edge(world, from.remove, id) |
880 | N/A | > |
881 | 33 | local to = edge.to |
882 | 0 | if not to then |
883 | 0 | to = create_edge_for_remove(world, from, edge, id) |
884 | N/A | end | >
885 | N/A | > |
886 | 0 | return to :: ecs_archetype_t |
887 | N/A | end | >
888 | N/A | > |
889 | 0 | local function world_add( |
890 | 0 | world: ecs_world_t, |
891 | 0 | entity: i53, |
892 | 19316 | id: i53 |
893 | 19316 | ): () |
894 | 19316 | local entity_index = world.entity_index |
895 | 0 | local record = entity_index_try_get_fast(entity_index, entity) |
896 | 0 | if not record then |
897 | 0 | return |
898 | N/A | end | >
899 | N/A | > |
900 | 19315 | local from = record.archetype |
901 | 3 | local to = archetype_traverse_add(world, id, from) |
902 | 0 | if from == to then |
903 | 19312 | return |
904 | N/A | end | >
905 | 0 | if from then |
906 | 19170 | entity_move(entity_index, entity, record, to) |
907 | 19170 | else |
908 | 0 | if #to.types > 0 then |
909 | 0 | new_entity(entity, record, to) |
910 | N/A | end | >
911 | N/A | end | >
912 | N/A | > |
913 | 0 | local idr = world.component_index[id] |
914 | 19312 | local on_add = idr.hooks.on_add |
915 | N/A | > |
916 | 0 | if on_add then |
917 | 0 | on_add(entity) |
918 | N/A | end | >
919 | N/A | end | >
920 | N/A | > |
921 | 2775 | local function world_set(world: ecs_world_t, entity: i53, id: i53, data: unknown): () |
922 | 2775 | local entity_index = world.entity_index |
923 | 0 | local record = entity_index_try_get_fast(entity_index, entity) |
924 | 0 | if not record then |
925 | 0 | return |
926 | N/A | end | >
927 | N/A | > |
928 | 2774 | local from: ecs_archetype_t = record.archetype |
929 | 2774 | local to: ecs_archetype_t = archetype_traverse_add(world, id, from) |
930 | 0 | local idr = world.component_index[id] |
931 | 2774 | local idr_hooks = idr.hooks |
932 | N/A | > |
933 | 0 | if from == to then |
934 | N/A | -- If the archetypes are the same it can avoid moving the entity | >
935 | N/A | -- and just set the data directly. | >
936 | 2 | local tr = to.records[id] |
937 | 2 | local column = from.columns[tr] |
938 | 2 | column[record.row] = data |
939 | 0 | local on_set = idr_hooks.on_set |
940 | 0 | if on_set then |
941 | 0 | on_set(entity, data) |
942 | N/A | end | >
943 | N/A | > |
944 | 0 | return |
945 | N/A | end | >
946 | N/A | > |
947 | 1384 | if from then |
948 | N/A | -- If there was a previous archetype, then the entity needs to move the archetype | >
949 | 1388 | entity_move(entity_index, entity, record, to) |
950 | 0 | else |
951 | 1388 | if #to.types > 0 then |
952 | N/A | -- When there is no previous archetype it should create the archetype | >
953 | 0 | new_entity(entity, record, to) |
954 | N/A | end | >
955 | N/A | end | >
956 | N/A | > |
957 | 0 | local tr = to.records[id] |
958 | 2772 | local column = to.columns[tr] |
959 | N/A | > |
960 | 2765 | column[record.row] = data |
961 | N/A | > |
962 | 0 | local on_add = idr_hooks.on_add |
963 | 0 | if on_add then |
964 | 0 | on_add(entity) |
965 | N/A | end | >
966 | N/A | > |
967 | 1 | local on_set = idr_hooks.on_set |
968 | 0 | if on_set then |
969 | 0 | on_set(entity, data) |
970 | N/A | end | >
971 | N/A | end | >
972 | N/A | > |
973 | 121 | local function world_component(world: World): i53 |
974 | 0 | local id = (world.max_component_id :: number) + 1 |
975 | 0 | if id > HI_COMPONENT_ID then |
976 | N/A | -- IDs are partitioned into ranges because component IDs are not nominal, | >
977 | N/A | -- so it needs to error when IDs intersect into the entity range. | >
978 | 121 | error("Too many components, consider using world:entity() instead to create components.") |
979 | N/A | end | >
980 | 121 | world.max_component_id = id |
981 | N/A | > |
982 | 0 | return id |
983 | N/A | end | >
984 | N/A | > |
985 | 298 | local function world_remove(world: ecs_world_t, entity: i53, id: i53) |
986 | 298 | local entity_index = world.entity_index |
987 | 0 | local record = entity_index_try_get_fast(entity_index, entity) |
988 | 0 | if not record then |
989 | 298 | return |
990 | N/A | end | >
991 | 298 | local from = record.archetype |
992 | N/A | > |
993 | 0 | if not from then |
994 | 0 | return |
995 | N/A | end | >
996 | N/A | > |
997 | 296 | if from.records[id] then |
998 | 296 | local idr = world.component_index[id] |
999 | 3 | local on_remove = idr.hooks.on_remove |
1000 | 0 | if on_remove then |
1001 | 0 | on_remove(entity) |
1002 | N/A | end | >
1003 | N/A | > |
1004 | 296 | local to = archetype_traverse_remove(world, id, record.archetype) |
1005 | N/A | > |
1006 | 0 | entity_move(entity_index, entity, record, to) |
1007 | N/A | end | >
1008 | N/A | end | >
1009 | N/A | > |
1010 | 153 | local function archetype_fast_delete_last(columns: { Column }, column_count: number, types: { i53 }, entity: i53) |
1011 | 135 | for i, column in columns do |
1012 | 0 | if column ~= NULL_ARRAY then |
1013 | 0 | column[column_count] = nil |
1014 | N/A | end | >
1015 | N/A | end | >
1016 | N/A | end | >
1017 | N/A | > |
1018 | 109 | local function archetype_fast_delete(columns: { Column }, column_count: number, row, types, entity) |
1019 | 103 | for i, column in columns do |
1020 | 103 | if column ~= NULL_ARRAY then |
1021 | 0 | column[row] = column[column_count] |
1022 | 0 | column[column_count] = nil |
1023 | N/A | end | >
1024 | N/A | end | >
1025 | N/A | end | >
1026 | N/A | > |
1027 | 134 | local function archetype_delete(world: ecs_world_t, archetype: ecs_archetype_t, row: number) |
1028 | 134 | local entity_index = world.entity_index |
1029 | 134 | local component_index = world.component_index |
1030 | 134 | local columns = archetype.columns |
1031 | 134 | local id_types = archetype.types |
1032 | 134 | local entities = archetype.entities |
1033 | 134 | local column_count = #entities |
1034 | 0 | local last = #entities |
1035 | 134 | local move = entities[last] |
1036 | N/A | -- We assume first that the entity is the last in the archetype | >
1037 | 134 | local delete = move |
1038 | N/A | > |
1039 | 58 | if row ~= last then |
1040 | 58 | local record_to_move = entity_index_try_get_any(entity_index, move) |
1041 | 0 | if record_to_move then |
1042 | 0 | record_to_move.row = row |
1043 | N/A | end | >
1044 | N/A | > |
1045 | 0 | delete = entities[row] |
1046 | 0 | entities[row] = move |
1047 | N/A | end | >
1048 | N/A | > |
1049 | 262 | for _, id in id_types do |
1050 | 262 | local idr = component_index[id] |
1051 | 3 | local on_remove = idr.hooks.on_remove |
1052 | 0 | if on_remove then |
1053 | 0 | on_remove(delete) |
1054 | N/A | end | >
1055 | N/A | end | >
1056 | N/A | > |
1057 | 134 | entities[last] = nil :: any |
1058 | N/A | > |
1059 | 0 | if row == last then |
1060 | 58 | archetype_fast_delete_last(columns, column_count, id_types, delete) |
1061 | 0 | else |
1062 | 0 | archetype_fast_delete(columns, column_count, row, id_types, delete) |
1063 | N/A | end | >
1064 | N/A | end | >
1065 | N/A | > |
1066 | 6 | local function world_clear(world: ecs_world_t, entity: i53) |
1067 | 6 | local entity_index = world.entity_index |
1068 | 6 | local component_index = world.component_index |
1069 | 6 | local archetypes = world.archetypes |
1070 | 6 | local tgt = ECS_PAIR(EcsWildcard, entity) |
1071 | 6 | local idr_t = component_index[tgt] |
1072 | 6 | local idr = component_index[entity] |
1073 | 0 | local rel = ECS_PAIR(entity, EcsWildcard) |
1074 | 6 | local idr_r = component_index[rel] |
1075 | N/A | > |
1076 | 4 | if idr then |
1077 | 4 | local count = 0 |
1078 | 11 | local queue = {} |
1079 | 11 | for archetype_id in idr.cache do |
1080 | 11 | local idr_archetype = archetypes[archetype_id] |
1081 | 11 | local entities = idr_archetype.entities |
1082 | 11 | local n = #entities |
1083 | 0 | count += n |
1084 | 4 | table.move(entities, 1, n, #queue + 1, queue) |
1085 | N/A | end | >
1086 | 0 | for _, e in queue do |
1087 | 0 | world_remove(world, e, entity) |
1088 | N/A | end | >
1089 | N/A | end | >
1090 | N/A | > |
1091 | 0 | if idr_t then |
1092 | 0 | local queue |
1093 | 0 | local ids |
1094 | N/A | > |
1095 | 0 | local count = 0 |
1096 | 0 | local archetype_ids = idr_t.cache |
1097 | 0 | for archetype_id in archetype_ids do |
1098 | 0 | local idr_t_archetype = archetypes[archetype_id] |
1099 | 0 | local idr_t_types = idr_t_archetype.types |
1100 | 0 | local entities = idr_t_archetype.entities |
1101 | 0 | local removal_queued = false |
1102 | N/A | > |
1103 | 0 | for _, id in idr_t_types do |
1104 | 0 | if not ECS_IS_PAIR(id) then |
1105 | 0 | continue |
1106 | N/A | end | >
1107 | 0 | local object = entity_index_get_alive( |
1108 | 0 | entity_index, ECS_PAIR_SECOND(id)) |
1109 | 0 | if object ~= entity then |
1110 | 0 | continue |
1111 | N/A | end | >
1112 | 0 | if not ids then |
1113 | 0 | ids = {} |
1114 | N/A | end | >
1115 | 0 | ids[id] = true |
1116 | 0 | removal_queued = true |
1117 | N/A | end | >
1118 | N/A | > |
1119 | 0 | if not removal_queued then |
1120 | 0 | continue |
1121 | N/A | end | >
1122 | N/A | > |
1123 | 0 | if not queue then |
1124 | 0 | queue = {} |
1125 | N/A | end | >
1126 | N/A | > |
1127 | 0 | local n = #entities |
1128 | 0 | table.move(entities, 1, n, count + 1, queue) |
1129 | 0 | count += n |
1130 | N/A | end | >
1131 | N/A | > |
1132 | 0 | for id in ids do |
1133 | 0 | for _, child in queue do |
1134 | 0 | world_remove(world, child, id) |
1135 | N/A | end | >
1136 | N/A | end | >
1137 | N/A | end | >
1138 | N/A | > |
1139 | 1 | if idr_r then |
1140 | 1 | local count = 0 |
1141 | 1 | local archetype_ids = idr_r.cache |
1142 | 1 | local ids = {} |
1143 | 2 | local queue = {} |
1144 | 2 | for archetype_id in archetype_ids do |
1145 | 2 | local idr_r_archetype = archetypes[archetype_id] |
1146 | 2 | local entities = idr_r_archetype.entities |
1147 | 2 | local tr = idr_r_archetype.records[rel] |
1148 | 2 | local tr_count = idr_r_archetype.counts[rel] |
1149 | 2 | local types = idr_r_archetype.types |
1150 | 0 | for i = tr, tr + tr_count - 1 do |
1151 | 2 | ids[types[i]] = true |
1152 | N/A | end | >
1153 | 2 | local n = #entities |
1154 | 0 | table.move(entities, 1, n, count + 1, queue) |
1155 | 0 | count += n |
1156 | N/A | end | >
1157 | N/A | > |
1158 | 3 | for _, e in queue do |
1159 | 0 | for id in ids do |
1160 | 0 | world_remove(world, e, id) |
1161 | N/A | end | >
1162 | N/A | end | >
1163 | N/A | end | >
1164 | N/A | end | >
1165 | N/A | > |
1166 | 50 | local function archetype_disconnect_edge(edge: ecs_graph_edge_t) |
1167 | 50 | local edge_next = edge.next |
1168 | 19 | local edge_prev = edge.prev |
1169 | 0 | if edge_next then |
1170 | 50 | edge_next.prev = edge_prev |
1171 | N/A | end | >
1172 | 0 | if edge_prev then |
1173 | 0 | edge_prev.next = edge_next |
1174 | N/A | end | >
1175 | N/A | end | >
1176 | N/A | > |
1177 | 23 | local function archetype_remove_edge(edges: ecs_graph_edges_t, id: i53, edge: ecs_graph_edge_t) |
1178 | 0 | archetype_disconnect_edge(edge) |
1179 | 0 | edges[id] = nil :: any |
1180 | N/A | end | >
1181 | N/A | > |
1182 | 36 | local function archetype_clear_edges(archetype: ecs_archetype_t) |
1183 | 36 | local add: ecs_graph_edges_t = archetype.add |
1184 | 36 | local remove: ecs_graph_edges_t = archetype.remove |
1185 | 9 | local node_refs = archetype.refs |
1186 | 9 | for id, edge in add do |
1187 | 0 | archetype_disconnect_edge(edge) |
1188 | 36 | add[id] = nil :: any |
1189 | N/A | end | >
1190 | 18 | for id, edge in remove do |
1191 | 0 | archetype_disconnect_edge(edge) |
1192 | 0 | remove[id] = nil :: any |
1193 | N/A | end | >
1194 | N/A | > |
1195 | 22 | local cur = node_refs.next |
1196 | 22 | while cur do |
1197 | 22 | local edge = cur :: ecs_graph_edge_t |
1198 | 22 | local next_edge = edge.next |
1199 | 0 | archetype_remove_edge(edge.from.add, edge.id, edge) |
1200 | 0 | cur = next_edge |
1201 | N/A | end | >
1202 | N/A | > |
1203 | 1 | cur = node_refs.prev |
1204 | 1 | while cur do |
1205 | 1 | local edge: ecs_graph_edge_t = cur |
1206 | 1 | local next_edge = edge.prev |
1207 | 0 | archetype_remove_edge(edge.from.remove, edge.id, edge) |
1208 | 0 | cur = next_edge |
1209 | N/A | end | >
1210 | N/A | > |
1211 | 0 | node_refs.next = nil |
1212 | 0 | node_refs.prev = nil |
1213 | N/A | end | >
1214 | N/A | > |
1215 | 1 | local function archetype_destroy(world: ecs_world_t, archetype: ecs_archetype_t) |
1216 | 0 | if archetype == world.ROOT_ARCHETYPE then |
1217 | 0 | return |
1218 | N/A | end | >
1219 | N/A | > |
1220 | 36 | local component_index = world.component_index |
1221 | 36 | archetype_clear_edges(archetype) |
1222 | 36 | local archetype_id = archetype.id |
1223 | 36 | world.archetypes[archetype_id] = nil :: any |
1224 | 0 | world.archetype_index[archetype.type] = nil :: any |
1225 | 36 | local records = archetype.records |
1226 | N/A | > |
1227 | 113 | for id in records do |
1228 | 0 | local observer_list = find_observers(world, EcsOnArchetypeDelete, id) |
1229 | 0 | if not observer_list then |
1230 | 2 | continue |
1231 | N/A | end | >
1232 | 1 | for _, observer in observer_list do |
1233 | 0 | if query_match(observer.query, archetype) then |
1234 | 0 | observer.callback(archetype) |
1235 | N/A | end | >
1236 | N/A | end | >
1237 | N/A | end | >
1238 | N/A | > |
1239 | 113 | for id in records do |
1240 | 113 | local idr = component_index[id] |
1241 | 113 | idr.cache[archetype_id] = nil :: any |
1242 | 113 | idr.counts[archetype_id] = nil |
1243 | 113 | idr.size -= 1 |
1244 | 0 | records[id] = nil :: any |
1245 | 0 | if idr.size == 0 then |
1246 | 0 | component_index[id] = nil :: any |
1247 | N/A | end | >
1248 | N/A | end | >
1249 | N/A | end | >
1250 | N/A | > |
1251 | 0 | local function world_cleanup(world: ecs_world_t) |
1252 | 1 | local archetypes = world.archetypes |
1253 | N/A | > |
1254 | 4 | for _, archetype in archetypes do |
1255 | 0 | if #archetype.entities == 0 then |
1256 | 0 | archetype_destroy(world, archetype) |
1257 | N/A | end | >
1258 | N/A | end | >
1259 | N/A | > |
1260 | 0 | local new_archetypes = table.create(#archetypes) :: { ecs_archetype_t } |
1261 | 1 | local new_archetype_map = {} |
1262 | N/A | > |
1263 | 6 | for index, archetype in archetypes do |
1264 | 0 | new_archetypes[index] = archetype |
1265 | 0 | new_archetype_map[archetype.type] = archetype |
1266 | N/A | end | >
1267 | N/A | > |
1268 | 0 | world.archetypes = new_archetypes |
1269 | 0 | world.archetype_index = new_archetype_map |
1270 | N/A | end | >
1271 | N/A | > |
1272 | 65684 | local function world_delete(world: ecs_world_t, entity: i53) |
1273 | 65684 | local entity_index = world.entity_index |
1274 | 1 | local record = entity_index_try_get(entity_index, entity) |
1275 | 0 | if not record then |
1276 | 0 | return |
1277 | N/A | end | >
1278 | N/A | > |
1279 | 0 | local archetype = record.archetype |
1280 | 65683 | local row = record.row |
1281 | N/A | > |
1282 | 0 | if archetype then |
1283 | N/A | -- In the future should have a destruct mode for | >
1284 | N/A | -- deleting archetypes themselves. Maybe requires recycling | >
1285 | 0 | archetype_delete(world, archetype, row) |
1286 | N/A | end | >
1287 | N/A | > |
1288 | 65683 | local delete = entity |
1289 | 65683 | local component_index = world.component_index |
1290 | 65683 | local archetypes = world.archetypes |
1291 | 0 | local tgt = ECS_PAIR(EcsWildcard, delete) |
1292 | 65683 | local rel = ECS_PAIR(delete, EcsWildcard) |
1293 | N/A | > |
1294 | 65683 | local idr_t = component_index[tgt] |
1295 | 0 | local idr = component_index[delete] |
1296 | 65683 | local idr_r = component_index[rel] |
1297 | N/A | > |
1298 | 8 | if idr then |
1299 | 1 | local flags = idr.flags |
1300 | 1 | if bit32.band(flags, ECS_ID_DELETE) ~= 0 then |
1301 | 0 | for archetype_id in idr.cache do |
1302 | 1 | local idr_archetype = archetypes[archetype_id] |
1303 | N/A | > |
1304 | 1 | local entities = idr_archetype.entities |
1305 | 2 | local n = #entities |
1306 | 0 | for i = n, 1, -1 do |
1307 | 0 | world_delete(world, entities[i]) |
1308 | N/A | end | >
1309 | N/A | > |
1310 | 0 | archetype_destroy(world, idr_archetype) |
1311 | N/A | end | >
1312 | 12 | else |
1313 | 12 | for archetype_id in idr.cache do |
1314 | 12 | local idr_archetype = archetypes[archetype_id] |
1315 | 12 | local entities = idr_archetype.entities |
1316 | 10 | local n = #entities |
1317 | 0 | for i = n, 1, -1 do |
1318 | 0 | world_remove(world, entities[i], delete) |
1319 | N/A | end | >
1320 | N/A | > |
1321 | 0 | archetype_destroy(world, idr_archetype) |
1322 | N/A | end | >
1323 | N/A | end | >
1324 | N/A | end | >
1325 | N/A | > |
1326 | 13 | if idr_t then |
1327 | 0 | local children |
1328 | 13 | local ids |
1329 | N/A | > |
1330 | 13 | local count = 0 |
1331 | 18 | local archetype_ids = idr_t.cache |
1332 | 18 | for archetype_id in archetype_ids do |
1333 | 18 | local idr_t_archetype = archetypes[archetype_id] |
1334 | 18 | local idr_t_types = idr_t_archetype.types |
1335 | 0 | local entities = idr_t_archetype.entities |
1336 | 18 | local removal_queued = false |
1337 | N/A | > |
1338 | 0 | for _, id in idr_t_types do |
1339 | 0 | if not ECS_IS_PAIR(id) then |
1340 | 24 | continue |
1341 | N/A | end | >
1342 | 24 | local object = entity_index_get_alive( |
1343 | 0 | entity_index, ECS_PAIR_SECOND(id)) |
1344 | 0 | if object ~= delete then |
1345 | 20 | continue |
1346 | N/A | end | >
1347 | 20 | local id_record = component_index[id] |
1348 | 20 | local flags = id_record.flags |
1349 | 8 | local flags_delete_mask: number = bit32.band(flags, ECS_ID_DELETE) |
1350 | 15 | if flags_delete_mask ~= 0 then |
1351 | 15 | for i = #entities, 1, -1 do |
1352 | 0 | local child = entities[i] |
1353 | 8 | world_delete(world, child) |
1354 | N/A | end | >
1355 | 12 | break |
1356 | 6 | else |
1357 | 0 | if not ids then |
1358 | 12 | ids = {} |
1359 | N/A | end | >
1360 | 0 | ids[id] = true |
1361 | 0 | removal_queued = true |
1362 | N/A | end | >
1363 | N/A | end | >
1364 | N/A | > |
1365 | 0 | if not removal_queued then |
1366 | 10 | continue |
1367 | N/A | end | >
1368 | 0 | if not children then |
1369 | 10 | children = {} |
1370 | N/A | end | >
1371 | 10 | local n = #entities |
1372 | 0 | table.move(entities, 1, n, count + 1, children) |
1373 | 0 | count += n |
1374 | N/A | end | >
1375 | N/A | > |
1376 | 17 | if ids then |
1377 | 19 | for _, child in children do |
1378 | 0 | for id in ids do |
1379 | 0 | world_remove(world, child, id) |
1380 | N/A | end | >
1381 | N/A | end | >
1382 | N/A | end | >
1383 | N/A | > |
1384 | 0 | for archetype_id in archetype_ids do |
1385 | 0 | archetype_destroy(world, archetypes[archetype_id]) |
1386 | N/A | end | >
1387 | N/A | end | >
1388 | N/A | > |
1389 | 0 | if idr_r then |
1390 | 0 | local archetype_ids = idr_r.cache |
1391 | 0 | local flags = idr_r.flags |
1392 | 0 | if bit32.band(flags, ECS_ID_DELETE) ~= 0 then |
1393 | 0 | for archetype_id in archetype_ids do |
1394 | 0 | local idr_r_archetype = archetypes[archetype_id] |
1395 | 0 | local entities = idr_r_archetype.entities |
1396 | 0 | local n = #entities |
1397 | 0 | for i = n, 1, -1 do |
1398 | 0 | world_delete(world, entities[i]) |
1399 | N/A | end | >
1400 | 0 | archetype_destroy(world, idr_r_archetype) |
1401 | N/A | end | >
1402 | 0 | else |
1403 | 0 | local children = {} |
1404 | 0 | local count = 0 |
1405 | 0 | local ids = {} |
1406 | 0 | for archetype_id in archetype_ids do |
1407 | 0 | local idr_r_archetype = archetypes[archetype_id] |
1408 | 0 | local entities = idr_r_archetype.entities |
1409 | 0 | local tr = idr_r_archetype.records[rel] |
1410 | 0 | local tr_count = idr_r_archetype.counts[rel] |
1411 | 0 | local types = idr_r_archetype.types |
1412 | 0 | for i = tr, tr_count - 1 do |
1413 | 0 | ids[types[tr]] = true |
1414 | N/A | end | >
1415 | 0 | local n = #entities |
1416 | 0 | table.move(entities, 1, n, count + 1, children) |
1417 | 0 | count += n |
1418 | N/A | end | >
1419 | N/A | > |
1420 | 0 | for _, child in children do |
1421 | 0 | for id in ids do |
1422 | 0 | world_remove(world, child, id) |
1423 | N/A | end | >
1424 | N/A | end | >
1425 | N/A | > |
1426 | 0 | for archetype_id in archetype_ids do |
1427 | 0 | archetype_destroy(world, archetypes[archetype_id]) |
1428 | N/A | end | >
1429 | N/A | end | >
1430 | N/A | end | >
1431 | N/A | > |
1432 | 65683 | local dense_array = entity_index.dense_array |
1433 | 65683 | local index_of_deleted_entity = record.dense |
1434 | 0 | local index_of_last_alive_entity = entity_index.alive_count |
1435 | 65683 | entity_index.alive_count = index_of_last_alive_entity - 1 |
1436 | N/A | > |
1437 | 65683 | local last_alive_entity = dense_array[index_of_last_alive_entity] |
1438 | 65683 | local r_swap = entity_index_try_get_any(entity_index, last_alive_entity) :: ecs_record_t |
1439 | 65683 | r_swap.dense = index_of_deleted_entity |
1440 | 65683 | record.archetype = nil :: any |
1441 | 0 | record.row = nil :: any |
1442 | 65683 | record.dense = index_of_last_alive_entity |
1443 | N/A | > |
1444 | 0 | dense_array[index_of_deleted_entity] = last_alive_entity |
1445 | 0 | dense_array[index_of_last_alive_entity] = ECS_GENERATION_INC(entity) |
1446 | N/A | end | >
1447 | N/A | > |
1448 | 0 | local function world_contains(world: ecs_world_t, entity): boolean |
1449 | 0 | return entity_index_is_alive(world.entity_index, entity) |
1450 | N/A | end | >
1451 | N/A | > |
1452 | 0 | local function NOOP() end |
1453 | N/A | > |
1454 | 0 | export type QueryInner = { |
1455 | 0 | compatible_archetypes: { Archetype }, |
1456 | 0 | ids: { i53 }, |
1457 | 0 | filter_with: { i53 }, |
1458 | 0 | filter_without: { i53 }, |
1459 | 0 | next: () -> (number, ...any), |
1460 | 0 | world: World, |
1461 | 1 | } |
1462 | N/A | > |
1463 | 0 | local function query_iter_init(query: ecs_query_data_t): () -> (number, ...any) |
1464 | 26 | local world_query_iter_next |
1465 | N/A | > |
1466 | 26 | local compatible_archetypes = query.compatible_archetypes |
1467 | 26 | local lastArchetype = 1 |
1468 | 4 | local archetype = compatible_archetypes[1] |
1469 | 0 | if not archetype then |
1470 | 22 | return NOOP :: () -> (number, ...any) |
1471 | N/A | end | >
1472 | 22 | local columns = archetype.columns |
1473 | 22 | local entities = archetype.entities |
1474 | 0 | local i = #entities |
1475 | 22 | local records = archetype.records |
1476 | N/A | > |
1477 | 22 | local ids = query.ids |
1478 | 22 | local A, B, C, D, E, F, G, H, I = unpack(ids) |
1479 | 0 | local a: Column, b: Column, c: Column, d: Column |
1480 | 22 | local e: Column, f: Column, g: Column, h: Column |
1481 | N/A | > |
1482 | 5 | if not B then |
1483 | 3 | a = columns[records[A]] |
1484 | 3 | elseif not C then |
1485 | 2 | a = columns[records[A]] |
1486 | 0 | b = columns[records[B]] |
1487 | 0 | elseif not D then |
1488 | 0 | a = columns[records[A]] |
1489 | 2 | b = columns[records[B]] |
1490 | 1 | c = columns[records[C]] |
1491 | 1 | elseif not E then |
1492 | 1 | a = columns[records[A]] |
1493 | 1 | b = columns[records[B]] |
1494 | 1 | c = columns[records[C]] |
1495 | 0 | d = columns[records[D]] |
1496 | 0 | elseif not F then |
1497 | 0 | a = columns[records[A]] |
1498 | 0 | b = columns[records[B]] |
1499 | 0 | c = columns[records[C]] |
1500 | 1 | d = columns[records[D]] |
1501 | 0 | e = columns[records[E]] |
1502 | 0 | elseif not G then |
1503 | 0 | a = columns[records[A]] |
1504 | 0 | b = columns[records[B]] |
1505 | 0 | c = columns[records[C]] |
1506 | 0 | d = columns[records[D]] |
1507 | 1 | e = columns[records[E]] |
1508 | 0 | f = columns[records[F]] |
1509 | 0 | elseif not H then |
1510 | 0 | a = columns[records[A]] |
1511 | 0 | b = columns[records[B]] |
1512 | 0 | c = columns[records[C]] |
1513 | 0 | d = columns[records[D]] |
1514 | 0 | e = columns[records[E]] |
1515 | 1 | f = columns[records[F]] |
1516 | 0 | g = columns[records[G]] |
1517 | 0 | elseif not I then |
1518 | 0 | a = columns[records[A]] |
1519 | 0 | b = columns[records[B]] |
1520 | 0 | c = columns[records[C]] |
1521 | 0 | d = columns[records[D]] |
1522 | 0 | e = columns[records[E]] |
1523 | 0 | f = columns[records[F]] |
1524 | 0 | g = columns[records[G]] |
1525 | 0 | h = columns[records[H]] |
1526 | N/A | end | >
1527 | N/A | > |
1528 | 556 | if not B then |
1529 | 556 | function world_query_iter_next(): any |
1530 | 26 | local entity = entities[i] |
1531 | 26 | while entity == nil do |
1532 | 26 | lastArchetype += 1 |
1533 | 18 | archetype = compatible_archetypes[lastArchetype] |
1534 | 0 | if not archetype then |
1535 | 0 | return nil |
1536 | N/A | end | >
1537 | N/A | > |
1538 | 8 | entities = archetype.entities |
1539 | 0 | i = #entities |
1540 | 0 | if i == 0 then |
1541 | 8 | continue |
1542 | N/A | end | >
1543 | 8 | entity = entities[i] |
1544 | 8 | columns = archetype.columns |
1545 | 0 | records = archetype.records |
1546 | 0 | a = columns[records[A]] |
1547 | N/A | end | >
1548 | N/A | > |
1549 | 0 | local row = i |
1550 | 538 | i -= 1 |
1551 | N/A | > |
1552 | 5 | return entity, a[row] |
1553 | N/A | end | >
1554 | 7 | elseif not C then |
1555 | 7 | function world_query_iter_next(): any |
1556 | 3 | local entity = entities[i] |
1557 | 3 | while entity == nil do |
1558 | 3 | lastArchetype += 1 |
1559 | 3 | archetype = compatible_archetypes[lastArchetype] |
1560 | 0 | if not archetype then |
1561 | 0 | return nil |
1562 | N/A | end | >
1563 | N/A | > |
1564 | 0 | entities = archetype.entities |
1565 | 0 | i = #entities |
1566 | 0 | if i == 0 then |
1567 | 0 | continue |
1568 | N/A | end | >
1569 | 0 | entity = entities[i] |
1570 | 0 | columns = archetype.columns |
1571 | 0 | records = archetype.records |
1572 | 0 | a = columns[records[A]] |
1573 | 0 | b = columns[records[B]] |
1574 | N/A | end | >
1575 | N/A | > |
1576 | 0 | local row = i |
1577 | 4 | i -= 1 |
1578 | N/A | > |
1579 | 2 | return entity, a[row], b[row] |
1580 | N/A | end | >
1581 | 0 | elseif not D then |
1582 | 0 | function world_query_iter_next(): any |
1583 | 0 | local entity = entities[i] |
1584 | 0 | while entity == nil do |
1585 | 0 | lastArchetype += 1 |
1586 | 0 | archetype = compatible_archetypes[lastArchetype] |
1587 | 0 | if not archetype then |
1588 | 0 | return nil |
1589 | N/A | end | >
1590 | N/A | > |
1591 | 0 | entities = archetype.entities |
1592 | 0 | i = #entities |
1593 | 0 | if i == 0 then |
1594 | 0 | continue |
1595 | N/A | end | >
1596 | 0 | entity = entities[i] |
1597 | 0 | columns = archetype.columns |
1598 | 0 | records = archetype.records |
1599 | 0 | a = columns[records[A]] |
1600 | 0 | b = columns[records[B]] |
1601 | 0 | c = columns[records[C]] |
1602 | N/A | end | >
1603 | N/A | > |
1604 | 0 | local row = i |
1605 | 0 | i -= 1 |
1606 | N/A | > |
1607 | 2 | return entity, a[row], b[row], c[row] |
1608 | N/A | end | >
1609 | 2 | elseif not E then |
1610 | 2 | function world_query_iter_next(): any |
1611 | 1 | local entity = entities[i] |
1612 | 1 | while entity == nil do |
1613 | 1 | lastArchetype += 1 |
1614 | 1 | archetype = compatible_archetypes[lastArchetype] |
1615 | 0 | if not archetype then |
1616 | 0 | return nil |
1617 | N/A | end | >
1618 | N/A | > |
1619 | 0 | entities = archetype.entities |
1620 | 0 | i = #entities |
1621 | 0 | if i == 0 then |
1622 | 0 | continue |
1623 | N/A | end | >
1624 | 0 | entity = entities[i] |
1625 | 0 | columns = archetype.columns |
1626 | 0 | records = archetype.records |
1627 | 0 | a = columns[records[A]] |
1628 | 0 | b = columns[records[B]] |
1629 | 0 | c = columns[records[C]] |
1630 | 0 | d = columns[records[D]] |
1631 | N/A | end | >
1632 | N/A | > |
1633 | 0 | local row = i |
1634 | 1 | i -= 1 |
1635 | N/A | > |
1636 | 1 | return entity, a[row], b[row], c[row], d[row] |
1637 | N/A | end | >
1638 | 0 | elseif not F then |
1639 | 0 | function world_query_iter_next(): any |
1640 | 0 | local entity = entities[i] |
1641 | 0 | while entity == nil do |
1642 | 0 | lastArchetype += 1 |
1643 | 0 | archetype = compatible_archetypes[lastArchetype] |
1644 | 0 | if not archetype then |
1645 | 0 | return nil |
1646 | N/A | end | >
1647 | N/A | > |
1648 | 0 | entities = archetype.entities |
1649 | 0 | i = #entities |
1650 | 0 | if i == 0 then |
1651 | 0 | continue |
1652 | N/A | end | >
1653 | 0 | entity = entities[i] |
1654 | 0 | columns = archetype.columns |
1655 | 0 | records = archetype.records |
1656 | 0 | a = columns[records[A]] |
1657 | 0 | b = columns[records[B]] |
1658 | 0 | c = columns[records[C]] |
1659 | 0 | d = columns[records[D]] |
1660 | 0 | e = columns[records[E]] |
1661 | N/A | end | >
1662 | N/A | > |
1663 | 0 | local row = i |
1664 | 0 | i -= 1 |
1665 | N/A | > |
1666 | 1 | return entity, a[row], b[row], c[row], d[row], e[row] |
1667 | N/A | end | >
1668 | 0 | elseif not G then |
1669 | 0 | function world_query_iter_next(): any |
1670 | 0 | local entity = entities[i] |
1671 | 0 | while entity == nil do |
1672 | 0 | lastArchetype += 1 |
1673 | 0 | archetype = compatible_archetypes[lastArchetype] |
1674 | 0 | if not archetype then |
1675 | 0 | return nil |
1676 | N/A | end | >
1677 | N/A | > |
1678 | 0 | entities = archetype.entities |
1679 | 0 | i = #entities |
1680 | 0 | if i == 0 then |
1681 | 0 | continue |
1682 | N/A | end | >
1683 | 0 | entity = entities[i] |
1684 | 0 | columns = archetype.columns |
1685 | 0 | records = archetype.records |
1686 | 0 | a = columns[records[A]] |
1687 | 0 | b = columns[records[B]] |
1688 | 0 | c = columns[records[C]] |
1689 | 0 | d = columns[records[D]] |
1690 | 0 | e = columns[records[E]] |
1691 | 0 | f = columns[records[F]] |
1692 | N/A | end | >
1693 | N/A | > |
1694 | 0 | local row = i |
1695 | 0 | i -= 1 |
1696 | N/A | > |
1697 | 1 | return entity, a[row], b[row], c[row], d[row], e[row], f[row] |
1698 | N/A | end | >
1699 | 0 | elseif not H then |
1700 | 0 | function world_query_iter_next(): any |
1701 | 0 | local entity = entities[i] |
1702 | 0 | while entity == nil do |
1703 | 0 | lastArchetype += 1 |
1704 | 0 | archetype = compatible_archetypes[lastArchetype] |
1705 | 0 | if not archetype then |
1706 | 0 | return nil |
1707 | N/A | end | >
1708 | N/A | > |
1709 | 0 | entities = archetype.entities |
1710 | 0 | i = #entities |
1711 | 0 | if i == 0 then |
1712 | 0 | continue |
1713 | N/A | end | >
1714 | 0 | entity = entities[i] |
1715 | 0 | columns = archetype.columns |
1716 | 0 | records = archetype.records |
1717 | 0 | a = columns[records[A]] |
1718 | 0 | b = columns[records[B]] |
1719 | 0 | c = columns[records[C]] |
1720 | 0 | d = columns[records[D]] |
1721 | 0 | e = columns[records[E]] |
1722 | 0 | f = columns[records[F]] |
1723 | 0 | g = columns[records[G]] |
1724 | N/A | end | >
1725 | N/A | > |
1726 | 0 | local row = i |
1727 | 0 | i -= 1 |
1728 | N/A | > |
1729 | 1 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row] |
1730 | N/A | end | >
1731 | 0 | elseif not I then |
1732 | 0 | function world_query_iter_next(): any |
1733 | 0 | local entity = entities[i] |
1734 | 0 | while entity == nil do |
1735 | 0 | lastArchetype += 1 |
1736 | 0 | archetype = compatible_archetypes[lastArchetype] |
1737 | 0 | if not archetype then |
1738 | 0 | return nil |
1739 | N/A | end | >
1740 | N/A | > |
1741 | 0 | entities = archetype.entities |
1742 | 0 | i = #entities |
1743 | 0 | if i == 0 then |
1744 | 0 | continue |
1745 | N/A | end | >
1746 | 0 | entity = entities[i] |
1747 | 0 | columns = archetype.columns |
1748 | 0 | records = archetype.records |
1749 | 0 | a = columns[records[A]] |
1750 | 0 | b = columns[records[B]] |
1751 | 0 | c = columns[records[C]] |
1752 | 0 | d = columns[records[D]] |
1753 | 0 | e = columns[records[E]] |
1754 | 0 | f = columns[records[F]] |
1755 | 0 | g = columns[records[G]] |
1756 | 0 | h = columns[records[H]] |
1757 | N/A | end | >
1758 | N/A | > |
1759 | 0 | local row = i |
1760 | 0 | i -= 1 |
1761 | N/A | > |
1762 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row] |
1763 | N/A | end | >
1764 | 1 | else |
1765 | 2 | local output = {} |
1766 | 2 | function world_query_iter_next(): any |
1767 | 1 | local entity = entities[i] |
1768 | 1 | while entity == nil do |
1769 | 1 | lastArchetype += 1 |
1770 | 1 | archetype = compatible_archetypes[lastArchetype] |
1771 | 0 | if not archetype then |
1772 | 0 | return nil |
1773 | N/A | end | >
1774 | N/A | > |
1775 | 0 | entities = archetype.entities |
1776 | 0 | i = #entities |
1777 | 0 | if i == 0 then |
1778 | 0 | continue |
1779 | N/A | end | >
1780 | 0 | entity = entities[i] |
1781 | 0 | columns = archetype.columns |
1782 | 0 | records = archetype.records |
1783 | N/A | end | >
1784 | N/A | > |
1785 | 0 | local row = i |
1786 | 1 | i -= 1 |
1787 | N/A | > |
1788 | 0 | for j, id in ids do |
1789 | 0 | output[j] = columns[records[id]][row] |
1790 | N/A | end | >
1791 | N/A | > |
1792 | 0 | return entity, unpack(output) |
1793 | N/A | end | >
1794 | N/A | end | >
1795 | N/A | > |
1796 | 0 | query.next = world_query_iter_next |
1797 | 0 | return world_query_iter_next |
1798 | N/A | end | >
1799 | N/A | > |
1800 | 20 | local function query_iter(query): () -> (number, ...any) |
1801 | 19 | local query_next = query.next |
1802 | 0 | if not query_next then |
1803 | 20 | query_next = query_iter_init(query) |
1804 | N/A | end | >
1805 | 0 | return query_next |
1806 | N/A | end | >
1807 | N/A | > |
1808 | 6 | local function query_without(query: ecs_query_data_t, ...: i53) |
1809 | 6 | local without = { ... } |
1810 | 6 | query.filter_without = without |
1811 | 3 | local compatible_archetypes = query.compatible_archetypes |
1812 | 3 | for i = #compatible_archetypes, 1, -1 do |
1813 | 3 | local archetype = compatible_archetypes[i] |
1814 | 0 | local records = archetype.records |
1815 | 3 | local matches = true |
1816 | N/A | > |
1817 | 2 | for _, id in without do |
1818 | 2 | if records[id] then |
1819 | 0 | matches = false |
1820 | 0 | break |
1821 | N/A | end | >
1822 | N/A | end | >
1823 | N/A | > |
1824 | 0 | if matches then |
1825 | 0 | continue |
1826 | N/A | end | >
1827 | N/A | > |
1828 | 0 | local last = #compatible_archetypes |
1829 | 0 | if last ~= i then |
1830 | 2 | compatible_archetypes[i] = compatible_archetypes[last] |
1831 | N/A | end | >
1832 | 0 | compatible_archetypes[last] = nil :: any |
1833 | N/A | end | >
1834 | N/A | > |
1835 | 0 | return query :: any |
1836 | N/A | end | >
1837 | N/A | > |
1838 | 1 | local function query_with(query: ecs_query_data_t, ...: i53) |
1839 | 1 | local compatible_archetypes = query.compatible_archetypes |
1840 | 0 | local with = { ... } |
1841 | 1 | query.filter_with = with |
1842 | N/A | > |
1843 | 0 | for i = #compatible_archetypes, 1, -1 do |
1844 | 0 | local archetype = compatible_archetypes[i] |
1845 | 0 | local records = archetype.records |
1846 | 0 | local matches = true |
1847 | N/A | > |
1848 | 0 | for _, id in with do |
1849 | 0 | if not records[id] then |
1850 | 0 | matches = false |
1851 | 0 | break |
1852 | N/A | end | >
1853 | N/A | end | >
1854 | N/A | > |
1855 | 0 | if matches then |
1856 | 0 | continue |
1857 | N/A | end | >
1858 | N/A | > |
1859 | 0 | local last = #compatible_archetypes |
1860 | 0 | if last ~= i then |
1861 | 0 | compatible_archetypes[i] = compatible_archetypes[last] |
1862 | N/A | end | >
1863 | 0 | compatible_archetypes[last] = nil :: any |
1864 | N/A | end | >
1865 | N/A | > |
1866 | 0 | return query :: any |
1867 | N/A | end | >
1868 | N/A | > |
1869 | N/A | -- Meant for directly iterating over archetypes to minimize | >
1870 | N/A | -- function call overhead. Should not be used unless iterating over | >
1871 | N/A | -- hundreds of thousands of entities in bulk. | >
1872 | 0 | local function query_archetypes(query) |
1873 | 0 | return query.compatible_archetypes |
1874 | N/A | end | >
1875 | N/A | > |
1876 | 6 | local function query_cached(query: ecs_query_data_t) |
1877 | 6 | local with = query.filter_with |
1878 | 1 | local ids = query.ids |
1879 | 0 | if with then |
1880 | 5 | table.move(ids, 1, #ids, #with + 1, with) |
1881 | 0 | else |
1882 | 0 | query.filter_with = ids |
1883 | N/A | end | >
1884 | N/A | > |
1885 | 0 | local compatible_archetypes = query.compatible_archetypes |
1886 | 6 | local lastArchetype = 1 |
1887 | N/A | > |
1888 | 6 | local A, B, C, D, E, F, G, H, I = unpack(ids) |
1889 | 0 | local a: Column, b: Column, c: Column, d: Column |
1890 | 6 | local e: Column, f: Column, g: Column, h: Column |
1891 | N/A | > |
1892 | 6 | local world_query_iter_next |
1893 | 6 | local columns: { Column } |
1894 | 6 | local entities: { number } |
1895 | 6 | local i: number |
1896 | 6 | local archetype: ecs_archetype_t |
1897 | 0 | local records: { number } |
1898 | 6 | local archetypes = query.compatible_archetypes |
1899 | N/A | > |
1900 | 0 | local world = query.world :: { observable: ecs_observable_t } |
1901 | N/A | -- Only need one observer for EcsArchetypeCreate and EcsArchetypeDelete respectively | >
1902 | N/A | -- because the event will be emitted for all components of that Archetype. | >
1903 | 6 | local observable = world.observable :: ecs_observable_t |
1904 | 6 | local on_create_action = observable[EcsOnArchetypeCreate] |
1905 | 6 | if not on_create_action then |
1906 | 0 | on_create_action = {} |
1907 | 6 | observable[EcsOnArchetypeCreate] = on_create_action |
1908 | N/A | end | >
1909 | 6 | local query_cache_on_create = on_create_action[A] |
1910 | 6 | if not query_cache_on_create then |
1911 | 0 | query_cache_on_create = {} |
1912 | 0 | on_create_action[A] = query_cache_on_create |
1913 | N/A | end | >
1914 | N/A | > |
1915 | 6 | local on_delete_action = observable[EcsOnArchetypeDelete] |
1916 | 6 | if not on_delete_action then |
1917 | 0 | on_delete_action = {} |
1918 | 6 | observable[EcsOnArchetypeDelete] = on_delete_action |
1919 | N/A | end | >
1920 | 6 | local query_cache_on_delete = on_delete_action[A] |
1921 | 6 | if not query_cache_on_delete then |
1922 | 0 | query_cache_on_delete = {} |
1923 | 0 | on_delete_action[A] = query_cache_on_delete |
1924 | N/A | end | >
1925 | N/A | > |
1926 | 0 | local function on_create_callback(archetype) |
1927 | 0 | table.insert(archetypes, archetype) |
1928 | N/A | end | >
1929 | N/A | > |
1930 | 1 | local function on_delete_callback(archetype) |
1931 | 1 | local i = table.find(archetypes, archetype) :: number |
1932 | 1 | local n = #archetypes |
1933 | 0 | archetypes[i] = archetypes[n] |
1934 | 0 | archetypes[n] = nil |
1935 | N/A | end | >
1936 | N/A | > |
1937 | 0 | local observer_for_create = { query = query, callback = on_create_callback } |
1938 | 6 | local observer_for_delete = { query = query, callback = on_delete_callback } |
1939 | N/A | > |
1940 | 0 | table.insert(query_cache_on_create, observer_for_create) |
1941 | 6 | table.insert(query_cache_on_delete, observer_for_delete) |
1942 | N/A | > |
1943 | 11 | local function cached_query_iter() |
1944 | 11 | lastArchetype = 1 |
1945 | 1 | archetype = compatible_archetypes[lastArchetype] |
1946 | 0 | if not archetype then |
1947 | 10 | return NOOP |
1948 | N/A | end | >
1949 | 10 | entities = archetype.entities |
1950 | 10 | i = #entities |
1951 | 10 | records = archetype.records |
1952 | 6 | columns = archetype.columns |
1953 | 4 | if not B then |
1954 | 4 | a = columns[records[A]] |
1955 | 4 | elseif not C then |
1956 | 0 | a = columns[records[A]] |
1957 | 0 | b = columns[records[B]] |
1958 | 0 | elseif not D then |
1959 | 0 | a = columns[records[A]] |
1960 | 0 | b = columns[records[B]] |
1961 | 0 | c = columns[records[C]] |
1962 | 0 | elseif not E then |
1963 | 0 | a = columns[records[A]] |
1964 | 0 | b = columns[records[B]] |
1965 | 0 | c = columns[records[C]] |
1966 | 0 | d = columns[records[D]] |
1967 | 0 | elseif not F then |
1968 | 0 | a = columns[records[A]] |
1969 | 0 | b = columns[records[B]] |
1970 | 0 | c = columns[records[C]] |
1971 | 0 | d = columns[records[D]] |
1972 | 0 | e = columns[records[E]] |
1973 | 0 | elseif not G then |
1974 | 0 | a = columns[records[A]] |
1975 | 0 | b = columns[records[B]] |
1976 | 0 | c = columns[records[C]] |
1977 | 0 | d = columns[records[D]] |
1978 | 0 | e = columns[records[E]] |
1979 | 0 | f = columns[records[F]] |
1980 | 0 | elseif not H then |
1981 | 0 | a = columns[records[A]] |
1982 | 0 | b = columns[records[B]] |
1983 | 0 | c = columns[records[C]] |
1984 | 0 | d = columns[records[D]] |
1985 | 0 | e = columns[records[E]] |
1986 | 0 | f = columns[records[F]] |
1987 | 0 | g = columns[records[G]] |
1988 | 0 | elseif not I then |
1989 | 0 | a = columns[records[A]] |
1990 | 0 | b = columns[records[B]] |
1991 | 0 | c = columns[records[C]] |
1992 | 0 | d = columns[records[D]] |
1993 | 0 | e = columns[records[E]] |
1994 | 0 | f = columns[records[F]] |
1995 | 0 | g = columns[records[G]] |
1996 | 0 | h = columns[records[H]] |
1997 | N/A | end | >
1998 | N/A | > |
1999 | 0 | return world_query_iter_next |
2000 | N/A | end | >
2001 | N/A | > |
2002 | 11 | if not B then |
2003 | 11 | function world_query_iter_next(): any |
2004 | 6 | local entity = entities[i] |
2005 | 6 | while entity == nil do |
2006 | 6 | lastArchetype += 1 |
2007 | 6 | archetype = compatible_archetypes[lastArchetype] |
2008 | 0 | if not archetype then |
2009 | 0 | return nil |
2010 | N/A | end | >
2011 | N/A | > |
2012 | 0 | entities = archetype.entities |
2013 | 0 | i = #entities |
2014 | 0 | if i == 0 then |
2015 | 0 | continue |
2016 | N/A | end | >
2017 | 0 | entity = entities[i] |
2018 | 0 | columns = archetype.columns |
2019 | 0 | records = archetype.records |
2020 | 0 | a = columns[records[A]] |
2021 | N/A | end | >
2022 | N/A | > |
2023 | 0 | local row = i |
2024 | 5 | i -= 1 |
2025 | N/A | > |
2026 | 1 | return entity, a[row] |
2027 | N/A | end | >
2028 | 8 | elseif not C then |
2029 | 8 | function world_query_iter_next(): any |
2030 | 4 | local entity = entities[i] |
2031 | 4 | while entity == nil do |
2032 | 4 | lastArchetype += 1 |
2033 | 4 | archetype = compatible_archetypes[lastArchetype] |
2034 | 0 | if not archetype then |
2035 | 0 | return nil |
2036 | N/A | end | >
2037 | N/A | > |
2038 | 0 | entities = archetype.entities |
2039 | 0 | i = #entities |
2040 | 0 | if i == 0 then |
2041 | 0 | continue |
2042 | N/A | end | >
2043 | 0 | entity = entities[i] |
2044 | 0 | columns = archetype.columns |
2045 | 0 | records = archetype.records |
2046 | 0 | a = columns[records[A]] |
2047 | 0 | b = columns[records[B]] |
2048 | N/A | end | >
2049 | N/A | > |
2050 | 0 | local row = i |
2051 | 4 | i -= 1 |
2052 | N/A | > |
2053 | 0 | return entity, a[row], b[row] |
2054 | N/A | end | >
2055 | 0 | elseif not D then |
2056 | 0 | function world_query_iter_next(): any |
2057 | 0 | local entity = entities[i] |
2058 | 0 | while entity == nil do |
2059 | 0 | lastArchetype += 1 |
2060 | 0 | archetype = compatible_archetypes[lastArchetype] |
2061 | 0 | if not archetype then |
2062 | 0 | return nil |
2063 | N/A | end | >
2064 | N/A | > |
2065 | 0 | entities = archetype.entities |
2066 | 0 | i = #entities |
2067 | 0 | if i == 0 then |
2068 | 0 | continue |
2069 | N/A | end | >
2070 | 0 | entity = entities[i] |
2071 | 0 | columns = archetype.columns |
2072 | 0 | records = archetype.records |
2073 | 0 | a = columns[records[A]] |
2074 | 0 | b = columns[records[B]] |
2075 | 0 | c = columns[records[C]] |
2076 | N/A | end | >
2077 | N/A | > |
2078 | 0 | local row = i |
2079 | 0 | i -= 1 |
2080 | N/A | > |
2081 | 0 | return entity, a[row], b[row], c[row] |
2082 | N/A | end | >
2083 | 0 | elseif not E then |
2084 | 0 | function world_query_iter_next(): any |
2085 | 0 | local entity = entities[i] |
2086 | 0 | while entity == nil do |
2087 | 0 | lastArchetype += 1 |
2088 | 0 | archetype = compatible_archetypes[lastArchetype] |
2089 | 0 | if not archetype then |
2090 | 0 | return nil |
2091 | N/A | end | >
2092 | N/A | > |
2093 | 0 | entities = archetype.entities |
2094 | 0 | i = #entities |
2095 | 0 | if i == 0 then |
2096 | 0 | continue |
2097 | N/A | end | >
2098 | 0 | entity = entities[i] |
2099 | 0 | columns = archetype.columns |
2100 | 0 | records = archetype.records |
2101 | 0 | a = columns[records[A]] |
2102 | 0 | b = columns[records[B]] |
2103 | 0 | c = columns[records[C]] |
2104 | 0 | d = columns[records[D]] |
2105 | N/A | end | >
2106 | N/A | > |
2107 | 0 | local row = i |
2108 | 0 | i -= 1 |
2109 | N/A | > |
2110 | 0 | return entity, a[row], b[row], c[row], d[row] |
2111 | N/A | end | >
2112 | 0 | elseif not F then |
2113 | 0 | function world_query_iter_next(): any |
2114 | 0 | local entity = entities[i] |
2115 | 0 | while entity == nil do |
2116 | 0 | lastArchetype += 1 |
2117 | 0 | archetype = compatible_archetypes[lastArchetype] |
2118 | 0 | if not archetype then |
2119 | 0 | return nil |
2120 | N/A | end | >
2121 | N/A | > |
2122 | 0 | entities = archetype.entities |
2123 | 0 | i = #entities |
2124 | 0 | if i == 0 then |
2125 | 0 | continue |
2126 | N/A | end | >
2127 | 0 | entity = entities[i] |
2128 | 0 | columns = archetype.columns |
2129 | 0 | records = archetype.records |
2130 | 0 | a = columns[records[A]] |
2131 | 0 | b = columns[records[B]] |
2132 | 0 | c = columns[records[C]] |
2133 | 0 | d = columns[records[D]] |
2134 | 0 | e = columns[records[E]] |
2135 | N/A | end | >
2136 | N/A | > |
2137 | 0 | local row = i |
2138 | 0 | i -= 1 |
2139 | N/A | > |
2140 | 0 | return entity, a[row], b[row], c[row], d[row], e[row] |
2141 | N/A | end | >
2142 | 0 | elseif not G then |
2143 | 0 | function world_query_iter_next(): any |
2144 | 0 | local entity = entities[i] |
2145 | 0 | while entity == nil do |
2146 | 0 | lastArchetype += 1 |
2147 | 0 | archetype = compatible_archetypes[lastArchetype] |
2148 | 0 | if not archetype then |
2149 | 0 | return nil |
2150 | N/A | end | >
2151 | N/A | > |
2152 | 0 | entities = archetype.entities |
2153 | 0 | i = #entities |
2154 | 0 | if i == 0 then |
2155 | 0 | continue |
2156 | N/A | end | >
2157 | 0 | entity = entities[i] |
2158 | 0 | columns = archetype.columns |
2159 | 0 | records = archetype.records |
2160 | 0 | a = columns[records[A]] |
2161 | 0 | b = columns[records[B]] |
2162 | 0 | c = columns[records[C]] |
2163 | 0 | d = columns[records[D]] |
2164 | 0 | e = columns[records[E]] |
2165 | 0 | f = columns[records[F]] |
2166 | N/A | end | >
2167 | N/A | > |
2168 | 0 | local row = i |
2169 | 0 | i -= 1 |
2170 | N/A | > |
2171 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row] |
2172 | N/A | end | >
2173 | 0 | elseif not H then |
2174 | 0 | function world_query_iter_next(): any |
2175 | 0 | local entity = entities[i] |
2176 | 0 | while entity == nil do |
2177 | 0 | lastArchetype += 1 |
2178 | 0 | archetype = compatible_archetypes[lastArchetype] |
2179 | 0 | if not archetype then |
2180 | 0 | return nil |
2181 | N/A | end | >
2182 | N/A | > |
2183 | 0 | entities = archetype.entities |
2184 | 0 | i = #entities |
2185 | 0 | if i == 0 then |
2186 | 0 | continue |
2187 | N/A | end | >
2188 | 0 | entity = entities[i] |
2189 | 0 | columns = archetype.columns |
2190 | 0 | records = archetype.records |
2191 | 0 | a = columns[records[A]] |
2192 | 0 | b = columns[records[B]] |
2193 | 0 | c = columns[records[C]] |
2194 | 0 | d = columns[records[D]] |
2195 | 0 | e = columns[records[E]] |
2196 | 0 | f = columns[records[F]] |
2197 | 0 | g = columns[records[G]] |
2198 | N/A | end | >
2199 | N/A | > |
2200 | 0 | local row = i |
2201 | 0 | i -= 1 |
2202 | N/A | > |
2203 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row] |
2204 | N/A | end | >
2205 | 0 | elseif not I then |
2206 | 0 | function world_query_iter_next(): any |
2207 | 0 | local entity = entities[i] |
2208 | 0 | while entity == nil do |
2209 | 0 | lastArchetype += 1 |
2210 | 0 | archetype = compatible_archetypes[lastArchetype] |
2211 | 0 | if not archetype then |
2212 | 0 | return nil |
2213 | N/A | end | >
2214 | N/A | > |
2215 | 0 | entities = archetype.entities |
2216 | 0 | i = #entities |
2217 | 0 | if i == 0 then |
2218 | 0 | continue |
2219 | N/A | end | >
2220 | 0 | entity = entities[i] |
2221 | 0 | columns = archetype.columns |
2222 | 0 | records = archetype.records |
2223 | 0 | a = columns[records[A]] |
2224 | 0 | b = columns[records[B]] |
2225 | 0 | c = columns[records[C]] |
2226 | 0 | d = columns[records[D]] |
2227 | 0 | e = columns[records[E]] |
2228 | 0 | f = columns[records[F]] |
2229 | 0 | g = columns[records[G]] |
2230 | 0 | h = columns[records[H]] |
2231 | N/A | end | >
2232 | N/A | > |
2233 | 0 | local row = i |
2234 | 0 | i -= 1 |
2235 | N/A | > |
2236 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row] |
2237 | N/A | end | >
2238 | 0 | else |
2239 | 0 | local queryOutput = {} |
2240 | 0 | function world_query_iter_next(): any |
2241 | 0 | local entity = entities[i] |
2242 | 0 | while entity == nil do |
2243 | 0 | lastArchetype += 1 |
2244 | 0 | archetype = compatible_archetypes[lastArchetype] |
2245 | 0 | if not archetype then |
2246 | 0 | return nil |
2247 | N/A | end | >
2248 | N/A | > |
2249 | 0 | entities = archetype.entities |
2250 | 0 | i = #entities |
2251 | 0 | if i == 0 then |
2252 | 0 | continue |
2253 | N/A | end | >
2254 | 0 | entity = entities[i] |
2255 | 0 | columns = archetype.columns |
2256 | 0 | records = archetype.records |
2257 | N/A | end | >
2258 | N/A | > |
2259 | 0 | local row = i |
2260 | 0 | i -= 1 |
2261 | N/A | > |
2262 | 0 | if not F then |
2263 | 0 | return entity, a[row], b[row], c[row], d[row], e[row] |
2264 | 0 | elseif not G then |
2265 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row] |
2266 | 0 | elseif not H then |
2267 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row] |
2268 | 0 | elseif not I then |
2269 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row] |
2270 | N/A | end | >
2271 | N/A | > |
2272 | 0 | for j, id in ids do |
2273 | 0 | queryOutput[j] = columns[records[id]][row] |
2274 | N/A | end | >
2275 | N/A | > |
2276 | 0 | return entity, unpack(queryOutput) |
2277 | N/A | end | >
2278 | N/A | end | >
2279 | N/A | > |
2280 | 6 | local cached_query = query :: any |
2281 | 6 | cached_query.archetypes = query_archetypes |
2282 | 6 | cached_query.__iter = cached_query_iter |
2283 | 6 | cached_query.iter = cached_query_iter |
2284 | 0 | setmetatable(cached_query, cached_query) |
2285 | 0 | return cached_query |
2286 | N/A | end | >
2287 | N/A | > |
2288 | 1 | local Query = {} |
2289 | 1 | Query.__index = Query |
2290 | 1 | Query.__iter = query_iter |
2291 | 1 | Query.iter = query_iter_init |
2292 | 1 | Query.without = query_without |
2293 | 1 | Query.with = query_with |
2294 | 0 | Query.archetypes = query_archetypes |
2295 | 1 | Query.cached = query_cached |
2296 | N/A | > |
2297 | 33 | local function world_query(world: ecs_world_t, ...) |
2298 | 0 | local compatible_archetypes = {} |
2299 | 33 | local length = 0 |
2300 | N/A | > |
2301 | 33 | local ids = { ... } |
2302 | N/A | > |
2303 | 33 | local archetypes = world.archetypes |
2304 | N/A | > |
2305 | 0 | local idr: ecs_id_record_t? |
2306 | 33 | local component_index = world.component_index |
2307 | N/A | > |
2308 | 33 | local q = setmetatable({ |
2309 | 33 | ids = ids, |
2310 | 33 | compatible_archetypes = compatible_archetypes, |
2311 | 0 | world = world, |
2312 | 33 | }, Query) |
2313 | N/A | > |
2314 | 47 | for _, id in ids do |
2315 | 7 | local map = component_index[id] |
2316 | 0 | if not map then |
2317 | 0 | return q |
2318 | N/A | end | >
2319 | N/A | > |
2320 | 0 | if idr == nil or map.size < idr.size then |
2321 | 0 | idr = map |
2322 | N/A | end | >
2323 | N/A | end | >
2324 | N/A | > |
2325 | 0 | if not idr then |
2326 | 0 | return q |
2327 | N/A | end | >
2328 | N/A | > |
2329 | 48 | for archetype_id in idr.cache do |
2330 | 0 | local compatibleArchetype = archetypes[archetype_id] |
2331 | 0 | if #compatibleArchetype.entities == 0 then |
2332 | 34 | continue |
2333 | N/A | end | >
2334 | 34 | local records = compatibleArchetype.records |
2335 | N/A | > |
2336 | 34 | local skip = false |
2337 | N/A | > |
2338 | 47 | for i, id in ids do |
2339 | 0 | local tr = records[id] |
2340 | 0 | if not tr then |
2341 | 0 | skip = true |
2342 | 0 | break |
2343 | N/A | end | >
2344 | N/A | end | >
2345 | N/A | > |
2346 | 0 | if skip then |
2347 | 0 | continue |
2348 | N/A | end | >
2349 | N/A | > |
2350 | 0 | length += 1 |
2351 | 0 | compatible_archetypes[length] = compatibleArchetype |
2352 | N/A | end | >
2353 | N/A | > |
2354 | 0 | return q |
2355 | N/A | end | >
2356 | N/A | > |
2357 | 4 | local function world_each(world: ecs_world_t, id: i53): () -> () |
2358 | 0 | local idr = world.component_index[id] |
2359 | 0 | if not idr then |
2360 | 0 | return NOOP |
2361 | N/A | end | >
2362 | N/A | > |
2363 | 4 | local idr_cache = idr.cache |
2364 | 4 | local archetypes = world.archetypes |
2365 | 4 | local archetype_id = next(idr_cache, nil) :: number |
2366 | 0 | local archetype = archetypes[archetype_id] |
2367 | 0 | if not archetype then |
2368 | 0 | return NOOP |
2369 | N/A | end | >
2370 | N/A | > |
2371 | 0 | local entities = archetype.entities |
2372 | 4 | local row = #entities |
2373 | N/A | > |
2374 | 12 | return function(): any |
2375 | 11 | local entity = entities[row] |
2376 | 11 | while not entity do |
2377 | 4 | archetype_id = next(idr_cache, archetype_id) :: number |
2378 | 0 | if not archetype_id then |
2379 | 7 | return |
2380 | N/A | end | >
2381 | 7 | archetype = archetypes[archetype_id] |
2382 | 7 | entities = archetype.entities |
2383 | 0 | row = #entities |
2384 | 8 | entity = entities[row] |
2385 | N/A | end | >
2386 | 0 | row -= 1 |
2387 | 0 | return entity |
2388 | N/A | end | >
2389 | N/A | end | >
2390 | N/A | > |
2391 | 0 | local function world_children(world: ecs_world_t, parent: i53) |
2392 | 0 | return world_each(world, ECS_PAIR(EcsChildOf, parent)) |
2393 | N/A | end | >
2394 | N/A | > |
2395 | 0 | export type Record = { |
2396 | 0 | archetype: Archetype, |
2397 | 0 | row: number, |
2398 | 0 | dense: i24, |
2399 | 0 | } |
2400 | 0 | export type ComponentRecord = { |
2401 | 0 | cache: { [Id]: number }, |
2402 | 0 | counts: { [Id]: number }, |
2403 | 0 | flags: number, |
2404 | 0 | size: number, |
2405 | 0 | hooks: { |
2406 | 0 | on_add: ((entity: Entity) -> ())?, |
2407 | 0 | on_set: ((entity: Entity, data: any) -> ())?, |
2408 | 0 | on_remove: ((entity: Entity) -> ())?, |
2409 | 0 | }, |
2410 | 0 | } |
2411 | 0 | export type ComponentIndex = Map |
2412 | 0 | export type Archetypes = { [Id]: Archetype } |
2413 | N/A | > |
2414 | 0 | export type EntityIndex = { |
2415 | 0 | dense_array: Map |
2416 | 0 | sparse_array: Map |
2417 | 0 | alive_count: number, |
2418 | 0 | max_id: number, |
2419 | 1 | } |
2420 | N/A | > |
2421 | 0 | local World = {} |
2422 | 1 | World.__index = World |
2423 | N/A | > |
2424 | 1 | World.entity = world_entity |
2425 | 1 | World.query = world_query |
2426 | 1 | World.remove = world_remove |
2427 | 1 | World.clear = world_clear |
2428 | 1 | World.delete = world_delete |
2429 | 1 | World.component = world_component |
2430 | 1 | World.add = world_add |
2431 | 1 | World.set = world_set |
2432 | 1 | World.get = world_get |
2433 | 1 | World.has = world_has |
2434 | 1 | World.target = world_target |
2435 | 1 | World.parent = world_parent |
2436 | 1 | World.contains = world_contains |
2437 | 1 | World.cleanup = world_cleanup |
2438 | 0 | World.each = world_each |
2439 | 1 | World.children = world_children |
2440 | N/A | > |
2441 | 73 | local function world_new() |
2442 | 73 | local entity_index = { |
2443 | 73 | dense_array = {}, |
2444 | 73 | sparse_array = {}, |
2445 | 0 | alive_count = 0, |
2446 | 73 | max_id = 0, |
2447 | 73 | } :: ecs_entity_index_t |
2448 | 73 | local self = setmetatable({ |
2449 | 73 | archetype_index = {} :: { [string]: Archetype }, |
2450 | 73 | archetypes = {} :: Archetypes, |
2451 | 73 | component_index = {} :: ComponentIndex, |
2452 | 0 | entity_index = entity_index, |
2453 | 73 | ROOT_ARCHETYPE = (nil :: any) :: Archetype, |
2454 | N/A | > |
2455 | 0 | max_archetype_id = 0, |
2456 | 73 | max_component_id = 0, |
2457 | N/A | > |
2458 | 0 | observable = {} :: Observable, |
2459 | 73 | }, World) :: any |
2460 | N/A | > |
2461 | 73 | self.ROOT_ARCHETYPE = archetype_create(self, {}, "") |
2462 | N/A | > |
2463 | 18688 | for i = 1, HI_COMPONENT_ID do |
2464 | 0 | local e = entity_index_new_id(entity_index) |
2465 | 0 | world_add(self, e, EcsComponent) |
2466 | N/A | end | >
2467 | N/A | > |
2468 | 1022 | for i = HI_COMPONENT_ID + 1, EcsRest do |
2469 | N/A | -- Initialize built-in components | >
2470 | 0 | entity_index_new_id(entity_index) |
2471 | N/A | end | >
2472 | N/A | > |
2473 | 73 | world_add(self, EcsName, EcsComponent) |
2474 | 73 | world_add(self, EcsOnSet, EcsComponent) |
2475 | 73 | world_add(self, EcsOnAdd, EcsComponent) |
2476 | 73 | world_add(self, EcsOnRemove, EcsComponent) |
2477 | 0 | world_add(self, EcsWildcard, EcsComponent) |
2478 | 73 | world_add(self, EcsRest, EcsComponent) |
2479 | N/A | > |
2480 | 73 | world_set(self, EcsOnAdd, EcsName, "jecs.OnAdd") |
2481 | 73 | world_set(self, EcsOnRemove, EcsName, "jecs.OnRemove") |
2482 | 73 | world_set(self, EcsOnSet, EcsName, "jecs.OnSet") |
2483 | 73 | world_set(self, EcsWildcard, EcsName, "jecs.Wildcard") |
2484 | 73 | world_set(self, EcsChildOf, EcsName, "jecs.ChildOf") |
2485 | 73 | world_set(self, EcsComponent, EcsName, "jecs.Component") |
2486 | 73 | world_set(self, EcsOnDelete, EcsName, "jecs.OnDelete") |
2487 | 73 | world_set(self, EcsOnDeleteTarget, EcsName, "jecs.OnDeleteTarget") |
2488 | 73 | world_set(self, EcsDelete, EcsName, "jecs.Delete") |
2489 | 73 | world_set(self, EcsRemove, EcsName, "jecs.Remove") |
2490 | 0 | world_set(self, EcsName, EcsName, "jecs.Name") |
2491 | 73 | world_set(self, EcsRest, EcsRest, "jecs.Rest") |
2492 | N/A | > |
2493 | 73 | world_add(self, EcsChildOf, ECS_PAIR(EcsOnDeleteTarget, EcsDelete)) |
2494 | N/A | > |
2495 | 0 | return self |
2496 | N/A | end | >
2497 | N/A | > |
2498 | 0 | World.new = world_new |
2499 | N/A | > |
2500 | 0 | export type Entity |
2501 | 0 | export type Id |
2502 | 0 | export type Pair = Id |
2503 | 0 | type ecs_id_t |
2504 | 0 | export type Item |
2505 | 0 | export type Iter |
2506 | N/A | > |
2507 | 0 | export type Query |
2508 | 0 | __iter = (nil :: any) :: Iter |
2509 | 0 | })) & { |
2510 | 0 | iter: Iter |
2511 | 0 | with: (self: Query |
2512 | 0 | without: (self: Query |
2513 | 0 | archetypes: (self: Query |
2514 | 0 | cached: (self: Query |
2515 | 0 | } |
2516 | N/A | > |
2517 | 0 | export type Observer = { |
2518 | 0 | callback: (archetype: Archetype) -> (), |
2519 | 0 | query: QueryInner, |
2520 | 0 | } |
2521 | N/A | > |
2522 | 0 | export type Observable = { |
2523 | 0 | [Id]: { |
2524 | 0 | [Id]: { |
2525 | 0 | { Observer } |
2526 | 0 | } |
2527 | 0 | } |
2528 | 0 | } |
2529 | N/A | > |
2530 | 0 | export type World = { |
2531 | 0 | archetype_index: { [string]: Archetype }, |
2532 | 0 | archetypes: Archetypes, |
2533 | 0 | component_index: ComponentIndex, |
2534 | 0 | entity_index: EntityIndex, |
2535 | 0 | ROOT_ARCHETYPE: Archetype, |
2536 | N/A | > |
2537 | 0 | max_component_id: number, |
2538 | 0 | max_archetype_id: number, |
2539 | N/A | > |
2540 | 0 | observable: any, |
2541 | N/A | > |
2542 | N/A | --- Creates a new entity | >
2543 | 0 | entity: (self: World, id: Entity?) -> Entity, |
2544 | N/A | --- Creates a new entity located in the first 256 ids. | >
2545 | N/A | --- These should be used for static components for fast access. | >
2546 | 0 | component: |
2547 | N/A | --- Gets the target of an relationship. For example, when a user calls | >
2548 | N/A | --- `world:target(id, ChildOf(parent), 0)`, you will obtain the parent entity. | >
2549 | 0 | target: (self: World, id: Entity, relation: Id, index: number?) -> Entity?, |
2550 | N/A | --- Deletes an entity and all it's related components and relationships. | >
2551 | 0 | delete: (self: World, id: Entity) -> (), |
2552 | N/A | > |
2553 | N/A | --- Adds a component to the entity with no value | >
2554 | 0 | add: |
2555 | N/A | --- Assigns a value to a component on the given entity | >
2556 | 0 | set: |
2557 | N/A | > |
2558 | 0 | cleanup: (self: World) -> (), |
2559 | N/A | -- Clears an entity from the world | >
2560 | 0 | clear: (self: World, id: Entity) -> (), |
2561 | N/A | --- Removes a component from the given entity | >
2562 | 0 | remove: (self: World, id: Entity, component: Id) -> (), |
2563 | N/A | --- Retrieves the value of up to 4 components. These values may be nil. | >
2564 | 0 | get: ((self: World, id: Entity, Id) -> A?) |
2565 | 0 | & ((self: World, id: Entity, Id, Id) -> (A?, B?)) |
2566 | 0 | & ((self: World, id: Entity, Id, Id, Id |
2567 | 0 | & (self: World, id: Entity, Id, Id, Id |
2568 | N/A | > |
2569 | N/A | --- Returns whether the entity has the ID. | >
2570 | 0 | has: (self: World, entity: Entity, ...Id) -> boolean, |
2571 | N/A | > |
2572 | N/A | --- Get parent (target of ChildOf relationship) for entity. If there is no ChildOf relationship pair, it will return nil. | >
2573 | 0 | parent:(self: World, entity: Entity) -> Entity, |
2574 | N/A | > |
2575 | N/A | --- Checks if the world contains the given entity | >
2576 | 0 | contains:(self: World, entity: Entity) -> boolean, |
2577 | N/A | > |
2578 | 0 | each: (self: World, id: Id) -> () -> Entity, |
2579 | N/A | > |
2580 | 0 | children: (self: World, id: Id) -> () -> Entity, |
2581 | N/A | > |
2582 | N/A | --- Searches the world for entities that match a given query | >
2583 | 0 | query: ((World, Id) -> Query) |
2584 | 0 | & ((World, Id, Id) -> Query) |
2585 | 0 | & ((World, Id, Id, Id |
2586 | 0 | & ((World, Id, Id, Id |
2587 | 0 | & ((World, Id, Id, Id |
2588 | 0 | & ((World, Id, Id, Id |
2589 | 0 | & ((World, Id, Id, Id |
2590 | 0 | & ((World, Id, Id, Id |
2591 | 0 | } |
2592 | N/A | -- type function ecs_id_t(entity) | >
2593 | N/A | -- local ty = entity:components()[2] | >
2594 | N/A | -- local __T = ty:readproperty(types.singleton("__T")) | >
2595 | N/A | -- if not __T then | >
2596 | N/A | -- return ty:readproperty(types.singleton("__jecs_pair_value")) | >
2597 | N/A | -- end | >
2598 | N/A | -- return __T | >
2599 | N/A | -- end | >
2600 | N/A | > |
2601 | N/A | -- type function ecs_pair_t(first, second) | >
2602 | N/A | -- if ecs_id_t(first):is("nil") then | >
2603 | N/A | -- return second | >
2604 | N/A | -- else | >
2605 | N/A | -- return first | >
2606 | N/A | -- end | >
2607 | N/A | -- end | >
2608 | N/A | > |
2609 | 1 | return { |
2610 | 0 | World = World :: { new: () -> World }, |
2611 | 1 | world = World.new :: () -> World, |
2612 | N/A | > |
2613 | 1 | OnAdd = EcsOnAdd :: Entity<(entity: Entity) -> ()>, |
2614 | 1 | OnRemove = EcsOnRemove :: Entity<(entity: Entity) -> ()>, |
2615 | 1 | OnSet = EcsOnSet :: Entity<(entity: Entity, data: any) -> ()>, |
2616 | 1 | ChildOf = EcsChildOf :: Entity, |
2617 | 1 | Component = EcsComponent :: Entity, |
2618 | 1 | Wildcard = EcsWildcard :: Entity, |
2619 | 1 | w = EcsWildcard :: Entity, |
2620 | 1 | OnDelete = EcsOnDelete :: Entity, |
2621 | 1 | OnDeleteTarget = EcsOnDeleteTarget :: Entity, |
2622 | 1 | Delete = EcsDelete :: Entity, |
2623 | 1 | Remove = EcsRemove :: Entity, |
2624 | 0 | Name = EcsName :: Entity |
2625 | 1 | Rest = EcsRest :: Entity, |
2626 | N/A | > |
2627 | 0 | pair = (ECS_PAIR :: any) :: (first: Id , second: Id , |
2628 | N/A | > |
2629 | N/A | -- Inwards facing API for testing | >
2630 | 1 | ECS_ID = ECS_ENTITY_T_LO, |
2631 | 1 | ECS_GENERATION_INC = ECS_GENERATION_INC, |
2632 | 0 | ECS_GENERATION = ECS_GENERATION, |
2633 | 1 | ECS_ID_IS_WILDCARD = ECS_ID_IS_WILDCARD, |
2634 | N/A | > |
2635 | 1 | ECS_ID_DELETE = ECS_ID_DELETE, |
2636 | N/A | > |
2637 | 1 | IS_PAIR = ECS_IS_PAIR, |
2638 | 1 | pair_first = ecs_pair_first, |
2639 | 0 | pair_second = ecs_pair_second, |
2640 | 1 | entity_index_get_alive = entity_index_get_alive, |
2641 | N/A | > |
2642 | 1 | archetype_append_to_records = archetype_append_to_records, |
2643 | 1 | id_record_ensure = id_record_ensure, |
2644 | 1 | archetype_create = archetype_create, |
2645 | 1 | archetype_ensure = archetype_ensure, |
2646 | 1 | find_insert = find_insert, |
2647 | 1 | find_archetype_with = find_archetype_with, |
2648 | 1 | find_archetype_without = find_archetype_without, |
2649 | 1 | archetype_init_edge = archetype_init_edge, |
2650 | 1 | archetype_ensure_edge = archetype_ensure_edge, |
2651 | 1 | init_edge_for_add = init_edge_for_add, |
2652 | 1 | init_edge_for_remove = init_edge_for_remove, |
2653 | 1 | create_edge_for_add = create_edge_for_add, |
2654 | 1 | create_edge_for_remove = create_edge_for_remove, |
2655 | 0 | archetype_traverse_add = archetype_traverse_add, |
2656 | 1 | archetype_traverse_remove = archetype_traverse_remove, |
2657 | N/A | > |
2658 | 1 | entity_move = entity_move, |
2659 | N/A | > |
2660 | 1 | entity_index_try_get = entity_index_try_get, |
2661 | 1 | entity_index_try_get_any = entity_index_try_get_any, |
2662 | 1 | entity_index_try_get_fast = entity_index_try_get_fast, |
2663 | 0 | entity_index_is_alive = entity_index_is_alive, |
2664 | 1 | entity_index_new_id = entity_index_new_id, |
2665 | N/A | > |
2666 | 1 | query_iter = query_iter, |
2667 | 1 | query_iter_init = query_iter_init, |
2668 | 1 | query_with = query_with, |
2669 | 1 | query_without = query_without, |
2670 | 0 | query_archetypes = query_archetypes, |
2671 | 1 | query_match = query_match, |
2672 | N/A | > |
2673 | 0 | find_observers = find_observers, |
2674 | 0 | } |