Get smallest map

This commit is contained in:
Ukendio 2024-04-25 05:45:33 +02:00
parent 37d5b0415a
commit 78775d19a3

View file

@ -35,7 +35,7 @@ type EntityIndex = { [i24]: Record }
type ComponentIndex = { [i24]: ArchetypeMap} type ComponentIndex = { [i24]: ArchetypeMap}
type ArchetypeRecord = number type ArchetypeRecord = number
type ArchetypeMap = { [ArchetypeId]: ArchetypeRecord } type ArchetypeMap = { map: { [ArchetypeId]: ArchetypeRecord } , size: number }
type Archetypes = { [ArchetypeId]: Archetype } type Archetypes = { [ArchetypeId]: Archetype }
local function transitionArchetype( local function transitionArchetype(
@ -107,9 +107,11 @@ local function createArchetypeRecords(componentIndex: ComponentIndex, to: Archet
local destinationId = destinationIds[i] local destinationId = destinationIds[i]
if not componentIndex[destinationId] then if not componentIndex[destinationId] then
componentIndex[destinationId] = {} componentIndex[destinationId] = { size = 0, map = {} }
end end
componentIndex[destinationId][to.id] = i
local archetypesMap = componentIndex[destinationId]
archetypesMap.map[to.id] = i
to.records[destinationId] = i to.records[destinationId] = i
end end
end end
@ -311,85 +313,157 @@ function World.entity(world: World)
return world.nextId return world.nextId
end end
function World.archetypesWith(world: World, componentId: i53)
local archetypes = world.archetypes
local archetypeMap = world.componentIndex[componentId]
local compatibleArchetypes = {}
for id, archetypeRecord in archetypeMap do
compatibleArchetypes[archetypes[id]] = true
end
return compatibleArchetypes
end
local function noop(): any local function noop(): any
return function() return function()
end end
end end
local function getSmallestMap(componentIndex, components)
local s: any
for i, componentId in components do
local map = componentIndex[componentId]
if s == nil or map.size < s.size then
s = map
end
end
return s.map
end
function World.query(world: World, ...: i53): (() -> (number, ...any)) | () -> () function World.query(world: World, ...: i53): (() -> (number, ...any)) | () -> ()
local compatibleArchetypes = {} local compatibleArchetypes = {}
local components = { ... } local components = { ... }
local archetypes = world.archetypes local archetypes = world.archetypes
local queryLength = #components local queryLength = #components
local firstArchetypeMap = getSmallestMap(world.componentIndex, components)
local a, b, c, d, e, f, g, h = ... local a, b, c, d, e, f, g, h = ...
local firstArchetypeMap = world.componentIndex[components[1]]
if not firstArchetypeMap then if not firstArchetypeMap then
return noop() return noop()
end end
if queryLength == 1 then if queryLength == 1 then
local function single() local id = next(firstArchetypeMap)
local id = next(firstArchetypeMap) local archetype = archetypes[id :: number]
local archetype = archetypes[id :: number] local lastRow
local lastRow
return function(): any return function(): any
local row, entity = next(archetype.entities, lastRow) local row, entity = next(archetype.entities, lastRow)
while row == nil do while row == nil do
id = next(firstArchetypeMap, id) id = next(firstArchetypeMap, id)
if id == nil then if id == nil then
return return
end end
archetype = archetypes[id] archetype = archetypes[id]
row = next(archetype.entities, row) row = next(archetype.entities, row)
end end
lastRow = row lastRow = row
return entity, archetype.columns[archetype.records[a]] return entity, archetype.columns[archetype.records[a]]
end end
end
return single()
elseif queryLength == 2 then elseif queryLength == 2 then
for id in firstArchetypeMap do for id in firstArchetypeMap do
local archetype = archetypes[id] local archetype = archetypes[id]
if archetype.records[b] then local archetypeRecords = archetype.records
if archetypeRecords[a] and archetypeRecords[b] then
table.insert(compatibleArchetypes, archetype) table.insert(compatibleArchetypes, archetype)
end end
end end
local function double() local lastArchetype, archetype = next(compatibleArchetypes)
local lastArchetype, archetype = next(compatibleArchetypes) local lastRow
local lastRow
return function()
return function() local row = next(archetype.entities, lastRow)
local row = next(archetype.entities, lastRow) while row == nil do
while row == nil do lastArchetype, archetype = next(compatibleArchetypes, lastArchetype)
lastArchetype, archetype = next(compatibleArchetypes, lastArchetype) if lastArchetype == nil then
if lastArchetype == nil then return
return end
end row = next(archetype.entities, row)
row = next(archetype.entities, row) end
end lastRow = row
lastRow = row
local entity = archetype.entities[row::number]
local entity = archetype.entities[row::number] local columns = archetype.columns
local columns = archetype.columns local archetypeRecords = archetype.records
local archetypeRecords = archetype.records return entity, columns[archetypeRecords[a]], columns[archetypeRecords[b]]
return entity, columns[archetypeRecords[a]], columns[archetypeRecords[b]] end
elseif queryLength == 3 then
for id in firstArchetypeMap do
local archetype = archetypes[id]
local archetypeRecords = archetype.records
if archetypeRecords[a]
and archetypeRecords[b]
and archetypeRecords[c]
then
table.insert(compatibleArchetypes, archetype)
end end
end end
return double()
local lastArchetype, archetype = next(compatibleArchetypes)
local lastRow
return function()
local row = next(archetype.entities, lastRow)
while row == nil do
lastArchetype, archetype = next(compatibleArchetypes, lastArchetype)
if lastArchetype == nil then
return
end
row = next(archetype.entities, row)
end
lastRow = row
local entity = archetype.entities[row::number]
local columns = archetype.columns
local archetypeRecords = archetype.records
return
entity,
columns[archetypeRecords[a]],
columns[archetypeRecords[b]],
columns[archetypeRecords[c]]
end
elseif queryLength == 4 then
for id in firstArchetypeMap do
local archetype = archetypes[id]
local archetypeRecords = archetype.records
if
archetypeRecords[a]
and archetypeRecords[b]
and archetypeRecords[c]
and archetypeRecords[d]
then
table.insert(compatibleArchetypes, archetype)
end
end
local lastArchetype, archetype = next(compatibleArchetypes)
local lastRow
return function()
local row = next(archetype.entities, lastRow)
while row == nil do
lastArchetype, archetype = next(compatibleArchetypes, lastArchetype)
if lastArchetype == nil then
return
end
row = next(archetype.entities, row)
end
lastRow = row
local entity = archetype.entities[row::number]
local columns = archetype.columns
local archetypeRecords = archetype.records
return
entity,
columns[archetypeRecords[a]],
columns[archetypeRecords[b]],
columns[archetypeRecords[c]],
columns[archetypeRecords[d]]
end
end end
for id in firstArchetypeMap do for id in firstArchetypeMap do
@ -411,7 +485,7 @@ function World.query(world: World, ...: i53): (() -> (number, ...any)) | () -> (
local lastRow local lastRow
local function queryNext() return function()
local row = next(archetype.entities, lastRow) local row = next(archetype.entities, lastRow)
while row == nil do while row == nil do
lastArchetype, archetype = next(compatibleArchetypes, lastArchetype) lastArchetype, archetype = next(compatibleArchetypes, lastArchetype)
@ -426,18 +500,7 @@ function World.query(world: World, ...: i53): (() -> (number, ...any)) | () -> (
local entityId = archetype.entities[row :: number] local entityId = archetype.entities[row :: number]
local archetypeRecords = archetype.records local archetypeRecords = archetype.records
if queryLength == 3 then if queryLength == 5 then
return entityId,
columns[archetypeRecords[a]],
columns[archetypeRecords[b]],
columns[archetypeRecords[c]]
elseif queryLength == 4 then
return entityId,
columns[archetypeRecords[a]],
columns[archetypeRecords[b]],
columns[archetypeRecords[c]],
columns[archetypeRecords[d]]
elseif queryLength == 5 then
return entityId, return entityId,
columns[archetypeRecords[a]], columns[archetypeRecords[a]],
columns[archetypeRecords[b]], columns[archetypeRecords[b]],
@ -480,11 +543,6 @@ function World.query(world: World, ...: i53): (() -> (number, ...any)) | () -> (
return entityId, unpack(queryOutput, 1, queryLength) return entityId, unpack(queryOutput, 1, queryLength)
end end
return function()
return queryNext()
end
end end
return { return {