mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-25 09:30:03 +00:00
Fix docs
This commit is contained in:
parent
09ae7794ea
commit
4375150683
4 changed files with 136 additions and 147 deletions
|
@ -31,7 +31,7 @@ local Name = world:component()
|
||||||
local function parent(entity)
|
local function parent(entity)
|
||||||
return world:target(entity, ChildOf)
|
return world:target(entity, ChildOf)
|
||||||
end
|
end
|
||||||
local function name(entity)
|
local function getName(entity)
|
||||||
return world:get(entity, Name)
|
return world:get(entity, Name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
0
docs/api/index.md
Normal file
0
docs/api/index.md
Normal file
|
@ -1,6 +0,0 @@
|
||||||
# Installing Jecs
|
|
||||||
|
|
||||||
To use Jecs, you will need to add the library to your project's source folder.
|
|
||||||
|
|
||||||
## Installing with Wally
|
|
||||||
Navigate over to the Wally
|
|
275
lib/init.lua
275
lib/init.lua
|
@ -6,10 +6,10 @@
|
||||||
type i53 = number
|
type i53 = number
|
||||||
type i24 = number
|
type i24 = number
|
||||||
|
|
||||||
type Ty = {i53}
|
type Ty = { i53 }
|
||||||
type ArchetypeId = number
|
type ArchetypeId = number
|
||||||
|
|
||||||
type Column = {any}
|
type Column = { any }
|
||||||
|
|
||||||
type Archetype = {
|
type Archetype = {
|
||||||
id: number,
|
id: number,
|
||||||
|
@ -21,20 +21,19 @@ type Archetype = {
|
||||||
},
|
},
|
||||||
types: Ty,
|
types: Ty,
|
||||||
type: string | number,
|
type: string | number,
|
||||||
entities: {number},
|
entities: { number },
|
||||||
columns: {Column},
|
columns: { Column },
|
||||||
records: {},
|
records: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Record = {
|
type Record = {
|
||||||
archetype: Archetype,
|
archetype: Archetype,
|
||||||
row: number,
|
row: number,
|
||||||
dense: i24,
|
dense: i24,
|
||||||
componentRecord: ArchetypeMap
|
componentRecord: ArchetypeMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
type EntityIndex = {dense: {[i24]: i53}, sparse: {[i53]: Record}}
|
type EntityIndex = { dense: { [i24]: i53 }, sparse: { [i53]: Record } }
|
||||||
|
|
||||||
type ArchetypeRecord = number
|
type ArchetypeRecord = number
|
||||||
--[[
|
--[[
|
||||||
|
@ -48,16 +47,16 @@ TODO:
|
||||||
]]
|
]]
|
||||||
|
|
||||||
type ArchetypeMap = {
|
type ArchetypeMap = {
|
||||||
cache: {[number]: ArchetypeRecord},
|
cache: { [number]: ArchetypeRecord },
|
||||||
first: ArchetypeMap,
|
first: ArchetypeMap,
|
||||||
second: ArchetypeMap,
|
second: ArchetypeMap,
|
||||||
parent: ArchetypeMap,
|
parent: ArchetypeMap,
|
||||||
size: number
|
size: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
type ComponentIndex = {[i24]: ArchetypeMap}
|
type ComponentIndex = { [i24]: ArchetypeMap }
|
||||||
|
|
||||||
type Archetypes = {[ArchetypeId]: Archetype}
|
type Archetypes = { [ArchetypeId]: Archetype }
|
||||||
|
|
||||||
type ArchetypeDiff = {
|
type ArchetypeDiff = {
|
||||||
added: Ty,
|
added: Ty,
|
||||||
|
@ -70,114 +69,108 @@ local ON_ADD = HI_COMPONENT_ID + 1
|
||||||
local ON_REMOVE = HI_COMPONENT_ID + 2
|
local ON_REMOVE = HI_COMPONENT_ID + 2
|
||||||
local ON_SET = HI_COMPONENT_ID + 3
|
local ON_SET = HI_COMPONENT_ID + 3
|
||||||
local WILDCARD = HI_COMPONENT_ID + 4
|
local WILDCARD = HI_COMPONENT_ID + 4
|
||||||
local REST = HI_COMPONENT_ID + 5
|
local REST = HI_COMPONENT_ID + 5
|
||||||
|
|
||||||
local ECS_ID_FLAGS_MASK = 0x10
|
local ECS_ID_FLAGS_MASK = 0x10
|
||||||
local ECS_ENTITY_MASK = bit32.lshift(1, 24)
|
local ECS_ENTITY_MASK = bit32.lshift(1, 24)
|
||||||
local ECS_GENERATION_MASK = bit32.lshift(1, 16)
|
local ECS_GENERATION_MASK = bit32.lshift(1, 16)
|
||||||
|
|
||||||
local function addFlags(isPair: boolean)
|
local function addFlags(isPair: boolean)
|
||||||
local typeFlags = 0x0
|
local typeFlags = 0x0
|
||||||
|
|
||||||
if isPair then
|
if isPair then
|
||||||
typeFlags = bit32.bor(typeFlags, FLAGS_PAIR) -- HIGHEST bit in the ID.
|
typeFlags = bit32.bor(typeFlags, FLAGS_PAIR) -- HIGHEST bit in the ID.
|
||||||
end
|
end
|
||||||
if false then
|
if false then
|
||||||
typeFlags = bit32.bor(typeFlags, 0x4) -- Set the second flag to true
|
typeFlags = bit32.bor(typeFlags, 0x4) -- Set the second flag to true
|
||||||
end
|
end
|
||||||
if false then
|
if false then
|
||||||
typeFlags = bit32.bor(typeFlags, 0x2) -- Set the third flag to true
|
typeFlags = bit32.bor(typeFlags, 0x2) -- Set the third flag to true
|
||||||
end
|
end
|
||||||
if false then
|
if false then
|
||||||
typeFlags = bit32.bor(typeFlags, 0x1) -- LAST BIT in the ID.
|
typeFlags = bit32.bor(typeFlags, 0x1) -- LAST BIT in the ID.
|
||||||
end
|
end
|
||||||
|
|
||||||
return typeFlags
|
return typeFlags
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ECS_COMBINE(source: number, target: number): i53
|
local function ECS_COMBINE(source: number, target: number): i53
|
||||||
local e = source * 2^28 + target * ECS_ID_FLAGS_MASK
|
local e = source * 268435456 + target * ECS_ID_FLAGS_MASK
|
||||||
return e
|
return e
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ECS_IS_PAIR(e: number)
|
local function ECS_IS_PAIR(e: number)
|
||||||
return (e % 2^4) // FLAGS_PAIR ~= 0
|
return (e % 2 ^ 4) // FLAGS_PAIR ~= 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function separate(entity: number)
|
function separate(e: number)
|
||||||
local _typeFlags = entity % 0x10
|
local _typeFlags = e % 0x10
|
||||||
entity //= ECS_ID_FLAGS_MASK
|
-- Revert to //= after highligting gets fixed
|
||||||
return entity // ECS_ENTITY_MASK, entity % ECS_GENERATION_MASK, _typeFlags
|
--
|
||||||
|
e = e // ECS_ID_FLAGS_MASK
|
||||||
|
return e // ECS_ENTITY_MASK, e % ECS_GENERATION_MASK, _typeFlags
|
||||||
end
|
end
|
||||||
|
|
||||||
-- HIGH 24 bits LOW 24 bits
|
-- HIGH 24 bits LOW 24 bits
|
||||||
local function ECS_GENERATION(e: i53)
|
local function ECS_GENERATION(e: i53)
|
||||||
e //= 0x10
|
e = e // 0x10
|
||||||
return e % ECS_GENERATION_MASK
|
return e % ECS_GENERATION_MASK
|
||||||
end
|
|
||||||
|
|
||||||
-- SECOND
|
|
||||||
local function ECS_ENTITY_T_LO(e: i53)
|
|
||||||
e //= 0x10
|
|
||||||
return e // ECS_ENTITY_MASK
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ECS_GENERATION_INC(e: i53)
|
local function ECS_GENERATION_INC(e: i53)
|
||||||
local id, generation, flags = separate(e)
|
local id, generation, flags = separate(e)
|
||||||
|
|
||||||
return ECS_COMBINE(id, generation + 1) + flags
|
return ECS_COMBINE(id, generation + 1) + flags
|
||||||
end
|
end
|
||||||
|
|
||||||
-- FIRST gets the high ID
|
-- FIRST gets the high ID
|
||||||
local function ECS_ENTITY_T_HI(entity: i53): i24
|
local function ECS_ENTITY_T_HI(e: i53): i24
|
||||||
entity //= 0x10
|
e = e // 0x10
|
||||||
local first = entity % ECS_ENTITY_MASK
|
return e % ECS_ENTITY_MASK
|
||||||
return first
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ECS_PAIR(pred: number, obj: number)
|
-- SECOND
|
||||||
local first
|
local function ECS_ENTITY_T_LO(e: i53)
|
||||||
|
e = e // 0x10
|
||||||
|
return e // ECS_ENTITY_MASK
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ECS_PAIR(pred: i53, obj: i53): i53
|
||||||
|
local first
|
||||||
local second: number = WILDCARD
|
local second: number = WILDCARD
|
||||||
|
|
||||||
if pred == WILDCARD then
|
if pred == WILDCARD then
|
||||||
first = obj
|
first = obj
|
||||||
elseif obj == WILDCARD then
|
elseif obj == WILDCARD then
|
||||||
first = pred
|
first = pred
|
||||||
else
|
else
|
||||||
first = obj
|
first = obj
|
||||||
second = ECS_ENTITY_T_LO(pred)
|
second = ECS_ENTITY_T_LO(pred)
|
||||||
end
|
end
|
||||||
|
|
||||||
return ECS_COMBINE(
|
return ECS_COMBINE(ECS_ENTITY_T_LO(first), second) + addFlags(--[[isPair]] true)
|
||||||
ECS_ENTITY_T_LO(first), second) + addFlags(--[[isPair]] true)
|
end
|
||||||
end
|
|
||||||
|
|
||||||
local function getAlive(entityIndex: EntityIndex, id: i24)
|
local function getAlive(entityIndex: EntityIndex, id: i24)
|
||||||
local entityId = entityIndex.dense[id]
|
local entityId = entityIndex.dense[id]
|
||||||
local record = entityIndex.sparse[entityIndex.dense[id]]
|
return entityId
|
||||||
if not record then
|
|
||||||
error(id.." is not alive")
|
|
||||||
end
|
|
||||||
return entityId
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ECS_PAIR_FIRST, gets the relationship target / obj / HIGH bits
|
-- ECS_PAIR_FIRST, gets the relationship target / obj / HIGH bits
|
||||||
local function ECS_PAIR_RELATION(entityIndex, e)
|
local function ECS_PAIR_RELATION(entityIndex, e)
|
||||||
assert(ECS_IS_PAIR(e))
|
return getAlive(entityIndex, ECS_ENTITY_T_HI(e))
|
||||||
return getAlive(entityIndex, ECS_ENTITY_T_HI(e))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ECS_PAIR_SECOND gets the relationship / pred / LOW bits
|
-- ECS_PAIR_SECOND gets the relationship / pred / LOW bits
|
||||||
local function ECS_PAIR_OBJECT(entityIndex, e)
|
local function ECS_PAIR_OBJECT(entityIndex, e)
|
||||||
assert(ECS_IS_PAIR(e))
|
return getAlive(entityIndex, ECS_ENTITY_T_LO(e))
|
||||||
return getAlive(entityIndex, ECS_ENTITY_T_LO(e))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function nextEntityId(entityIndex, index: i24): i53
|
local function nextEntityId(entityIndex, index: i24): i53
|
||||||
local id = ECS_COMBINE(index, 0)
|
local id = ECS_COMBINE(index, 0)
|
||||||
entityIndex.sparse[id] = {
|
entityIndex.sparse[id] = {
|
||||||
dense = index
|
dense = index,
|
||||||
} :: Record
|
} :: Record
|
||||||
entityIndex.dense[index] = id
|
entityIndex.dense[index] = id
|
||||||
|
|
||||||
return id
|
return id
|
||||||
|
@ -224,7 +217,7 @@ local function transitionArchetype(
|
||||||
local e1 = sourceEntities[sourceRow]
|
local e1 = sourceEntities[sourceRow]
|
||||||
local e2 = sourceEntities[movedAway]
|
local e2 = sourceEntities[movedAway]
|
||||||
|
|
||||||
if sourceRow ~= movedAway then
|
if sourceRow ~= movedAway then
|
||||||
sourceEntities[sourceRow] = e2
|
sourceEntities[sourceRow] = e2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -252,7 +245,7 @@ local function newEntity(entityId: i53, record: Record, archetype: Archetype)
|
||||||
return record
|
return record
|
||||||
end
|
end
|
||||||
|
|
||||||
local function moveEntity(entityIndex, entityId: i53, record: Record, to: Archetype)
|
local function moveEntity(entityIndex: EntityIndex, entityId: i53, record: Record, to: Archetype)
|
||||||
local sourceRow = record.row
|
local sourceRow = record.row
|
||||||
local from = record.archetype
|
local from = record.archetype
|
||||||
local destinationRow = archetypeAppend(entityId, to)
|
local destinationRow = archetypeAppend(entityId, to)
|
||||||
|
@ -265,11 +258,16 @@ local function hash(arr): string | number
|
||||||
return table.concat(arr, "_")
|
return table.concat(arr, "_")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ensureComponentRecord(componentIndex: ComponentIndex, archetypeId, componentId, i): ArchetypeMap
|
local function ensureComponentRecord(
|
||||||
|
componentIndex: ComponentIndex,
|
||||||
|
archetypeId: number,
|
||||||
|
componentId: number,
|
||||||
|
i: number
|
||||||
|
): ArchetypeMap
|
||||||
local archetypesMap = componentIndex[componentId]
|
local archetypesMap = componentIndex[componentId]
|
||||||
|
|
||||||
if not archetypesMap then
|
if not archetypesMap then
|
||||||
archetypesMap = {size = 0, cache = {}, first = {}, second = {}} :: ArchetypeMap
|
archetypesMap = { size = 0, cache = {}, first = {}, second = {} } :: ArchetypeMap
|
||||||
componentIndex[componentId] = archetypesMap
|
componentIndex[componentId] = archetypesMap
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -279,15 +277,14 @@ local function ensureComponentRecord(componentIndex: ComponentIndex, archetypeId
|
||||||
return archetypesMap
|
return archetypesMap
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ECS_ID_IS_WILDCARD(e)
|
local function ECS_ID_IS_WILDCARD(e)
|
||||||
assert(ECS_IS_PAIR(e))
|
assert(ECS_IS_PAIR(e))
|
||||||
local first = ECS_ENTITY_T_HI(e)
|
local first = ECS_ENTITY_T_HI(e)
|
||||||
local second = ECS_ENTITY_T_LO(e)
|
local second = ECS_ENTITY_T_LO(e)
|
||||||
return first == WILDCARD or second == WILDCARD
|
return first == WILDCARD or second == WILDCARD
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function archetypeOf(world: any, types: { i24 }, prev: Archetype?): Archetype
|
||||||
local function archetypeOf(world: any, types: {i24}, prev: Archetype?): Archetype
|
|
||||||
local ty = hash(types)
|
local ty = hash(types)
|
||||||
|
|
||||||
local id = world.nextArchetypeId + 1
|
local id = world.nextArchetypeId + 1
|
||||||
|
@ -301,31 +298,29 @@ local function archetypeOf(world: any, types: {i24}, prev: Archetype?): Archetyp
|
||||||
for i, componentId in types do
|
for i, componentId in types do
|
||||||
ensureComponentRecord(componentIndex, id, componentId, i)
|
ensureComponentRecord(componentIndex, id, componentId, i)
|
||||||
records[componentId] = i
|
records[componentId] = i
|
||||||
if ECS_IS_PAIR(componentId) then
|
if ECS_IS_PAIR(componentId) then
|
||||||
local relation = ECS_PAIR_RELATION(world.entityIndex, componentId)
|
local relation = ECS_PAIR_RELATION(world.entityIndex, componentId)
|
||||||
local object = ECS_PAIR_OBJECT(world.entityIndex, componentId)
|
local object = ECS_PAIR_OBJECT(world.entityIndex, componentId)
|
||||||
|
|
||||||
local idr_r = ECS_PAIR(relation, WILDCARD)
|
local idr_r = ECS_PAIR(relation, WILDCARD)
|
||||||
ensureComponentRecord(
|
ensureComponentRecord(componentIndex, id, idr_r, i)
|
||||||
componentIndex, id, idr_r, i)
|
|
||||||
records[idr_r] = i
|
records[idr_r] = i
|
||||||
|
|
||||||
local idr_t = ECS_PAIR(WILDCARD, object)
|
local idr_t = ECS_PAIR(WILDCARD, object)
|
||||||
ensureComponentRecord(
|
ensureComponentRecord(componentIndex, id, idr_t, i)
|
||||||
componentIndex, id, idr_t, i)
|
|
||||||
records[idr_t] = i
|
records[idr_t] = i
|
||||||
end
|
end
|
||||||
columns[i] = {}
|
columns[i] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
local archetype = {
|
local archetype = {
|
||||||
columns = columns;
|
columns = columns,
|
||||||
edges = {};
|
edges = {},
|
||||||
entities = {};
|
entities = {},
|
||||||
id = id;
|
id = id,
|
||||||
records = records;
|
records = records,
|
||||||
type = ty;
|
type = ty,
|
||||||
types = types;
|
types = types,
|
||||||
}
|
}
|
||||||
world.archetypeIndex[ty] = archetype
|
world.archetypeIndex[ty] = archetype
|
||||||
world.archetypes[id] = archetype
|
world.archetypes[id] = archetype
|
||||||
|
@ -337,20 +332,20 @@ local World = {}
|
||||||
World.__index = World
|
World.__index = World
|
||||||
function World.new()
|
function World.new()
|
||||||
local self = setmetatable({
|
local self = setmetatable({
|
||||||
archetypeIndex = {};
|
archetypeIndex = {},
|
||||||
archetypes = {} :: Archetypes;
|
archetypes = {} :: Archetypes,
|
||||||
componentIndex = {} :: ComponentIndex;
|
componentIndex = {} :: ComponentIndex,
|
||||||
entityIndex = {
|
entityIndex = {
|
||||||
dense = {},
|
dense = {},
|
||||||
sparse = {}
|
sparse = {},
|
||||||
} :: EntityIndex;
|
} :: EntityIndex,
|
||||||
hooks = {
|
hooks = {
|
||||||
[ON_ADD] = {};
|
[ON_ADD] = {},
|
||||||
};
|
},
|
||||||
nextArchetypeId = 0;
|
nextArchetypeId = 0,
|
||||||
nextComponentId = 0;
|
nextComponentId = 0,
|
||||||
nextEntityId = 0;
|
nextEntityId = 0,
|
||||||
ROOT_ARCHETYPE = (nil :: any) :: Archetype;
|
ROOT_ARCHETYPE = (nil :: any) :: Archetype,
|
||||||
}, World)
|
}, World)
|
||||||
self.ROOT_ARCHETYPE = archetypeOf(self, {})
|
self.ROOT_ARCHETYPE = archetypeOf(self, {})
|
||||||
return self
|
return self
|
||||||
|
@ -380,16 +375,16 @@ function World.target(world: World, entity: i53, relation: i24): i24?
|
||||||
local entityIndex = world.entityIndex
|
local entityIndex = world.entityIndex
|
||||||
local record = entityIndex.sparse[entity]
|
local record = entityIndex.sparse[entity]
|
||||||
local archetype = record.archetype
|
local archetype = record.archetype
|
||||||
if not archetype then
|
if not archetype then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
local componentRecord = world.componentIndex[ECS_PAIR(relation, WILDCARD)]
|
local componentRecord = world.componentIndex[ECS_PAIR(relation, WILDCARD)]
|
||||||
if not componentRecord then
|
if not componentRecord then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local archetypeRecord = componentRecord.cache[archetype.id]
|
local archetypeRecord = componentRecord.cache[archetype.id]
|
||||||
if not archetypeRecord then
|
if not archetypeRecord then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -397,37 +392,37 @@ function World.target(world: World, entity: i53, relation: i24): i24?
|
||||||
end
|
end
|
||||||
|
|
||||||
-- should reuse this logic in World.set instead of swap removing in transition archetype
|
-- should reuse this logic in World.set instead of swap removing in transition archetype
|
||||||
local function destructColumns(columns, count, row)
|
local function destructColumns(columns, count, row)
|
||||||
if row == count then
|
if row == count then
|
||||||
for _, column in columns do
|
for _, column in columns do
|
||||||
column[count] = nil
|
column[count] = nil
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for _, column in columns do
|
for _, column in columns do
|
||||||
column[row] = column[count]
|
column[row] = column[count]
|
||||||
column[count] = nil
|
column[count] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function archetypeDelete(world: World, id: i53)
|
local function archetypeDelete(world: World, id: i53)
|
||||||
local componentIndex = world.componentIndex
|
local componentIndex = world.componentIndex
|
||||||
local archetypesMap = componentIndex[id]
|
local archetypesMap = componentIndex[id]
|
||||||
local archetypes = world.archetypes
|
local archetypes = world.archetypes
|
||||||
if archetypesMap then
|
if archetypesMap then
|
||||||
for archetypeId in archetypesMap.cache do
|
for archetypeId in archetypesMap.cache do
|
||||||
for _, entity in archetypes[archetypeId].entities do
|
for _, entity in archetypes[archetypeId].entities do
|
||||||
world:remove(entity, id)
|
world:remove(entity, id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
componentIndex[id] = nil
|
componentIndex[id] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function World.delete(world: World, entityId: i53)
|
function World.delete(world: World, entityId: i53)
|
||||||
local record = world.entityIndex.sparse[entityId]
|
local record = world.entityIndex.sparse[entityId]
|
||||||
if not record then
|
if not record then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local entityIndex = world.entityIndex
|
local entityIndex = world.entityIndex
|
||||||
|
@ -439,12 +434,12 @@ function World.delete(world: World, entityId: i53)
|
||||||
-- TODO: should traverse linked )component records to pairs including entityId
|
-- TODO: should traverse linked )component records to pairs including entityId
|
||||||
archetypeDelete(world, ECS_PAIR(entityId, WILDCARD))
|
archetypeDelete(world, ECS_PAIR(entityId, WILDCARD))
|
||||||
archetypeDelete(world, ECS_PAIR(WILDCARD, entityId))
|
archetypeDelete(world, ECS_PAIR(WILDCARD, entityId))
|
||||||
|
|
||||||
if archetype then
|
if archetype then
|
||||||
local entities = archetype.entities
|
local entities = archetype.entities
|
||||||
local last = #entities
|
local last = #entities
|
||||||
|
|
||||||
if row ~= last then
|
if row ~= last then
|
||||||
local entityToMove = entities[last]
|
local entityToMove = entities[last]
|
||||||
dense[record.dense] = entityToMove
|
dense[record.dense] = entityToMove
|
||||||
sparse[entityToMove] = record
|
sparse[entityToMove] = record
|
||||||
|
@ -477,7 +472,7 @@ local function ensureArchetype(world: World, types, prev)
|
||||||
return archetypeOf(world, types, prev)
|
return archetypeOf(world, types, prev)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function findInsert(types: {i53}, toAdd: i53)
|
local function findInsert(types: { i53 }, toAdd: i53)
|
||||||
for i, id in types do
|
for i, id in types do
|
||||||
if id == toAdd then
|
if id == toAdd then
|
||||||
return -1
|
return -1
|
||||||
|
@ -494,7 +489,7 @@ local function findArchetypeWith(world: World, node: Archetype, componentId: i53
|
||||||
-- Component IDs are added incrementally, so inserting and sorting
|
-- Component IDs are added incrementally, so inserting and sorting
|
||||||
-- them each time would be expensive. Instead this insertion sort can find the insertion
|
-- them each time would be expensive. Instead this insertion sort can find the insertion
|
||||||
-- point in the types array.
|
-- point in the types array.
|
||||||
|
|
||||||
local destinationType = table.clone(node.types)
|
local destinationType = table.clone(node.types)
|
||||||
local at = findInsert(types, componentId)
|
local at = findInsert(types, componentId)
|
||||||
if at == -1 then
|
if at == -1 then
|
||||||
|
@ -532,7 +527,7 @@ local function archetypeTraverseAdd(world: World, componentId: i53, from: Archet
|
||||||
return add
|
return add
|
||||||
end
|
end
|
||||||
|
|
||||||
function World.add(world: World, entityId: i53, componentId: i53)
|
function World.add(world: World, entityId: i53, componentId: i53)
|
||||||
local entityIndex = world.entityIndex
|
local entityIndex = world.entityIndex
|
||||||
local record = entityIndex.sparse[entityId]
|
local record = entityIndex.sparse[entityId]
|
||||||
local from = record.archetype
|
local from = record.archetype
|
||||||
|
@ -582,7 +577,7 @@ local function archetypeTraverseRemove(world: World, componentId: i53, from: Arc
|
||||||
if not remove then
|
if not remove then
|
||||||
local to = table.clone(from.types)
|
local to = table.clone(from.types)
|
||||||
local at = table.find(to, componentId)
|
local at = table.find(to, componentId)
|
||||||
if not at then
|
if not at then
|
||||||
return from
|
return from
|
||||||
end
|
end
|
||||||
table.remove(to, at)
|
table.remove(to, at)
|
||||||
|
@ -607,7 +602,7 @@ end
|
||||||
-- Keeping the function as small as possible to enable inlining
|
-- Keeping the function as small as possible to enable inlining
|
||||||
local function get(record: Record, componentId: i24)
|
local function get(record: Record, componentId: i24)
|
||||||
local archetype = record.archetype
|
local archetype = record.archetype
|
||||||
if not archetype then
|
if not archetype then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -644,20 +639,20 @@ end
|
||||||
|
|
||||||
-- the less creation the better
|
-- the less creation the better
|
||||||
local function actualNoOperation() end
|
local function actualNoOperation() end
|
||||||
local function noop(_self: Query, ...: i53): () -> (number, ...any)
|
local function noop(_self: Query, ...): () -> ()
|
||||||
return actualNoOperation :: any
|
return actualNoOperation :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
local EmptyQuery = {
|
local EmptyQuery = {
|
||||||
__iter = noop;
|
__iter = noop,
|
||||||
without = noop;
|
without = noop,
|
||||||
}
|
}
|
||||||
EmptyQuery.__index = EmptyQuery
|
EmptyQuery.__index = EmptyQuery
|
||||||
setmetatable(EmptyQuery, EmptyQuery)
|
setmetatable(EmptyQuery, EmptyQuery)
|
||||||
|
|
||||||
export type Query = typeof(EmptyQuery)
|
export type Query = typeof(EmptyQuery)
|
||||||
|
|
||||||
function World.query(world: World, ...: i53): Query
|
function World.query(world: World, ...): Query
|
||||||
-- breaking?
|
-- breaking?
|
||||||
if (...) == nil then
|
if (...) == nil then
|
||||||
error("Missing components")
|
error("Missing components")
|
||||||
|
@ -666,7 +661,7 @@ function World.query(world: World, ...: i53): Query
|
||||||
local compatibleArchetypes = {}
|
local compatibleArchetypes = {}
|
||||||
local length = 0
|
local length = 0
|
||||||
|
|
||||||
local components = {...}
|
local components = { ... }
|
||||||
local archetypes = world.archetypes
|
local archetypes = world.archetypes
|
||||||
local queryLength = #components
|
local queryLength = #components
|
||||||
|
|
||||||
|
@ -707,8 +702,8 @@ function World.query(world: World, ...: i53): Query
|
||||||
|
|
||||||
length += 1
|
length += 1
|
||||||
compatibleArchetypes[length] = {
|
compatibleArchetypes[length] = {
|
||||||
archetype = archetype,
|
archetype = archetype,
|
||||||
indices = indices
|
indices = indices,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -721,7 +716,7 @@ function World.query(world: World, ...: i53): Query
|
||||||
preparedQuery.__index = preparedQuery
|
preparedQuery.__index = preparedQuery
|
||||||
|
|
||||||
function preparedQuery:without(...)
|
function preparedQuery:without(...)
|
||||||
local withoutComponents = {...}
|
local withoutComponents = { ... }
|
||||||
for i = #compatibleArchetypes, 1, -1 do
|
for i = #compatibleArchetypes, 1, -1 do
|
||||||
local archetype = compatibleArchetypes[i].archetype
|
local archetype = compatibleArchetypes[i].archetype
|
||||||
local records = archetype.records
|
local records = archetype.records
|
||||||
|
@ -828,16 +823,16 @@ function World.__iter(world: World): () -> (number?, unknown?)
|
||||||
local sparse = world.entityIndex.sparse
|
local sparse = world.entityIndex.sparse
|
||||||
local last
|
local last
|
||||||
|
|
||||||
return function()
|
return function()
|
||||||
local lastEntity, entityId = next(dense, last)
|
local lastEntity, entityId = next(dense, last)
|
||||||
if not lastEntity then
|
if not lastEntity then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
last = lastEntity
|
last = lastEntity
|
||||||
|
|
||||||
local record = sparse[entityId]
|
local record = sparse[entityId]
|
||||||
local archetype = record.archetype
|
local archetype = record.archetype
|
||||||
if not archetype then
|
if not archetype then
|
||||||
-- Returns only the entity id as an entity without data should not return
|
-- Returns only the entity id as an entity without data should not return
|
||||||
-- data and allow the user to get an error if they don't handle the case.
|
-- data and allow the user to get an error if they don't handle the case.
|
||||||
return entityId
|
return entityId
|
||||||
|
@ -851,17 +846,17 @@ function World.__iter(world: World): () -> (number?, unknown?)
|
||||||
-- We use types because the key should be the component ID not the column index
|
-- We use types because the key should be the component ID not the column index
|
||||||
entityData[types[i]] = column[row]
|
entityData[types[i]] = column[row]
|
||||||
end
|
end
|
||||||
|
|
||||||
return entityId, entityData
|
return entityId, entityData
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return table.freeze({
|
return table.freeze({
|
||||||
World = World;
|
World = World,
|
||||||
|
|
||||||
OnAdd = ON_ADD;
|
OnAdd = ON_ADD,
|
||||||
OnRemove = ON_REMOVE;
|
OnRemove = ON_REMOVE,
|
||||||
OnSet = ON_SET;
|
OnSet = ON_SET,
|
||||||
Wildcard = WILDCARD,
|
Wildcard = WILDCARD,
|
||||||
w = WILDCARD,
|
w = WILDCARD,
|
||||||
Rest = REST,
|
Rest = REST,
|
||||||
|
|
Loading…
Reference in a new issue