Handle filters on table creation

This commit is contained in:
Ukendio 2024-12-24 08:24:45 +01:00
parent 670a27711f
commit 927bee30cd
2 changed files with 63 additions and 35 deletions

View file

@ -252,17 +252,34 @@ local function ecs_pair_second(world, e)
end
local function query_match(query, archetype)
local matches = true
local records = archetype.records
for _, id in query.ids do
if not records[id] then
matches = false
break
return false
end
end
return matches
local filters = query.filters
if filters then
local without = filters.without
if without then
for _, id in filters.without do
if records[id] then
return false
end
end
end
local with = filters.with
if with then
for _, id in filters.without do
if not records[id] then
return false
end
end
end
end
return true
end
local function observer_invoke(observer, event)
@ -1470,32 +1487,35 @@ local function query_iter(query): () -> (number, ...any)
end
local function query_without(query: { compatible_archetypes: { Archetype } }, ...)
local filters = query.filters
local without = { ... }
if not filters then
filters = {}
query.filters = filters
end
filters.without = without
local compatible_archetypes = query.compatible_archetypes
local N = select("#", ...)
for i = #compatible_archetypes, 1, -1 do
local archetype = compatible_archetypes[i]
local records = archetype.records
local shouldRemove = false
local matches = true
for j = 1, N do
local id = select(j, ...)
for _, id in without do
if records[id] then
shouldRemove = true
matches = false
break
end
end
if shouldRemove then
local last = #compatible_archetypes
if last ~= i then
compatible_archetypes[i] = compatible_archetypes[last]
end
compatible_archetypes[last] = nil :: any
if matches then
continue
end
end
if #compatible_archetypes == 0 then
return EMPTY_QUERY
local last = #compatible_archetypes
if last ~= i then
compatible_archetypes[i] = compatible_archetypes[last]
end
compatible_archetypes[last] = nil :: any
end
return query :: any
@ -1503,31 +1523,36 @@ end
local function query_with(query: { compatible_archetypes: { Archetype } }, ...)
local compatible_archetypes = query.compatible_archetypes
local N = select("#", ...)
local filters = query.filters
local with = { ... }
if not filters then
filters = {}
query.filters = filters
end
filters.with = with
for i = #compatible_archetypes, 1, -1 do
local archetype = compatible_archetypes[i]
local records = archetype.records
local shouldRemove = false
local matches = true
for j = 1, N do
local id = select(j, ...)
for _, id in with do
if not records[id] then
shouldRemove = true
matches = false
break
end
end
if shouldRemove then
local last = #compatible_archetypes
if last ~= i then
compatible_archetypes[i] = compatible_archetypes[last]
end
compatible_archetypes[last] = nil :: any
if matches then
continue
end
local last = #compatible_archetypes
if last ~= i then
compatible_archetypes[i] = compatible_archetypes[last]
end
compatible_archetypes[last] = nil :: any
end
if #compatible_archetypes == 0 then
return EMPTY_QUERY
end
return query :: any
end

View file

@ -361,14 +361,17 @@ TEST("world:query()", function()
local world = world_new()
local Foo = world:component()
local Bar = world:component()
local Baz = world:component()
local e = world:entity()
local q = world:query(Foo, Bar):without(Baz):cached()
world:set(e, Foo, true)
local q = world:query(Foo):cached()
world:set(e, Bar, false)
world:set(e, Baz, true)
for _, e in q do
CHECK(true)
end
CHECK(#q.compatible_archetypes == 2)
CHECK(#q:archetypes() == 1)
CHECK(not table.find(q:archetypes(), world.archetypes[table.concat({Foo, Bar, Baz}, "_")]))
end
do CASE("multiple iter")
local world = jecs.World.new()