mirror of
https://github.com/Ukendio/jecs.git
synced 2025-10-14 09:49:18 +00:00
Observers should handle non queried pairs in :with
Some checks failed
Some checks failed
This commit is contained in:
parent
9514fb758a
commit
698854d11b
2 changed files with 114 additions and 22 deletions
|
@ -6,7 +6,6 @@ type Query<T...> = jecs.Query<T...>
|
|||
|
||||
type Id<T=any> = jecs.Id<T>
|
||||
|
||||
type Entity<T> = jecs.Entity<T>
|
||||
|
||||
export type Iter<T...> = (Observer<T...>) -> () -> (jecs.Entity, T...)
|
||||
|
||||
|
@ -22,7 +21,7 @@ export type Monitor<T...> = {
|
|||
|
||||
local function observers_new<T...>(
|
||||
query: Query<T...>,
|
||||
callback: ((Entity<nil>) -> ())
|
||||
callback: (jecs.Entity) -> ()
|
||||
): Observer<T...>
|
||||
query:cached()
|
||||
|
||||
|
@ -51,10 +50,10 @@ local function observers_new<T...>(
|
|||
archetypes[archetype.id] = true
|
||||
end
|
||||
|
||||
local function emplaced<T, a>(
|
||||
entity: jecs.Entity<T>,
|
||||
local function emplaced<a>(
|
||||
entity: jecs.Entity,
|
||||
id: jecs.Id<a>,
|
||||
value: a?
|
||||
value: a
|
||||
)
|
||||
local r = entity_index.sparse_array[jecs.ECS_ID(entity)]
|
||||
|
||||
|
@ -69,13 +68,27 @@ local function observers_new<T...>(
|
|||
|
||||
for _, term in terms do
|
||||
if jecs.IS_PAIR(term) then
|
||||
term = jecs.ECS_PAIR_FIRST(term)
|
||||
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 not wc and id ~= term then
|
||||
return
|
||||
end
|
||||
local r = jecs.record(world, entity)
|
||||
if archetypes[r.archetype.id] then
|
||||
callback(entity)
|
||||
end
|
||||
end)
|
||||
table.insert(cleanup, onadded)
|
||||
else
|
||||
local onadded = world:added(term, emplaced)
|
||||
local onchanged = world:changed(term, emplaced)
|
||||
table.insert(cleanup, onadded)
|
||||
table.insert(cleanup, onchanged)
|
||||
end
|
||||
end
|
||||
|
||||
local without = query.filter_without
|
||||
if without then
|
||||
|
@ -138,7 +151,7 @@ local function observers_new<T...>(
|
|||
disconnect = disconnect,
|
||||
}
|
||||
|
||||
return (observer :: any) :: Observer<T...>
|
||||
return observer
|
||||
end
|
||||
|
||||
local function monitors_new<T...>(query: Query<T...>): Monitor<T...>
|
||||
|
@ -169,10 +182,10 @@ local function monitors_new<T...>(query: Query<T...>): Monitor<T...>
|
|||
local callback_added: ((jecs.Entity) -> ())?
|
||||
local callback_removed: ((jecs.Entity) -> ())?
|
||||
|
||||
local function emplaced<T, a>(
|
||||
entity: jecs.Entity<T>,
|
||||
local function emplaced<a>(
|
||||
entity: jecs.Entity,
|
||||
id: jecs.Id<a>,
|
||||
value: a?
|
||||
value: a
|
||||
)
|
||||
if callback_added == nil then
|
||||
return
|
||||
|
@ -203,13 +216,50 @@ local function monitors_new<T...>(query: Query<T...>): Monitor<T...>
|
|||
|
||||
for _, term in terms do
|
||||
if jecs.IS_PAIR(term) then
|
||||
term = jecs.ECS_PAIR_FIRST(term)
|
||||
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_added == nil then
|
||||
return
|
||||
end
|
||||
|
||||
if not wc and id ~= term then
|
||||
return
|
||||
end
|
||||
|
||||
local r = jecs.entity_index_try_get_fast(
|
||||
entity_index, entity :: any) :: jecs.Record
|
||||
|
||||
local archetype = r.archetype
|
||||
|
||||
if archetypes[archetype.id] then
|
||||
callback_added(entity)
|
||||
end
|
||||
end)
|
||||
local onremoved = world:removed(rel, function(entity, id)
|
||||
if callback_removed == nil then
|
||||
return
|
||||
end
|
||||
if not wc and id ~= term then
|
||||
return
|
||||
end
|
||||
local r = jecs.record(world, entity)
|
||||
if not archetypes[r.archetype.id] then
|
||||
return
|
||||
end
|
||||
callback_removed(entity)
|
||||
end)
|
||||
table.insert(cleanup, onadded)
|
||||
table.insert(cleanup, onremoved)
|
||||
else
|
||||
local onadded = world:added(term, emplaced)
|
||||
local onremoved = world:removed(term, removed)
|
||||
table.insert(cleanup, onadded)
|
||||
table.insert(cleanup, onremoved)
|
||||
end
|
||||
end
|
||||
|
||||
local without = query.filter_without
|
||||
if without then
|
||||
|
@ -311,13 +361,13 @@ local function monitors_new<T...>(query: Query<T...>): Monitor<T...>
|
|||
callback_removed = callback
|
||||
end
|
||||
|
||||
local observer = {
|
||||
local monitor = {
|
||||
disconnect = disconnect,
|
||||
added = monitor_added,
|
||||
removed = monitor_removed
|
||||
}
|
||||
} :: Monitor<T...>
|
||||
|
||||
return (observer :: any) :: Monitor<T...>
|
||||
return monitor
|
||||
end
|
||||
|
||||
return {
|
||||
|
|
|
@ -7,6 +7,26 @@ local ob = require("@addons/ob")
|
|||
|
||||
TEST("addons/ob::observer", function()
|
||||
local world = jecs.world()
|
||||
do CASE [[should not invoke callbacks with a related but non-queried pair that
|
||||
while the entity still matches against the query]]
|
||||
local A = world:component()
|
||||
local B = world:component()
|
||||
local C = world:component()
|
||||
|
||||
local c = 1
|
||||
|
||||
ob.observer(world:query(jecs.pair(A, B)), function()
|
||||
c+=1
|
||||
end)
|
||||
|
||||
local e = world:entity()
|
||||
CHECK(c==1)
|
||||
world:add(e, jecs.pair(A, B))
|
||||
CHECK(c==2)
|
||||
world:add(e, jecs.pair(A, C))
|
||||
CHECK(c==2)
|
||||
end
|
||||
|
||||
do CASE "should match against archetypes that were already created"
|
||||
local A = world:component()
|
||||
|
||||
|
@ -203,6 +223,28 @@ end)
|
|||
|
||||
TEST("addons/ob::monitor", function()
|
||||
local world = jecs.world()
|
||||
do CASE [[should not invoke callbacks with a related but non-queried pair that
|
||||
while the entity still matches against the query]]
|
||||
local A = world:component()
|
||||
local B = world:component()
|
||||
local C = world:component()
|
||||
|
||||
local c = 1
|
||||
|
||||
local monitor = ob.monitor(world:query(jecs.pair(A, B)))
|
||||
|
||||
monitor.added(function()
|
||||
c += 1
|
||||
end)
|
||||
|
||||
|
||||
local e = world:entity()
|
||||
CHECK(c==1)
|
||||
world:add(e, jecs.pair(A, B))
|
||||
CHECK(c==2)
|
||||
world:add(e, jecs.pair(A, C))
|
||||
CHECK(c==2)
|
||||
end
|
||||
do CASE "should match against archetypes that were already created"
|
||||
local A = world:component()
|
||||
|
||||
|
|
Loading…
Reference in a new issue