From aa178981dcf0c47586493c764c93428ff9234377 Mon Sep 17 00:00:00 2001 From: Ukendio Date: Thu, 10 Jul 2025 12:50:59 +0200 Subject: [PATCH] Hotfix archetype not being marked dead --- jecs.luau | 17 ++++++++++---- test/tests.luau | 60 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/jecs.luau b/jecs.luau index cc909a6..8cf42d5 100755 --- a/jecs.luau +++ b/jecs.luau @@ -781,6 +781,7 @@ local function archetype_register(world: World, archetype: Archetype) local archetype_id = archetype.id local columns_map = archetype.columns_map local columns = archetype.columns + for i, component_id in archetype.types do local idr = id_record_ensure(world, component_id) local is_tag = bit32.btest(idr.flags, ECS_ID_IS_TAG) @@ -803,6 +804,10 @@ local function archetype_register(world: World, archetype: Archetype) archetype_append_to_records(idr_t, archetype_id, columns_map, t, i, column) end end + + world.archetype_index[archetype.type] = archetype + world.archetypes[archetype_id] = archetype + world.archetype_edges[archetype.id] = {} :: Map end local function archetype_create(world: World, id_types: { Id }, ty, prev: i53?): Archetype @@ -824,7 +829,7 @@ local function archetype_create(world: World, id_types: { Id }, ty, prev: i53?): dead = false, } - archetype_register(world, archetype) + archetype_register(world, archetype, false) for id in columns_map do local observer_list = find_observers(world, EcsOnArchetypeCreate, id) @@ -838,9 +843,6 @@ local function archetype_create(world: World, id_types: { Id }, ty, prev: i53?): end end - world.archetype_index[ty] = archetype - world.archetypes[archetype_id] = archetype - world.archetype_edges[archetype.id] = {} :: Map return archetype end @@ -1078,6 +1080,8 @@ local function archetype_destroy(world: World, archetype: Archetype) end end end + + archetype.dead = true end local function NOOP() end @@ -2324,6 +2328,10 @@ local function world_new() end edge[id] = to else + if to.dead then + archetype_register(world, to) + to.dead = false + end idr = component_index[id] end if from == to then @@ -2342,6 +2350,7 @@ local function world_new() if on_add then on_add(entity, id) end + return end local to = archetype_traverse_add(world, id, from) diff --git a/test/tests.luau b/test/tests.luau index a899b01..0758d9f 100755 --- a/test/tests.luau +++ b/test/tests.luau @@ -24,6 +24,44 @@ type Id = jecs.Id local entity_visualiser = require("@tools/entity_visualiser") local dwi = entity_visualiser.stringify +FOCUS() +TEST("", function() + local world = jecs.world() + local data = world:component() + local relation = world:component() + world:add(relation, jecs.pair(jecs.OnDeleteTarget, jecs.Delete)) + + local e1 = world:entity() + local e2 = world:entity() + world:set(e2, data, 456) + world:add(e2, jecs.pair(relation, e1)) + world:delete(e1) + + local e1v1 = world:entity() + CHECK(ECS_ID(e1v1) == e1) + local e2v1 = world:entity() + CHECK(ECS_ID(e2v1) == e2) + world:set(e2v1, data, 456) + + CHECK(world:contains(e1v1)) + CHECK(not world:contains(e2)) + CHECK(world:contains(e2v1)) + + local count = 0 + for i,val in world:query(data):iter() do + count += 1 + end + CHECK(count == 1) + count = 0 + world:add(e2v1, jecs.pair(relation, e1v1)) + CHECK(world:has(e2v1, jecs.pair(relation, e1v1))) + + for i,val in world:query(data):iter() do + count += 1 + end + + CHECK(count==1) +end) TEST("bulk", function() local world = jecs.world() local A = world:component() @@ -885,7 +923,6 @@ TEST("world:each()", function() end end) -FOCUS() TEST("world:range()", function() do CASE "spawn entity under min range" @@ -1122,6 +1159,7 @@ end) TEST("world:query()", function() local N = 2^8 + do CASE "cached" local world = jecs.world() local Foo = world:component() @@ -1158,6 +1196,26 @@ TEST("world:query()", function() world:delete(Foo) CHECK(#q:archetypes() == 0) end + + do CASE "3 components" + local world = jecs.world() + local A = world:component() :: jecs.Entity + local B = world:component() :: jecs.Entity + local C = world:component() :: jecs.Entity + local e = world:entity() + world:set(e, A, true) + world:set(e, B, true) + world:set(e, C, true) + local q = world:query(A, B, C):cached() + local counter = 0 + for x, a, b, c in q:iter() do + counter += 1 + CHECK(a) + CHECK(b) + CHECK(c) + end + CHECK(counter == 1) + end do CASE "multiple iter" local world = jecs.world() local A = world:component() :: jecs.Entity