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 Id<T=any> = jecs.Id<T>
|
||||||
|
|
||||||
type Entity<T> = jecs.Entity<T>
|
|
||||||
|
|
||||||
export type Iter<T...> = (Observer<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...>(
|
local function observers_new<T...>(
|
||||||
query: Query<T...>,
|
query: Query<T...>,
|
||||||
callback: ((Entity<nil>) -> ())
|
callback: (jecs.Entity) -> ()
|
||||||
): Observer<T...>
|
): Observer<T...>
|
||||||
query:cached()
|
query:cached()
|
||||||
|
|
||||||
|
@ -51,10 +50,10 @@ local function observers_new<T...>(
|
||||||
archetypes[archetype.id] = true
|
archetypes[archetype.id] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function emplaced<T, a>(
|
local function emplaced<a>(
|
||||||
entity: jecs.Entity<T>,
|
entity: jecs.Entity,
|
||||||
id: jecs.Id<a>,
|
id: jecs.Id<a>,
|
||||||
value: a?
|
value: a
|
||||||
)
|
)
|
||||||
local r = entity_index.sparse_array[jecs.ECS_ID(entity)]
|
local r = entity_index.sparse_array[jecs.ECS_ID(entity)]
|
||||||
|
|
||||||
|
@ -69,12 +68,26 @@ local function observers_new<T...>(
|
||||||
|
|
||||||
for _, term in terms do
|
for _, term in terms do
|
||||||
if jecs.IS_PAIR(term) then
|
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 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
|
local without = query.filter_without
|
||||||
|
@ -138,7 +151,7 @@ local function observers_new<T...>(
|
||||||
disconnect = disconnect,
|
disconnect = disconnect,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (observer :: any) :: Observer<T...>
|
return observer
|
||||||
end
|
end
|
||||||
|
|
||||||
local function monitors_new<T...>(query: Query<T...>): Monitor<T...>
|
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_added: ((jecs.Entity) -> ())?
|
||||||
local callback_removed: ((jecs.Entity) -> ())?
|
local callback_removed: ((jecs.Entity) -> ())?
|
||||||
|
|
||||||
local function emplaced<T, a>(
|
local function emplaced<a>(
|
||||||
entity: jecs.Entity<T>,
|
entity: jecs.Entity,
|
||||||
id: jecs.Id<a>,
|
id: jecs.Id<a>,
|
||||||
value: a?
|
value: a
|
||||||
)
|
)
|
||||||
if callback_added == nil then
|
if callback_added == nil then
|
||||||
return
|
return
|
||||||
|
@ -203,12 +216,49 @@ local function monitors_new<T...>(query: Query<T...>): Monitor<T...>
|
||||||
|
|
||||||
for _, term in terms do
|
for _, term in terms do
|
||||||
if jecs.IS_PAIR(term) then
|
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 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
|
local without = query.filter_without
|
||||||
|
@ -311,13 +361,13 @@ local function monitors_new<T...>(query: Query<T...>): Monitor<T...>
|
||||||
callback_removed = callback
|
callback_removed = callback
|
||||||
end
|
end
|
||||||
|
|
||||||
local observer = {
|
local monitor = {
|
||||||
disconnect = disconnect,
|
disconnect = disconnect,
|
||||||
added = monitor_added,
|
added = monitor_added,
|
||||||
removed = monitor_removed
|
removed = monitor_removed
|
||||||
}
|
} :: Monitor<T...>
|
||||||
|
|
||||||
return (observer :: any) :: Monitor<T...>
|
return monitor
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -7,6 +7,26 @@ local ob = require("@addons/ob")
|
||||||
|
|
||||||
TEST("addons/ob::observer", function()
|
TEST("addons/ob::observer", function()
|
||||||
local world = jecs.world()
|
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"
|
do CASE "should match against archetypes that were already created"
|
||||||
local A = world:component()
|
local A = world:component()
|
||||||
|
|
||||||
|
@ -203,6 +223,28 @@ end)
|
||||||
|
|
||||||
TEST("addons/ob::monitor", function()
|
TEST("addons/ob::monitor", function()
|
||||||
local world = jecs.world()
|
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"
|
do CASE "should match against archetypes that were already created"
|
||||||
local A = world:component()
|
local A = world:component()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue