diff --git a/modules/OB/module.luau b/modules/OB/module.luau index bea62b9..536aaac 100755 --- a/modules/OB/module.luau +++ b/modules/OB/module.luau @@ -9,7 +9,7 @@ local function duplicate(query: jecs.Query<...any>): jecs.CachedQuery<...any> local world = (query :: jecs.Query & { world: World }).world local dup = world:query() dup.filter_with = table.clone(query.filter_with) - if query.filter_without then + if query.filter_without then dup.filter_without = query.filter_without end return dup:cached() @@ -152,11 +152,6 @@ local function monitors_new(query: jecs.Query<...any>): Monitor local entity_index = world.entity_index :: any - local terms_lookup: { [jecs.Id]: boolean } = {} - for _, term in terms do - terms_lookup[term] = true - end - local callback_added: ((jecs.Entity) -> ())? local callback_removed: ((jecs.Entity) -> ())? @@ -176,7 +171,7 @@ local function monitors_new(query: jecs.Query<...any>): Monitor local r = jecs.entity_index_try_get_fast( entity_index, entity :: any) :: jecs.Record if not archetypes[oldarchetype.id] and archetypes[r.archetype.id] then - if last_old_archetype == oldarchetype and last_entity == entity and terms_lookup[id] then + if last_old_archetype == oldarchetype and last_entity == entity then return end @@ -193,13 +188,13 @@ local function monitors_new(query: jecs.Query<...any>): Monitor if callback_removed == nil then return end - + local r = jecs.record(world, entity) if not r then return end - + local src = r.archetype if not src then return end - + if not archetypes[src.id] then return end if last_entity == entity and last_old_archetype == src then @@ -232,7 +227,7 @@ local function monitors_new(query: jecs.Query<...any>): Monitor entity_index, entity :: any) :: jecs.Record if not archetypes[oldarchetype.id] and archetypes[r.archetype.id] then - if last_old_archetype == oldarchetype and last_entity == entity and terms_lookup[id] then + if last_old_archetype == oldarchetype and last_entity == entity then return end @@ -253,10 +248,17 @@ local function monitors_new(query: jecs.Query<...any>): Monitor end local r = jecs.record(world, entity) - if archetypes[r.archetype.id] then - last_old_archetype = nil - callback_removed(entity) + local src = r.archetype + + if last_entity == entity and last_old_archetype == src then + return end + if not archetypes[src.id] then + return + end + last_entity = entity + last_old_archetype = src + callback_removed(entity) end) table.insert(cleanup, onadded) table.insert(cleanup, onremoved) @@ -294,7 +296,7 @@ local function monitors_new(query: jecs.Query<...any>): Monitor callback_removed(entity) end end) - local onremoved = world:removed(rel, function(entity, id, delete) + local onremoved = world:removed(rel, function(entity: jecs.Entity, id: jecs.Id, delete) if delete then return end @@ -310,7 +312,7 @@ local function monitors_new(query: jecs.Query<...any>): Monitor if not archetype then return end - if last_old_archetype == archetype and terms_lookup[id] then + if last_old_archetype == archetype then return end diff --git a/test/ob.luau b/test/ob.luau index d6a9bb0..cdabd06 100755 --- a/test/ob.luau +++ b/test/ob.luau @@ -309,19 +309,19 @@ TEST("modules/ob::monitor", function() local A = world:component() local B = world:component() local C = world:component() - + local count = 0 - ob.monitor(world:query(A, C)).removed(function() + ob.monitor(world:query(A, C)).removed(function() count += 1 end) - + local e = world:entity() jecs.bulk_insert(world, e, {A, B}, {0,0}) CHECK(count==0) world:remove(e, A) CHECK(count==0) end - + do CASE [[should not invoke monitor.added callback multiple times in a bulk_move ]] local A = world:component() @@ -838,27 +838,47 @@ TEST("modules/ob::monitor", function() do CASE "monitor with wildcard pair should handle bulk_insert" local A = world:component() local B = world:component() - local e1 = world:entity() - local e2 = world:entity() - local e3 = world:entity() + local C = world:component() + local Relation = world:component() + local entity1 = world:entity() + local entity = world:entity() - local monitor = ob.monitor(world:query(A, jecs.pair(B, jecs.w))) + local monitor = ob.monitor(world:query(A, B, C, jecs.pair(Relation, jecs.w))) local c = 0 monitor.added(function() c += 1 end) - local e = world:entity() - world:add(e, A) - CHECK(c == 0) - world:add(e, jecs.pair(B, e1)) - CHECK(c == 1) - world:add(e, jecs.pair(B, e2)) - CHECK(c == 1) - world:add(e, jecs.pair(B, e3)) + jecs.bulk_insert(world, entity, { A, B, C, jecs.pair(Relation, entity1) }, { 1, 2, 3, 4 }) CHECK(c == 1) end + do CASE "monitor with wildcard pair: bulk_remove reports removed exactly once" + local A = world:component() + local B = world:component() + local C = world:component() + local Relation = world:component() + local entity1 = world:entity() + local entity = world:entity() + + local monitor = ob.monitor(world:query(A, B, C, jecs.pair(Relation, jecs.w))) + local added_count = 0 + local removed_count = 0 + monitor.added(function() + added_count += 1 + end) + monitor.removed(function() + removed_count += 1 + end) + + jecs.bulk_insert(world, entity, { A, B, C, jecs.pair(Relation, entity1) }, { 1, 2, 3, 4 }) + CHECK(added_count == 1) + CHECK(removed_count == 0) + + jecs.bulk_remove(world, entity, { A, B, C, jecs.pair(Relation, entity1) }) + CHECK(removed_count == 1) + end + do CASE "monitor with multiple pairs should handle separate operations correctly" local A = world:component() local B = world:component()