mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Update newMatter.lua (#30)
This commit is contained in:
parent
93165e0ad9
commit
64824a6808
1 changed files with 121 additions and 78 deletions
199
newMatter.lua
199
newMatter.lua
|
@ -447,19 +447,23 @@ local function transitionArchetype(
|
||||||
targetColumn[destinationRow] = column[sourceRow]
|
targetColumn[destinationRow] = column[sourceRow]
|
||||||
end
|
end
|
||||||
|
|
||||||
if sourceRow ~= #column then
|
local last = #column
|
||||||
column[sourceRow] = column[#column]
|
if sourceRow ~= last then
|
||||||
column[#column] = nil
|
column[sourceRow] = column[last]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
column[last] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
destinationEntities[destinationRow] = sourceEntities[sourceRow]
|
local atSourceRow = sourceEntities[sourceRow]
|
||||||
entityIndex[sourceEntities[sourceRow]].row = destinationRow
|
destinationEntities[destinationRow] = atSourceRow
|
||||||
|
entityIndex[atSourceRow].row = destinationRow
|
||||||
|
|
||||||
local movedAway = #sourceEntities
|
local movedAway = #sourceEntities
|
||||||
if sourceRow ~= movedAway then
|
if sourceRow ~= movedAway then
|
||||||
sourceEntities[sourceRow] = sourceEntities[movedAway]
|
local atMovedAway = sourceEntities[movedAway]
|
||||||
entityIndex[sourceEntities[movedAway]].row = sourceRow
|
sourceEntities[sourceRow] = atMovedAway
|
||||||
|
entityIndex[atMovedAway].row = sourceRow
|
||||||
end
|
end
|
||||||
|
|
||||||
sourceEntities[movedAway] = nil
|
sourceEntities[movedAway] = nil
|
||||||
|
@ -492,17 +496,20 @@ local function hash(arr): string | number
|
||||||
end
|
end
|
||||||
|
|
||||||
local function createArchetypeRecords(componentIndex: ComponentIndex, to: Archetype)
|
local function createArchetypeRecords(componentIndex: ComponentIndex, to: Archetype)
|
||||||
local destinationCount = #to.types
|
|
||||||
local destinationIds = to.types
|
local destinationIds = to.types
|
||||||
|
local records = to.records
|
||||||
|
local id = to.id
|
||||||
|
|
||||||
for i = 1, destinationCount do
|
for i, destinationId in destinationIds do
|
||||||
local destinationId = destinationIds[i]
|
local archetypesMap = componentIndex[destinationId]
|
||||||
|
|
||||||
if not componentIndex[destinationId] then
|
if not archetypesMap then
|
||||||
componentIndex[destinationId] = { sparse = {}, size = 0 }
|
archetypesMap = { size = 0, sparse = {} }
|
||||||
|
componentIndex[destinationId] = archetypesMap
|
||||||
end
|
end
|
||||||
componentIndex[destinationId].sparse[to.id] = i
|
|
||||||
to.records[destinationId] = i
|
archetypesMap.sparse[id] = i
|
||||||
|
records[destinationId] = i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -512,10 +519,11 @@ local function archetypeOf(world: World, types: { i24 }, prev: Archetype?): Arch
|
||||||
world.nextArchetypeId = (world.nextArchetypeId :: number) + 1
|
world.nextArchetypeId = (world.nextArchetypeId :: number) + 1
|
||||||
local id = world.nextArchetypeId
|
local id = world.nextArchetypeId
|
||||||
|
|
||||||
local columns = {} :: { any }
|
local length = #types
|
||||||
|
local columns = table.create(length) :: { any }
|
||||||
|
|
||||||
for _ in types do
|
for index in types do
|
||||||
table.insert(columns, {})
|
columns[index] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
local archetype = {
|
local archetype = {
|
||||||
|
@ -531,8 +539,8 @@ local function archetypeOf(world: World, types: { i24 }, prev: Archetype?): Arch
|
||||||
world.archetypeIndex[ty] = archetype
|
world.archetypeIndex[ty] = archetype
|
||||||
world.archetypes[id] = archetype
|
world.archetypes[id] = archetype
|
||||||
|
|
||||||
if #types > 0 then
|
if length > 0 then
|
||||||
createArchetypeRecords(world.componentIndex, archetype, prev)
|
createArchetypeRecords(world.componentIndex, archetype)
|
||||||
end
|
end
|
||||||
|
|
||||||
return archetype
|
return archetype
|
||||||
|
@ -552,9 +560,9 @@ function World.new()
|
||||||
nextArchetypeId = 0,
|
nextArchetypeId = 0,
|
||||||
_size = 0,
|
_size = 0,
|
||||||
_changedStorage = {},
|
_changedStorage = {},
|
||||||
|
ROOT_ARCHETYPE = (nil :: any) :: Archetype,
|
||||||
}, World)
|
}, World)
|
||||||
|
|
||||||
self.ROOT_ARCHETYPE = archetypeOf(self, {}, nil)
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -575,9 +583,7 @@ local function ensureArchetype(world: World, types, prev)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function findInsert(types: { i53 }, toAdd: i53)
|
local function findInsert(types: { i53 }, toAdd: i53)
|
||||||
local count = #types
|
for i, id in types do
|
||||||
for i = 1, count do
|
|
||||||
local id = types[i]
|
|
||||||
if id == toAdd then
|
if id == toAdd then
|
||||||
return -1
|
return -1
|
||||||
end
|
end
|
||||||
|
@ -585,7 +591,8 @@ local function findInsert(types: { i53 }, toAdd: i53)
|
||||||
return i
|
return i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return count + 1
|
|
||||||
|
return #types + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local function findArchetypeWith(world: World, node: Archetype, componentId: i53)
|
local function findArchetypeWith(world: World, node: Archetype, componentId: i53)
|
||||||
|
@ -601,21 +608,49 @@ local function findArchetypeWith(world: World, node: Archetype, componentId: i53
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ensureEdge(archetype: Archetype, componentId: i53)
|
local function ensureEdge(archetype: Archetype, componentId: i53)
|
||||||
if not archetype.edges[componentId] then
|
local edges = archetype.edges
|
||||||
archetype.edges[componentId] = {} :: any
|
local edge = edges[componentId]
|
||||||
|
if not edge then
|
||||||
|
edge = {} :: any
|
||||||
|
edges[componentId] = edge
|
||||||
end
|
end
|
||||||
return archetype.edges[componentId]
|
|
||||||
|
return edge
|
||||||
end
|
end
|
||||||
|
|
||||||
local function archetypeTraverseAdd(world: World, componentId: i53, archetype: Archetype?): Archetype
|
local function archetypeTraverseAdd(world: World, componentId: i53, from: Archetype?): Archetype
|
||||||
local from = (archetype or world.ROOT_ARCHETYPE) :: Archetype
|
if not from then
|
||||||
local edge = ensureEdge(from, componentId)
|
-- 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
|
from = ROOT_ARCHETYPE
|
||||||
edge.add = findArchetypeWith(world, from, componentId)
|
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
local function componentAdd(world: World, entityId: i53, componentInstance)
|
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
|
-- This never gets cleaned up
|
||||||
world.componentIdToComponent[componentId] = component
|
world.componentIdToComponent[componentId] = component
|
||||||
|
|
||||||
local record = world:ensureRecord(entityId)
|
local record = ensureRecord(world.entityIndex, entityId)
|
||||||
local sourceArchetype = record.archetype
|
local sourceArchetype = record.archetype
|
||||||
local destinationArchetype = archetypeTraverseAdd(world, componentId, sourceArchetype)
|
local destinationArchetype = archetypeTraverseAdd(world, componentId, sourceArchetype)
|
||||||
|
|
||||||
|
@ -649,29 +684,22 @@ local function componentAdd(world: World, entityId: i53, componentInstance)
|
||||||
destinationArchetype.columns[archetypeRecord][record.row] = componentInstance
|
destinationArchetype.columns[archetypeRecord][record.row] = componentInstance
|
||||||
end
|
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 function archetypeTraverseRemove(world: World, componentId: i53, archetype: Archetype?): Archetype
|
||||||
local from = (archetype or world.ROOT_ARCHETYPE) :: Archetype
|
local from = (archetype or world.ROOT_ARCHETYPE) :: Archetype
|
||||||
local edge = ensureEdge(from, componentId)
|
local edge = ensureEdge(from, componentId)
|
||||||
|
|
||||||
if not edge.remove then
|
local remove = edge.remove
|
||||||
|
if not remove then
|
||||||
local to = table.clone(from.types)
|
local to = table.clone(from.types)
|
||||||
table.remove(to, table.find(to, componentId))
|
table.remove(to, table.find(to, componentId))
|
||||||
edge.remove = ensureArchetype(world, to, from)
|
remove = ensureArchetype(world, to, from)
|
||||||
|
edge.remove = remove :: never
|
||||||
end
|
end
|
||||||
|
|
||||||
return edge.remove
|
return remove
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get(componentIndex: ComponentIndex, record: Record, componentId: i24): ComponentInstance?
|
local function get(record: Record, componentId: i24): ComponentInstance?
|
||||||
local archetype = record.archetype
|
local archetype = record.archetype
|
||||||
if archetype == nil then
|
if archetype == nil then
|
||||||
return nil
|
return nil
|
||||||
|
@ -685,15 +713,19 @@ local function get(componentIndex: ComponentIndex, record: Record, componentId:
|
||||||
return archetype.columns[archetypeRecord][record.row]
|
return archetype.columns[archetypeRecord][record.row]
|
||||||
end
|
end
|
||||||
|
|
||||||
local function componentRemove(world: World, entityId: i53, component: Component)
|
local function componentRemove(world: World, entityId: i53, component: Component): ComponentInstance?
|
||||||
local componentId = #component
|
local componentId = #component
|
||||||
local record = world:ensureRecord(entityId)
|
local record = ensureRecord(world.entityIndex, entityId)
|
||||||
local sourceArchetype = record.archetype
|
local sourceArchetype = record.archetype
|
||||||
local destinationArchetype = archetypeTraverseRemove(world, componentId, sourceArchetype)
|
local destinationArchetype = archetypeTraverseRemove(world, componentId, sourceArchetype)
|
||||||
|
|
||||||
-- TODO:
|
-- TODO:
|
||||||
-- There is a better way to get the component for returning
|
-- 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
|
if sourceArchetype and not (sourceArchetype == destinationArchetype) then
|
||||||
moveEntity(world.entityIndex, entityId, record, destinationArchetype)
|
moveEntity(world.entityIndex, entityId, record, destinationArchetype)
|
||||||
end
|
end
|
||||||
|
@ -720,40 +752,35 @@ function World.remove(world: World, entityId: i53, ...)
|
||||||
local length = select("#", ...)
|
local length = select("#", ...)
|
||||||
local removed = {}
|
local removed = {}
|
||||||
for i = 1, length do
|
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
|
end
|
||||||
|
|
||||||
return unpack(removed, 1, length)
|
return unpack(removed, 1, length)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World.get(
|
function World.get(world: World, entityId: i53, ...: Component): any
|
||||||
world: World,
|
|
||||||
entityId: i53,
|
|
||||||
a: Component,
|
|
||||||
b: Component?,
|
|
||||||
c: Component?,
|
|
||||||
d: Component?,
|
|
||||||
e: Component?
|
|
||||||
): any
|
|
||||||
local componentIndex = world.componentIndex
|
local componentIndex = world.componentIndex
|
||||||
local record = world.entityIndex[entityId]
|
local record = world.entityIndex[entityId]
|
||||||
if not record then
|
if not record then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local va = get(componentIndex, record, #a)
|
local length = select("#", ...)
|
||||||
|
local components = {}
|
||||||
if b == nil then
|
for i = 1, length do
|
||||||
return va
|
local metatable = select(i, ...)
|
||||||
elseif c == nil then
|
assertValidComponent(metatable, i)
|
||||||
return va, get(componentIndex, record, #b)
|
components[i] = get(record, #metatable)
|
||||||
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")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return unpack(components, 1, length)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World.insert(world: World, entityId: i53, ...)
|
function World.insert(world: World, entityId: i53, ...)
|
||||||
|
@ -863,7 +890,7 @@ function World.spawnAt(world: World, entityId: i53, ...: ComponentInstance)
|
||||||
end
|
end
|
||||||
|
|
||||||
world._size += 1
|
world._size += 1
|
||||||
world:ensureRecord(entityId)
|
ensureRecord(world.entityIndex, entityId)
|
||||||
|
|
||||||
local components = {}
|
local components = {}
|
||||||
for i = 1, select("#", ...) do
|
for i = 1, select("#", ...) do
|
||||||
|
@ -897,8 +924,14 @@ end
|
||||||
function World.despawn(world: World, entityId: i53)
|
function World.despawn(world: World, entityId: i53)
|
||||||
local entityIndex = world.entityIndex
|
local entityIndex = world.entityIndex
|
||||||
local record = entityIndex[entityId]
|
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
|
entityIndex[entityId] = nil
|
||||||
world._size -= 1
|
world._size -= 1
|
||||||
end
|
end
|
||||||
|
@ -1481,14 +1514,24 @@ function World.queryChanged(world: World, componentToTrack, ...: nil)
|
||||||
|
|
||||||
table.insert(world._changedStorage[componentToTrack], storage)
|
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
|
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
|
if entityId then
|
||||||
return entityId, table.freeze({ new = component })
|
return entityId, table.freeze({ new = component })
|
||||||
end
|
end
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue