From 3a560393f1bce659ea675c91150d07ab2a0b01cc Mon Sep 17 00:00:00 2001 From: lolmanurfunny <77128366+lolmanurfunny@users.noreply.github.com> Date: Fri, 7 Mar 2025 05:45:55 -0500 Subject: [PATCH 1/5] Optimize deletion logic --- jecs.luau | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/jecs.luau b/jecs.luau index 9433147..b9c7e05 100644 --- a/jecs.luau +++ b/jecs.luau @@ -1113,11 +1113,11 @@ do end local delete = entity - local component_index = world.component_index local archetypes: Archetypes = world.archetypes - local tgt = ECS_PAIR(EcsWildcard, delete) - local idr_t = component_index[tgt] - local idr = component_index[delete] + local component_index = world.component_index + + local idr = component_index[entity] + local idr_t = component_index[ECS_PAIR(EcsWildcard, entity)] if idr then local flags = idr.flags @@ -1152,21 +1152,16 @@ do if idr_t then for archetype_id in idr_t.columns do - local children = {} local idr_t_archetype = archetypes[archetype_id] - local idr_t_types = idr_t_archetype.types - - for _, child in idr_t_archetype.entities do - table.insert(children, child) - end - + local children = table.clone(idr_t_archetype.entities) local n = #children for _, id in idr_t_types do if not ECS_IS_PAIR(id) then continue end + local object = ecs_pair_second(world, id) if object == delete then local id_record = component_index[id] @@ -1181,14 +1176,24 @@ do local on_remove = id_record.hooks.on_remove local to = archetype_traverse_remove(world, id, idr_t_archetype) local empty = #to.types == 0 - for i = n, 1, -1 do - local child = children[i] - if on_remove then + + if on_remove then + for i = n, 1, -1 do + local child = children[i] on_remove(child) + + if not empty then + local r = sparse_array[ECS_ENTITY_T_LO(child)] + entity_move(entity_index, child, r, to) + end end - local r = sparse_array[ECS_ENTITY_T_LO(child)] - if not empty then - entity_move(entity_index, child, r, to) + else + if not empty then -- no on_remove hook set; fast path + for i = n, 1, -1 do + local child = children[i] + local r = sparse_array[ECS_ENTITY_T_LO(child)] + entity_move(entity_index, child, r, to) + end end end end From fa4df24adaba7c815f49cb25f5c043832a75a2b9 Mon Sep 17 00:00:00 2001 From: lolmanurfunny <77128366+lolmanurfunny@users.noreply.github.com> Date: Fri, 7 Mar 2025 19:56:40 -0500 Subject: [PATCH 2/5] undo variable changes --- jecs.luau | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jecs.luau b/jecs.luau index b9c7e05..68d6990 100644 --- a/jecs.luau +++ b/jecs.luau @@ -1113,11 +1113,11 @@ do end local delete = entity - local archetypes: Archetypes = world.archetypes local component_index = world.component_index - - local idr = component_index[entity] - local idr_t = component_index[ECS_PAIR(EcsWildcard, entity)] + local archetypes: Archetypes = world.archetypes + local tgt = ECS_PAIR(EcsWildcard, delete) + local idr_t = component_index[tgt] + local idr = component_index[delete] if idr then local flags = idr.flags From 870823f9fc8290a0886d8f902d20c3e5677f072e Mon Sep 17 00:00:00 2001 From: lolmanurfunny <77128366+lolmanurfunny@users.noreply.github.com> Date: Fri, 7 Mar 2025 23:17:43 -0500 Subject: [PATCH 3/5] shorten loop --- jecs.luau | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/jecs.luau b/jecs.luau index 68d6990..97d1479 100644 --- a/jecs.luau +++ b/jecs.luau @@ -1176,24 +1176,14 @@ do local on_remove = id_record.hooks.on_remove local to = archetype_traverse_remove(world, id, idr_t_archetype) local empty = #to.types == 0 - - if on_remove then - for i = n, 1, -1 do - local child = children[i] + for i = n, 1, -1 do + local child = children[i] + if on_remove then on_remove(child) - - if not empty then - local r = sparse_array[ECS_ENTITY_T_LO(child)] - entity_move(entity_index, child, r, to) - end end - else - if not empty then -- no on_remove hook set; fast path - for i = n, 1, -1 do - local child = children[i] - local r = sparse_array[ECS_ENTITY_T_LO(child)] - entity_move(entity_index, child, r, to) - end + if not empty then + local r = sparse_array[ECS_ENTITY_T_LO(child)] + entity_move(entity_index, child, r, to) end end end From e2ea71a7fe64173e4a0b7e4123cdc3b7017b70ef Mon Sep 17 00:00:00 2001 From: lolmanurfunny <77128366+lolmanurfunny@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:39:04 -0400 Subject: [PATCH 4/5] add fix for #207 --- jecs.luau | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/jecs.luau b/jecs.luau index 97d1479..691bf07 100644 --- a/jecs.luau +++ b/jecs.luau @@ -1154,6 +1154,8 @@ do for archetype_id in idr_t.columns do local idr_t_archetype = archetypes[archetype_id] local idr_t_types = idr_t_archetype.types + local to = idr_t_archetype + local children = table.clone(idr_t_archetype.entities) local n = #children @@ -1163,28 +1165,30 @@ do end local object = ecs_pair_second(world, id) - if object == delete then - local id_record = component_index[id] - local flags = id_record.flags - local flags_delete_mask: number = bit32.band(flags, ECS_ID_DELETE) - if flags_delete_mask ~= 0 then - for i = n, 1, -1 do - world_delete(world, children[i]) + if object ~= delete then + continue + end + + local id_record = component_index[id] + local flags = id_record.flags + local flags_delete_mask: number = bit32.band(flags, ECS_ID_DELETE) + if flags_delete_mask ~= 0 then + for i = n, 1, -1 do + world_delete(world, children[i]) + end + break + else + local on_remove = id_record.hooks.on_remove + to = archetype_traverse_remove(world, id, to) + local empty = #to.types == 0 + for i = n, 1, -1 do + local child = children[i] + if on_remove then + on_remove(child) end - break - else - local on_remove = id_record.hooks.on_remove - local to = archetype_traverse_remove(world, id, idr_t_archetype) - local empty = #to.types == 0 - for i = n, 1, -1 do - local child = children[i] - if on_remove then - on_remove(child) - end - if not empty then - local r = sparse_array[ECS_ENTITY_T_LO(child)] - entity_move(entity_index, child, r, to) - end + if not empty then + local r = sparse_array[ECS_ENTITY_T_LO(child)] + entity_move(entity_index, child, r, to) end end end From 03666c9b615a00fe14f47b854830752db1a90e3e Mon Sep 17 00:00:00 2001 From: lolmanurfunny <77128366+lolmanurfunny@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:39:30 -0400 Subject: [PATCH 5/5] test case --- test/tests.luau | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/tests.luau b/test/tests.luau index 504027f..b1615b4 100644 --- a/test/tests.luau +++ b/test/tests.luau @@ -1333,6 +1333,26 @@ TEST("world:target", function() CHECK(i == 10) end + + do CASE("should return correct targets after deletion") -- ISSUE #207 + local world = jecs.World.new() + + local Attacks = world:component() + local Eats = world:component() + local a = world:entity() + local b = world:entity() + local c = world:entity() + + world:add(a, jecs.pair(Attacks, b)) + world:add(a, jecs.pair(Attacks, c)) + world:add(a, jecs.pair(Eats, c)) + world:add(a, jecs.pair(Eats, b)) + world:delete(c) + + CHECK(world:target(a, Attacks, 0) == b) + CHECK(not world:target(a, Attacks, 1)) + CHECK(not world:target(a, Attacks, 2)) + end end) TEST("world:contains", function()