Update newMatter.lua (#30)

This commit is contained in:
Michael 2024-05-04 20:56:22 -04:00 committed by GitHub
parent 93165e0ad9
commit 64824a6808
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -447,19 +447,23 @@ local function transitionArchetype(
targetColumn[destinationRow] = column[sourceRow]
end
if sourceRow ~= #column then
column[sourceRow] = column[#column]
column[#column] = nil
local last = #column
if sourceRow ~= last then
column[sourceRow] = column[last]
end
column[last] = nil
end
destinationEntities[destinationRow] = sourceEntities[sourceRow]
entityIndex[sourceEntities[sourceRow]].row = destinationRow
local atSourceRow = sourceEntities[sourceRow]
destinationEntities[destinationRow] = atSourceRow
entityIndex[atSourceRow].row = destinationRow
local movedAway = #sourceEntities
if sourceRow ~= movedAway then
sourceEntities[sourceRow] = sourceEntities[movedAway]
entityIndex[sourceEntities[movedAway]].row = sourceRow
local atMovedAway = sourceEntities[movedAway]
sourceEntities[sourceRow] = atMovedAway
entityIndex[atMovedAway].row = sourceRow
end
sourceEntities[movedAway] = nil
@ -492,17 +496,20 @@ local function hash(arr): string | number
end
local function createArchetypeRecords(componentIndex: ComponentIndex, to: Archetype)
local destinationCount = #to.types
local destinationIds = to.types
local records = to.records
local id = to.id
for i = 1, destinationCount do
local destinationId = destinationIds[i]
for i, destinationId in destinationIds do
local archetypesMap = componentIndex[destinationId]
if not componentIndex[destinationId] then
componentIndex[destinationId] = { sparse = {}, size = 0 }
if not archetypesMap then
archetypesMap = { size = 0, sparse = {} }
componentIndex[destinationId] = archetypesMap
end
componentIndex[destinationId].sparse[to.id] = i
to.records[destinationId] = i
archetypesMap.sparse[id] = i
records[destinationId] = i
end
end
@ -512,10 +519,11 @@ local function archetypeOf(world: World, types: { i24 }, prev: Archetype?): Arch
world.nextArchetypeId = (world.nextArchetypeId :: number) + 1
local id = world.nextArchetypeId
local columns = {} :: { any }
local length = #types
local columns = table.create(length) :: { any }
for _ in types do
table.insert(columns, {})
for index in types do
columns[index] = {}
end
local archetype = {
@ -531,8 +539,8 @@ local function archetypeOf(world: World, types: { i24 }, prev: Archetype?): Arch
world.archetypeIndex[ty] = archetype
world.archetypes[id] = archetype
if #types > 0 then
createArchetypeRecords(world.componentIndex, archetype, prev)
if length > 0 then
createArchetypeRecords(world.componentIndex, archetype)
end
return archetype
@ -552,9 +560,9 @@ function World.new()
nextArchetypeId = 0,
_size = 0,
_changedStorage = {},
ROOT_ARCHETYPE = (nil :: any) :: Archetype,
}, World)
self.ROOT_ARCHETYPE = archetypeOf(self, {}, nil)
return self
end
@ -575,9 +583,7 @@ local function ensureArchetype(world: World, types, prev)
end
local function findInsert(types: { i53 }, toAdd: i53)
local count = #types
for i = 1, count do
local id = types[i]
for i, id in types do
if id == toAdd then
return -1
end
@ -585,7 +591,8 @@ local function findInsert(types: { i53 }, toAdd: i53)
return i
end
end
return count + 1
return #types + 1
end
local function findArchetypeWith(world: World, node: Archetype, componentId: i53)
@ -601,21 +608,49 @@ local function findArchetypeWith(world: World, node: Archetype, componentId: i53
end
local function ensureEdge(archetype: Archetype, componentId: i53)
if not archetype.edges[componentId] then
archetype.edges[componentId] = {} :: any
local edges = archetype.edges
local edge = edges[componentId]
if not edge then
edge = {} :: any
edges[componentId] = edge
end
return archetype.edges[componentId]
return edge
end
local function archetypeTraverseAdd(world: World, componentId: i53, archetype: Archetype?): Archetype
local from = (archetype or world.ROOT_ARCHETYPE) :: Archetype
local edge = ensureEdge(from, componentId)
local function archetypeTraverseAdd(world: World, componentId: i53, from: Archetype?): Archetype
if not from then
-- If there was no source archetype then it should return the ROOT_ARCHETYPE
local ROOT_ARCHETYPE = world.ROOT_ARCHETYPE
if not ROOT_ARCHETYPE then
ROOT_ARCHETYPE = archetypeOf(world, {}, nil)
world.ROOT_ARCHETYPE = ROOT_ARCHETYPE :: never
end
if not edge.add then
edge.add = findArchetypeWith(world, from, componentId)
from = ROOT_ARCHETYPE
end
return edge.add
local edge = ensureEdge(from :: Archetype, componentId)
local add = edge.add
if not add then
-- Save an edge using the component ID to the archetype to allow
-- faster traversals to adjacent archetypes.
add = findArchetypeWith(world, from :: Archetype, componentId)
edge.add = add :: never
end
return add
end
local function ensureRecord(entityIndex, entityId): Record
local record = entityIndex[entityId]
if not record then
record = {}
entityIndex[entityId] = record
end
return record :: Record
end
local function componentAdd(world: World, entityId: i53, componentInstance)
@ -626,7 +661,7 @@ local function componentAdd(world: World, entityId: i53, componentInstance)
-- This never gets cleaned up
world.componentIdToComponent[componentId] = component
local record = world:ensureRecord(entityId)
local record = ensureRecord(world.entityIndex, entityId)
local sourceArchetype = record.archetype
local destinationArchetype = archetypeTraverseAdd(world, componentId, sourceArchetype)
@ -649,29 +684,22 @@ local function componentAdd(world: World, entityId: i53, componentInstance)
destinationArchetype.columns[archetypeRecord][record.row] = componentInstance
end
function World.ensureRecord(world: World, entityId: i53)
local entityIndex = world.entityIndex
local id = entityId
if not entityIndex[id] then
entityIndex[id] = {} :: Record
end
return entityIndex[id]
end
local function archetypeTraverseRemove(world: World, componentId: i53, archetype: Archetype?): Archetype
local from = (archetype or world.ROOT_ARCHETYPE) :: Archetype
local edge = ensureEdge(from, componentId)
if not edge.remove then
local remove = edge.remove
if not remove then
local to = table.clone(from.types)
table.remove(to, table.find(to, componentId))
edge.remove = ensureArchetype(world, to, from)
remove = ensureArchetype(world, to, from)
edge.remove = remove :: never
end
return edge.remove
return remove
end
local function get(componentIndex: ComponentIndex, record: Record, componentId: i24): ComponentInstance?
local function get(record: Record, componentId: i24): ComponentInstance?
local archetype = record.archetype
if archetype == nil then
return nil
@ -685,15 +713,19 @@ local function get(componentIndex: ComponentIndex, record: Record, componentId:
return archetype.columns[archetypeRecord][record.row]
end
local function componentRemove(world: World, entityId: i53, component: Component)
local function componentRemove(world: World, entityId: i53, component: Component): ComponentInstance?
local componentId = #component
local record = world:ensureRecord(entityId)
local record = ensureRecord(world.entityIndex, entityId)
local sourceArchetype = record.archetype
local destinationArchetype = archetypeTraverseRemove(world, componentId, sourceArchetype)
-- TODO:
-- There is a better way to get the component for returning
local componentInstance = get(world.componentIndex, record, componentId)
local componentInstance = get(record, componentId)
if componentInstance == nil then
return nil
end
if sourceArchetype and not (sourceArchetype == destinationArchetype) then
moveEntity(world.entityIndex, entityId, record, destinationArchetype)
end
@ -720,40 +752,35 @@ function World.remove(world: World, entityId: i53, ...)
local length = select("#", ...)
local removed = {}
for i = 1, length do
table.insert(removed, componentRemove(world, entityId, select(i, ...)))
local oldComponent = componentRemove(world, entityId, select(i, ...))
if not oldComponent then
continue
end
table.insert(removed, oldComponent)
world:_trackChanged(select(i, ...), entityId, oldComponent, nil)
end
return unpack(removed, 1, length)
end
function World.get(
world: World,
entityId: i53,
a: Component,
b: Component?,
c: Component?,
d: Component?,
e: Component?
): any
function World.get(world: World, entityId: i53, ...: Component): any
local componentIndex = world.componentIndex
local record = world.entityIndex[entityId]
if not record then
return nil
end
local va = get(componentIndex, record, #a)
if b == nil then
return va
elseif c == nil then
return va, get(componentIndex, record, #b)
elseif d == nil then
return va, get(componentIndex, record, #b), get(componentIndex, record, #c)
elseif e == nil then
return va, get(componentIndex, record, #b), get(componentIndex, record, #c), get(componentIndex, record, #d)
else
error("args exceeded")
local length = select("#", ...)
local components = {}
for i = 1, length do
local metatable = select(i, ...)
assertValidComponent(metatable, i)
components[i] = get(record, #metatable)
end
return unpack(components, 1, length)
end
function World.insert(world: World, entityId: i53, ...)
@ -863,7 +890,7 @@ function World.spawnAt(world: World, entityId: i53, ...: ComponentInstance)
end
world._size += 1
world:ensureRecord(entityId)
ensureRecord(world.entityIndex, entityId)
local components = {}
for i = 1, select("#", ...) do
@ -897,8 +924,14 @@ end
function World.despawn(world: World, entityId: i53)
local entityIndex = world.entityIndex
local record = entityIndex[entityId]
moveEntity(entityIndex, entityId, record, world.ROOT_ARCHETYPE)
world.ROOT_ARCHETYPE.entities[record.row] = nil
-- TODO:
-- Track despawn changes
if record.archetype then
moveEntity(entityIndex, entityId, record, world.ROOT_ARCHETYPE)
world.ROOT_ARCHETYPE.entities[record.row] = nil
end
entityIndex[entityId] = nil
world._size -= 1
end
@ -1481,14 +1514,24 @@ function World.queryChanged(world: World, componentToTrack, ...: nil)
table.insert(world._changedStorage[componentToTrack], storage)
local queryResult = world:query(componentToTrack)
-- TODO:
-- Go back to lazy evaluation of the query
-- Switched because next is not working
local snapshot = world:query(componentToTrack):snapshot()
local last
return function(): any
local entityId, component = queryResult:next()
local index, entry = next(snapshot, last)
last = index
if not index then
return
end
local entityId, component = entry[1], entry[2]
if entityId then
return entityId, table.freeze({ new = component })
end
return
end
end