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

View file

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