From 98003551319377a4808729feb07db028f20a404f Mon Sep 17 00:00:00 2001 From: Ukendio Date: Fri, 28 Mar 2025 02:29:50 +0100 Subject: [PATCH] Styling on coverage reports --- coverage/ansi.luau.html | 10 +- coverage/entity_visualiser.luau.html | 10 +- coverage/index.html | 6 +- coverage/jecs.luau.html | 1801 +++++++++++++------------- coverage/lifetime_tracker.luau.html | 10 +- coverage/testkit.luau.html | 90 +- coverage/tests.luau.html | 58 +- tools/read_lcov.py | 17 +- 8 files changed, 1015 insertions(+), 987 deletions(-) diff --git a/coverage/ansi.luau.html b/coverage/ansi.luau.html index 87c5c73..3246e47 100644 --- a/coverage/ansi.luau.html +++ b/coverage/ansi.luau.html @@ -2,12 +2,16 @@

jecs.luau Coverage

-

Total Execution Hits: 161937

-

Function Coverage Overview: 52.04%

+

Total Execution Hits: 1006447

+

Function Coverage Overview: 84.54%

Function Coverage:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionHits
1
ECS_COMBINE:1440
ECS_IS_PAIR:1494
ECS_GENERATION_INC:1531
ECS_ENTITY_T_LO:1684
ECS_GENERATION:1725
ECS_ENTITY_T_HI:1760
ECS_PAIR:180186
ECS_PAIR_FIRST:1870
ECS_PAIR_SECOND:1910
entity_index_try_get_any:19517
entity_index_try_get:2081
entity_index_try_get_fast:2220
entity_index_is_alive:2320
entity_index_get_alive:2360
ecs_get_alive:2440
entity_index_new_id:2670
ecs_pair_first:2884
ecs_pair_second:2935
query_match:2980
find_observers:3210
archetype_move:3301822
archetype_append:3900
new_entity:4000
entity_move:4110
hash:4250
fetch:4290
world_get:440734
world_has_one_inline:4710
world_has:48780
world_target:5091440
ECS_ID_IS_WILDCARD:5410
id_record_ensure:547704
archetype_append_to_records:6100
archetype_create:635987
world_entity:70066852
world_parent:7041
archetype_ensure:7080
find_insert:7220
find_archetype_with:7340
find_archetype_without:75222
archetype_init_edge:7690
archetype_ensure_edge:7800
init_edge_for_add:7940
init_edge_for_remove:8110
create_edge_for_add:8340
create_edge_for_remove:8450
archetype_traverse_add:8561
archetype_traverse_remove:8721
world_add:88919316
world_set:9212775
world_component:973121
world_remove:985298
archetype_fast_delete_last:10100
archetype_fast_delete:10180
archetype_delete:102758
world_clear:10660
archetype_disconnect_edge:11660
archetype_remove_edge:11770
archetype_clear_edges:118222
archetype_destroy:12152
world_cleanup:12511
world_delete:127265539
world_contains:1448145
NOOP:14520
query_iter_init:146326
world_query_iter_next:1529556
world_query_iter_next:15557
world_query_iter_next:15820
world_query_iter_next:16102
world_query_iter_next:16390
world_query_iter_next:16690
world_query_iter_next:17000
world_query_iter_next:17320
world_query_iter_next:17662
query_iter:180020
query_without:18086
query_with:18381
query_archetypes:18725
query_cached:18766
on_create_callback:19264
on_delete_callback:19301
cached_query_iter:194311
world_query_iter_next:200311
world_query_iter_next:20298
world_query_iter_next:20560
world_query_iter_next:20840
world_query_iter_next:21130
world_query_iter_next:21430
world_query_iter_next:21740
world_query_iter_next:22060
world_query_iter_next:22400
world_query:229733
world_each:23572
:237412
world_children:23912
:23740
world_new:244173
ECS_COMBINE:14265683
ECS_IS_PAIR:1471729
ECS_GENERATION_INC:15165684
ECS_ENTITY_T_LO:166162390
ECS_GENERATION:1705
ECS_ENTITY_T_HI:1740
ECS_PAIR:178133381
ECS_PAIR_FIRST:185648
ECS_PAIR_SECOND:189722
entity_index_try_get_any:193133207
entity_index_try_get:20666607
entity_index_try_get_fast:22025535
entity_index_is_alive:230922
entity_index_get_alive:234842
ecs_get_alive:2429
entity_index_new_id:26586562
ecs_pair_first:2864
ecs_pair_second:2915
query_match:29610
find_observers:3191518
archetype_move:3281822
archetype_append:38822380
new_entity:39820558
entity_move:4091822
hash:423569
fetch:4271809
world_get:438734
world_has_one_inline:469892
world_has:48580
world_target:5071440
ECS_ID_IS_WILDCARD:5390
id_record_ensure:5451509
archetype_append_to_records:6081507
archetype_create:633635
world_entity:69866852
world_parent:7021
archetype_ensure:706580
find_insert:720551
find_archetype_with:732551
find_archetype_without:75033
archetype_init_edge:767582
archetype_ensure_edge:77822971
init_edge_for_add:792549
init_edge_for_remove:80933
create_edge_for_add:832551
create_edge_for_remove:84333
archetype_traverse_add:85422092
archetype_traverse_remove:870297
world_add:88719316
world_set:9192775
world_component:971121
world_remove:983298
archetype_fast_delete_last:100876
archetype_fast_delete:101658
archetype_delete:1025134
world_clear:10646
archetype_disconnect_edge:116450
archetype_remove_edge:117523
archetype_clear_edges:118036
archetype_destroy:121337
world_cleanup:12491
world_delete:127065684
world_contains:1446145
NOOP:14500
query_iter_init:146126
world_query_iter_next:1527556
world_query_iter_next:15537
world_query_iter_next:15800
world_query_iter_next:16082
world_query_iter_next:16370
world_query_iter_next:16670
world_query_iter_next:16980
world_query_iter_next:17300
world_query_iter_next:17642
query_iter:179820
query_without:18066
query_with:18361
query_archetypes:18705
query_cached:18746
on_create_callback:19244
on_delete_callback:19281
cached_query_iter:194111
world_query_iter_next:200111
world_query_iter_next:20278
world_query_iter_next:20540
world_query_iter_next:20820
world_query_iter_next:21110
world_query_iter_next:21410
world_query_iter_next:21720
world_query_iter_next:22040
world_query_iter_next:22380
world_query:229533
world_each:23554
:237212
world_children:23892
world_new:243973
-

Source Code:

+

Source Code:

LineHitsCode
>>> @@ -225,7 +228,7 @@ table.table tr { height: auto; } - +>> @@ -241,142 +244,142 @@ table.table tr { height: auto; } - +> - +> - +> - - + +> - +> - - + +>> - - + +>> - - - + + +> - - - + + +>> - +> - +>> - - + +>> - - + +>> - +>> - - - + + +> - +>> - - + +>> - - + +>> - + - + - +> - +>> - +>> - - - - - - + + + + + +> - - + +>> - +>> - - - - + + + +>> - +>> - - + +>> - - - - + + + +>>> - - + +>> - +> - - + +>>>> - +> @@ -384,203 +387,203 @@ table.table tr { height: auto; } >> - - - - - - - + + + + + + +>> - - - - - - + + + + + +> - +>> - - - + + +>> - - - + + +>> - - - - + + + +> - - - + + +>>> - - - - + + + +>>>> - +>> - - - - - + + + + +> - +>> - + - - + + - +> - +> - - + +>>> - +>> - - + +>>> - +> - +> - +>> - +>>>> - +> - - + +>> - +>> - - + +>> - + - - - - - - + + + + + +>> - + - - - - - + + + + +>> - + - - - - - - - - + + + + + + + +>> - - + +>> - + - +> - - + +>> - +>> - - - - - + + + + +>> - - - + + +>> - +>> - - + + - - - + + + @@ -588,116 +591,116 @@ table.table tr { height: auto; } >>> - - - - + + + +>> - - - + + +>> - +> - +>> - - - - + + + +>> - - - + + +>>> - - - + + +>>> - +>> - + - - - + + +>> - - - + + +>>> - - - + + +>> - - + +>> - - - + + +>> - - + +>> - +>> - + - +> - + - - + + - - + + - - + +>> - +>> - - + +>>>> - - + +>> @@ -705,9 +708,9 @@ table.table tr { height: auto; } - - - + + +> @@ -716,50 +719,50 @@ table.table tr { height: auto; } - - + + - +> - +>> - +>> - + - - - - - - - - - - - + + + + + + + + + + +> - - - - - - + + + + + +>>> - - + +> - +> - +> @@ -768,447 +771,447 @@ table.table tr { height: auto; } - +> - - - + + +> - - + +> - + - +> - - + +>> - - + + - +>>> - - - - + + + +> - - - + + +>>>> - +> - +>> - - + +>> - - + +>> - - + +>> - - - + + +>> - +>> - - - - + + + +> - - + +>> - +>> - - + +>>>> - - - + + +>> - +> - +> - +>> - + - - + + - - + +>> - +> - +>> - + - - - - - + + + + +>> - + - - - - - - + + + + + +>> - +>> - - - - - - + + + + + +> - - - + + +> - +>>>> - + - - - - - - - + + + + + + +> - - - + + +> - - + +>>>> - + - - - - - + + + + +>> - + - - - - - + + + + +>> - + - - - - + + + +> - - - + + +>> - +>> - + - + - +> - +> - - - + + +>> - +>> - + - - + + - - + +>> - - - - + + + +> - - - - - + + + + +>>> - +> - - + +>>> - + - - + +>> - - - + + +> - +>> - - + +>> - +>> - +> - +> - +>>> - +> - +> - - + +>> - - - + + +>>> - - - + + +>> - +>> - +>> - + - - - + + +>> - - + +>> - + - - - + + +>>> - +>>> - - - - + + + +>>>> - - - - - + + + + +>>>> - + - +>> - + - - + +>> - - + +>> - + - - - + + +>>>> - - + + - +>>> - + - +> - + - - + + - - + +> - - + +>>> - +> @@ -1256,257 +1259,257 @@ table.table tr { height: auto; } >>> - + - - + + - +> - - + +>> - - - + + +>>>>> - - - - - + + + + +> - - + +>>> - - - + + +>> - + - - - - + + + +> - - - + + +>> - - + + - - + +>> - - + + - - + +>> - - + +>> - - + +>> - +> - - - - + + + +> - - - + + +>>>> - + - - + +>>>> - +> - - - + + +>>> - +> - - - + + +>> - - + +>> - + - - - + + +>> - +> - +>> - +>> - +> - +> - - - - + + + +> - - - + + +>> - +> - - + + - - - + + +>> - +>>>> - - + +> - - + + - +> - - - + + +> - - - + + +> - - - - - + + + + +> - - - - + + + +> - - + +>>> - - + +> - - + +> - - + +>> - - - - + + + +>>>> - - + +>>> - + @@ -1551,25 +1554,25 @@ table.table tr { height: auto; } > - +> - +> - - + +>> - - + +>> - +> @@ -1578,63 +1581,63 @@ table.table tr { height: auto; } - +> - +> - - - + + +> - +> - +> - - - - - - + + + + + + - - - + + + - - + + - + - + - + - + - + - + @@ -1645,40 +1648,40 @@ table.table tr { height: auto; } >> - - - - + + + + - - - + + +>> - - - + + +> - - + +>> - +> - +> - - - - + + + + - - + +>> @@ -1693,12 +1696,12 @@ table.table tr { height: auto; } >> - +> - +> - + @@ -1724,16 +1727,16 @@ table.table tr { height: auto; } > - +> - - - + + + - - + +>> @@ -1750,12 +1753,12 @@ table.table tr { height: auto; } >> - +>> - + @@ -1783,9 +1786,9 @@ table.table tr { height: auto; } > - +> - + @@ -1814,9 +1817,9 @@ table.table tr { height: auto; } > - +> - + @@ -1846,9 +1849,9 @@ table.table tr { height: auto; } > - +> - + @@ -1881,15 +1884,15 @@ table.table tr { height: auto; } >> - - - - - + + + + + - - + +>> @@ -1902,65 +1905,65 @@ table.table tr { height: auto; } >> - +> - - + +>> - +>>> - - + +>> - - - - + + + +> - +>> - + - - + + - +> - - - - + + + +>>> - +>> - - - + + +> - +>> - +>> - +> - + @@ -1983,30 +1986,30 @@ table.table tr { height: auto; } >> - +>>>>> - - + +>> - + - - - + + + - +>> - +> - +> @@ -2014,67 +2017,67 @@ table.table tr { height: auto; } - +> - +>> - +> - - + +>> - +> - - + +>> - - + +>> - + - - + +>> - +> - +> - + - - - + + +> - - - + + + - - + + @@ -2116,17 +2119,17 @@ table.table tr { height: auto; } >> - +>> - - - - + + + + - - + +>> @@ -2140,19 +2143,19 @@ table.table tr { height: auto; } >> - +> - +> - - - - + + + + - - + +>> @@ -2167,10 +2170,10 @@ table.table tr { height: auto; } >> - +> - +> @@ -2401,8 +2404,8 @@ table.table tr { height: auto; } - - + +>> @@ -2411,105 +2414,105 @@ table.table tr { height: auto; } - +> - - + +>>> - +> - +> - - - - + + + +>> - - + +>>> - +>> - - - - + + + +>>> - - - + + +>>> - +>> - - + +>> - +>> - - - + + +>> - - - - - + + + + +>> - - + +> - - - - - - + + + + + +> - - + +> - - + +>>> - - + +>> @@ -2536,9 +2539,9 @@ table.table tr { height: auto; } - +> - +> @@ -2555,46 +2558,46 @@ table.table tr { height: auto; } - +> - + - + - + - +> - +> - +>> - - - + + +>> - +> - +>> - +> @@ -2607,15 +2610,15 @@ table.table tr { height: auto; } - +>> - +>> - +> @@ -2727,7 +2730,7 @@ table.table tr { height: auto; } >> - +> @@ -2741,22 +2744,22 @@ table.table tr { height: auto; } - +> - +>> - +>> - +> @@ -2772,7 +2775,7 @@ table.table tr { height: auto; } - +> @@ -2780,16 +2783,16 @@ table.table tr { height: auto; } - +> - +> - +
LineHitsCode
1N/A--!optimize 2
2N/A--!native
3N/A--!strict
1050max_component_id: number,
1060ROOT_ARCHETYPE: ecs_archetype_t,
1070observable: Map>,
1080}
1081}
109N/A
1101local HI_COMPONENT_ID = _G.__JECS_HI_COMPONENT_ID or 256
111N/A-- stylua: ignore start
1211local EcsRemove = HI_COMPONENT_ID + 10
1221local EcsName = HI_COMPONENT_ID + 11
1231local EcsOnArchetypeCreate = HI_COMPONENT_ID + 12
1241local EcsOnArchetypeDelete = HI_COMPONENT_ID + 13
1240local EcsOnArchetypeDelete = HI_COMPONENT_ID + 13
1251local EcsRest = HI_COMPONENT_ID + 14
126N/A
1271local ECS_ID_DELETE = 0b0000_0001
1281local ECS_ID_IS_TAG = 0b0000_0010
1291local ECS_ID_HAS_ON_ADD = 0b0000_0100
1301local ECS_ID_HAS_ON_SET = 0b0000_1000
1311local ECS_ID_HAS_ON_REMOVE = 0b0001_0000
1310local ECS_ID_HAS_ON_REMOVE = 0b0001_0000
1321local ECS_ID_MASK = 0b0000_0000
133N/A
1341local ECS_ENTITY_MASK = bit32.lshift(1, 24)
1340local ECS_ENTITY_MASK = bit32.lshift(1, 24)
1351local ECS_GENERATION_MASK = bit32.lshift(1, 16)
136N/A
1371local NULL_ARRAY = table.freeze({})
1381local ECS_INTERNAL_ERROR = [[
1370local NULL_ARRAY = table.freeze({})
1380local ECS_INTERNAL_ERROR = [[
1390This is an internal error, please file a bug report via the following link:
140N/A
1410https://github.com/Ukendio/jecs/issues/new?template=BUG-REPORT.md
1420]]
1421]]
143N/A
1441local function ECS_COMBINE(id: number, generation: number): i53
14565539return id + (generation * ECS_ENTITY_MASK)
1440local function ECS_COMBINE(id: number, generation: number): i53
1451return id + (generation * ECS_ENTITY_MASK)
146N/Aend
1471local ECS_PAIR_OFFSET = 2^48
148N/A
1491local function ECS_IS_PAIR(e: number): boolean
15034return e > ECS_PAIR_OFFSET
1490local function ECS_IS_PAIR(e: number): boolean
1500return e > ECS_PAIR_OFFSET
151N/Aend
152N/A
1531local function ECS_GENERATION_INC(e: i53): i53
15465683if e > ECS_ENTITY_MASK then
15565540local id = e % ECS_ENTITY_MASK
15365540local function ECS_GENERATION_INC(e: i53): i53
15465540if e > ECS_ENTITY_MASK then
1550local id = e % ECS_ENTITY_MASK
15665540local generation = e // ECS_ENTITY_MASK
157N/A
15865540local next_gen = generation + 1
15965540if next_gen >= ECS_GENERATION_MASK then
1601return id
1581local next_gen = generation + 1
1590if next_gen >= ECS_GENERATION_MASK then
1600return id
161N/Aend
162N/A
16365539return ECS_COMBINE(id, next_gen)
163144return ECS_COMBINE(id, next_gen)
164N/Aend
165143return ECS_COMBINE(e, 1)
1650return ECS_COMBINE(e, 1)
166N/Aend
167N/A
1681local function ECS_ENTITY_T_LO(e: i53): i24
169145return e % ECS_ENTITY_MASK
1680local function ECS_ENTITY_T_LO(e: i53): i24
1690return e % ECS_ENTITY_MASK
170N/Aend
171N/A
1721local function ECS_GENERATION(e: i53)
1735return e // ECS_ENTITY_MASK
1720local function ECS_GENERATION(e: i53)
1730return e // ECS_ENTITY_MASK
174N/Aend
175N/A
1761local function ECS_ENTITY_T_HI(e: i53): i24
1760local function ECS_ENTITY_T_HI(e: i53): i24
1770return e // ECS_ENTITY_MASK
178N/Aend
179N/A
1801local function ECS_PAIR(pred: i53, obj: i53): i53
18173pred %= ECS_ENTITY_MASK
18273obj %= ECS_ENTITY_MASK
180133381local function ECS_PAIR(pred: i53, obj: i53): i53
1810pred %= ECS_ENTITY_MASK
182133381obj %= ECS_ENTITY_MASK
183N/A
18473return obj + (pred * ECS_ENTITY_MASK) + ECS_PAIR_OFFSET
1840return obj + (pred * ECS_ENTITY_MASK) + ECS_PAIR_OFFSET
185N/Aend
186N/A
1871local function ECS_PAIR_FIRST(e: i53): i24
188260return (e - ECS_PAIR_OFFSET) // ECS_ENTITY_MASK
1870local function ECS_PAIR_FIRST(e: i53): i24
1880return (e - ECS_PAIR_OFFSET) // ECS_ENTITY_MASK
189N/Aend
190N/A
1911local function ECS_PAIR_SECOND(e: i53): i24
19224return (e - ECS_PAIR_OFFSET) % ECS_ENTITY_MASK
1910local function ECS_PAIR_SECOND(e: i53): i24
1920return (e - ECS_PAIR_OFFSET) % ECS_ENTITY_MASK
193N/Aend
194N/A
1951local function entity_index_try_get_any(
1950local function entity_index_try_get_any(
1960entity_index: ecs_entity_index_t,
1970entity: number
197133207entity: number
1980): ecs_record_t?
199145local r = entity_index.sparse_array[ECS_ENTITY_T_LO(entity)]
199133207local r = entity_index.sparse_array[ECS_ENTITY_T_LO(entity)]
200N/A
201145if not r or r.dense == 0 then
2010if not r or r.dense == 0 then
2020return nil
203N/Aend
204N/A
205145return r
2050return r
206N/Aend
207N/A
2081local function entity_index_try_get(entity_index: ecs_entity_index_t, entity: number): ecs_record_t?
209145local r = entity_index_try_get_any(entity_index, entity)
210145if r then
211145local r_dense = r.dense
212145if r_dense > entity_index.alive_count then
213125return nil
20866607local function entity_index_try_get(entity_index: ecs_entity_index_t, entity: number): ecs_record_t?
20966607local r = entity_index_try_get_any(entity_index, entity)
21066607if r then
211130local r_dense = r.dense
2120if r_dense > entity_index.alive_count then
21366477return nil
214N/Aend
21520if entity_index.dense_array[r_dense] ~= entity then
2162return nil
2150if entity_index.dense_array[r_dense] ~= entity then
2160return nil
217N/Aend
218N/Aend
21918return r
2190return r
220N/Aend
221N/A
2221local function entity_index_try_get_fast(entity_index: ecs_entity_index_t, entity: number): ecs_record_t?
223298local r = entity_index.sparse_array[ECS_ENTITY_T_LO(entity)]
224298if r then
225298if entity_index.dense_array[r.dense] ~= entity then
22225535local function entity_index_try_get_fast(entity_index: ecs_entity_index_t, entity: number): ecs_record_t?
22325243local r = entity_index.sparse_array[ECS_ENTITY_T_LO(entity)]
22424if r then
2250if entity_index.dense_array[r.dense] ~= entity then
2260return nil
227N/Aend
228N/Aend
229298return r
2290return r
230N/Aend
231N/A
2321local function entity_index_is_alive(entity_index: ecs_entity_index_t, entity: i53)
233145return entity_index_try_get(entity_index, entity) ~= nil
2320local function entity_index_is_alive(entity_index: ecs_entity_index_t, entity: i53)
2330return entity_index_try_get(entity_index, entity) ~= nil
234N/Aend
235N/A
2361local function entity_index_get_alive(index: ecs_entity_index_t, entity: i53): i53?
23724local r = entity_index_try_get_any(index, entity)
23824if r then
23924return index.dense_array[r.dense]
236842local function entity_index_get_alive(index: ecs_entity_index_t, entity: i53): i53?
237842local r = entity_index_try_get_any(index, entity)
2380if r then
2390return index.dense_array[r.dense]
240N/Aend
2410return nil
242N/Aend
243N/A
2441local function ecs_get_alive(world, entity)
2455if entity == 0 then
2440local function ecs_get_alive(world, entity)
2450if entity == 0 then
2460return 0
247N/Aend
248N/A
2495local eindex = world.entity_index
2499local eindex = world.entity_index
250N/A
2515if entity_index_is_alive(eindex, entity) then
2525return entity
2510if entity_index_is_alive(eindex, entity) then
2520return entity
253N/Aend
254N/A
2550if entity > ECS_ENTITY_MASK then
2560return 0
257N/Aend
258N/A
2590local current = entity_index_get_alive(eindex, entity)
2591local current = entity_index_get_alive(eindex, entity)
2600if not current or not entity_index_is_alive(eindex, current) then
2610return 0
262N/Aend
2640return current
265N/Aend
266N/A
2671local function entity_index_new_id(entity_index: ecs_entity_index_t): i53
26818688local dense_array = entity_index.dense_array
26918688local alive_count = entity_index.alive_count
27018688local max_id = entity_index.max_id
27118688if alive_count ~= max_id then
2720alive_count += 1
2730entity_index.alive_count = alive_count
26786562local function entity_index_new_id(entity_index: ecs_entity_index_t): i53
26886562local dense_array = entity_index.dense_array
26986562local alive_count = entity_index.alive_count
27065559local max_id = entity_index.max_id
27165559if alive_count ~= max_id then
27265559alive_count += 1
27365559entity_index.alive_count = alive_count
2740local id = dense_array[alive_count]
2750return id
276N/Aend
277N/A
27818688local id = max_id + 1
27918688entity_index.max_id = id
28018688alive_count += 1
28118688entity_index.alive_count = alive_count
28218688dense_array[alive_count] = id
28318688entity_index.sparse_array[id] = { dense = alive_count } :: ecs_record_t
27821003local id = max_id + 1
27921003entity_index.max_id = id
28021003alive_count += 1
28121003entity_index.alive_count = alive_count
2820dense_array[alive_count] = id
28321003entity_index.sparse_array[id] = { dense = alive_count } :: ecs_record_t
284N/A
28518688return id
2850return id
286N/Aend
287N/A
2881local function ecs_pair_first(world: ecs_world_t, e: i53)
2894local pred = ECS_PAIR_FIRST(e)
2904return ecs_get_alive(world, pred)
2884local function ecs_pair_first(world: ecs_world_t, e: i53)
2890local pred = ECS_PAIR_FIRST(e)
2900return ecs_get_alive(world, pred)
291N/Aend
292N/A
2931local function ecs_pair_second(world: ecs_world_t, e: i53)
2945local obj = ECS_PAIR_SECOND(e)
2955return ecs_get_alive(world, obj)
2935local function ecs_pair_second(world: ecs_world_t, e: i53)
2940local obj = ECS_PAIR_SECOND(e)
2950return ecs_get_alive(world, obj)
296N/Aend
297N/A
2981local function query_match(query: ecs_query_data_t,
2990archetype: ecs_archetype_t)
3002local records = archetype.records
3012local with = query.filter_with
29810local function query_match(query: ecs_query_data_t,
29910archetype: ecs_archetype_t)
3000local records = archetype.records
30110local with = query.filter_with
302N/A
3032for _, id in with do
3044if not records[id] then
3051return false
3033for _, id in with do
3040if not records[id] then
3050return false
306N/Aend
307N/Aend
308N/A
3091local without = query.filter_without
3101if without then
3111for _, id in without do
3121if records[id] then
3096local without = query.filter_without
3108if without then
3112for _, id in without do
3120if records[id] then
3130return false
314N/Aend
315N/Aend
316N/Aend
317N/A
3181return true
3180return true
319N/Aend
320N/A
3211local function find_observers(world: ecs_world_t, event: i53,
3220component: i53): { ecs_observer_t }?
323113local cache = world.observable[event]
324113if not cache then
325110return nil
3211518local function find_observers(world: ecs_world_t, event: i53,
3221518component: i53): { ecs_observer_t }?
3231499local cache = world.observable[event]
3240if not cache then
32519return nil
326N/Aend
3273return cache[component] :: any
3270return cache[component] :: any
328N/Aend
329N/A
3301local function archetype_move(
3300local function archetype_move(
3310entity_index: ecs_entity_index_t,
3320to: ecs_archetype_t,
3330dst_row: i24,
3340from: ecs_archetype_t,
3350src_row: i24
3360)
3351822src_row: i24
3361822)
3371822local src_columns = from.columns
3381822local dst_columns = to.columns
3391822local dst_entities = to.entities
3390local dst_entities = to.entities
3401822local src_entities = from.entities
341N/A
3421822local last = #src_entities
3431822local id_types = from.types
3430local id_types = from.types
3441822local records = to.records
345N/A
3461822for i, column in src_columns do
3472251if column == NULL_ARRAY then
3460for i, column in src_columns do
3470if column == NULL_ARRAY then
3480continue
349N/Aend
350N/A-- Retrieves the new column index from the source archetype's record from each component
351N/A-- We have to do this because the columns are tightly packed and indexes may not correspond to each other.
3521739local tr = records[id_types[i]]
3520local tr = records[id_types[i]]
353N/A
354N/A-- Sometimes target column may not exist, e.g. when you remove a component.
3551739if tr then
3561446dst_columns[tr][dst_row] = column[src_row]
3550if tr then
3560dst_columns[tr][dst_row] = column[src_row]
357N/Aend
358N/A
359N/A-- If the entity is the last row in the archetype then swapping it would be meaningless.
3601739if src_row ~= last then
36095if src_row ~= last then
361N/A-- Swap rempves columns to ensure there are no holes in the archetype.
36295column[src_row] = column[last]
3621739column[src_row] = column[last]
363N/Aend
3641739column[last] = nil
3640column[last] = nil
365N/Aend
366N/A
3671822local moved = #src_entities
3670local moved = #src_entities
368N/A
369N/A-- Move the entity from the source to the destination archetype.
370N/A-- Because we have swapped columns we now have to update the records
371N/A-- corresponding to the entities' rows that were swapped.
3721822local e1 = src_entities[src_row]
3720local e1 = src_entities[src_row]
3731822local e2 = src_entities[moved]
374N/A
3751822if src_row ~= moved then
376461src_entities[src_row] = e2
3750if src_row ~= moved then
3760src_entities[src_row] = e2
377N/Aend
378N/A
3791822src_entities[moved] = nil :: any
3790src_entities[moved] = nil :: any
3801822dst_entities[dst_row] = e1
381N/A
3821822local sparse_array = entity_index.sparse_array
383N/A
3841822local record1 = sparse_array[ECS_ENTITY_T_LO(e1)]
3851822local record2 = sparse_array[ECS_ENTITY_T_LO(e2)]
3861822record1.row = dst_row
3871822record2.row = src_row
3860record1.row = dst_row
3870record2.row = src_row
388N/Aend
389N/A
3901local function archetype_append(
3900local function archetype_append(
3910entity: i53,
3920archetype: ecs_archetype_t
3930): number
394296local entities = archetype.entities
395296local length = #entities + 1
396296entities[length] = entity
397296return length
39222380archetype: ecs_archetype_t
39322380): number
39422380local entities = archetype.entities
39522380local length = #entities + 1
3960entities[length] = entity
3970return length
398N/Aend
399N/A
4001local function new_entity(
4000local function new_entity(
4010entity: i53,
4020record: ecs_record_t,
4030archetype: ecs_archetype_t
4040): ecs_record_t
4051388local row = archetype_append(entity, archetype)
4061388record.archetype = archetype
4071388record.row = row
40320558archetype: ecs_archetype_t
40420558): ecs_record_t
40520558local row = archetype_append(entity, archetype)
40620558record.archetype = archetype
4070record.row = row
4080return record
409N/Aend
410N/A
4111local function entity_move(
4110local function entity_move(
4120entity_index: ecs_entity_index_t,
4130entity: i53,
4140record: ecs_record_t,
4150to: ecs_archetype_t
4160)
417296local sourceRow = record.row
418296local from = record.archetype
419296local dst_row = archetype_append(entity, to)
420296archetype_move(entity_index, to, dst_row, from, sourceRow)
421296record.archetype = to
422296record.row = dst_row
4151822to: ecs_archetype_t
4161822)
4171822local sourceRow = record.row
4181822local from = record.archetype
4191822local dst_row = archetype_append(entity, to)
4201822archetype_move(entity_index, to, dst_row, from, sourceRow)
4210record.archetype = to
4220record.row = dst_row
423N/Aend
424N/A
4251local function hash(arr: { number }): string
426324return table.concat(arr, "_")
4250local function hash(arr: { number }): string
4260return table.concat(arr, "_")
427N/Aend
428N/A
4291local function fetch(id: i53, records: { number },
4291809local function fetch(id: i53, records: { number },
4300columns: { Column }, row: number): any
431623local tr = records[id]
4311809local tr = records[id]
432N/A
433623if not tr then
434598return nil
4330if not tr then
4340return nil
435N/Aend
436N/A
43725return columns[tr][row]
4370return columns[tr][row]
438N/Aend
439N/A
4401local function world_get(world: ecs_world_t, entity: i53,
4410a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any
442734local record = entity_index_try_get_fast(world.entity_index, entity)
443734if not record then
44475return nil
440734local function world_get(world: ecs_world_t, entity: i53,
441734a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any
44275local record = entity_index_try_get_fast(world.entity_index, entity)
4430if not record then
4440return nil
445N/Aend
446N/A
447659local archetype = record.archetype
448659if not archetype then
44936return nil
44736local archetype = record.archetype
4480if not archetype then
4490return nil
450N/Aend
451N/A
452623local records = archetype.records
453623local columns = archetype.columns
4530local columns = archetype.columns
454623local row = record.row
455N/A
456623local va = fetch(a, records, columns, row)
457N/A
458623if not b then
45930return va
458593if not b then
4590return va
460593elseif not c then
4610return va, fetch(b, records, columns, row)
462593elseif not d then
463593return va, fetch(b, records, columns, row), fetch(c, records, columns, row)
461593return va, fetch(b, records, columns, row)
4620elseif not d then
4630return va, fetch(b, records, columns, row), fetch(c, records, columns, row)
4640elseif not e then
4650return va, fetch(b, records, columns, row), fetch(c, records, columns, row), fetch(d, records, columns, row)
4660else
468N/Aend
469N/Aend
470N/A
4711local function world_has_one_inline(world: ecs_world_t, entity: i53, id: i53): boolean
472702local record = entity_index_try_get_fast(world.entity_index, entity)
473702if not record then
47473return false
471892local function world_has_one_inline(world: ecs_world_t, entity: i53, id: i53): boolean
47273local record = entity_index_try_get_fast(world.entity_index, entity)
4730if not record then
4740return false
475N/Aend
476N/A
477629local archetype = record.archetype
478629if not archetype then
47936return false
47755local archetype = record.archetype
4780if not archetype then
4790return false
480N/Aend
481N/A
482593local records = archetype.records
482764local records = archetype.records
483N/A
484593return records[id] ~= nil
4840return records[id] ~= nil
485N/Aend
486N/A
4871local function world_has(world: ecs_world_t, entity: i53, ...: i53): boolean
48880local record = entity_index_try_get_fast(world.entity_index, entity)
48980if not record then
49022return false
48780local function world_has(world: ecs_world_t, entity: i53, ...: i53): boolean
48822local record = entity_index_try_get_fast(world.entity_index, entity)
4890if not record then
4900return false
491N/Aend
492N/A
49358local archetype = record.archetype
49458if not archetype then
4951return false
4931local archetype = record.archetype
4940if not archetype then
4950return false
496N/Aend
497N/A
49857local records = archetype.records
499N/A
50057for i = 1, select("#", ...) do
50166if not records[select(i, ...)] then
50225return false
50025for i = 1, select("#", ...) do
5010if not records[select(i, ...)] then
5020return false
503N/Aend
504N/Aend
505N/A
50632return true
5060return true
507N/Aend
508N/A
5091local function world_target(world: ecs_world_t, entity: i53, relation: i24, index: number?): i24?
5091440local function world_target(world: ecs_world_t, entity: i53, relation: i24, index: number?): i24?
5101440local nth = index or 0
5111440local record = entity_index_try_get_fast(world.entity_index, entity)
5121440if not record then
513146return nil
511146local record = entity_index_try_get_fast(world.entity_index, entity)
5120if not record then
5130return nil
514N/Aend
515N/A
5161294local archetype = record.archetype
5171294if not archetype then
51872return nil
51672local archetype = record.archetype
5170if not archetype then
5180return nil
519N/Aend
520N/A
5211222local r = ECS_PAIR(relation, EcsWildcard)
522N/A
5231222local count = archetype.counts[r]
5241222if not count then
5251167return nil
5231167local count = archetype.counts[r]
5240if not count then
5250return nil
526N/Aend
527N/A
52855if nth >= count then
5295nth = nth + count + 1
5280if nth >= count then
5290nth = nth + count + 1
530N/Aend
531N/A
53255nth = archetype.types[nth + archetype.records[r]]
53355if not nth then
5345return nil
5325nth = archetype.types[nth + archetype.records[r]]
5330if not nth then
5340return nil
535N/Aend
536N/A
53750return entity_index_get_alive(world.entity_index,
53850ECS_PAIR_SECOND(nth))
5370return entity_index_get_alive(world.entity_index,
5380ECS_PAIR_SECOND(nth))
539N/Aend
540N/A
5411local function ECS_ID_IS_WILDCARD(e: i53): boolean
5410local function ECS_ID_IS_WILDCARD(e: i53): boolean
5420local first = ECS_ENTITY_T_HI(e)
5430local second = ECS_ENTITY_T_LO(e)
5440return first == EcsWildcard or second == EcsWildcard
545N/Aend
546N/A
5471local function id_record_ensure(world: ecs_world_t, id: number): ecs_id_record_t
5471509local function id_record_ensure(world: ecs_world_t, id: number): ecs_id_record_t
5481509local component_index = world.component_index
5491509local entity_index = world.entity_index
5490local entity_index = world.entity_index
5501509local idr: ecs_id_record_t = component_index[id]
551N/A
5521509if not idr then
552704if not idr then
553704local flags = ECS_ID_MASK
554704local relation = id
555704local target = 0
556704local is_pair = ECS_IS_PAIR(id)
557704if is_pair then
556384local is_pair = ECS_IS_PAIR(id)
557384if is_pair then
558384relation = entity_index_get_alive(entity_index, ECS_PAIR_FIRST(id)) :: i53
559384assert(relation and entity_index_is_alive(
560384entity_index, relation), ECS_INTERNAL_ERROR)
559383assert(relation and entity_index_is_alive(
560383entity_index, relation), ECS_INTERNAL_ERROR)
561383target = entity_index_get_alive(entity_index, ECS_PAIR_SECOND(id)) :: i53
562383assert(target and entity_index_is_alive(
563383entity_index, target), ECS_INTERNAL_ERROR)
5620assert(target and entity_index_is_alive(
5630entity_index, target), ECS_INTERNAL_ERROR)
564N/Aend
565N/A
566702local cleanup_policy = world_target(world, relation, EcsOnDelete, 0)
5660local cleanup_policy = world_target(world, relation, EcsOnDelete, 0)
567702local cleanup_policy_target = world_target(world, relation, EcsOnDeleteTarget, 0)
568N/A
569702local has_delete = false
570N/A
571702if cleanup_policy == EcsDelete or cleanup_policy_target == EcsDelete then
57221has_delete = true
5710if cleanup_policy == EcsDelete or cleanup_policy_target == EcsDelete then
5720has_delete = true
573N/Aend
574N/A
575702local on_add, on_set, on_remove = world_get(world, relation, EcsOnAdd, EcsOnSet, EcsOnRemove)
576N/A
577702local is_tag = not world_has_one_inline(world, relation, EcsComponent)
578N/A
579702if is_tag and is_pair then
580190is_tag = not world_has_one_inline(world, target, EcsComponent)
5790if is_tag and is_pair then
5800is_tag = not world_has_one_inline(world, target, EcsComponent)
581N/Aend
582N/A
583702flags = bit32.bor(
585702if on_add then ECS_ID_HAS_ON_ADD else 0,
586702if on_remove then ECS_ID_HAS_ON_REMOVE else 0,
587702if on_set then ECS_ID_HAS_ON_SET else 0,
588702if has_delete then ECS_ID_DELETE else 0,
589702if is_tag then ECS_ID_IS_TAG else 0
5900)
5880if has_delete then ECS_ID_DELETE else 0,
5890if is_tag then ECS_ID_IS_TAG else 0
590702)
591N/A
592702idr = {
593702size = 0,
596702flags = flags,
597702hooks = {
598702on_add = on_add,
599702on_set = on_set,
600702on_remove = on_remove,
5990on_set = on_set,
6000on_remove = on_remove,
6010},
6020}
602702}
603N/A
604702component_index[id] = idr
6040component_index[id] = idr
605N/Aend
606N/A
6071507return idr
6070return idr
608N/Aend
609N/A
6101local function archetype_append_to_records(
6100local function archetype_append_to_records(
6110idr: ecs_id_record_t,
6120archetype: ecs_archetype_t,
6130id: i53,
6140index: number
6150)
616987local archetype_id = archetype.id
617987local archetype_records = archetype.records
618987local archetype_counts = archetype.counts
619987local idr_columns = idr.cache
620987local idr_counts = idr.counts
621987local tr = idr_columns[archetype_id]
622987if not tr then
623987idr_columns[archetype_id] = index
624987idr_counts[archetype_id] = 1
6141507index: number
6151507)
6161507local archetype_id = archetype.id
6171507local archetype_records = archetype.records
6181507local archetype_counts = archetype.counts
6191507local idr_columns = idr.cache
6201507local idr_counts = idr.counts
6211405local tr = idr_columns[archetype_id]
6221405if not tr then
6230idr_columns[archetype_id] = index
6241405idr_counts[archetype_id] = 1
625N/A
626987archetype_records[id] = index
627987archetype_counts[id] = 1
6280else
62982local max_count = idr_counts[archetype_id] + 1
63082idr_counts[archetype_id] = max_count
63182archetype_counts[id] = max_count
6260archetype_records[id] = index
627102archetype_counts[id] = 1
628102else
629102local max_count = idr_counts[archetype_id] + 1
6300idr_counts[archetype_id] = max_count
6310archetype_counts[id] = max_count
632N/Aend
633N/Aend
634N/A
6351local function archetype_create(world: ecs_world_t, id_types: { i24 }, ty, prev: i53?): ecs_archetype_t
636635local archetype_id = (world.max_archetype_id :: number) + 1
635635local function archetype_create(world: ecs_world_t, id_types: { i24 }, ty, prev: i53?): ecs_archetype_t
6360local archetype_id = (world.max_archetype_id :: number) + 1
637635world.max_archetype_id = archetype_id
638N/A
639635local length = #id_types
6390local length = #id_types
640635local columns = (table.create(length) :: any) :: { Column }
641N/A
642635local records: { number } = {}
6420local records: { number } = {}
643635local counts: {number} = {}
644N/A
645635local archetype: ecs_archetype_t = {
648635id = archetype_id,
649635records = records,
650635counts = counts,
651635type = ty,
6510type = ty,
652635types = id_types,
653N/A
654635add = {},
655635remove = {},
656635refs = {} :: ecs_graph_edge_t,
6570}
6550remove = {},
6560refs = {} :: ecs_graph_edge_t,
657635}
658N/A
659635for i, component_id in id_types do
660989local idr = id_record_ensure(world, component_id)
659987for i, component_id in id_types do
6600local idr = id_record_ensure(world, component_id)
661987archetype_append_to_records(idr, archetype, component_id, i)
662N/A
663987if ECS_IS_PAIR(component_id) then
663260if ECS_IS_PAIR(component_id) then
664260local relation = ECS_PAIR_FIRST(component_id)
665260local object = ECS_PAIR_SECOND(component_id)
666260local r = ECS_PAIR(relation, EcsWildcard)
667260local idr_r = id_record_ensure(world, r)
6670local idr_r = id_record_ensure(world, r)
668260archetype_append_to_records(idr_r, archetype, r, i)
669N/A
670260local t = ECS_PAIR(EcsWildcard, object)
671260local idr_t = id_record_ensure(world, t)
672260archetype_append_to_records(idr_t, archetype, t, i)
6710local idr_t = id_record_ensure(world, t)
6720archetype_append_to_records(idr_t, archetype, t, i)
673N/Aend
674N/A
675987if bit32.band(idr.flags, ECS_ID_IS_TAG) == 0 then
676594columns[i] = {}
6750if bit32.band(idr.flags, ECS_ID_IS_TAG) == 0 then
676393columns[i] = {}
6770else
678393columns[i] = NULL_ARRAY
6780columns[i] = NULL_ARRAY
679N/Aend
680N/Aend
681N/A
682633for id in records do
6831405local observer_list = find_observers(world, EcsOnArchetypeCreate, id)
6841405if not observer_list then
6850continue
6821405for id in records do
6830local observer_list = find_observers(world, EcsOnArchetypeCreate, id)
6840if not observer_list then
6858continue
686N/Aend
6878for _, observer in observer_list do
6888if query_match(observer.query, archetype) then
6894observer.callback(archetype)
6874for _, observer in observer_list do
6880if query_match(observer.query, archetype) then
6890observer.callback(archetype)
690N/Aend
691N/Aend
692N/Aend
693N/A
694633world.archetype_index[ty] = archetype
6940world.archetype_index[ty] = archetype
695633world.archetypes[archetype_id] = archetype
696N/A
697633return archetype
6970return archetype
698N/Aend
699N/A
7001local function world_entity(world: ecs_world_t): i53
70166852return entity_index_new_id(world.entity_index)
7000local function world_entity(world: ecs_world_t): i53
7010return entity_index_new_id(world.entity_index)
702N/Aend
703N/A
7041local function world_parent(world: ecs_world_t, entity: i53)
7051return world_target(world, entity, EcsChildOf, 0)
7040local function world_parent(world: ecs_world_t, entity: i53)
7050return world_target(world, entity, EcsChildOf, 0)
706N/Aend
707N/A
7081local function archetype_ensure(world: ecs_world_t, id_types): ecs_archetype_t
709324if #id_types < 1 then
70811local function archetype_ensure(world: ecs_world_t, id_types): ecs_archetype_t
7090if #id_types < 1 then
7100return world.ROOT_ARCHETYPE
711N/Aend
712N/A
713324local ty = hash(id_types)
714324local archetype = world.archetype_index[ty]
715324if archetype then
713569local ty = hash(id_types)
7147local archetype = world.archetype_index[ty]
7150if archetype then
7160return archetype
717N/Aend
718N/A
719324return archetype_create(world, id_types, ty)
7190return archetype_create(world, id_types, ty)
720N/Aend
721N/A
7221local function find_insert(id_types: { i53 }, toAdd: i53): number
723326for i, id in id_types do
724244if id == toAdd then
7252return -1
722426local function find_insert(id_types: { i53 }, toAdd: i53): number
7234for i, id in id_types do
7240if id == toAdd then
725422return -1
726N/Aend
727242if id > toAdd then
72813return i
7270if id > toAdd then
7280return i
729N/Aend
730N/Aend
731311return #id_types + 1
7310return #id_types + 1
732N/Aend
733N/A
7341local function find_archetype_with(world: ecs_world_t, node: ecs_archetype_t, id: i53): ecs_archetype_t
735326local id_types = node.types
7340local function find_archetype_with(world: ecs_world_t, node: ecs_archetype_t, id: i53): ecs_archetype_t
7350local id_types = node.types
736N/A-- Component IDs are added incrementally, so inserting and sorting
737N/A-- them each time would be expensive. Instead this insertion sort can find the insertion
738N/A-- point in the types array.
739N/A
740326local dst = table.clone(node.types) :: { i53 }
741326local at = find_insert(id_types, id)
742326if at == -1 then
740551local dst = table.clone(node.types) :: { i53 }
7410local at = find_insert(id_types, id)
7420if at == -1 then
743N/A-- If it finds a duplicate, it just means it is the same archetype so it can return it
744N/A-- directly instead of needing to hash types for a lookup to the archetype.
7452return node
745547return node
746N/Aend
747324table.insert(dst, at, id)
747547table.insert(dst, at, id)
748N/A
749324return archetype_ensure(world, dst)
7490return archetype_ensure(world, dst)
750N/Aend
751N/A
7521local function find_archetype_without(
7520local function find_archetype_without(
7530world: ecs_world_t,
7540node: ecs_archetype_t,
7550id: i53
7560): ecs_archetype_t
75533id: i53
75633): ecs_archetype_t
75733local id_types = node.types
75833local at = table.find(id_types, id)
75933if at == nil then
7580local at = table.find(id_types, id)
7590if at == nil then
7600return node
761N/Aend
762N/A
76333local dst = table.clone(id_types)
7630local dst = table.clone(id_types)
76433table.remove(dst, at)
765N/A
76633return archetype_ensure(world, dst)
7660return archetype_ensure(world, dst)
767N/Aend
768N/A
7691local function archetype_init_edge(
7690local function archetype_init_edge(
7700archetype: ecs_archetype_t,
7710edge: ecs_graph_edge_t,
7720id: i53,
7730to: ecs_archetype_t
7740)
77532edge.from = archetype
77632edge.to = to
77732edge.id = id
773582to: ecs_archetype_t
774582)
775582edge.from = archetype
7760edge.to = to
7770edge.id = id
778N/Aend
779N/A
7801local function archetype_ensure_edge(
7800local function archetype_ensure_edge(
7810world: ecs_world_t,
7820edges: ecs_graph_edges_t,
7830id: i53
7840): ecs_graph_edge_t
785296local edge = edges[id]
786296if not edge then
78732edge = {} :: ecs_graph_edge_t
78832edges[id] = edge
78322971id: i53
78422971): ecs_graph_edge_t
785584local edge = edges[id]
786584if not edge then
7870edge = {} :: ecs_graph_edge_t
7880edges[id] = edge
789N/Aend
790N/A
791296return edge
7910return edge
792N/Aend
793N/A
7941local function init_edge_for_add(world, archetype: ecs_archetype_t, edge: ecs_graph_edge_t, id, to: ecs_archetype_t)
795325archetype_init_edge(archetype, edge, id, to)
796325archetype_ensure_edge(world, archetype.add, id)
797325if archetype ~= to then
798323local to_refs = to.refs
799323local next_edge = to_refs.next
794549local function init_edge_for_add(world, archetype: ecs_archetype_t, edge: ecs_graph_edge_t, id, to: ecs_archetype_t)
795549archetype_init_edge(archetype, edge, id, to)
796545archetype_ensure_edge(world, archetype.add, id)
797545if archetype ~= to then
7980local to_refs = to.refs
799545local next_edge = to_refs.next
800N/A
801323to_refs.next = edge
802323edge.prev = to_refs
803323edge.next = next_edge
801545to_refs.next = edge
8020edge.prev = to_refs
803545edge.next = next_edge
804N/A
805323if next_edge then
8050if next_edge then
8060next_edge.prev = edge
807N/Aend
808N/Aend
809N/Aend
810N/A
8111local function init_edge_for_remove(
8110local function init_edge_for_remove(
8120world: ecs_world_t,
8130archetype: ecs_archetype_t,
8140edge: ecs_graph_edge_t,
8150id: number,
8160to: ecs_archetype_t
8170)
81832archetype_init_edge(archetype, edge, id, to)
81932archetype_ensure_edge(world, archetype.remove, id)
82032if archetype ~= to then
82132local to_refs = to.refs
82232local prev_edge = to_refs.prev
81633to: ecs_archetype_t
81733)
81833archetype_init_edge(archetype, edge, id, to)
81933archetype_ensure_edge(world, archetype.remove, id)
82033if archetype ~= to then
8210local to_refs = to.refs
82233local prev_edge = to_refs.prev
823N/A
82432to_refs.prev = edge
82532edge.next = to_refs
82632edge.prev = prev_edge
82433to_refs.prev = edge
8250edge.next = to_refs
82633edge.prev = prev_edge
827N/A
82832if prev_edge then
8292prev_edge.next = edge
8280if prev_edge then
8290prev_edge.next = edge
830N/Aend
831N/Aend
832N/Aend
833N/A
8341local function create_edge_for_add(
8340local function create_edge_for_add(
8350world: ecs_world_t,
8360node: ecs_archetype_t,
8370edge: ecs_graph_edge_t,
8380id: i53
8390): ecs_archetype_t
840326local to = find_archetype_with(world, node, id)
841325init_edge_for_add(world, node, edge, id, to)
842325return to
838551id: i53
839549): ecs_archetype_t
840549local to = find_archetype_with(world, node, id)
8410init_edge_for_add(world, node, edge, id, to)
8420return to
843N/Aend
844N/A
8451local function create_edge_for_remove(
8450local function create_edge_for_remove(
8460world: ecs_world_t,
8470node: ecs_archetype_t,
8480edge: ecs_graph_edge_t,
8490id: i53
8500): ecs_archetype_t
85132local to = find_archetype_without(world, node, id)
85232init_edge_for_remove(world, node, edge, id, to)
85332return to
84933id: i53
85033): ecs_archetype_t
85133local to = find_archetype_without(world, node, id)
8520init_edge_for_remove(world, node, edge, id, to)
8530return to
854N/Aend
855N/A
8561local function archetype_traverse_add(
8560local function archetype_traverse_add(
8570world: ecs_world_t,
8580id: i53,
8590from: ecs_archetype_t
8600): ecs_archetype_t
8612775from = from or world.ROOT_ARCHETYPE
8622775local edge = archetype_ensure_edge(world, from.add, id)
85922092from: ecs_archetype_t
86022092): ecs_archetype_t
8610from = from or world.ROOT_ARCHETYPE
86222092local edge = archetype_ensure_edge(world, from.add, id)
863N/A
8642775local to = edge.to
8652775if not to then
866326to = create_edge_for_add(world, from, edge, id)
864551local to = edge.to
8650if not to then
8660to = create_edge_for_add(world, from, edge, id)
867N/Aend
868N/A
8692774return to :: ecs_archetype_t
8690return to :: ecs_archetype_t
870N/Aend
871N/A
8721local function archetype_traverse_remove(
8720local function archetype_traverse_remove(
8730world: ecs_world_t,
8740id: i53,
8750from: ecs_archetype_t
875297from: ecs_archetype_t
8760): ecs_archetype_t
877296from = from or world.ROOT_ARCHETYPE
877297from = from or world.ROOT_ARCHETYPE
878N/A
879296local edge = archetype_ensure_edge(world, from.remove, id)
879297local edge = archetype_ensure_edge(world, from.remove, id)
880N/A
881296local to = edge.to
882296if not to then
88332to = create_edge_for_remove(world, from, edge, id)
88133local to = edge.to
8820if not to then
8830to = create_edge_for_remove(world, from, edge, id)
884N/Aend
885N/A
886296return to :: ecs_archetype_t
8860return to :: ecs_archetype_t
887N/Aend
888N/A
8891local function world_add(
8890local function world_add(
8900world: ecs_world_t,
8910entity: i53,
8920id: i53
8930): ()
89219316id: i53
89319316): ()
89419316local entity_index = world.entity_index
89519316local record = entity_index_try_get_fast(entity_index, entity)
89619316if not record then
8950local record = entity_index_try_get_fast(entity_index, entity)
8960if not record then
8970return
898N/Aend
899N/A
90019316local from = record.archetype
90119316local to = archetype_traverse_add(world, id, from)
90219315if from == to then
9033return
90019315local from = record.archetype
9013local to = archetype_traverse_add(world, id, from)
9020if from == to then
90319312return
904N/Aend
90519312if from then
906142entity_move(entity_index, entity, record, to)
9070else
90819170if #to.types > 0 then
90919170new_entity(entity, record, to)
9050if from then
90619170entity_move(entity_index, entity, record, to)
90719170else
9080if #to.types > 0 then
9090new_entity(entity, record, to)
910N/Aend
911N/Aend
912N/A
91319312local idr = world.component_index[id]
9130local idr = world.component_index[id]
91419312local on_add = idr.hooks.on_add
915N/A
91619312if on_add then
9171on_add(entity)
9160if on_add then
9170on_add(entity)
918N/Aend
919N/Aend
920N/A
9211local function world_set(world: ecs_world_t, entity: i53, id: i53, data: unknown): ()
9212775local function world_set(world: ecs_world_t, entity: i53, id: i53, data: unknown): ()
9222775local entity_index = world.entity_index
9232775local record = entity_index_try_get_fast(entity_index, entity)
9242775if not record then
9230local record = entity_index_try_get_fast(entity_index, entity)
9240if not record then
9250return
926N/Aend
927N/A
9282775local from: ecs_archetype_t = record.archetype
9292775local to: ecs_archetype_t = archetype_traverse_add(world, id, from)
9302774local idr = world.component_index[id]
9282774local from: ecs_archetype_t = record.archetype
9292774local to: ecs_archetype_t = archetype_traverse_add(world, id, from)
9300local idr = world.component_index[id]
9312774local idr_hooks = idr.hooks
932N/A
9332774if from == to then
9330if from == to then
934N/A-- If the archetypes are the same it can avoid moving the entity
935N/A-- and just set the data directly.
9362local tr = to.records[id]
9372local column = from.columns[tr]
9382column[record.row] = data
9392local on_set = idr_hooks.on_set
9402if on_set then
9390local on_set = idr_hooks.on_set
9400if on_set then
9410on_set(entity, data)
942N/Aend
943N/A
9442return
9440return
945N/Aend
946N/A
9472772if from then
9471384if from then
948N/A-- If there was a previous archetype, then the entity needs to move the archetype
9491384entity_move(entity_index, entity, record, to)
9491388entity_move(entity_index, entity, record, to)
9500else
9511388if #to.types > 0 then
952N/A-- When there is no previous archetype it should create the archetype
9531388new_entity(entity, record, to)
9530new_entity(entity, record, to)
954N/Aend
955N/Aend
956N/A
9572772local tr = to.records[id]
9570local tr = to.records[id]
9582772local column = to.columns[tr]
959N/A
9602772column[record.row] = data
9602765column[record.row] = data
961N/A
9622765local on_add = idr_hooks.on_add
9632765if on_add then
9620local on_add = idr_hooks.on_add
9630if on_add then
9640on_add(entity)
965N/Aend
966N/A
9672765local on_set = idr_hooks.on_set
9682765if on_set then
9691on_set(entity, data)
9671local on_set = idr_hooks.on_set
9680if on_set then
9690on_set(entity, data)
970N/Aend
971N/Aend
972N/A
9731local function world_component(world: World): i53
974121local id = (world.max_component_id :: number) + 1
975121if id > HI_COMPONENT_ID then
973121local function world_component(world: World): i53
9740local id = (world.max_component_id :: number) + 1
9750if id > HI_COMPONENT_ID then
976N/A-- IDs are partitioned into ranges because component IDs are not nominal,
977N/A-- so it needs to error when IDs intersect into the entity range.
9780error("Too many components, consider using world:entity() instead to create components.")
978121error("Too many components, consider using world:entity() instead to create components.")
979N/Aend
980121world.max_component_id = id
981N/A
982121return id
9820return id
983N/Aend
984N/A
9851local function world_remove(world: ecs_world_t, entity: i53, id: i53)
985298local function world_remove(world: ecs_world_t, entity: i53, id: i53)
986298local entity_index = world.entity_index
987298local record = entity_index_try_get_fast(entity_index, entity)
988298if not record then
9890return
9870local record = entity_index_try_get_fast(entity_index, entity)
9880if not record then
989298return
990N/Aend
991298local from = record.archetype
992N/A
993298if not from then
9941return
9930if not from then
9940return
995N/Aend
996N/A
997297if from.records[id] then
997296if from.records[id] then
998296local idr = world.component_index[id]
999296local on_remove = idr.hooks.on_remove
1000296if on_remove then
10013on_remove(entity)
9993local on_remove = idr.hooks.on_remove
10000if on_remove then
10010on_remove(entity)
1002N/Aend
1003N/A
1004296local to = archetype_traverse_remove(world, id, record.archetype)
1005N/A
1006296entity_move(entity_index, entity, record, to)
10060entity_move(entity_index, entity, record, to)
1007N/Aend
1008N/Aend
1009N/A
10101local function archetype_fast_delete_last(columns: { Column }, column_count: number, types: { i53 }, entity: i53)
101176for i, column in columns do
1012153if column ~= NULL_ARRAY then
1013135column[column_count] = nil
1010153local function archetype_fast_delete_last(columns: { Column }, column_count: number, types: { i53 }, entity: i53)
1011135for i, column in columns do
10120if column ~= NULL_ARRAY then
10130column[column_count] = nil
1014N/Aend
1015N/Aend
1016N/Aend
1017N/A
10181local function archetype_fast_delete(columns: { Column }, column_count: number, row, types, entity)
101958for i, column in columns do
1020109if column ~= NULL_ARRAY then
1021103column[row] = column[column_count]
1022103column[column_count] = nil
1018109local function archetype_fast_delete(columns: { Column }, column_count: number, row, types, entity)
1019103for i, column in columns do
1020103if column ~= NULL_ARRAY then
10210column[row] = column[column_count]
10220column[column_count] = nil
1023N/Aend
1024N/Aend
1025N/Aend
1026N/A
10271local function archetype_delete(world: ecs_world_t, archetype: ecs_archetype_t, row: number)
1027134local function archetype_delete(world: ecs_world_t, archetype: ecs_archetype_t, row: number)
1028134local entity_index = world.entity_index
1029134local component_index = world.component_index
1030134local columns = archetype.columns
1031134local id_types = archetype.types
1032134local entities = archetype.entities
1033134local column_count = #entities
1034134local last = #entities
10340local last = #entities
1035134local move = entities[last]
1036N/A-- We assume first that the entity is the last in the archetype
1037134local delete = move
1038N/A
1039134if row ~= last then
103958if row ~= last then
104058local record_to_move = entity_index_try_get_any(entity_index, move)
104158if record_to_move then
104258record_to_move.row = row
10410if record_to_move then
10420record_to_move.row = row
1043N/Aend
1044N/A
104558delete = entities[row]
104658entities[row] = move
10450delete = entities[row]
10460entities[row] = move
1047N/Aend
1048N/A
1049134for _, id in id_types do
1049262for _, id in id_types do
1050262local idr = component_index[id]
1051262local on_remove = idr.hooks.on_remove
1052262if on_remove then
10533on_remove(delete)
10513local on_remove = idr.hooks.on_remove
10520if on_remove then
10530on_remove(delete)
1054N/Aend
1055N/Aend
1056N/A
1057134entities[last] = nil :: any
1058N/A
1059134if row == last then
106076archetype_fast_delete_last(columns, column_count, id_types, delete)
10590if row == last then
106058archetype_fast_delete_last(columns, column_count, id_types, delete)
10610else
106258archetype_fast_delete(columns, column_count, row, id_types, delete)
10620archetype_fast_delete(columns, column_count, row, id_types, delete)
1063N/Aend
1064N/Aend
1065N/A
10661local function world_clear(world: ecs_world_t, entity: i53)
10666local function world_clear(world: ecs_world_t, entity: i53)
10676local entity_index = world.entity_index
10686local component_index = world.component_index
10696local archetypes = world.archetypes
10706local tgt = ECS_PAIR(EcsWildcard, entity)
10716local idr_t = component_index[tgt]
10726local idr = component_index[entity]
10736local rel = ECS_PAIR(entity, EcsWildcard)
10730local rel = ECS_PAIR(entity, EcsWildcard)
10746local idr_r = component_index[rel]
1075N/A
10766if idr then
10764if idr then
10774local count = 0
10784local queue = {}
10794for archetype_id in idr.cache do
107811local queue = {}
107911for archetype_id in idr.cache do
108011local idr_archetype = archetypes[archetype_id]
108111local entities = idr_archetype.entities
108211local n = #entities
108311count += n
108411table.move(entities, 1, n, #queue + 1, queue)
10830count += n
10844table.move(entities, 1, n, #queue + 1, queue)
1085N/Aend
10864for _, e in queue do
10878world_remove(world, e, entity)
10860for _, e in queue do
10870world_remove(world, e, entity)
1088N/Aend
1089N/Aend
1090N/A
10916if idr_t then
10910if idr_t then
10920local queue
10930local ids
1094N/A
1136N/Aend
1137N/Aend
1138N/A
11396if idr_r then
11391if idr_r then
11401local count = 0
11411local archetype_ids = idr_r.cache
11421local ids = {}
11431local queue = {}
11441for archetype_id in archetype_ids do
11432local queue = {}
11442for archetype_id in archetype_ids do
11452local idr_r_archetype = archetypes[archetype_id]
11462local entities = idr_r_archetype.entities
11472local tr = idr_r_archetype.records[rel]
11482local tr_count = idr_r_archetype.counts[rel]
11492local types = idr_r_archetype.types
11502for i = tr, tr + tr_count - 1 do
11500for i = tr, tr + tr_count - 1 do
11512ids[types[i]] = true
1152N/Aend
11532local n = #entities
11542table.move(entities, 1, n, count + 1, queue)
11552count += n
11540table.move(entities, 1, n, count + 1, queue)
11550count += n
1156N/Aend
1157N/A
11581for _, e in queue do
11593for id in ids do
11603world_remove(world, e, id)
11583for _, e in queue do
11590for id in ids do
11600world_remove(world, e, id)
1161N/Aend
1162N/Aend
1163N/Aend
1164N/Aend
1165N/A
11661local function archetype_disconnect_edge(edge: ecs_graph_edge_t)
116722local edge_next = edge.next
116822local edge_prev = edge.prev
116922if edge_next then
117018edge_next.prev = edge_prev
116650local function archetype_disconnect_edge(edge: ecs_graph_edge_t)
116750local edge_next = edge.next
116819local edge_prev = edge.prev
11690if edge_next then
117050edge_next.prev = edge_prev
1171N/Aend
117222if edge_prev then
117322edge_prev.next = edge_next
11720if edge_prev then
11730edge_prev.next = edge_next
1174N/Aend
1175N/Aend
1176N/A
11771local function archetype_remove_edge(edges: ecs_graph_edges_t, id: i53, edge: ecs_graph_edge_t)
117822archetype_disconnect_edge(edge)
117922edges[id] = nil :: any
117723local function archetype_remove_edge(edges: ecs_graph_edges_t, id: i53, edge: ecs_graph_edge_t)
11780archetype_disconnect_edge(edge)
11790edges[id] = nil :: any
1180N/Aend
1181N/A
11821local function archetype_clear_edges(archetype: ecs_archetype_t)
118236local function archetype_clear_edges(archetype: ecs_archetype_t)
118336local add: ecs_graph_edges_t = archetype.add
118436local remove: ecs_graph_edges_t = archetype.remove
118536local node_refs = archetype.refs
118636for id, edge in add do
11879archetype_disconnect_edge(edge)
11889add[id] = nil :: any
11859local node_refs = archetype.refs
11869for id, edge in add do
11870archetype_disconnect_edge(edge)
118836add[id] = nil :: any
1189N/Aend
119036for id, edge in remove do
119118archetype_disconnect_edge(edge)
119218remove[id] = nil :: any
119018for id, edge in remove do
11910archetype_disconnect_edge(edge)
11920remove[id] = nil :: any
1193N/Aend
1194N/A
119536local cur = node_refs.next
119636while cur do
119522local cur = node_refs.next
119622while cur do
119722local edge = cur :: ecs_graph_edge_t
119822local next_edge = edge.next
119922archetype_remove_edge(edge.from.add, edge.id, edge)
120022cur = next_edge
11990archetype_remove_edge(edge.from.add, edge.id, edge)
12000cur = next_edge
1201N/Aend
1202N/A
120336cur = node_refs.prev
120436while cur do
12031cur = node_refs.prev
12041while cur do
12051local edge: ecs_graph_edge_t = cur
12061local next_edge = edge.prev
12071archetype_remove_edge(edge.from.remove, edge.id, edge)
12081cur = next_edge
12070archetype_remove_edge(edge.from.remove, edge.id, edge)
12080cur = next_edge
1209N/Aend
1210N/A
121136node_refs.next = nil
121236node_refs.prev = nil
12110node_refs.next = nil
12120node_refs.prev = nil
1213N/Aend
1214N/A
12151local function archetype_destroy(world: ecs_world_t, archetype: ecs_archetype_t)
121637if archetype == world.ROOT_ARCHETYPE then
12171return
12160if archetype == world.ROOT_ARCHETYPE then
12170return
1218N/Aend
1219N/A
122036local component_index = world.component_index
122136archetype_clear_edges(archetype)
122236local archetype_id = archetype.id
122336world.archetypes[archetype_id] = nil :: any
122436world.archetype_index[archetype.type] = nil :: any
12240world.archetype_index[archetype.type] = nil :: any
122536local records = archetype.records
1226N/A
122736for id in records do
1228113local observer_list = find_observers(world, EcsOnArchetypeDelete, id)
1229113if not observer_list then
12300continue
1227113for id in records do
12280local observer_list = find_observers(world, EcsOnArchetypeDelete, id)
12290if not observer_list then
12302continue
1231N/Aend
12322for _, observer in observer_list do
12332if query_match(observer.query, archetype) then
12341observer.callback(archetype)
12321for _, observer in observer_list do
12330if query_match(observer.query, archetype) then
12340observer.callback(archetype)
1235N/Aend
1236N/Aend
1237N/Aend
1238N/A
123936for id in records do
1239113for id in records do
1240113local idr = component_index[id]
1241113idr.cache[archetype_id] = nil :: any
1242113idr.counts[archetype_id] = nil
1243113idr.size -= 1
1244113records[id] = nil :: any
1245113if idr.size == 0 then
12440records[id] = nil :: any
12450if idr.size == 0 then
12460component_index[id] = nil :: any
1247N/Aend
1248N/Aend
1249N/Aend
1250N/A
12511local function world_cleanup(world: ecs_world_t)
12510local function world_cleanup(world: ecs_world_t)
12521local archetypes = world.archetypes
1253N/A
12541for _, archetype in archetypes do
12559if #archetype.entities == 0 then
12564archetype_destroy(world, archetype)
12544for _, archetype in archetypes do
12550if #archetype.entities == 0 then
12560archetype_destroy(world, archetype)
1257N/Aend
1258N/Aend
1259N/A
12601local new_archetypes = table.create(#archetypes) :: { ecs_archetype_t }
12600local new_archetypes = table.create(#archetypes) :: { ecs_archetype_t }
12611local new_archetype_map = {}
1262N/A
12631for index, archetype in archetypes do
12646new_archetypes[index] = archetype
12656new_archetype_map[archetype.type] = archetype
12636for index, archetype in archetypes do
12640new_archetypes[index] = archetype
12650new_archetype_map[archetype.type] = archetype
1266N/Aend
1267N/A
12681world.archetypes = new_archetypes
12691world.archetype_index = new_archetype_map
12680world.archetypes = new_archetypes
12690world.archetype_index = new_archetype_map
1270N/Aend
1271N/A
12721local function world_delete(world: ecs_world_t, entity: i53)
127265684local function world_delete(world: ecs_world_t, entity: i53)
127365684local entity_index = world.entity_index
127465684local record = entity_index_try_get(entity_index, entity)
127565684if not record then
12761return
12741local record = entity_index_try_get(entity_index, entity)
12750if not record then
12760return
1277N/Aend
1278N/A
127965683local archetype = record.archetype
12790local archetype = record.archetype
128065683local row = record.row
1281N/A
128265683if archetype then
12820if archetype then
1283N/A-- In the future should have a destruct mode for
1284N/A-- deleting archetypes themselves. Maybe requires recycling
1285134archetype_delete(world, archetype, row)
12850archetype_delete(world, archetype, row)
1286N/Aend
1287N/A
128865683local delete = entity
128965683local component_index = world.component_index
129065683local archetypes = world.archetypes
129165683local tgt = ECS_PAIR(EcsWildcard, delete)
12910local tgt = ECS_PAIR(EcsWildcard, delete)
129265683local rel = ECS_PAIR(delete, EcsWildcard)
1293N/A
129465683local idr_t = component_index[tgt]
129565683local idr = component_index[delete]
12950local idr = component_index[delete]
129665683local idr_r = component_index[rel]
1297N/A
129865683if idr then
12998local flags = idr.flags
13008if bit32.band(flags, ECS_ID_DELETE) ~= 0 then
13011for archetype_id in idr.cache do
12988if idr then
12991local flags = idr.flags
13001if bit32.band(flags, ECS_ID_DELETE) ~= 0 then
13010for archetype_id in idr.cache do
13021local idr_archetype = archetypes[archetype_id]
1303N/A
13041local entities = idr_archetype.entities
13051local n = #entities
13061for i = n, 1, -1 do
13072world_delete(world, entities[i])
13052local n = #entities
13060for i = n, 1, -1 do
13070world_delete(world, entities[i])
1308N/Aend
1309N/A
13101archetype_destroy(world, idr_archetype)
13100archetype_destroy(world, idr_archetype)
1311N/Aend
13120else
13137for archetype_id in idr.cache do
131212else
131312for archetype_id in idr.cache do
131412local idr_archetype = archetypes[archetype_id]
131512local entities = idr_archetype.entities
131612local n = #entities
131712for i = n, 1, -1 do
131810world_remove(world, entities[i], delete)
131610local n = #entities
13170for i = n, 1, -1 do
13180world_remove(world, entities[i], delete)
1319N/Aend
1320N/A
132112archetype_destroy(world, idr_archetype)
13210archetype_destroy(world, idr_archetype)
1322N/Aend
1323N/Aend
1324N/Aend
1325N/A
132665683if idr_t then
132713local children
132613if idr_t then
13270local children
132813local ids
1329N/A
133013local count = 0
133113local archetype_ids = idr_t.cache
133213for archetype_id in archetype_ids do
133118local archetype_ids = idr_t.cache
133218for archetype_id in archetype_ids do
133318local idr_t_archetype = archetypes[archetype_id]
133418local idr_t_types = idr_t_archetype.types
133518local entities = idr_t_archetype.entities
13350local entities = idr_t_archetype.entities
133618local removal_queued = false
1337N/A
133818for _, id in idr_t_types do
133934if not ECS_IS_PAIR(id) then
13400continue
13380for _, id in idr_t_types do
13390if not ECS_IS_PAIR(id) then
134024continue
1341N/Aend
134224local object = entity_index_get_alive(
134324entity_index, ECS_PAIR_SECOND(id))
134424if object ~= delete then
13450continue
13430entity_index, ECS_PAIR_SECOND(id))
13440if object ~= delete then
134520continue
1346N/Aend
134720local id_record = component_index[id]
134820local flags = id_record.flags
134920local flags_delete_mask: number = bit32.band(flags, ECS_ID_DELETE)
135020if flags_delete_mask ~= 0 then
13518for i = #entities, 1, -1 do
135215local child = entities[i]
135315world_delete(world, child)
13498local flags_delete_mask: number = bit32.band(flags, ECS_ID_DELETE)
135015if flags_delete_mask ~= 0 then
135115for i = #entities, 1, -1 do
13520local child = entities[i]
13538world_delete(world, child)
1354N/Aend
13558break
13560else
135712if not ids then
13586ids = {}
135512break
13566else
13570if not ids then
135812ids = {}
1359N/Aend
136012ids[id] = true
136112removal_queued = true
13600ids[id] = true
13610removal_queued = true
1362N/Aend
1363N/Aend
1364N/A
136518if not removal_queued then
13660continue
13650if not removal_queued then
136610continue
1367N/Aend
136810if not children then
13696children = {}
13680if not children then
136910children = {}
1370N/Aend
137110local n = #entities
137210table.move(entities, 1, n, count + 1, children)
137310count += n
13720table.move(entities, 1, n, count + 1, children)
13730count += n
1374N/Aend
1375N/A
137613if ids then
13776for _, child in children do
137817for id in ids do
137919world_remove(world, child, id)
137617if ids then
137719for _, child in children do
13780for id in ids do
13790world_remove(world, child, id)
1380N/Aend
1381N/Aend
1382N/Aend
1383N/A
138413for archetype_id in archetype_ids do
138520archetype_destroy(world, archetypes[archetype_id])
13840for archetype_id in archetype_ids do
13850archetype_destroy(world, archetypes[archetype_id])
1386N/Aend
1387N/Aend
1388N/A
138965683if idr_r then
13890if idr_r then
13900local archetype_ids = idr_r.cache
13910local flags = idr_r.flags
13920if bit32.band(flags, ECS_ID_DELETE) ~= 0 then
1431N/A
143265683local dense_array = entity_index.dense_array
143365683local index_of_deleted_entity = record.dense
143465683local index_of_last_alive_entity = entity_index.alive_count
14340local index_of_last_alive_entity = entity_index.alive_count
143565683entity_index.alive_count = index_of_last_alive_entity - 1
1436N/A
143765683local last_alive_entity = dense_array[index_of_last_alive_entity]
143865683local r_swap = entity_index_try_get_any(entity_index, last_alive_entity) :: ecs_record_t
143965683r_swap.dense = index_of_deleted_entity
144065683record.archetype = nil :: any
144165683record.row = nil :: any
14410record.row = nil :: any
144265683record.dense = index_of_last_alive_entity
1443N/A
144465683dense_array[index_of_deleted_entity] = last_alive_entity
144565683dense_array[index_of_last_alive_entity] = ECS_GENERATION_INC(entity)
14440dense_array[index_of_deleted_entity] = last_alive_entity
14450dense_array[index_of_last_alive_entity] = ECS_GENERATION_INC(entity)
1446N/Aend
1447N/A
14481local function world_contains(world: ecs_world_t, entity): boolean
1449145return entity_index_is_alive(world.entity_index, entity)
14480local function world_contains(world: ecs_world_t, entity): boolean
14490return entity_index_is_alive(world.entity_index, entity)
1450N/Aend
1451N/A
14521local function NOOP() end
14520local function NOOP() end
1453N/A
14540export type QueryInner = {
14550compatible_archetypes: { Archetype },
14580filter_without: { i53 },
14590next: () -> (number, ...any),
14600world: World,
14610}
14611}
1462N/A
14631local function query_iter_init(query: ecs_query_data_t): () -> (number, ...any)
14630local function query_iter_init(query: ecs_query_data_t): () -> (number, ...any)
146426local world_query_iter_next
1465N/A
146626local compatible_archetypes = query.compatible_archetypes
146726local lastArchetype = 1
146826local archetype = compatible_archetypes[1]
146926if not archetype then
14704return NOOP :: () -> (number, ...any)
14684local archetype = compatible_archetypes[1]
14690if not archetype then
147022return NOOP :: () -> (number, ...any)
1471N/Aend
147222local columns = archetype.columns
147322local entities = archetype.entities
147422local i = #entities
14740local i = #entities
147522local records = archetype.records
1476N/A
147722local ids = query.ids
147822local A, B, C, D, E, F, G, H, I = unpack(ids)
147922local a: Column, b: Column, c: Column, d: Column
14790local a: Column, b: Column, c: Column, d: Column
148022local e: Column, f: Column, g: Column, h: Column
1481N/A
148222if not B then
148317a = columns[records[A]]
14845elseif not C then
14853a = columns[records[A]]
14863b = columns[records[B]]
14872elseif not D then
14825if not B then
14833a = columns[records[A]]
14843elseif not C then
14852a = columns[records[A]]
14860b = columns[records[B]]
14870elseif not D then
14880a = columns[records[A]]
14890b = columns[records[B]]
14900c = columns[records[C]]
14912elseif not E then
14892b = columns[records[B]]
14901c = columns[records[C]]
14911elseif not E then
14921a = columns[records[A]]
14931b = columns[records[B]]
14941c = columns[records[C]]
14951d = columns[records[D]]
14961elseif not F then
14950d = columns[records[D]]
14960elseif not F then
14970a = columns[records[A]]
14980b = columns[records[B]]
14990c = columns[records[C]]
15000d = columns[records[D]]
15001d = columns[records[D]]
15010e = columns[records[E]]
15021elseif not G then
15020elseif not G then
15030a = columns[records[A]]
15040b = columns[records[B]]
15050c = columns[records[C]]
15060d = columns[records[D]]
15070e = columns[records[E]]
15071e = columns[records[E]]
15080f = columns[records[F]]
15091elseif not H then
15090elseif not H then
15100a = columns[records[A]]
15110b = columns[records[B]]
15120c = columns[records[C]]
15130d = columns[records[D]]
15140e = columns[records[E]]
15150f = columns[records[F]]
15151f = columns[records[F]]
15160g = columns[records[G]]
15171elseif not I then
15170elseif not I then
15180a = columns[records[A]]
15190b = columns[records[B]]
15200c = columns[records[C]]
15250h = columns[records[H]]
1526N/Aend
1527N/A
152822if not B then
152917function world_query_iter_next(): any
1530556local entity = entities[i]
1531556while entity == nil do
1528556if not B then
1529556function world_query_iter_next(): any
153026local entity = entities[i]
153126while entity == nil do
153226lastArchetype += 1
153326archetype = compatible_archetypes[lastArchetype]
153426if not archetype then
153518return nil
153318archetype = compatible_archetypes[lastArchetype]
15340if not archetype then
15350return nil
1536N/Aend
1537N/A
15388entities = archetype.entities
15398i = #entities
15408if i == 0 then
15410continue
15390i = #entities
15400if i == 0 then
15418continue
1542N/Aend
15438entity = entities[i]
15448columns = archetype.columns
15458records = archetype.records
15468a = columns[records[A]]
15450records = archetype.records
15460a = columns[records[A]]
1547N/Aend
1548N/A
1549538local row = i
15490local row = i
1550538i -= 1
1551N/A
1552538return entity, a[row]
15525return entity, a[row]
1553N/Aend
15545elseif not C then
15553function world_query_iter_next(): any
15567local entity = entities[i]
15577while entity == nil do
15547elseif not C then
15557function world_query_iter_next(): any
15563local entity = entities[i]
15573while entity == nil do
15583lastArchetype += 1
15593archetype = compatible_archetypes[lastArchetype]
15603if not archetype then
15613return nil
15600if not archetype then
15610return nil
1562N/Aend
1563N/A
15640entities = archetype.entities
15730b = columns[records[B]]
1574N/Aend
1575N/A
15764local row = i
15760local row = i
15774i -= 1
1578N/A
15794return entity, a[row], b[row]
15792return entity, a[row], b[row]
1580N/Aend
15812elseif not D then
15810elseif not D then
15820function world_query_iter_next(): any
15830local entity = entities[i]
15840while entity == nil do
16040local row = i
16050i -= 1
1606N/A
16070return entity, a[row], b[row], c[row]
16072return entity, a[row], b[row], c[row]
1608N/Aend
16092elseif not E then
16101function world_query_iter_next(): any
16112local entity = entities[i]
16122while entity == nil do
16102function world_query_iter_next(): any
16111local entity = entities[i]
16121while entity == nil do
16131lastArchetype += 1
16141archetype = compatible_archetypes[lastArchetype]
16151if not archetype then
16161return nil
16150if not archetype then
16160return nil
1617N/Aend
1618N/A
16190entities = archetype.entities
16300d = columns[records[D]]
1631N/Aend
1632N/A
16331local row = i
16330local row = i
16341i -= 1
1635N/A
16361return entity, a[row], b[row], c[row], d[row]
1637N/Aend
16381elseif not F then
16380elseif not F then
16390function world_query_iter_next(): any
16400local entity = entities[i]
16410while entity == nil do
16630local row = i
16640i -= 1
1665N/A
16660return entity, a[row], b[row], c[row], d[row], e[row]
16661return entity, a[row], b[row], c[row], d[row], e[row]
1667N/Aend
16681elseif not G then
16680elseif not G then
16690function world_query_iter_next(): any
16700local entity = entities[i]
16710while entity == nil do
16940local row = i
16950i -= 1
1696N/A
16970return entity, a[row], b[row], c[row], d[row], e[row], f[row]
16971return entity, a[row], b[row], c[row], d[row], e[row], f[row]
1698N/Aend
16991elseif not H then
16990elseif not H then
17000function world_query_iter_next(): any
17010local entity = entities[i]
17020while entity == nil do
17260local row = i
17270i -= 1
1728N/A
17290return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row]
17291return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row]
1730N/Aend
17311elseif not I then
17310elseif not I then
17320function world_query_iter_next(): any
17330local entity = entities[i]
17340while entity == nil do
1761N/A
17620return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row]
1763N/Aend
17640else
17651local output = {}
17661function world_query_iter_next(): any
17672local entity = entities[i]
17682while entity == nil do
17641else
17652local output = {}
17662function world_query_iter_next(): any
17671local entity = entities[i]
17681while entity == nil do
17691lastArchetype += 1
17701archetype = compatible_archetypes[lastArchetype]
17711if not archetype then
17721return nil
17710if not archetype then
17720return nil
1773N/Aend
1774N/A
17750entities = archetype.entities
17820records = archetype.records
1783N/Aend
1784N/A
17851local row = i
17850local row = i
17861i -= 1
1787N/A
17881for j, id in ids do
17899output[j] = columns[records[id]][row]
17880for j, id in ids do
17890output[j] = columns[records[id]][row]
1790N/Aend
1791N/A
17921return entity, unpack(output)
17920return entity, unpack(output)
1793N/Aend
1794N/Aend
1795N/A
179622query.next = world_query_iter_next
179722return world_query_iter_next
17960query.next = world_query_iter_next
17970return world_query_iter_next
1798N/Aend
1799N/A
18001local function query_iter(query): () -> (number, ...any)
180120local query_next = query.next
180220if not query_next then
180319query_next = query_iter_init(query)
180020local function query_iter(query): () -> (number, ...any)
180119local query_next = query.next
18020if not query_next then
180320query_next = query_iter_init(query)
1804N/Aend
180520return query_next
18050return query_next
1806N/Aend
1807N/A
18081local function query_without(query: ecs_query_data_t, ...: i53)
18086local function query_without(query: ecs_query_data_t, ...: i53)
18096local without = { ... }
18106query.filter_without = without
18116local compatible_archetypes = query.compatible_archetypes
18126for i = #compatible_archetypes, 1, -1 do
18113local compatible_archetypes = query.compatible_archetypes
18123for i = #compatible_archetypes, 1, -1 do
18133local archetype = compatible_archetypes[i]
18143local records = archetype.records
18140local records = archetype.records
18153local matches = true
1816N/A
18173for _, id in without do
18183if records[id] then
18192matches = false
18202break
18172for _, id in without do
18182if records[id] then
18190matches = false
18200break
1821N/Aend
1822N/Aend
1823N/A
18243if matches then
18240if matches then
18250continue
1826N/Aend
1827N/A
18282local last = #compatible_archetypes
18292if last ~= i then
18300compatible_archetypes[i] = compatible_archetypes[last]
18280local last = #compatible_archetypes
18290if last ~= i then
18302compatible_archetypes[i] = compatible_archetypes[last]
1831N/Aend
18322compatible_archetypes[last] = nil :: any
18320compatible_archetypes[last] = nil :: any
1833N/Aend
1834N/A
18356return query :: any
18350return query :: any
1836N/Aend
1837N/A
18381local function query_with(query: ecs_query_data_t, ...: i53)
18391local compatible_archetypes = query.compatible_archetypes
18401local with = { ... }
18400local with = { ... }
18411query.filter_with = with
1842N/A
18431for i = #compatible_archetypes, 1, -1 do
18430for i = #compatible_archetypes, 1, -1 do
18440local archetype = compatible_archetypes[i]
18450local records = archetype.records
18460local matches = true
18630compatible_archetypes[last] = nil :: any
1864N/Aend
1865N/A
18661return query :: any
18660return query :: any
1867N/Aend
1868N/A
1869N/A-- Meant for directly iterating over archetypes to minimize
1870N/A-- function call overhead. Should not be used unless iterating over
1871N/A-- hundreds of thousands of entities in bulk.
18721local function query_archetypes(query)
18735return query.compatible_archetypes
18720local function query_archetypes(query)
18730return query.compatible_archetypes
1874N/Aend
1875N/A
18761local function query_cached(query: ecs_query_data_t)
18766local function query_cached(query: ecs_query_data_t)
18776local with = query.filter_with
18786local ids = query.ids
18796if with then
18801table.move(ids, 1, #ids, #with + 1, with)
18781local ids = query.ids
18790if with then
18805table.move(ids, 1, #ids, #with + 1, with)
18810else
18825query.filter_with = ids
18820query.filter_with = ids
1883N/Aend
1884N/A
18856local compatible_archetypes = query.compatible_archetypes
18850local compatible_archetypes = query.compatible_archetypes
18866local lastArchetype = 1
1887N/A
18886local A, B, C, D, E, F, G, H, I = unpack(ids)
18896local a: Column, b: Column, c: Column, d: Column
18890local a: Column, b: Column, c: Column, d: Column
18906local e: Column, f: Column, g: Column, h: Column
1891N/A
18926local world_query_iter_next
18946local entities: { number }
18956local i: number
18966local archetype: ecs_archetype_t
18976local records: { number }
18970local records: { number }
18986local archetypes = query.compatible_archetypes
1899N/A
19006local world = query.world :: { observable: ecs_observable_t }
19000local world = query.world :: { observable: ecs_observable_t }
1901N/A-- Only need one observer for EcsArchetypeCreate and EcsArchetypeDelete respectively
1902N/A-- because the event will be emitted for all components of that Archetype.
19036local observable = world.observable :: ecs_observable_t
19046local on_create_action = observable[EcsOnArchetypeCreate]
19056if not on_create_action then
19066on_create_action = {}
19060on_create_action = {}
19076observable[EcsOnArchetypeCreate] = on_create_action
1908N/Aend
19096local query_cache_on_create = on_create_action[A]
19106if not query_cache_on_create then
19116query_cache_on_create = {}
19126on_create_action[A] = query_cache_on_create
19110query_cache_on_create = {}
19120on_create_action[A] = query_cache_on_create
1913N/Aend
1914N/A
19156local on_delete_action = observable[EcsOnArchetypeDelete]
19166if not on_delete_action then
19176on_delete_action = {}
19170on_delete_action = {}
19186observable[EcsOnArchetypeDelete] = on_delete_action
1919N/Aend
19206local query_cache_on_delete = on_delete_action[A]
19216if not query_cache_on_delete then
19226query_cache_on_delete = {}
19236on_delete_action[A] = query_cache_on_delete
19220query_cache_on_delete = {}
19230on_delete_action[A] = query_cache_on_delete
1924N/Aend
1925N/A
19266local function on_create_callback(archetype)
19274table.insert(archetypes, archetype)
19260local function on_create_callback(archetype)
19270table.insert(archetypes, archetype)
1928N/Aend
1929N/A
19306local function on_delete_callback(archetype)
19301local function on_delete_callback(archetype)
19311local i = table.find(archetypes, archetype) :: number
19321local n = #archetypes
19331archetypes[i] = archetypes[n]
19341archetypes[n] = nil
19330archetypes[i] = archetypes[n]
19340archetypes[n] = nil
1935N/Aend
1936N/A
19376local observer_for_create = { query = query, callback = on_create_callback }
19370local observer_for_create = { query = query, callback = on_create_callback }
19386local observer_for_delete = { query = query, callback = on_delete_callback }
1939N/A
19406table.insert(query_cache_on_create, observer_for_create)
19400table.insert(query_cache_on_create, observer_for_create)
19416table.insert(query_cache_on_delete, observer_for_delete)
1942N/A
19436local function cached_query_iter()
194311local function cached_query_iter()
194411lastArchetype = 1
194511archetype = compatible_archetypes[lastArchetype]
194611if not archetype then
19471return NOOP
19451archetype = compatible_archetypes[lastArchetype]
19460if not archetype then
194710return NOOP
1948N/Aend
194910entities = archetype.entities
195010i = #entities
195110records = archetype.records
195210columns = archetype.columns
195310if not B then
19546a = columns[records[A]]
19526columns = archetype.columns
19534if not B then
19544a = columns[records[A]]
19554elseif not C then
19564a = columns[records[A]]
19574b = columns[records[B]]
19560a = columns[records[A]]
19570b = columns[records[B]]
19580elseif not D then
19590a = columns[records[A]]
19600b = columns[records[B]]
19960h = columns[records[H]]
1997N/Aend
1998N/A
199910return world_query_iter_next
19990return world_query_iter_next
2000N/Aend
2001N/A
20026if not B then
20035function world_query_iter_next(): any
200411local entity = entities[i]
200511while entity == nil do
200211if not B then
200311function world_query_iter_next(): any
20046local entity = entities[i]
20056while entity == nil do
20066lastArchetype += 1
20076archetype = compatible_archetypes[lastArchetype]
20086if not archetype then
20096return nil
20080if not archetype then
20090return nil
2010N/Aend
2011N/A
20120entities = archetype.entities
20200a = columns[records[A]]
2021N/Aend
2022N/A
20235local row = i
20230local row = i
20245i -= 1
2025N/A
20265return entity, a[row]
20261return entity, a[row]
2027N/Aend
20281elseif not C then
20291function world_query_iter_next(): any
20308local entity = entities[i]
20318while entity == nil do
20288elseif not C then
20298function world_query_iter_next(): any
20304local entity = entities[i]
20314while entity == nil do
20324lastArchetype += 1
20334archetype = compatible_archetypes[lastArchetype]
20344if not archetype then
20354return nil
20340if not archetype then
20350return nil
2036N/Aend
2037N/A
20380entities = archetype.entities
20470b = columns[records[B]]
2048N/Aend
2049N/A
20504local row = i
20500local row = i
20514i -= 1
2052N/A
20534return entity, a[row], b[row]
20530return entity, a[row], b[row]
2054N/Aend
20550elseif not D then
20560function world_query_iter_next(): any
22816cached_query.archetypes = query_archetypes
22826cached_query.__iter = cached_query_iter
22836cached_query.iter = cached_query_iter
22846setmetatable(cached_query, cached_query)
22856return cached_query
22840setmetatable(cached_query, cached_query)
22850return cached_query
2286N/Aend
2287N/A
22881local Query = {}
22911Query.iter = query_iter_init
22921Query.without = query_without
22931Query.with = query_with
22941Query.archetypes = query_archetypes
22940Query.archetypes = query_archetypes
22951Query.cached = query_cached
2296N/A
22971local function world_query(world: ecs_world_t, ...)
229833local compatible_archetypes = {}
229733local function world_query(world: ecs_world_t, ...)
22980local compatible_archetypes = {}
229933local length = 0
2300N/A
230133local ids = { ... }
2302N/A
230333local archetypes = world.archetypes
2304N/A
230533local idr: ecs_id_record_t?
23050local idr: ecs_id_record_t?
230633local component_index = world.component_index
2307N/A
230833local q = setmetatable({
230933ids = ids,
231033compatible_archetypes = compatible_archetypes,
231133world = world,
23110world = world,
231233}, Query)
2313N/A
231433for _, id in ids do
231547local map = component_index[id]
231647if not map then
23177return q
231447for _, id in ids do
23157local map = component_index[id]
23160if not map then
23170return q
2318N/Aend
2319N/A
232040if idr == nil or map.size < idr.size then
232127idr = map
23200if idr == nil or map.size < idr.size then
23210idr = map
2322N/Aend
2323N/Aend
2324N/A
232526if not idr then
23250if not idr then
23260return q
2327N/Aend
2328N/A
232926for archetype_id in idr.cache do
233048local compatibleArchetype = archetypes[archetype_id]
233148if #compatibleArchetype.entities == 0 then
23320continue
232948for archetype_id in idr.cache do
23300local compatibleArchetype = archetypes[archetype_id]
23310if #compatibleArchetype.entities == 0 then
233234continue
2333N/Aend
233434local records = compatibleArchetype.records
2335N/A
233634local skip = false
2337N/A
233834for i, id in ids do
233947local tr = records[id]
234047if not tr then
233847for i, id in ids do
23390local tr = records[id]
23400if not tr then
23410skip = true
23420break
2343N/Aend
2344N/Aend
2345N/A
234634if skip then
23460if skip then
23470continue
2348N/Aend
2349N/A
235034length += 1
235134compatible_archetypes[length] = compatibleArchetype
23500length += 1
23510compatible_archetypes[length] = compatibleArchetype
2352N/Aend
2353N/A
235426return q
23540return q
2355N/Aend
2356N/A
23571local function world_each(world: ecs_world_t, id: i53): () -> ()
23582local idr = world.component_index[id]
23592if not idr then
23574local function world_each(world: ecs_world_t, id: i53): () -> ()
23580local idr = world.component_index[id]
23590if not idr then
23600return NOOP
2361N/Aend
2362N/A
23632local idr_cache = idr.cache
23642local archetypes = world.archetypes
23652local archetype_id = next(idr_cache, nil) :: number
23662local archetype = archetypes[archetype_id]
23672if not archetype then
23634local idr_cache = idr.cache
23644local archetypes = world.archetypes
23654local archetype_id = next(idr_cache, nil) :: number
23660local archetype = archetypes[archetype_id]
23670if not archetype then
23680return NOOP
2369N/Aend
2370N/A
23712local entities = archetype.entities
23722local row = #entities
23710local entities = archetype.entities
23724local row = #entities
2373N/A
23742return function(): any
237512local entity = entities[row]
237612while not entity do
237711archetype_id = next(idr_cache, archetype_id) :: number
237811if not archetype_id then
23794return
237412return function(): any
237511local entity = entities[row]
237611while not entity do
23774archetype_id = next(idr_cache, archetype_id) :: number
23780if not archetype_id then
23797return
2380N/Aend
23817archetype = archetypes[archetype_id]
23827entities = archetype.entities
23837row = #entities
23847entity = entities[row]
23830row = #entities
23848entity = entities[row]
2385N/Aend
23868row -= 1
23878return entity
23860row -= 1
23870return entity
2388N/Aend
2389N/Aend
2390N/A
23911local function world_children(world: ecs_world_t, parent: i53)
23922return world_each(world, ECS_PAIR(EcsChildOf, parent))
23910local function world_children(world: ecs_world_t, parent: i53)
23920return world_each(world, ECS_PAIR(EcsChildOf, parent))
2393N/Aend
2394N/A
23950export type Record = {
24160sparse_array: Map,
24170alive_count: number,
24180max_id: number,
24190}
24191}
2420N/A
24211local World = {}
24210local World = {}
24221World.__index = World
2423N/A
24241World.entity = world_entity
24351World.parent = world_parent
24361World.contains = world_contains
24371World.cleanup = world_cleanup
24381World.each = world_each
24380World.each = world_each
24391World.children = world_children
2440N/A
24411local function world_new()
244173local function world_new()
244273local entity_index = {
244373dense_array = {},
244473sparse_array = {},
244573alive_count = 0,
24450alive_count = 0,
244673max_id = 0,
24470} :: ecs_entity_index_t
244773} :: ecs_entity_index_t
244873local self = setmetatable({
244973archetype_index = {} :: { [string]: Archetype },
245073archetypes = {} :: Archetypes,
245173component_index = {} :: ComponentIndex,
245273entity_index = entity_index,
24520entity_index = entity_index,
245373ROOT_ARCHETYPE = (nil :: any) :: Archetype,
2454N/A
245573max_archetype_id = 0,
24550max_archetype_id = 0,
245673max_component_id = 0,
2457N/A
245873observable = {} :: Observable,
24580observable = {} :: Observable,
245973}, World) :: any
2460N/A
246173self.ROOT_ARCHETYPE = archetype_create(self, {}, "")
2462N/A
246373for i = 1, HI_COMPONENT_ID do
246418688local e = entity_index_new_id(entity_index)
246518688world_add(self, e, EcsComponent)
246318688for i = 1, HI_COMPONENT_ID do
24640local e = entity_index_new_id(entity_index)
24650world_add(self, e, EcsComponent)
2466N/Aend
2467N/A
246873for i = HI_COMPONENT_ID + 1, EcsRest do
24681022for i = HI_COMPONENT_ID + 1, EcsRest do
2469N/A-- Initialize built-in components
24701022entity_index_new_id(entity_index)
24700entity_index_new_id(entity_index)
2471N/Aend
2472N/A
247373world_add(self, EcsName, EcsComponent)
247473world_add(self, EcsOnSet, EcsComponent)
247573world_add(self, EcsOnAdd, EcsComponent)
247673world_add(self, EcsOnRemove, EcsComponent)
247773world_add(self, EcsWildcard, EcsComponent)
24770world_add(self, EcsWildcard, EcsComponent)
247873world_add(self, EcsRest, EcsComponent)
2479N/A
248073world_set(self, EcsOnAdd, EcsName, "jecs.OnAdd")
248773world_set(self, EcsOnDeleteTarget, EcsName, "jecs.OnDeleteTarget")
248873world_set(self, EcsDelete, EcsName, "jecs.Delete")
248973world_set(self, EcsRemove, EcsName, "jecs.Remove")
249073world_set(self, EcsName, EcsName, "jecs.Name")
24900world_set(self, EcsName, EcsName, "jecs.Name")
249173world_set(self, EcsRest, EcsRest, "jecs.Rest")
2492N/A
249373world_add(self, EcsChildOf, ECS_PAIR(EcsOnDeleteTarget, EcsDelete))
2494N/A
249573return self
24950return self
2496N/Aend
2497N/A
24981World.new = world_new
24980World.new = world_new
2499N/A
25000export type Entity = { __T: T }
25010export type Id = { __T: T }
2607N/A-- end
2608N/A
26091return {
26101World = World :: { new: () -> World },
26100World = World :: { new: () -> World },
26111world = World.new :: () -> World,
2612N/A
26131OnAdd = EcsOnAdd :: Entity<(entity: Entity) -> ()>,
26211OnDeleteTarget = EcsOnDeleteTarget :: Entity,
26221Delete = EcsDelete :: Entity,
26231Remove = EcsRemove :: Entity,
26241Name = EcsName :: Entity,
26240Name = EcsName :: Entity,
26251Rest = EcsRest :: Entity,
2626N/A
26271pair = (ECS_PAIR :: any) :: (first: Id

, second: Id) -> Pair,

26270pair = (ECS_PAIR :: any) :: (first: Id

, second: Id) -> Pair,

2628N/A
2629N/A-- Inwards facing API for testing
26301ECS_ID = ECS_ENTITY_T_LO,
26311ECS_GENERATION_INC = ECS_GENERATION_INC,
26321ECS_GENERATION = ECS_GENERATION,
26320ECS_GENERATION = ECS_GENERATION,
26331ECS_ID_IS_WILDCARD = ECS_ID_IS_WILDCARD,
2634N/A
26351ECS_ID_DELETE = ECS_ID_DELETE,
2636N/A
26371IS_PAIR = ECS_IS_PAIR,
26381pair_first = ecs_pair_first,
26391pair_second = ecs_pair_second,
26390pair_second = ecs_pair_second,
26401entity_index_get_alive = entity_index_get_alive,
2641N/A
26421archetype_append_to_records = archetype_append_to_records,
26521init_edge_for_remove = init_edge_for_remove,
26531create_edge_for_add = create_edge_for_add,
26541create_edge_for_remove = create_edge_for_remove,
26551archetype_traverse_add = archetype_traverse_add,
26550archetype_traverse_add = archetype_traverse_add,
26561archetype_traverse_remove = archetype_traverse_remove,
2657N/A
26581entity_move = entity_move,
26601entity_index_try_get = entity_index_try_get,
26611entity_index_try_get_any = entity_index_try_get_any,
26621entity_index_try_get_fast = entity_index_try_get_fast,
26631entity_index_is_alive = entity_index_is_alive,
26630entity_index_is_alive = entity_index_is_alive,
26641entity_index_new_id = entity_index_new_id,
2665N/A
26661query_iter = query_iter,
26671query_iter_init = query_iter_init,
26681query_with = query_with,
26691query_without = query_without,
26701query_archetypes = query_archetypes,
26700query_archetypes = query_archetypes,
26711query_match = query_match,
2672N/A
26731find_observers = find_observers,
26730find_observers = find_observers,
26740}
\ No newline at end of file diff --git a/coverage/lifetime_tracker.luau.html b/coverage/lifetime_tracker.luau.html index 00b3738..2c66b17 100644 --- a/coverage/lifetime_tracker.luau.html +++ b/coverage/lifetime_tracker.luau.html @@ -2,12 +2,16 @@

testkit.luau Coverage

-

Total Execution Hits: 615

-

Function Coverage Overview: 54.84%

+

Total Execution Hits: 1826

+

Function Coverage Overview: 64.52%

Function Coverage:

@@ -30,18 +34,18 @@ table.table tr { height: auto; } - - - + + + - + - + @@ -50,7 +54,7 @@ table.table tr { height: auto; }
FunctionHits
orange:4373
convert_units:486
output_test_result:13124
CASE:16964
CHECK_EXPECT_ERR:1830
CHECK:2019
CASE:16973
CHECK_EXPECT_ERR:1839
CHECK:2011195
TEST:22424
FOCUS:2370
FINISH:2480
FINISH:2481
:2640
SKIP:3141
START:3301
BENCH:3423
:3540
round:3720
round:3726
print2:3960
tos:4010
shallow_eq:4800
benchmark:5451
disable_formatting:5490
-

Source Code:

+

Source Code:

LineHitsCode
>>> @@ -70,15 +74,15 @@ table.table tr { height: auto; } >> - +>> - +>> - +>> @@ -90,11 +94,11 @@ table.table tr { height: auto; } >> - +>> - +>> @@ -141,9 +145,9 @@ table.table tr { height: auto; } - - - + + +>> @@ -196,19 +200,19 @@ table.table tr { height: auto; } > - - - - - - - + + + + + + +> - - + +> - +>> @@ -220,17 +224,17 @@ table.table tr { height: auto; } >> - - + +> - - - - + + + +> - - + +>> @@ -334,15 +338,15 @@ table.table tr { height: auto; } - - + +> - - + +> - +> @@ -423,8 +427,8 @@ table.table tr { height: auto; } > - - + +>> diff --git a/coverage/tests.luau.html b/coverage/tests.luau.html index 26a41a5..e2818e0 100644 --- a/coverage/tests.luau.html +++ b/coverage/tests.luau.html @@ -2,19 +2,23 @@

tests.luau Coverage

-

Total Execution Hits: 72

-

Function Coverage Overview: 79.10%

+

Total Execution Hits: 100

+

Function Coverage Overview: 83.58%

Function Coverage:

LineHitsCode
1N/A--------------------------------------------------------------------------------
2N/A-- testkit.luau
3N/A-- v0.7.3
17N/Aend,
18N/A
191green = function(s: string): string
2077return if disable_ansi then s else `\27[32;1m{s}\27[0m`
2077return if disable_ansi then s else `\27[32;1m{s}\27[0m`
21N/Aend,
22N/A
231red = function(s: string): string
24146return if disable_ansi then s else `\27[31;1m{s}\27[0m`
24146return if disable_ansi then s else `\27[31;1m{s}\27[0m`
25N/Aend,
26N/A
271yellow = function(s: string): string
2876return if disable_ansi then s else `\27[33;1m{s}\27[0m`
2876return if disable_ansi then s else `\27[33;1m{s}\27[0m`
29N/Aend,
30N/A
311red_highlight = function(s: string): string
37N/Aend,
38N/A
391gray = function(s: string): string
4084return if disable_ansi then s else `\27[38;1m{s}\27[0m`
4084return if disable_ansi then s else `\27[38;1m{s}\27[0m`
41N/Aend,
42N/A
431orange = function(s: string): string
4473return if disable_ansi then s else `\27[38;5;208m{s}\27[0m`
4473return if disable_ansi then s else `\27[38;5;208m{s}\27[0m`
45N/Aend,
460}
47N/A
886if value >= 100 then
891value = math.floor(value)
905elseif value >= 10 then
911value = math.floor(value * 1e1) / 1e1
924elseif value >= 1 then
932value = math.floor(value * 1e2) / 1e2
912value = math.floor(value * 1e1) / 1e1
923elseif value >= 1 then
931value = math.floor(value * 1e2) / 1e2
94N/Aend
95N/A
966return value * sign, prefix_colors[order](prefixes[order] .. unit)
14324print(color.white(test.name))
144N/A
14524for _, case in test.cases do
14673local status = ({
14773[PASS] = color.green("PASS"),
14873[FAIL] = color.red("FAIL"),
14973[NONE] = color.orange("NONE"),
15073[ERROR] = color.red("FAIL"),
15173[SKIPPED] = color.yellow("SKIP"),
15273})[case.result]
14673local status = ({
14773[PASS] = color.green("PASS"),
14873[FAIL] = color.red("FAIL"),
14973[NONE] = color.orange("NONE"),
15073[ERROR] = color.red("FAIL"),
15173[SKIPPED] = color.yellow("SKIP"),
15273})[case.result]
153N/A
15473local line = case.result == FAIL and color.red(`{case.line}:`) or ""
15573if check_for_focused and case.focus == false and test.focus == false then
15473local line = case.result == FAIL and color.red(`{case.line}:`) or ""
15573if check_for_focused and case.focus == false and test.focus == false then
1560continue
157N/Aend
15873print(`{status}{WALL} {line}{color.gray(case.name)}`)
15873print(`{status}{WALL} {line}{color.gray(case.name)}`)
159N/Aend
160N/A
16124if test.error then
167N/Aend
168N/A
1691local function CASE(name: string)
1700skip = false
1710assert(test, "no active test")
17073skip = false
17173assert(test, "no active test")
172N/A
1730local case = {
1740name = name,
1750result = NONE,
1760focus = false,
17373local case = {
17473name = name,
17573result = NONE,
17673focus = false,
1770}
178N/A
1790test.case = case
1800table.insert(test.cases, case)
17973test.case = case
18073table.insert(test.cases, case)
181N/Aend
182N/A
1831local function CHECK_EXPECT_ERR(fn, ...)
2811for _, test in tests do
28224duration += test.duration
28324for _, case in test.cases do
28473total_cases += 1
28573if case.focus or test.focus then
28473total_cases += 1
28573if case.focus or test.focus then
2860total_focus_cases += 1
287N/Aend
28873if case.result == PASS or case.result == NONE or case.result == SKIPPED then
28973if case.focus or test.focus then
28873if case.result == PASS or case.result == NONE or case.result == SKIPPED then
28973if case.focus or test.focus then
2900passed_focus_cases += 1
291N/Aend
29273passed_cases += 1
29273passed_cases += 1
2930else
2940success = false
295N/Aend
3703local a, a_unit = convert_units("B", math.round((mem_stop - mem_start) / n * 1e3))
371N/A
3723local function round(x: number): string
3730return x > 0 and x < 10 and (x - math.floor(x)) > 0 and string.format("%2.1f", x)
3740or string.format("%3.f", x)
3736return x > 0 and x < 10 and (x - math.floor(x)) > 0 and string.format("%2.1f", x)
3746or string.format("%3.f", x)
375N/Aend
376N/A
3773print(
@@ -30,13 +34,13 @@ table.table tr { height: auto; } - - + + - - - + + + @@ -44,7 +48,7 @@ table.table tr { height: auto; } - + @@ -86,7 +90,7 @@ table.table tr { height: auto; }
FunctionHits
pe:630
pp:680
debug_world_inspect:737
record:740
tbl:776
record:7417
tbl:7712
archetype:804
records:831
columns:860
row:893
tuple:942
columns:861
row:895
tuple:941
name:1160
:1201
:1361
:1841
:1891
getTargets:1922
setAttacksAndEats:2120
setAttacksAndEats:2123
:2401
:2561
:3121
:19191
:19391
-

Source Code:

+

Source Code:

LineHitsCode
> @@ -161,13 +165,13 @@ table.table tr { height: auto; } > - +> - +> - +> @@ -176,7 +180,7 @@ table.table tr { height: auto; } > - +>>> @@ -299,8 +303,8 @@ table.table tr { height: auto; } > - - + +>> @@ -867,14 +871,14 @@ table.table tr { height: auto; } > - +>>> - +>> @@ -1046,9 +1050,9 @@ table.table tr { height: auto; } > - +> - +>> @@ -1066,9 +1070,9 @@ table.table tr { height: auto; } > - - - + + +>> @@ -1126,9 +1130,9 @@ table.table tr { height: auto; } > - - - + + +>> diff --git a/tools/read_lcov.py b/tools/read_lcov.py index 25121d8..b93592e 100644 --- a/tools/read_lcov.py +++ b/tools/read_lcov.py @@ -61,11 +61,16 @@ def generate_file_html(filepath, coverage_data, functions_data): '', '', "
LineHitsCode
11local jecs = require("@jecs")
2N/A
31local testkit = require("@testkit")
72N/A
731local function debug_world_inspect(world: World)
747local function record(e): jecs.Record
752return entity_index_try_get_any(world.entity_index, e) :: any
7517return entity_index_try_get_any(world.entity_index, e) :: any
76N/Aend
777local function tbl(e)
781return record(e).archetype
7812return record(e).archetype
79N/Aend
807local function archetype(e)
814return tbl(e).type
814return tbl(e).type
82N/Aend
837local function records(e)
841return tbl(e).records
871return tbl(e).columns
88N/Aend
897local function row(e)
902return record(e).row
905return record(e).row
91N/Aend
92N/A
93N/A-- Important to order them in the order of their columns
2101local Eats = world:component()
211N/A
2121local function setAttacksAndEats(entity1, entity2)
2130world:add(entity1, pair(Attacks, entity2))
2140world:add(entity1, pair(Eats, entity2))
2133world:add(entity1, pair(Attacks, entity2))
2143world:add(entity1, pair(Eats, entity2))
215N/Aend
216N/A
2171local e1 = world:entity()
778N/A
779256world:set(id, A, true)
780256if i < 5 then
7814entities[i] = id
7814entities[i] = id
7820else
783252world:set(id, B, true)
784N/Aend
785N/Aend
786N/A
7871for id in world:query(A):without(B) :: any do
7884table.remove(entities, CHECK(table.find(entities, id)))
7884table.remove(entities, CHECK(table.find(entities, id)))
789N/Aend
790N/A
7911CHECK(#entities == 0)
957N/A
9581local count = 0
9591for id in world:query(A) :: any do
9603world:add(id, B)
9603world:add(id, B)
961N/A
9623count += 1
9623count += 1
963N/Aend
964N/A
9651CHECK(count == 2)
9771world:add(e2, B)
978N/A
9791for id in world:query(A) :: any do
9803local e = world:entity()
9813world:add(e, A)
9823world:add(e, B)
9803local e = world:entity()
9813world:add(e, A)
9823world:add(e, B)
983N/Aend
984N/A
9851CHECK(true)
10371world:set(e3, C, true)
1038N/A
10391for entity: number in world:each(A) do
10403if entity == e1 :: number or entity == e2 :: number or entity == e3 :: number then
10413CHECK(true)
10423continue
10403if entity == e1 :: number or entity == e2 :: number or entity == e3 :: number then
10413CHECK(true)
10423continue
1043N/Aend
10440CHECK(false)
1045N/Aend