invoke OnRemove hooks when overwritten

This commit is contained in:
lolmanurfunny 2025-04-02 02:21:47 -04:00
parent f6cac301db
commit 31e364afdf
2 changed files with 74 additions and 13 deletions

View file

@ -923,7 +923,19 @@ local function world_add(
if from == to then
return
end
local idr = world.component_index[id]
local idr_hooks = idr.hooks
local on_add = idr_hooks.on_add
if from then
if ECS_IS_PAIR(id) and bit32.band(idr.flags, ECS_ID_EXCLUSIVE) ~= 0 then
local on_remove = idr_hooks.on_remove
if on_remove then
on_remove(entity)
end
end
entity_move(entity_index, entity, record, to)
else
if #to.types > 0 then
@ -931,9 +943,6 @@ local function world_add(
end
end
local idr = world.component_index[id]
local on_add = idr.hooks.on_add
if on_add then
on_add(entity)
end
@ -966,6 +975,13 @@ local function world_set(world: ecs_world_t, entity: i53, id: i53, data: unknown
end
if from then
if ECS_IS_PAIR(id) and bit32.band(idr.flags, ECS_ID_EXCLUSIVE) ~= 0 then
local on_remove = idr_hooks.on_remove
if on_remove then
on_remove(entity)
end
end
-- If there was a previous archetype, then the entity needs to move the archetype
entity_move(entity_index, entity, record, to)
else

View file

@ -1949,22 +1949,67 @@ TEST("world:delete() invokes OnRemove hook", function()
end)
TEST("exclusive relationships", function()
local world = world_new()
local pair = jecs.pair
do CASE "enforce exclusivity"
local world = world_new()
local pair = jecs.pair
local child = world:entity()
local e = world:entity()
for _ = 1, 10 do
for _ = 1, 10 do
local A = world:entity()
local B = world:entity()
world:add(e, pair(world:entity(), e)) -- noise
world:add(e, pair(ChildOf, A))
world:add(e, pair(ChildOf, B))
CHECK(not world:has(e, pair(ChildOf, A)))
CHECK(world:has(e, pair(ChildOf, B)))
end
end
do CASE "invoke OnRemove when overwritten using world:add()"
local world = world_new()
local pair = jecs.pair
local relation = world:component()
world:add(relation, jecs.Exclusive)
local e = world:entity()
local A = world:entity()
local B = world:entity()
world:add(child, pair(world:entity(), child)) -- noise
world:add(child, pair(ChildOf, A))
world:add(child, pair(child, world:entity())) -- noise
world:add(child, pair(ChildOf, B))
local called = false
world:set(relation, jecs.OnRemove, function(e)
called = true
CHECK(world:target(e, relation) == A)
end)
CHECK(world:has(child, pair(ChildOf, B)))
CHECK(not world:has(child, pair(ChildOf, A)))
world:add(e, pair(relation, A))
world:add(e, pair(relation, B))
CHECK(called)
end
do CASE "invoke OnRemove when overwritten using world:set()"
local world = world_new()
local pair = jecs.pair
local relation = world:component()
world:add(relation, jecs.Exclusive)
local e = world:entity()
local A = world:entity()
local B = world:entity()
local called = false
world:set(relation, jecs.OnRemove, function(e)
called = true
CHECK(world:target(e, relation) == A)
end)
world:set(e, pair(relation, A), nil)
world:set(e, pair(relation, B), nil)
CHECK(called)
end
end)