Fix entities with pairs of non delete policies

* fix world_delete clearing archetype entities before proper cleanup

* make changes
This commit is contained in:
PepeElToro41 2026-01-02 00:55:59 -06:00 committed by GitHub
parent e494c35b78
commit 1e7d957a5b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -3485,10 +3485,14 @@ local function world_new(DEBUG: boolean?)
end end
if idr_t then if idr_t then
local archetype_ids = idr_t.records local archetype_ids = idr_t.records
local to_remove = {}:: { [i53]: componentrecord}
for archetype_id in archetype_ids do for archetype_id in archetype_ids do
local idr_t_archetype = archetypes[archetype_id] local idr_t_archetype = archetypes[archetype_id]
local idr_t_types = idr_t_archetype.types local idr_t_types = idr_t_archetype.types
local entities = idr_t_archetype.entities local entities = idr_t_archetype.entities
local deleted_any = false
local remove_count = 0
for _, id in idr_t_types do for _, id in idr_t_types do
if not ECS_IS_PAIR(id) then if not ECS_IS_PAIR(id) then
@ -3503,27 +3507,71 @@ local function world_new(DEBUG: boolean?)
local flags = id_record.flags local flags = id_record.flags
local flags_delete_mask = bit32.btest(flags, ECS_ID_DELETE) local flags_delete_mask = bit32.btest(flags, ECS_ID_DELETE)
if flags_delete_mask then if flags_delete_mask then
for i = #entities, 1, -1 do for i = #entities, 1, -1 do
local child = entities[i] local child = entities[i]
world_delete(world, child) world_delete(world, child)
end end
deleted_any = true
break break
else else
local on_remove = id_record.on_remove to_remove[id] = id_record
remove_count += 1
local to = archetype_traverse_remove(world, id, idr_t_archetype)
for i = #entities, 1, -1 do
local child = entities[i]
if on_remove then
on_remove(child, id)
end
local r = entity_index_try_get_unsafe(child) :: record
inner_entity_move(child, r, to)
end
end end
end end
if deleted_any then
continue
end
if remove_count == 1 then
local id, id_record = next(to_remove)
local to_u = archetype_traverse_remove(world, id :: i53, idr_t_archetype)
local on_remove = id_record.on_remove
for i = #entities, 1, -1 do
local child = entities[i]
local r = entity_index_try_get_unsafe(child) :: record
local to = to_u
if on_remove then
on_remove(child, id :: i53)
local src = r.archetype
if src ~= idr_t_archetype then
to = archetype_traverse_remove(world, id::i53, src)
end
end
inner_entity_move(child, r, to)
end
elseif remove_count > 1 then
local dst_types = table.clone(idr_t_types)
for id, component_record in to_remove do
table.remove(dst_types, table.find(dst_types, id))
end
local to_u = archetype_ensure(world, dst_types)
for i = #entities, 1, -1 do
local child = entities[i]
local r = entity_index_try_get_unsafe(child) :: record
local to = to_u
for id, component_record in to_remove do
local on_remove = component_record.on_remove
if on_remove then
-- NOTE(marcus): We could be smarter with this and
-- assume hooks are deterministic and that they will
-- move to the same archetype. However users often are not reasonable people.
on_remove(child, id)
local src = r.archetype
if src ~= idr_t_archetype then
to = archetype_traverse_remove(world, id, src)
end
end
end
inner_entity_move(child, r, to)
end
end
table.clear(to_remove)
archetype_destroy(world, idr_t_archetype) archetype_destroy(world, idr_t_archetype)
end end
end end