Fix tmp references

This commit is contained in:
Ukendio 2025-12-28 11:07:51 +01:00
parent ef4d880b0a
commit 5208aa7749
3 changed files with 181 additions and 170 deletions

View file

@ -37,4 +37,9 @@ end)
When an entity graph contains cycles, order is undefined. This includes cycles When an entity graph contains cycles, order is undefined. This includes cycles
that can be formed using different relationships. that can be formed using different relationships.
However an important note to make is that structural changes are not
necessarily always safe in OnRemove hooks. For instance, when an entity is
being deleted and invokes all of the OnRemove hooks on its components. It
can cause a lot of issues with moving entities
]] ]]

View file

@ -1468,7 +1468,7 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row] return e, col0[row], col1[row]
end end
elseif not id3 then elseif not id3 then
function world_query_iter_next(): any function world_query_iter_next(): any
@ -1594,7 +1594,7 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row], captured_c[row], captured_d[row], captured_e[row] return e, col0[row], col1[row], col2[row], col3[row], col4[row]
end end
elseif not id6 then elseif not id6 then
function world_query_iter_next(): any function world_query_iter_next(): any
@ -1642,7 +1642,7 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row], captured_c[row], captured_d[row], captured_e[row], captured_f[row] return e, col0[row], col1[row], col2[row], col3[row], col4[row], col5[row]
end end
elseif not id7 then elseif not id7 then
function world_query_iter_next(): any function world_query_iter_next(): any
@ -1693,7 +1693,7 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row], captured_c[row], captured_d[row], captured_e[row], captured_f[row], captured_g[row] return e, col0[row], col1[row], col2[row], col3[row], col4[row], col5[row], captured_g[row]
end end
elseif not id8 then elseif not id8 then
function world_query_iter_next(): any function world_query_iter_next(): any
@ -1741,80 +1741,80 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
col4_u = col4 col4_u = col4
col5_u = col5 col5_u = col5
col6_u = col6 col6_u = col6
col7_u = col7 col7_u = col7
end
local row = i_u
i_u -= 1
return e, captured_a[row], captured_b[row], captured_c[row], captured_d[row], captured_e[row], captured_f[row], captured_g[row], captured_h[row]
end end
else
local output = {}
local ids_len = #ids
function world_query_iter_next(): any
local entities = entities_u
local e = entities[i_u]
local col0 = col0_u
local col1 = col1_u
local col2 = col2_u
local col3 = col3_u
local col4 = col4_u
local col5 = col5_u
local col6 = col6_u
local col7 = col7_u
local captured_ids = ids
local captured_columns_map = columns_map
while e == nil do local row = i_u
last_archetype_u += 1 i_u -= 1
local compatible_archetypes = compatible_archetypes_u
local archetype = compatible_archetypes[last_archetype_u]
archetype_u = archetype
if not archetype then return e, col0[row], col1[row], col2[row], col3[row], col4[row], col5[row], col6[row], col7[row]
return nil
end
entities = archetype.entities
i_u = #entities
if i_u == 0 then
continue
end
e = entities[i_u]
entities_u = entities
columns_map = archetype.columns_map
columns_map = captured_columns_map
col0 = columns_map[id0]
col1 = columns_map[id1]
col2 = columns_map[id2]
col3 = columns_map[id3]
col4 = columns_map[id4]
col5 = columns_map[id5]
col6 = columns_map[id6]
col7 = columns_map[id7]
col0_u = col0
col1_u = col1
col2_u = col2
col3_u = col3
col4_u = col4
col5_u = col5
col6_u = col6
col7_u = col7
end
local row = i_u
i_u -= 1
for i = 9, ids_len do
output[i - 8] = columns_map[ids[i]::any][row]
end
return e, col0[row], col1[row], col2[row], col3[row], col4[row], col5[row], col6[row], col7[row], unpack(output)
end
end end
else
local output = {}
local ids_len = #ids_u
function world_query_iter_next(): any
local entities = entities_u
local e = entities[i_u]
local col0 = col0_u
local col1 = col1_u
local col2 = col2_u
local col3 = col3_u
local col4 = col4_u
local col5 = col5_u
local col6 = col6_u
local col7 = col7_u
local ids = ids_u
local columns_map = columns_map_u
query.next = world_query_iter_next while e == nil do
return world_query_iter_next last_archetype_u += 1
local compatible_archetypes = compatible_archetypes_u
local archetype = compatible_archetypes[last_archetype_u]
archetype_u = archetype
if not archetype then
return nil
end
entities = archetype.entities
i_u = #entities
if i_u == 0 then
continue
end
e = entities[i_u]
entities_u = entities
columns_map = archetype.columns_map
columns_map_u = columns_map
col0 = columns_map[id0]
col1 = columns_map[id1]
col2 = columns_map[id2]
col3 = columns_map[id3]
col4 = columns_map[id4]
col5 = columns_map[id5]
col6 = columns_map[id6]
col7 = columns_map[id7]
col0_u = col0
col1_u = col1
col2_u = col2
col3_u = col3
col4_u = col4
col5_u = col5
col6_u = col6
col7_u = col7
end
local row = i_u
i_u -= 1
for i = 9, ids_len do
output[i - 8] = columns_map[ids[i]::any][row]
end
return e, col0[row], col1[row], col2[row], col3[row], col4[row], col5[row], col6[row], col7[row], unpack(output)
end
end
query.next = world_query_iter_next
return world_query_iter_next
end end
local function query_iter(query): () -> (number, ...any) local function query_iter(query): () -> (number, ...any)
@ -1826,21 +1826,16 @@ local function query_iter(query): () -> (number, ...any)
end end
local function query_cached(query: QueryInner) local function query_cached(query: QueryInner)
local ids = query.ids local ids_u = query.ids
local last_archetype = 1
local A, B, C, D, E, F, G, H, I = unpack(ids :: { Component }) local id0, id1, id2, id3, id4, id5, id6, id7, id8 = unpack(ids_u :: { Component })
if not id0 then if not id0 then
A = query.filter_with[1] id0 = query.filter_with[1]
end end
local a: Column, b: Column, c: Column, d: Column local col0_u: Column, col1_u: Column, col2_u: Column, col3_u: Column
local e: Column, f: Column, g: Column, h: Column local col4_u: Column, col5_u: Column, col6_u: Column, col7_u: Column
local world_query_iter_next local world_query_iter_next
local entities: { Entity }
local i: number
local archetype: Archetype
local columns_map: { [Component]: Column }
local archetypes = query_archetypes(query :: any) :: { Archetype } local archetypes = query_archetypes(query :: any) :: { Archetype }
local archetypes_map = {} local archetypes_map = {}
query.archetypes_map = archetypes_map query.archetypes_map = archetypes_map
@ -1849,7 +1844,21 @@ local function query_cached(query: QueryInner)
archetypes_map[arche.id] = j archetypes_map[arche.id] = j
end end
local compatible_archetypes = archetypes :: { Archetype } local compatible_archetypes_u = archetypes :: { Archetype }
local last_archetype_u = 1
local archetype_u = compatible_archetypes_u[1]
local entities_u: { Entity }
local i_u: number
local columns_map_u: { [Component]: Column }
if not archetype_u then
entities_u = {}
i_u = 0
columns_map_u = {}
else
entities_u = archetype_u.entities
i_u = #entities_u
columns_map_u = archetype_u.columns_map
end
local world = (query :: { world: World }).world local world = (query :: { world: World }).world
-- Only need one observer for EcsArchetypeCreate and EcsArchetypeDelete respectively -- Only need one observer for EcsArchetypeCreate and EcsArchetypeDelete respectively
@ -1860,10 +1869,10 @@ local function query_cached(query: QueryInner)
on_create_action = {} :: Map<Component, { Observer }> on_create_action = {} :: Map<Component, { Observer }>
observable[EcsOnArchetypeCreate::any] = on_create_action observable[EcsOnArchetypeCreate::any] = on_create_action
end end
local query_cache_on_create: { Observer } = on_create_action[A] local query_cache_on_create: { Observer } = on_create_action[id0]
if not query_cache_on_create then if not query_cache_on_create then
query_cache_on_create = {} query_cache_on_create = {}
on_create_action[A] = query_cache_on_create on_create_action[id0] = query_cache_on_create
end end
local on_delete_action = observable[EcsOnArchetypeDelete::any] local on_delete_action = observable[EcsOnArchetypeDelete::any]
@ -1871,10 +1880,10 @@ local function query_cached(query: QueryInner)
on_delete_action = {} :: Map<Component, { Observer }> on_delete_action = {} :: Map<Component, { Observer }>
observable[EcsOnArchetypeDelete::any] = on_delete_action observable[EcsOnArchetypeDelete::any] = on_delete_action
end end
local query_cache_on_delete: { Observer } = on_delete_action[A] local query_cache_on_delete: { Observer } = on_delete_action[id0]
if not query_cache_on_delete then if not query_cache_on_delete then
query_cache_on_delete = {} query_cache_on_delete = {}
on_delete_action[A] = query_cache_on_delete on_delete_action[id0] = query_cache_on_delete
end end
local function on_create_callback(archetype: Archetype) local function on_create_callback(archetype: Archetype)
@ -1902,60 +1911,61 @@ local function query_cached(query: QueryInner)
table.insert(query_cache_on_create, observer_for_create) table.insert(query_cache_on_create, observer_for_create)
table.insert(query_cache_on_delete, observer_for_delete) table.insert(query_cache_on_delete, observer_for_delete)
local function cached_query_iter() local function cached_query_iter()
last_archetype = 1 last_archetype_u = 1
archetype = compatible_archetypes[last_archetype] local compatible_archetypes = compatible_archetypes_u
if not archetype then archetype_u = compatible_archetypes[last_archetype_u]
if not archetype_u then
return NOOP return NOOP
end end
entities = archetype.entities entities_u = archetype_u.entities
i = #entities i_u = #entities_u
columns_map = archetype.columns_map columns_map_u = archetype_u.columns_map
if not id0 then if not id0 then
elseif not id1 then elseif not id1 then
a = columns_map[A] col0_u = columns_map_u[id0]
elseif not id2 then elseif not id2 then
a = columns_map[A] col0_u = columns_map_u[id0]
b = columns_map[B] col1_u = columns_map_u[id1]
elseif not id3 then elseif not id3 then
a = columns_map[A] col0_u = columns_map_u[id0]
b = columns_map[B] col1_u = columns_map_u[id1]
c = columns_map[C] col2_u = columns_map_u[id2]
elseif not id4 then elseif not id4 then
a = columns_map[A] col0_u = columns_map_u[id0]
b = columns_map[B] col1_u = columns_map_u[id1]
c = columns_map[C] col2_u = columns_map_u[id2]
d = columns_map[D] col3_u = columns_map_u[id3]
elseif not id5 then elseif not id5 then
a = columns_map[A] col0_u = columns_map_u[id0]
b = columns_map[B] col1_u = columns_map_u[id1]
c = columns_map[C] col2_u = columns_map_u[id2]
d = columns_map[D] col3_u = columns_map_u[id3]
e = columns_map[E] col4_u = columns_map_u[id4]
elseif not id6 then elseif not id6 then
a = columns_map[A] col0_u = columns_map_u[id0]
b = columns_map[B] col1_u = columns_map_u[id1]
c = columns_map[C] col2_u = columns_map_u[id2]
d = columns_map[D] col3_u = columns_map_u[id3]
e = columns_map[E] col4_u = columns_map_u[id4]
f = columns_map[F] col5_u = columns_map_u[id5]
elseif not id7 then elseif not id7 then
a = columns_map[A] col0_u = columns_map_u[id0]
b = columns_map[B] col1_u = columns_map_u[id1]
c = columns_map[C] col2_u = columns_map_u[id2]
d = columns_map[D] col3_u = columns_map_u[id3]
e = columns_map[E] col4_u = columns_map_u[id4]
f = columns_map[F] col5_u = columns_map_u[id5]
g = columns_map[G] col6_u = columns_map_u[id6]
else else
a = columns_map[A] col0_u = columns_map_u[id0]
b = columns_map[B] col1_u = columns_map_u[id1]
c = columns_map[C] col2_u = columns_map_u[id2]
d = columns_map[D] col3_u = columns_map_u[id3]
e = columns_map[E] col4_u = columns_map_u[id4]
f = columns_map[F] col5_u = columns_map_u[id5]
g = columns_map[G] col6_u = columns_map_u[id6]
h = columns_map[H] col7_u = columns_map_u[id7]
end end
return world_query_iter_next return world_query_iter_next
@ -1981,7 +1991,7 @@ local function query_cached(query: QueryInner)
continue continue
end end
e = entities[i_u] e = entities[i_u]
captured_entities = entities entities_u = entities
end end
i_u -= 1 i_u -= 1
return e return e
@ -2053,7 +2063,7 @@ local function query_cached(query: QueryInner)
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row] return e, col0[row], col1[row]
end end
elseif not id3 then elseif not id3 then
function world_query_iter_next(): any function world_query_iter_next(): any
@ -2092,7 +2102,7 @@ local function query_cached(query: QueryInner)
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row], captured_c[row] return e, col0[row], col1[row], col2[row]
end end
elseif not id4 then elseif not id4 then
function world_query_iter_next(): any function world_query_iter_next(): any
@ -2121,20 +2131,20 @@ local function query_cached(query: QueryInner)
entities_u = entities entities_u = entities
local columns_map = archetype.columns_map local columns_map = archetype.columns_map
columns_map_u = columns_map columns_map_u = columns_map
captured_a = captured_columns_map[A] col0 = columns_map[id0]
captured_b = captured_columns_map[B] col1 = columns_map[id1]
captured_c = captured_columns_map[C] col2 = columns_map[id2]
captured_d = captured_columns_map[D] col3 = columns_map[id3]
a = captured_a col0_u = col0
b = captured_b col1_u = col1
c = captured_c col2_u = col2
d = captured_d col3_u = col3
end end
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row], captured_c[row], captured_d[row] return e, col0[row], col1[row], col2[row], col3[row]
end end
elseif not id5 then elseif not id5 then
function world_query_iter_next(): any function world_query_iter_next(): any
@ -2179,7 +2189,7 @@ local function query_cached(query: QueryInner)
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row], captured_c[row], captured_d[row], captured_e[row] return e, col0[row], col1[row], col2[row], col3[row], col4[row]
end end
elseif not id6 then elseif not id6 then
function world_query_iter_next(): any function world_query_iter_next(): any
@ -2227,7 +2237,7 @@ local function query_cached(query: QueryInner)
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row], captured_c[row], captured_d[row], captured_e[row], captured_f[row] return e, col0[row], col1[row], col2[row], col3[row], col4[row], col5[row]
end end
elseif not id7 then elseif not id7 then
function world_query_iter_next(): any function world_query_iter_next(): any
@ -2278,7 +2288,7 @@ local function query_cached(query: QueryInner)
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row], captured_c[row], captured_d[row], captured_e[row], captured_f[row], captured_g[row] return e, col0[row], col1[row], col2[row], col3[row], col4[row], col5[row], captured_g[row]
end end
elseif not id8 then elseif not id8 then
function world_query_iter_next(): any function world_query_iter_next(): any
@ -2332,11 +2342,11 @@ local function query_cached(query: QueryInner)
local row = i_u local row = i_u
i_u -= 1 i_u -= 1
return e, captured_a[row], captured_b[row], captured_c[row], captured_d[row], captured_e[row], captured_f[row], captured_g[row], captured_h[row] return e, col0[row], col1[row], col2[row], col3[row], col4[row], col5[row], col6[row], col7[row]
end end
else else
local output = {} local output = {}
local ids_len = #ids local ids_len = #ids_u
function world_query_iter_next(): any function world_query_iter_next(): any
local entities = entities_u local entities = entities_u
local e = entities[i_u] local e = entities[i_u]
@ -2348,16 +2358,16 @@ local function query_cached(query: QueryInner)
local col5 = col5_u local col5 = col5_u
local col6 = col6_u local col6 = col6_u
local col7 = col7_u local col7 = col7_u
local captured_ids = ids local ids = ids_u
local captured_columns_map = columns_map local columns_map = columns_map_u
while e == nil do while e == nil do
last_archetype_u += 1 last_archetype_u += 1
local compatible_archetypes = compatible_archetypes_u local compatible_archetypes = compatible_archetypes_u
local archetype = compatible_archetypes[last_archetype_u] local archetype = compatible_archetypes[last_archetype_u]
archetype_u = archetype archetype_u = archetype
if not archetype then if not archetype then
return nil return nil
end end
entities = archetype.entities entities = archetype.entities
@ -2368,7 +2378,7 @@ local function query_cached(query: QueryInner)
e = entities[i_u] e = entities[i_u]
entities_u = entities entities_u = entities
columns_map = archetype.columns_map columns_map = archetype.columns_map
columns_map = captured_columns_map columns_map_u = columns_map
col0 = columns_map[id0] col0 = columns_map[id0]
col1 = columns_map[id1] col1 = columns_map[id1]
col2 = columns_map[id2] col2 = columns_map[id2]
@ -2387,14 +2397,14 @@ local function query_cached(query: QueryInner)
col7_u = col7 col7_u = col7
end end
local row = i local row = i_u
i -= 1 i_u -= 1
for i = 9, ids_len do for i = 9, ids_len do
output[i - 8] = captured_columns_map[captured_ids[i]::any][row] output[i - 8] = columns_map[ids[i]::any][row]
end end
return e, captured_a[row], captured_b[row], captured_c[row], captured_d[row], captured_e[row], captured_f[row], captured_g[row], captured_h[row], unpack(output) return e, col0[row], col1[row], col2[row], col3[row], col4[row], col5[row], col6[row], col7[row], unpack(output)
end end
end end

View file

@ -24,7 +24,6 @@ type Id<T=unknown> = jecs.Id<T>
local entity_visualiser = require("@modules/entity_visualiser") local entity_visualiser = require("@modules/entity_visualiser")
local dwi = entity_visualiser.stringify local dwi = entity_visualiser.stringify
FOCUS()
TEST("reproduce idr_t nil archetype bug", function() TEST("reproduce idr_t nil archetype bug", function()
local world = jecs.world() local world = jecs.world()
@ -47,7 +46,7 @@ TEST("reproduce idr_t nil archetype bug", function()
local src = r.archetype local src = r.archetype
--REMOVING THIS jecs.archetype_traverse_remove CALL STOPS IT FROM HAPPENING --REMOVING THIS jecs.archetype_traverse_remove CALL STOPS IT FROM HAPPENING
local dst = src and jecs.archetype_traverse_remove(world, id, src) -- local dst = src and jecs.archetype_traverse_remove(world, id, src)
end) end)
local batchSize = 200 local batchSize = 200
@ -79,26 +78,23 @@ TEST("reproduce idr_t nil archetype bug", function()
local q = world:query(jecs.pair(jecs.ChildOf, jecs.w)):cached() local q = world:query(jecs.pair(jecs.ChildOf, jecs.w)):cached()
print("---- delete start root")
print("--- root", world:contains(root), root, jecs.ECS_ID(root), jecs.ECS_GENERATION(root))
world:delete(root) world:delete(root)
print("---- delete end root")
for entity in q do
local parent = world:parent(entity) :: jecs.Entity
print("--- root", world:contains(root), jecs.ECS_ID(root), jecs.ECS_GENERATION(root))
print(world:get(entity, jecs.Name), jecs.ECS_ID(parent), jecs.ECS_GENERATION(parent), "root ->", root)
CHECK(world:parent(entity) == nil)
end
for entityId, info in trackedEntities do for entityId, info in trackedEntities do
if world:contains(entityId) and not world:parent(entityId :: any) then if world:contains(entityId) and not world:parent(entityId :: any) then
print(`bugged entity found: {entityId}`) print(`bugged entity found: {entityId}`)
print(`original parent: {info.parentId}`) print(`original parent: {info.parentId}`)
print(`current parent: {i}`)
print(`batch = {batch}, i = {i}`) print(`batch = {batch}, i = {i}`)
print("==========================================") print("==========================================")
trackedEntities[entityId] = nil trackedEntities[entityId] = nil
end end
end end
for entity in q do
local parent = world:parent(entity) :: jecs.Entity
CHECK(world:parent(entity) == nil)
end
end end
end) end)