mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Fix upvalues conflict in nested queries
This commit is contained in:
parent
3e639db371
commit
e5634b10b2
1 changed files with 458 additions and 460 deletions
918
src/init.luau
918
src/init.luau
|
@ -721,364 +721,21 @@ end
|
||||||
local Arm = function(self: Query, ...)
|
local Arm = function(self: Query, ...)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
local EmptyQuery: Query = {
|
local world_query
|
||||||
__iter = function(): Item
|
do
|
||||||
return noop
|
|
||||||
end,
|
|
||||||
drain = Arm,
|
|
||||||
next = noop :: Item,
|
|
||||||
replace = noop :: (Query, ...any) -> (),
|
|
||||||
with = Arm,
|
|
||||||
without = Arm,
|
|
||||||
}
|
|
||||||
|
|
||||||
setmetatable(EmptyQuery, EmptyQuery)
|
local EmptyQuery: Query = {
|
||||||
|
__iter = function(): Item
|
||||||
|
return noop
|
||||||
|
end,
|
||||||
|
drain = Arm,
|
||||||
|
next = noop :: Item,
|
||||||
|
replace = noop :: (Query, ...any) -> (),
|
||||||
|
with = Arm,
|
||||||
|
without = Arm,
|
||||||
|
}
|
||||||
|
|
||||||
local function world_query(world, ...)
|
setmetatable(EmptyQuery, EmptyQuery)
|
||||||
-- breaking
|
|
||||||
if (...) == nil then
|
|
||||||
error("Missing components")
|
|
||||||
end
|
|
||||||
|
|
||||||
local compatible_archetypes = {}
|
|
||||||
local length = 0
|
|
||||||
|
|
||||||
local components = { ... } :: any
|
|
||||||
local A, B, C, D, E, F, G, H, I = ...
|
|
||||||
local a, b, c, d, e, f, g, h
|
|
||||||
|
|
||||||
local archetypes = world.archetypes
|
|
||||||
|
|
||||||
local firstArchetypeMap: ArchetypeMap
|
|
||||||
local componentIndex = world.componentIndex
|
|
||||||
|
|
||||||
for _, componentId in components do
|
|
||||||
local map = componentIndex[componentId]
|
|
||||||
if not map then
|
|
||||||
return EmptyQuery
|
|
||||||
end
|
|
||||||
|
|
||||||
if firstArchetypeMap == nil or map.size < firstArchetypeMap.size then
|
|
||||||
firstArchetypeMap = map
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for id in firstArchetypeMap.cache do
|
|
||||||
local compatibleArchetype = archetypes[id]
|
|
||||||
local archetypeRecords = compatibleArchetype.records
|
|
||||||
|
|
||||||
local skip = false
|
|
||||||
|
|
||||||
for i, componentId in components do
|
|
||||||
local index = archetypeRecords[componentId]
|
|
||||||
if not index then
|
|
||||||
skip = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if skip then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
length += 1
|
|
||||||
compatible_archetypes[length] = compatibleArchetype
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local init = false
|
|
||||||
local drain = false
|
|
||||||
local ids = components
|
|
||||||
|
|
||||||
local world_query_iter_next
|
|
||||||
|
|
||||||
local lastArchetype = 1
|
|
||||||
local archetype
|
|
||||||
local columns
|
|
||||||
local entities
|
|
||||||
local i
|
|
||||||
local queryOutput
|
|
||||||
|
|
||||||
local function world_query_iter_create()
|
|
||||||
if not B then
|
|
||||||
function world_query_iter_next(): any
|
|
||||||
local entityId = entities[i]
|
|
||||||
while entityId == nil do
|
|
||||||
lastArchetype += 1
|
|
||||||
archetype = compatible_archetypes[lastArchetype]
|
|
||||||
if not archetype then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
entities = archetype.entities
|
|
||||||
i = #entities
|
|
||||||
if i == 0 then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
entityId = entities[i]
|
|
||||||
columns = archetype.columns
|
|
||||||
local records = archetype.records
|
|
||||||
a = columns[records[A].column]
|
|
||||||
end
|
|
||||||
|
|
||||||
local row = i
|
|
||||||
i-=1
|
|
||||||
|
|
||||||
return entityId, a[row]
|
|
||||||
end
|
|
||||||
elseif not C then
|
|
||||||
function world_query_iter_next(): any
|
|
||||||
local entityId = entities[i]
|
|
||||||
while entityId == nil do
|
|
||||||
lastArchetype += 1
|
|
||||||
archetype = compatible_archetypes[lastArchetype]
|
|
||||||
if not archetype then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
entities = archetype.entities
|
|
||||||
i = #entities
|
|
||||||
if i == 0 then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
entityId = entities[i]
|
|
||||||
columns = archetype.columns
|
|
||||||
local records = archetype.records
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
end
|
|
||||||
|
|
||||||
local row = i
|
|
||||||
i-=1
|
|
||||||
|
|
||||||
return entityId, a[row], b[row]
|
|
||||||
end
|
|
||||||
elseif not D then
|
|
||||||
function world_query_iter_next(): any
|
|
||||||
local entityId = entities[i]
|
|
||||||
while entityId == nil do
|
|
||||||
lastArchetype += 1
|
|
||||||
archetype = compatible_archetypes[lastArchetype]
|
|
||||||
if not archetype then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
entities = archetype.entities
|
|
||||||
i = #entities
|
|
||||||
if i == 0 then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
entityId = entities[i]
|
|
||||||
columns = archetype.columns
|
|
||||||
local records = archetype.records
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
end
|
|
||||||
|
|
||||||
local row = i
|
|
||||||
i-=1
|
|
||||||
|
|
||||||
return entityId, a[row], b[row], c[row]
|
|
||||||
end
|
|
||||||
elseif not E then
|
|
||||||
function world_query_iter_next(): any
|
|
||||||
local entityId = entities[i]
|
|
||||||
while entityId == nil do
|
|
||||||
lastArchetype += 1
|
|
||||||
archetype = compatible_archetypes[lastArchetype]
|
|
||||||
if not archetype then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
entities = archetype.entities
|
|
||||||
i = #entities
|
|
||||||
if i == 0 then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
entityId = entities[i]
|
|
||||||
columns = archetype.columns
|
|
||||||
local records = archetype.records
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
end
|
|
||||||
|
|
||||||
local row = i
|
|
||||||
i-=1
|
|
||||||
|
|
||||||
return entityId, a[row], b[row], c[row], d[row]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
function world_query_iter_next(): any
|
|
||||||
local entityId = entities[i]
|
|
||||||
while entityId == nil do
|
|
||||||
lastArchetype += 1
|
|
||||||
archetype = compatible_archetypes[lastArchetype]
|
|
||||||
if not archetype then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
entities = archetype.entities
|
|
||||||
i = #entities
|
|
||||||
if i == 0 then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
entityId = entities[i]
|
|
||||||
columns = archetype.columns
|
|
||||||
local records = archetype.records
|
|
||||||
|
|
||||||
if not F then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
elseif not G then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
f = columns[records[F].column]
|
|
||||||
elseif not H then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
f = columns[records[F].column]
|
|
||||||
g = columns[records[G].column]
|
|
||||||
elseif not I then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
f = columns[records[F].column]
|
|
||||||
g = columns[records[G].column]
|
|
||||||
h = columns[records[H].column]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local row = i
|
|
||||||
i-=1
|
|
||||||
|
|
||||||
if not F then
|
|
||||||
return entityId, a[row], b[row], c[row], d[row], e[row]
|
|
||||||
elseif not G then
|
|
||||||
return entityId, a[row], b[row], c[row], d[row], e[row], f[row]
|
|
||||||
elseif not H then
|
|
||||||
return entityId, a[row], b[row], c[row], d[row], e[row], f[row], g[row]
|
|
||||||
elseif not I then
|
|
||||||
return entityId, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row]
|
|
||||||
end
|
|
||||||
|
|
||||||
local field = archetype.records
|
|
||||||
for j, id in ids do
|
|
||||||
queryOutput[j] = columns[field[id].column][row]
|
|
||||||
end
|
|
||||||
|
|
||||||
return entityId, unpack(queryOutput)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function query_init(query)
|
|
||||||
if init and drain then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
init = true
|
|
||||||
lastArchetype = 1
|
|
||||||
archetype = compatible_archetypes[lastArchetype]
|
|
||||||
|
|
||||||
if not archetype then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
queryOutput = {}
|
|
||||||
|
|
||||||
entities = archetype.entities
|
|
||||||
i = #entities
|
|
||||||
columns = archetype.columns
|
|
||||||
|
|
||||||
local records = archetype.records
|
|
||||||
if not B then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
elseif not C then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
elseif not D then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
elseif not E then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
elseif not F then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
elseif not G then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
f = columns[records[F].column]
|
|
||||||
elseif not H then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
f = columns[records[F].column]
|
|
||||||
g = columns[records[G].column]
|
|
||||||
elseif not I then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
f = columns[records[F].column]
|
|
||||||
g = columns[records[G].column]
|
|
||||||
h = columns[records[H].column]
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function world_query_without(self, ...)
|
|
||||||
local withoutComponents = { ... }
|
|
||||||
for i = #compatible_archetypes, 1, -1 do
|
|
||||||
local archetype = compatible_archetypes[i]
|
|
||||||
local records = archetype.records
|
|
||||||
local shouldRemove = false
|
|
||||||
|
|
||||||
for _, componentId in withoutComponents do
|
|
||||||
if records[componentId] then
|
|
||||||
shouldRemove = true
|
|
||||||
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
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
local function world_query_replace_values(row, columns, ...)
|
local function world_query_replace_values(row, columns, ...)
|
||||||
for i, column in columns do
|
for i, column in columns do
|
||||||
|
@ -1086,133 +743,474 @@ local function world_query(world, ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function world_query_replace(query, fn: (...any) -> (...any))
|
function world_query(world, ...)
|
||||||
query_init(query)
|
-- breaking
|
||||||
|
if (...) == nil then
|
||||||
|
error("Missing components")
|
||||||
|
end
|
||||||
|
|
||||||
for i, archetype in compatible_archetypes do
|
local compatible_archetypes = {}
|
||||||
local columns = archetype.columns
|
local length = 0
|
||||||
local tr = archetype.records
|
|
||||||
for row in archetype.entities do
|
|
||||||
if not B then
|
|
||||||
local va = columns[tr[A].column]
|
|
||||||
local pa = fn(va[row])
|
|
||||||
|
|
||||||
va[row] = pa
|
local ids = { ... }
|
||||||
elseif not C then
|
local A, B, C, D, E, F, G, H, I = ...
|
||||||
local va = columns[tr[A].column]
|
local a, b, c, d, e, f, g, h
|
||||||
local vb = columns[tr[B].column]
|
|
||||||
|
|
||||||
va[row], vb[row] = fn(va[row], vb[row])
|
local archetypes = world.archetypes
|
||||||
elseif not D then
|
|
||||||
local va = columns[tr[A].column]
|
|
||||||
local vb = columns[tr[B].column]
|
|
||||||
local vc = columns[tr[C].column]
|
|
||||||
|
|
||||||
va[row], vb[row], vc[row] = fn(va[row], vb[row], vc[row])
|
local idr: ArchetypeMap
|
||||||
elseif not E then
|
local componentIndex = world.componentIndex
|
||||||
local va = columns[tr[A].column]
|
|
||||||
local vb = columns[tr[B].column]
|
|
||||||
local vc = columns[tr[C].column]
|
|
||||||
local vd = columns[tr[D].column]
|
|
||||||
|
|
||||||
va[row], vb[row], vc[row], vd[row] = fn(
|
for _, id in ids do
|
||||||
va[row], vb[row], vc[row], vd[row])
|
local map = componentIndex[id]
|
||||||
else
|
if not map then
|
||||||
local field = archetype.records
|
return EmptyQuery
|
||||||
for j, id in ids do
|
end
|
||||||
queryOutput[j] = columns[field[id].column][row]
|
|
||||||
end
|
if idr == nil or map.size < idr.size then
|
||||||
world_query_replace_values(row, columns,
|
idr = map
|
||||||
fn(unpack(queryOutput)))
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
for archetype_id in idr.cache do
|
||||||
|
local compatibleArchetype = archetypes[archetype_id]
|
||||||
|
local tr = compatibleArchetype.records
|
||||||
|
|
||||||
|
local skip = false
|
||||||
|
|
||||||
|
for i, id in ids do
|
||||||
|
local index = tr[id]
|
||||||
|
if not index then
|
||||||
|
skip = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if skip then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
length += 1
|
||||||
|
compatible_archetypes[length] = compatibleArchetype
|
||||||
|
end
|
||||||
|
|
||||||
|
if length == 0 then
|
||||||
|
return EmptyQuery
|
||||||
|
end
|
||||||
|
|
||||||
|
local lastArchetype = 1
|
||||||
|
local archetype
|
||||||
|
local columns
|
||||||
|
local entities
|
||||||
|
local i
|
||||||
|
local queryOutput
|
||||||
|
|
||||||
|
local world_query_iter_next
|
||||||
|
|
||||||
|
if not B then
|
||||||
|
function world_query_iter_next(): any
|
||||||
|
local entityId = entities[i]
|
||||||
|
while entityId == nil do
|
||||||
|
lastArchetype += 1
|
||||||
|
archetype = compatible_archetypes[lastArchetype]
|
||||||
|
if not archetype then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
entities = archetype.entities
|
||||||
|
i = #entities
|
||||||
|
if i == 0 then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
entityId = entities[i]
|
||||||
|
columns = archetype.columns
|
||||||
|
local records = archetype.records
|
||||||
|
a = columns[records[A].column]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local row = i
|
||||||
|
i-=1
|
||||||
|
|
||||||
|
return entityId, a[row]
|
||||||
end
|
end
|
||||||
end
|
elseif not C then
|
||||||
|
function world_query_iter_next(): any
|
||||||
|
local entityId = entities[i]
|
||||||
|
while entityId == nil do
|
||||||
|
lastArchetype += 1
|
||||||
|
archetype = compatible_archetypes[lastArchetype]
|
||||||
|
if not archetype then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
local function world_query_with(query, ...)
|
entities = archetype.entities
|
||||||
local ids = { ... }
|
i = #entities
|
||||||
for i = #compatible_archetypes, 1, -1 do
|
if i == 0 then
|
||||||
local archetype = compatible_archetypes[i]
|
continue
|
||||||
local records = archetype.records
|
end
|
||||||
local shouldRemove = false
|
entityId = entities[i]
|
||||||
|
columns = archetype.columns
|
||||||
|
local records = archetype.records
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
end
|
||||||
|
|
||||||
for _, id in ids do
|
local row = i
|
||||||
if not records[id] then
|
i-=1
|
||||||
shouldRemove = true
|
|
||||||
break
|
return entityId, a[row], b[row]
|
||||||
end
|
end
|
||||||
|
elseif not D then
|
||||||
|
function world_query_iter_next(): any
|
||||||
|
local entityId = entities[i]
|
||||||
|
while entityId == nil do
|
||||||
|
lastArchetype += 1
|
||||||
|
archetype = compatible_archetypes[lastArchetype]
|
||||||
|
if not archetype then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
entities = archetype.entities
|
||||||
|
i = #entities
|
||||||
|
if i == 0 then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
entityId = entities[i]
|
||||||
|
columns = archetype.columns
|
||||||
|
local records = archetype.records
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
end
|
end
|
||||||
|
|
||||||
if shouldRemove then
|
local row = i
|
||||||
local last = #compatible_archetypes
|
i-=1
|
||||||
if last ~= i then
|
|
||||||
compatible_archetypes[i] = compatible_archetypes[last]
|
return entityId, a[row], b[row], c[row]
|
||||||
|
end
|
||||||
|
elseif not E then
|
||||||
|
function world_query_iter_next(): any
|
||||||
|
local entityId = entities[i]
|
||||||
|
while entityId == nil do
|
||||||
|
lastArchetype += 1
|
||||||
|
archetype = compatible_archetypes[lastArchetype]
|
||||||
|
if not archetype then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
entities = archetype.entities
|
||||||
|
i = #entities
|
||||||
|
if i == 0 then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
entityId = entities[i]
|
||||||
|
columns = archetype.columns
|
||||||
|
local records = archetype.records
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
end
|
||||||
|
|
||||||
|
local row = i
|
||||||
|
i-=1
|
||||||
|
|
||||||
|
return entityId, a[row], b[row], c[row], d[row]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
function world_query_iter_next(): any
|
||||||
|
local entityId = entities[i]
|
||||||
|
while entityId == nil do
|
||||||
|
lastArchetype += 1
|
||||||
|
archetype = compatible_archetypes[lastArchetype]
|
||||||
|
if not archetype then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
entities = archetype.entities
|
||||||
|
i = #entities
|
||||||
|
if i == 0 then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
entityId = entities[i]
|
||||||
|
columns = archetype.columns
|
||||||
|
local records = archetype.records
|
||||||
|
|
||||||
|
if not F then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
elseif not G then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
f = columns[records[F].column]
|
||||||
|
elseif not H then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
f = columns[records[F].column]
|
||||||
|
g = columns[records[G].column]
|
||||||
|
elseif not I then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
f = columns[records[F].column]
|
||||||
|
g = columns[records[G].column]
|
||||||
|
h = columns[records[H].column]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local row = i
|
||||||
|
i-=1
|
||||||
|
|
||||||
|
if not F then
|
||||||
|
return entityId, a[row], b[row], c[row], d[row], e[row]
|
||||||
|
elseif not G then
|
||||||
|
return entityId, a[row], b[row], c[row], d[row], e[row], f[row]
|
||||||
|
elseif not H then
|
||||||
|
return entityId, a[row], b[row], c[row], d[row], e[row], f[row], g[row]
|
||||||
|
elseif not I then
|
||||||
|
return entityId, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row]
|
||||||
|
end
|
||||||
|
|
||||||
|
local field = archetype.records
|
||||||
|
for j, id in ids do
|
||||||
|
queryOutput[j] = columns[field[id].column][row]
|
||||||
|
end
|
||||||
|
|
||||||
|
return entityId, unpack(queryOutput)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local init = false
|
||||||
|
local drain = false
|
||||||
|
|
||||||
|
local function query_init(query)
|
||||||
|
if init and drain then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
init = true
|
||||||
|
lastArchetype = 1
|
||||||
|
archetype = compatible_archetypes[lastArchetype]
|
||||||
|
|
||||||
|
if not archetype then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
queryOutput = {}
|
||||||
|
|
||||||
|
entities = archetype.entities
|
||||||
|
i = #entities
|
||||||
|
columns = archetype.columns
|
||||||
|
|
||||||
|
local records = archetype.records
|
||||||
|
if not B then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
elseif not C then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
elseif not D then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
elseif not E then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
elseif not F then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
elseif not G then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
f = columns[records[F].column]
|
||||||
|
elseif not H then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
f = columns[records[F].column]
|
||||||
|
g = columns[records[G].column]
|
||||||
|
elseif not I then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
f = columns[records[F].column]
|
||||||
|
g = columns[records[G].column]
|
||||||
|
h = columns[records[H].column]
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function world_query_without(query, ...)
|
||||||
|
local withoutComponents = { ... }
|
||||||
|
for i = #compatible_archetypes, 1, -1 do
|
||||||
|
local archetype = compatible_archetypes[i]
|
||||||
|
local records = archetype.records
|
||||||
|
local shouldRemove = false
|
||||||
|
|
||||||
|
for _, componentId in withoutComponents do
|
||||||
|
if records[componentId] then
|
||||||
|
shouldRemove = true
|
||||||
|
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
|
||||||
|
length -= 1
|
||||||
end
|
end
|
||||||
compatible_archetypes[last] = nil
|
end
|
||||||
end
|
|
||||||
|
if length == 0 then
|
||||||
|
return EmptyQuery
|
||||||
|
end
|
||||||
|
|
||||||
|
return query
|
||||||
|
end
|
||||||
|
|
||||||
|
local function world_query_replace(query, fn: (...any) -> (...any))
|
||||||
|
query_init(query)
|
||||||
|
|
||||||
|
for i, archetype in compatible_archetypes do
|
||||||
|
local columns = archetype.columns
|
||||||
|
local tr = archetype.records
|
||||||
|
for row in archetype.entities do
|
||||||
|
if not B then
|
||||||
|
local va = columns[tr[A].column]
|
||||||
|
local pa = fn(va[row])
|
||||||
|
|
||||||
|
va[row] = pa
|
||||||
|
elseif not C then
|
||||||
|
local va = columns[tr[A].column]
|
||||||
|
local vb = columns[tr[B].column]
|
||||||
|
|
||||||
|
va[row], vb[row] = fn(va[row], vb[row])
|
||||||
|
elseif not D then
|
||||||
|
local va = columns[tr[A].column]
|
||||||
|
local vb = columns[tr[B].column]
|
||||||
|
local vc = columns[tr[C].column]
|
||||||
|
|
||||||
|
va[row], vb[row], vc[row] = fn(va[row], vb[row], vc[row])
|
||||||
|
elseif not E then
|
||||||
|
local va = columns[tr[A].column]
|
||||||
|
local vb = columns[tr[B].column]
|
||||||
|
local vc = columns[tr[C].column]
|
||||||
|
local vd = columns[tr[D].column]
|
||||||
|
|
||||||
|
va[row], vb[row], vc[row], vd[row] = fn(
|
||||||
|
va[row], vb[row], vc[row], vd[row])
|
||||||
|
else
|
||||||
|
local field = archetype.records
|
||||||
|
for j, id in ids do
|
||||||
|
queryOutput[j] = columns[field[id].column][row]
|
||||||
|
end
|
||||||
|
world_query_replace_values(row, columns,
|
||||||
|
fn(unpack(queryOutput)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function world_query_with(query, ...)
|
||||||
|
local with = { ... }
|
||||||
|
for i = #compatible_archetypes, 1, -1 do
|
||||||
|
local archetype = compatible_archetypes[i]
|
||||||
|
local tr = archetype.records
|
||||||
|
local shouldRemove = false
|
||||||
|
|
||||||
|
for _, id in with do
|
||||||
|
if not tr[id] then
|
||||||
|
shouldRemove = true
|
||||||
|
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
|
||||||
|
length -= 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if length == 0 then
|
||||||
|
return EmptyQuery
|
||||||
|
end
|
||||||
|
return query
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Meant for directly iterating over archetypes to minimize
|
||||||
|
-- function call overhead. Should not be used unless iterating over
|
||||||
|
-- hundreds of thousands of entities in bulk.
|
||||||
|
local function world_query_archetypes()
|
||||||
|
return compatible_archetypes
|
||||||
|
end
|
||||||
|
|
||||||
|
local function world_query_drain(query)
|
||||||
|
drain = true
|
||||||
|
if query_init(query) then
|
||||||
|
return query
|
||||||
end
|
end
|
||||||
|
return EmptyQuery
|
||||||
|
end
|
||||||
|
|
||||||
|
local function world_query_iter(query)
|
||||||
query_init(query)
|
query_init(query)
|
||||||
|
return world_query_iter_next
|
||||||
return query
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Meant for directly iterating over archetypes to minimize
|
|
||||||
-- function call overhead. Should not be used unless iterating over
|
|
||||||
-- hundreds of thousands of entities in bulk.
|
|
||||||
local function world_query_archetypes()
|
|
||||||
return compatible_archetypes
|
|
||||||
end
|
|
||||||
|
|
||||||
local function world_query_drain(query)
|
|
||||||
drain = true
|
|
||||||
if query_init(query) then
|
|
||||||
return query
|
|
||||||
end
|
end
|
||||||
return EmptyQuery
|
|
||||||
end
|
|
||||||
|
|
||||||
local function world_query_iter(query)
|
local function world_query_next(world)
|
||||||
query_init(query)
|
if not drain then
|
||||||
return world_query_iter_next
|
error("Did you forget to call query:drain()?")
|
||||||
end
|
end
|
||||||
|
return world_query_iter_next(world)
|
||||||
local function world_query_next()
|
|
||||||
if not drain then
|
|
||||||
error("Did you forget to call query:drain()?")
|
|
||||||
end
|
end
|
||||||
return world_query_iter_next()
|
|
||||||
|
local it = {
|
||||||
|
__iter = world_query_iter,
|
||||||
|
drain = world_query_drain,
|
||||||
|
next = world_query_next,
|
||||||
|
with = world_query_with,
|
||||||
|
without = world_query_without,
|
||||||
|
replace = world_query_replace,
|
||||||
|
archetypes = world_query_archetypes
|
||||||
|
} :: any
|
||||||
|
|
||||||
|
setmetatable(it, it)
|
||||||
|
|
||||||
|
return it
|
||||||
end
|
end
|
||||||
|
|
||||||
if #compatible_archetypes == 0 then
|
|
||||||
return EmptyQuery
|
|
||||||
end
|
|
||||||
|
|
||||||
local it = {
|
|
||||||
__iter = world_query_iter,
|
|
||||||
drain = world_query_drain,
|
|
||||||
next = world_query_next,
|
|
||||||
with = world_query_with,
|
|
||||||
without = world_query_without,
|
|
||||||
replace = world_query_replace,
|
|
||||||
archetypes = world_query_archetypes
|
|
||||||
} :: any
|
|
||||||
|
|
||||||
setmetatable(it, it)
|
|
||||||
|
|
||||||
drain = false
|
|
||||||
init = false
|
|
||||||
ids = components
|
|
||||||
|
|
||||||
world_query_iter_create()
|
|
||||||
|
|
||||||
return it
|
|
||||||
end
|
end
|
||||||
|
|
||||||
type WorldIterator = (() -> (i53, { [unknown]: unknown? })) & (() -> ()) & (() -> i53)
|
|
||||||
-- __nominal_type_dont_use could not be any or T as it causes a type error
|
-- __nominal_type_dont_use could not be any or T as it causes a type error
|
||||||
-- or produces a union
|
-- or produces a union
|
||||||
export type Entity<T = any> = number & { __nominal_type_dont_use: T }
|
export type Entity<T = any> = number & { __DO_NOT_USE_OR_YOU_WILL_BE_FIRED: T }
|
||||||
export type Pair = number
|
export type Pair = number
|
||||||
|
|
||||||
export type QueryShim<T...> = typeof(setmetatable({
|
export type QueryShim<T...> = typeof(setmetatable({
|
||||||
|
|
Loading…
Reference in a new issue