Handle wildcard pairs in observers

This commit is contained in:
Ukendio 2025-09-16 10:35:52 +02:00
parent 4ed2fb7a40
commit 23bf021f01
3 changed files with 149 additions and 31 deletions

View file

@ -77,19 +77,38 @@ local function observers_new<T...>(
if without then
for _, term in without do
if jecs.IS_PAIR(term) then
term = jecs.ECS_PAIR_FIRST(term)
end
local onremoved = world:removed(term, function(entity, id)
local r = jecs.record(world, entity)
local archetype = r.archetype
if archetype then
local dst = jecs.archetype_traverse_remove(world, id, archetype)
if archetypes[dst.id] then
callback(entity)
local rel = jecs.ECS_PAIR_SECOND(term)
local tgt = jecs.ECS_PAIR_SECOND(term)
local wc = tgt == jecs.w
local onremoved = world:removed(term, function(entity, id)
local r = jecs.record(world, entity)
local archetype = r.archetype
if archetype then
if not wc and id ~= tgt then
return
end
local dst = jecs.archetype_traverse_remove(world, id, archetype)
if archetypes[dst.id] then
callback(entity)
end
end
end
end)
table.insert(cleanup, onremoved)
end)
table.insert(cleanup, onremoved)
else
local onremoved = world:removed(term, function(entity, id)
local r = jecs.record(world, entity)
local archetype = r.archetype
if archetype then
local dst = jecs.archetype_traverse_remove(world, id, archetype)
if archetypes[dst.id] then
callback(entity)
end
end
end)
table.insert(cleanup, onremoved)
end
end
end
@ -192,24 +211,70 @@ local function monitors_new<T...>(query: Query<T...>): Observer<T...>
if without then
for _, term in without do
if jecs.IS_PAIR(term) then
term = jecs.ECS_PAIR_FIRST(term)
end
local onadded = world:added(term, removed)
local onremoved = world:removed(term, function(entity, id)
if callback_added == nil then
return
end
local r = jecs.record(world, entity)
local archetype = r.archetype
if archetype then
local dst = jecs.archetype_traverse_remove(world, id, archetype)
if archetypes[dst.id] then
callback_added(entity)
local rel = jecs.ECS_PAIR_FIRST(term)
local tgt = jecs.ECS_PAIR_SECOND(term)
local wc = tgt == jecs.w
local onadded = world:added(rel, function(entity, id)
if callback_removed == nil then
return
end
end
end)
table.insert(cleanup, onadded)
table.insert(cleanup, onremoved)
local r = jecs.record(world, entity)
local archetype = r.archetype
if archetype then
if not wc and id ~= term then
return
end
local dst = jecs.archetype_traverse_remove(world, id, archetype)
if archetypes[dst.id] then
callback_removed(entity)
end
end
end)
local onremoved = world:removed(rel, function(entity, id)
if callback_added == nil then
return
end
local r = jecs.record(world, entity)
local archetype = r.archetype
if archetype then
local dst = jecs.archetype_traverse_remove(world, id, archetype)
if archetypes[dst.id] then
callback_added(entity)
end
end
end)
table.insert(cleanup, onadded)
table.insert(cleanup, onremoved)
else
local onadded = world:added(term, function(entity, id)
if callback_removed == nil then
return
end
local r = jecs.record(world, entity)
local archetype = r.archetype
if archetype then
local dst = jecs.archetype_traverse_remove(world, id, archetype)
if archetypes[dst.id] then
callback_removed(entity)
end
end
end)
local onremoved = world:removed(term, function(entity, id)
if callback_added == nil then
return
end
local r = jecs.record(world, entity)
local archetype = r.archetype
if archetype then
local dst = jecs.archetype_traverse_remove(world, id, archetype)
if archetypes[dst.id] then
callback_added(entity)
end
end
end)
table.insert(cleanup, onadded)
table.insert(cleanup, onremoved)
end
end
end

View file

@ -3244,8 +3244,7 @@ local function world_new()
return world
end
-- type function ecs_id_t(entity)
-- local ty = entity:components()[2]
-- type function ecs_id_t(ty)
-- local __T = ty:readproperty(types.singleton("__T"))
-- if not __T then
-- return ty:readproperty(types.singleton("__jecs_pair_value"))

View file

@ -24,6 +24,60 @@ TEST("addons/ob", function()
CHECK(c==2)
end
do CASE "Should support query:without(pair(R, t1)) when adding pair(R, t2)"
local A = world:component()
local B = world:component()
local C = world:component()
local D = world:component()
local c = 1
local r = 1
local monitor = ob.monitor(world:query(A):without(jecs.pair(B, C)))
monitor.added(function()
c += 1
end)
monitor.removed(function()
r += 1
end)
local child = world:entity()
world:add(child, A)
CHECK(c==2)
world:add(child, jecs.pair(B, D))
CHECK(c==2)
CHECK(r==1)
world:add(child, jecs.pair(B, C))
CHECK(c==2)
CHECK(r==2)
end
do CASE "Should support query:without(pair(R, *)) when adding pair(R, t1)"
local A = world:component()
local B = world:component()
local C = world:component()
local D = world:component()
local c = 1
local r = 1
local monitor = ob.monitor(world:query(A):without(jecs.pair(B, jecs.w)))
monitor.added(function()
c += 1
end)
monitor.removed(function()
r += 1
end)
local child = world:entity()
world:add(child, A)
CHECK(c==2)
world:add(child, jecs.pair(B, D))
CHECK(c==2)
CHECK(r==2)
world:add(child, jecs.pair(B, C))
CHECK(c==2)
CHECK(r==2)
end
do CASE "Should support query:without()"
local A = world:component()
local B = world:component()