optimize deletion

This commit is contained in:
Ukendio 2024-08-13 20:58:07 +02:00
parent 735eb01526
commit 8dd53b8c2a
2 changed files with 45 additions and 40 deletions

View file

@ -676,8 +676,6 @@ local function archetype_fast_delete_last(world, columns,
column_count, types, entity) column_count, types, entity)
for i, column in columns do for i, column in columns do
invoke_hook(world, EcsOnRemove, types[i], entity)
column[column_count] = nil column[column_count] = nil
end end
end end
@ -685,15 +683,15 @@ end
local function archetype_fast_delete(world, columns, local function archetype_fast_delete(world, columns,
column_count, row, types, entity) column_count, row, types, entity)
for i, column in columns do for i, column in columns do
invoke_hook(world, EcsOnRemove, types[i], entity)
column[row] = column[column_count] column[row] = column[column_count]
column[column_count] = nil column[column_count] = nil
end end
end end
local function archetype_delete(world: World, archetype, row) local function archetype_delete(world: World, archetype,
row, track)
local entityIndex = world.entityIndex local entityIndex = world.entityIndex
local columns = archetype.columns local columns = archetype.columns
local types = archetype.types local types = archetype.types
@ -715,6 +713,10 @@ local function archetype_delete(world: World, archetype, row)
-- TODO: if last == 0 then deactivate table -- TODO: if last == 0 then deactivate table
for _, id in types do
invoke_hook(world, EcsOnRemove, id, delete)
end
if row == last then if row == last then
archetype_fast_delete_last(world, columns, archetype_fast_delete_last(world, columns,
column_count, types, delete) column_count, types, delete)
@ -724,29 +726,25 @@ local function archetype_delete(world: World, archetype, row)
end end
local component_index = world.componentIndex local component_index = world.componentIndex
local archetypes = world.archetypes local archetypes = world.archetypes
local idr = component_index[delete] local idr = component_index[delete]
if idr then if idr then
component_index[delete] = nil component_index[delete] = nil
-- TODO: remove direct descendamt because local children = {}
for archetype_id in idr.cache do for archetype_id in idr.cache do
local idr_archetype = archetypes[archetype_id] local idr_archetype = archetypes[archetype_id]
local children = {}
for i, child in idr_archetype.entities do for i, child in idr_archetype.entities do
table.insert(children, child) table.insert(children, child)
end end
end
for _, child in children do for _, child in children do
if world_has_one_inline(world, child, EcsDelete) then if world_has_one_inline(world, child, EcsDelete) then
world_delete(world, child) world_delete(world, child)
else else
world_remove(world, child, delete) world_remove(world, child, delete)
end
end end
end end
end end
@ -776,30 +774,37 @@ local function archetype_delete(world: World, archetype, row)
local o = ECS_PAIR(EcsWildcard, delete) local o = ECS_PAIR(EcsWildcard, delete)
local idr_o = component_index[o] local idr_o = component_index[o]
if idr_o then if idr_o then
for archetype_id in idr_o.cache do for archetype_id in idr_o.cache do
local children = {} local children = {}
local idr_o_archetype = archetypes[archetype_id] 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 local idr_o_types = idr_o_archetype.types
for _, child in idr_o_archetype.entities do for _, child in idr_o_archetype.entities do
table.insert(children, child) table.insert(children, child)
end end
for _, child in children do for _, id in idr_o_types do
-- In the future, this needs to be optimized to only if not ECS_IS_PAIR(id) then
-- look for linked records instead of doing this linearly continue
for _, id in idr_o_types do end
if not ECS_IS_PAIR(id) then
continue 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 end
local relation = ECS_ENTITY_T_HI(id) else
if world_target(world, child, relation) == delete then local p = ECS_PAIR(relation, delete)
if world_has_one_inline(world, relation, EcsDelete) then
-- Cascade deletions of it has Delete as component trait for _, child in children do
world_delete(world, child) if world_target(world, child, relation) == delete then
else
local p = ECS_PAIR(relation, delete)
world_remove(world, child, p) world_remove(world, child, p)
end end
end end
@ -809,7 +814,7 @@ local function archetype_delete(world: World, archetype, row)
end end
end end
function world_delete(world: World, entity: i53) function world_delete(world: World, entity: i53, track)
local entityIndex = world.entityIndex local entityIndex = world.entityIndex
local record = entityIndex.sparse[entity] local record = entityIndex.sparse[entity]
@ -823,7 +828,7 @@ function world_delete(world: World, entity: i53)
if archetype then if archetype then
-- In the future should have a destruct mode for -- In the future should have a destruct mode for
-- deleting archetypes themselves. Maybe requires recycling -- deleting archetypes themselves. Maybe requires recycling
archetype_delete(world, archetype, row) archetype_delete(world, archetype, row, track)
end end
record.archetype = nil :: any record.archetype = nil :: any

View file

@ -813,14 +813,14 @@ TEST("world:delete", function()
end end
BENCH("remove friends of entity", function() BENCH("remove friends of entity", function()
world:delete(e) world:delete(e)
end) end)
for i, friend in friends do for i, friend in friends do
CHECK(not world:has(friends, pair(jecs.ChildOf, e))) CHECK(not world:has(friends, pair(jecs.ChildOf, e)))
CHECK(world:has(friend, Health)) CHECK(world:has(friend, Health))
end end
end end
do CASE "fast delete" do CASE "fast delete"
local world = jecs.World.new() local world = jecs.World.new()
@ -829,7 +829,7 @@ TEST("world:delete", function()
local Health = world:component() local Health = world:component()
local Poison = world:component() local Poison = world:component()
for i = 1, 10 do for i = 1, 100 do
local child = world:entity() local child = world:entity()
world:set(child, Poison, 9999) world:set(child, Poison, 9999)
world:set(child, Health, 100) world:set(child, Health, 100)
@ -837,7 +837,7 @@ TEST("world:delete", function()
end end
BENCH("simple deletion of entity", function() BENCH("simple deletion of entity", function()
for i = 1, START(10) do for i = 1, START(100) do
local e = entities[i] local e = entities[i]
world:delete(e) world:delete(e)
end end