From 8dd53b8c2aa23c10dc4cc5f74f7c4bc3ee15200b Mon Sep 17 00:00:00 2001 From: Ukendio Date: Tue, 13 Aug 2024 20:58:07 +0200 Subject: [PATCH] optimize deletion --- src/init.luau | 67 ++++++++++++++++++++++++++----------------------- test/tests.luau | 18 ++++++------- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/init.luau b/src/init.luau index 36858b1..09a741d 100644 --- a/src/init.luau +++ b/src/init.luau @@ -676,8 +676,6 @@ local function archetype_fast_delete_last(world, columns, column_count, types, entity) for i, column in columns do - invoke_hook(world, EcsOnRemove, types[i], entity) - column[column_count] = nil end end @@ -685,15 +683,15 @@ end local function archetype_fast_delete(world, columns, column_count, row, types, entity) for i, column in columns do - invoke_hook(world, EcsOnRemove, types[i], entity) - column[row] = column[column_count] column[column_count] = nil end end -local function archetype_delete(world: World, archetype, row) +local function archetype_delete(world: World, archetype, + row, track) + local entityIndex = world.entityIndex local columns = archetype.columns local types = archetype.types @@ -715,6 +713,10 @@ local function archetype_delete(world: World, archetype, row) -- TODO: if last == 0 then deactivate table + for _, id in types do + invoke_hook(world, EcsOnRemove, id, delete) + end + if row == last then archetype_fast_delete_last(world, columns, column_count, types, delete) @@ -724,29 +726,25 @@ local function archetype_delete(world: World, archetype, row) end - local component_index = world.componentIndex local archetypes = world.archetypes local idr = component_index[delete] if idr then component_index[delete] = nil - -- TODO: remove direct descendamt because + local children = {} for archetype_id in idr.cache do local idr_archetype = archetypes[archetype_id] - local children = {} - for i, child in idr_archetype.entities do table.insert(children, child) end - - for _, child in children do - if world_has_one_inline(world, child, EcsDelete) then - world_delete(world, child) - else - world_remove(world, child, delete) - end + end + for _, child in children do + if world_has_one_inline(world, child, EcsDelete) then + world_delete(world, child) + else + world_remove(world, child, delete) end end end @@ -776,30 +774,37 @@ local function archetype_delete(world: World, archetype, row) local o = ECS_PAIR(EcsWildcard, delete) local idr_o = component_index[o] + if idr_o then for archetype_id in idr_o.cache do local children = {} local idr_o_archetype = archetypes[archetype_id] + -- In the future, this needs to be optimized to only + -- look for linked records instead of doing this linearly + local idr_o_types = idr_o_archetype.types for _, child in idr_o_archetype.entities do table.insert(children, child) end - for _, child in children do - -- In the future, this needs to be optimized to only - -- look for linked records instead of doing this linearly - for _, id in idr_o_types do - if not ECS_IS_PAIR(id) then - continue + for _, id in idr_o_types do + if not ECS_IS_PAIR(id) then + continue + end + + local relation = ECS_ENTITY_T_HI(id) + + if world_has_one_inline(world, relation, EcsDelete) then + for _, child in children do + -- Cascade deletions of it has Delete as component trait + world_delete(world, child) end - local relation = ECS_ENTITY_T_HI(id) - if world_target(world, child, relation) == delete then - if world_has_one_inline(world, relation, EcsDelete) then - -- Cascade deletions of it has Delete as component trait - world_delete(world, child) - else - local p = ECS_PAIR(relation, delete) + else + local p = ECS_PAIR(relation, delete) + + for _, child in children do + if world_target(world, child, relation) == delete then world_remove(world, child, p) end end @@ -809,7 +814,7 @@ local function archetype_delete(world: World, archetype, row) end end -function world_delete(world: World, entity: i53) +function world_delete(world: World, entity: i53, track) local entityIndex = world.entityIndex local record = entityIndex.sparse[entity] @@ -823,7 +828,7 @@ function world_delete(world: World, entity: i53) if archetype then -- In the future should have a destruct mode for -- deleting archetypes themselves. Maybe requires recycling - archetype_delete(world, archetype, row) + archetype_delete(world, archetype, row, track) end record.archetype = nil :: any diff --git a/test/tests.luau b/test/tests.luau index 4dceed6..d452c4b 100644 --- a/test/tests.luau +++ b/test/tests.luau @@ -813,14 +813,14 @@ TEST("world:delete", function() end BENCH("remove friends of entity", function() - world:delete(e) - end) + world:delete(e) + end) - for i, friend in friends do - CHECK(not world:has(friends, pair(jecs.ChildOf, e))) - CHECK(world:has(friend, Health)) - end - end + for i, friend in friends do + CHECK(not world:has(friends, pair(jecs.ChildOf, e))) + CHECK(world:has(friend, Health)) + end + end do CASE "fast delete" local world = jecs.World.new() @@ -829,7 +829,7 @@ TEST("world:delete", function() local Health = world:component() local Poison = world:component() - for i = 1, 10 do + for i = 1, 100 do local child = world:entity() world:set(child, Poison, 9999) world:set(child, Health, 100) @@ -837,7 +837,7 @@ TEST("world:delete", function() end BENCH("simple deletion of entity", function() - for i = 1, START(10) do + for i = 1, START(100) do local e = entities[i] world:delete(e) end