mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-25 09:30:03 +00:00
Add EcsComponent built-in component
This commit is contained in:
parent
f041d6fa74
commit
de34636bb3
1 changed files with 196 additions and 190 deletions
386
lib/init.luau
386
lib/init.luau
|
@ -70,7 +70,8 @@ local EcsOnRemove = HI_COMPONENT_ID + 2
|
||||||
local EcsOnSet = HI_COMPONENT_ID + 3
|
local EcsOnSet = HI_COMPONENT_ID + 3
|
||||||
local EcsWildcard = HI_COMPONENT_ID + 4
|
local EcsWildcard = HI_COMPONENT_ID + 4
|
||||||
local EcsChildOf = HI_COMPONENT_ID + 5
|
local EcsChildOf = HI_COMPONENT_ID + 5
|
||||||
local EcsRest = HI_COMPONENT_ID + 6
|
local EcsComponent = HI_COMPONENT_ID + 6
|
||||||
|
local EcsRest = HI_COMPONENT_ID + 7
|
||||||
|
|
||||||
local ECS_PAIR_FLAG = 0x8
|
local ECS_PAIR_FLAG = 0x8
|
||||||
local ECS_ID_FLAGS_MASK = 0x10
|
local ECS_ID_FLAGS_MASK = 0x10
|
||||||
|
@ -138,8 +139,28 @@ local function ECS_PAIR(pred: i53, obj: i53): i53
|
||||||
return ECS_COMBINE(ECS_ENTITY_T_LO(obj), ECS_ENTITY_T_LO(pred)) + addFlags(--[[isPair]] true) :: i53
|
return ECS_COMBINE(ECS_ENTITY_T_LO(obj), ECS_ENTITY_T_LO(pred)) + addFlags(--[[isPair]] true) :: i53
|
||||||
end
|
end
|
||||||
|
|
||||||
local function getAlive(entityIndex: EntityIndex, id: i24): i53
|
local ERROR_ENTITY_NOT_ALIVE = "Entity is not alive"
|
||||||
return entityIndex.dense[id]
|
local ERROR_GENERATION_INVALID = "INVALID GENERATION"
|
||||||
|
|
||||||
|
local function getAlive(index: EntityIndex, e: i24): i53
|
||||||
|
local denseArray = index.dense
|
||||||
|
local id = denseArray[ECS_ENTITY_T_LO(e)]
|
||||||
|
|
||||||
|
if id then
|
||||||
|
local currentGeneration = ECS_GENERATION(id)
|
||||||
|
local gen = ECS_GENERATION(e)
|
||||||
|
if gen == currentGeneration then
|
||||||
|
return id
|
||||||
|
end
|
||||||
|
|
||||||
|
error(ERROR_GENERATION_INVALID)
|
||||||
|
end
|
||||||
|
|
||||||
|
error(ERROR_ENTITY_NOT_ALIVE)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sparseGet(entityIndex, id)
|
||||||
|
return entityIndex.sparse[getAlive(entityIndex, id)]
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ECS_PAIR_FIRST, gets the relationship target / obj / HIGH bits
|
-- ECS_PAIR_FIRST, gets the relationship target / obj / HIGH bits
|
||||||
|
@ -316,48 +337,18 @@ local function archetypeOf(world: any, types: { i24 }, prev: Archetype?): Archet
|
||||||
return archetype
|
return archetype
|
||||||
end
|
end
|
||||||
|
|
||||||
local World = {}
|
export type World = {
|
||||||
World.__index = World
|
archetypeIndex: { [string]: Archetype },
|
||||||
|
archetypes: Archetypes,
|
||||||
|
componentIndex: ComponentIndex,
|
||||||
|
entityIndex: EntityIndex,
|
||||||
|
nextArchetypeId: number,
|
||||||
|
nextComponentId: number,
|
||||||
|
nextEntityId: number,
|
||||||
|
ROOT_ARCHETYPE: Archetype
|
||||||
|
}
|
||||||
|
|
||||||
function World.new(): World
|
local function entity(world: World): i53
|
||||||
local self = setmetatable({
|
|
||||||
archetypeIndex = {} :: { [string]: Archetype },
|
|
||||||
archetypes = {} :: Archetypes,
|
|
||||||
componentIndex = {} :: ComponentIndex,
|
|
||||||
entityIndex = {
|
|
||||||
dense = {} :: { [i24]: i53 },
|
|
||||||
sparse = {} :: { [i53]: Record },
|
|
||||||
} :: EntityIndex,
|
|
||||||
hooks = {
|
|
||||||
[EcsOnAdd] = {},
|
|
||||||
},
|
|
||||||
nextArchetypeId = 0,
|
|
||||||
nextComponentId = 0,
|
|
||||||
nextEntityId = 0,
|
|
||||||
ROOT_ARCHETYPE = (nil :: any) :: Archetype,
|
|
||||||
}, World)
|
|
||||||
self.ROOT_ARCHETYPE = archetypeOf(self, {})
|
|
||||||
|
|
||||||
-- Initialize built-in components
|
|
||||||
nextEntityId(self.entityIndex, EcsChildOf)
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
export type World = typeof(World.new())
|
|
||||||
|
|
||||||
function World.component(world: World): i53
|
|
||||||
local componentId = world.nextComponentId + 1
|
|
||||||
if componentId > HI_COMPONENT_ID then
|
|
||||||
-- IDs are partitioned into ranges because component IDs are not nominal,
|
|
||||||
-- so it needs to error when IDs intersect into the entity range.
|
|
||||||
error("Too many components, consider using world:entity() instead to create components.")
|
|
||||||
end
|
|
||||||
world.nextComponentId = componentId
|
|
||||||
return nextEntityId(world.entityIndex, componentId)
|
|
||||||
end
|
|
||||||
|
|
||||||
function World.entity(world: World): i53
|
|
||||||
local entityId = world.nextEntityId + 1
|
local entityId = world.nextEntityId + 1
|
||||||
world.nextEntityId = entityId
|
world.nextEntityId = entityId
|
||||||
return nextEntityId(world.entityIndex, entityId + EcsRest)
|
return nextEntityId(world.entityIndex, entityId + EcsRest)
|
||||||
|
@ -391,93 +382,6 @@ local function parent(world: World, entity: i53)
|
||||||
return target(world, entity, EcsChildOf)
|
return target(world, entity, EcsChildOf)
|
||||||
end
|
end
|
||||||
|
|
||||||
World.target = target
|
|
||||||
World.parent = parent
|
|
||||||
|
|
||||||
-- should reuse this logic in World.set instead of swap removing in transition archetype
|
|
||||||
local function destructColumns(columns: { Column }, count: number, row: number)
|
|
||||||
if row == count then
|
|
||||||
for _, column in columns do
|
|
||||||
column[count] = nil
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for _, column in columns do
|
|
||||||
column[row] = column[count]
|
|
||||||
column[count] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function archetypeDelete(world: World, id: i53)
|
|
||||||
local componentIndex = world.componentIndex
|
|
||||||
local archetypesMap = componentIndex[id]
|
|
||||||
local archetypes = world.archetypes
|
|
||||||
|
|
||||||
if archetypesMap then
|
|
||||||
for archetypeId in archetypesMap.cache do
|
|
||||||
for _, entity in archetypes[archetypeId].entities do
|
|
||||||
world:remove(entity, id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
componentIndex[id] = nil :: any
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function World.delete(world: World, entityId: i53)
|
|
||||||
local record = world.entityIndex.sparse[entityId]
|
|
||||||
if not record then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local entityIndex = world.entityIndex
|
|
||||||
local sparse, dense = entityIndex.sparse, entityIndex.dense
|
|
||||||
local archetype = record.archetype
|
|
||||||
local row = record.row
|
|
||||||
|
|
||||||
archetypeDelete(world, entityId)
|
|
||||||
-- TODO: should traverse linked )component records to pairs including entityId
|
|
||||||
archetypeDelete(world, ECS_PAIR(entityId, EcsWildcard))
|
|
||||||
archetypeDelete(world, ECS_PAIR(EcsWildcard, entityId))
|
|
||||||
|
|
||||||
if archetype then
|
|
||||||
local entities = archetype.entities
|
|
||||||
local last = #entities
|
|
||||||
|
|
||||||
if row ~= last then
|
|
||||||
local entityToMove = entities[last]
|
|
||||||
dense[record.dense] = entityToMove
|
|
||||||
sparse[entityToMove] = record
|
|
||||||
end
|
|
||||||
|
|
||||||
entities[row], entities[last] = entities[last], nil :: any
|
|
||||||
|
|
||||||
local columns = archetype.columns
|
|
||||||
|
|
||||||
destructColumns(columns, last, row)
|
|
||||||
end
|
|
||||||
|
|
||||||
sparse[entityId] = nil :: any
|
|
||||||
dense[#dense] = nil :: any
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function World.clear(world: World, entityId: i53)
|
|
||||||
--TODO: use sparse_get (stashed)
|
|
||||||
local record = world.entityIndex.sparse[entityId]
|
|
||||||
if not record then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local ROOT_ARCHETYPE = world.ROOT_ARCHETYPE
|
|
||||||
local archetype = record.archetype
|
|
||||||
|
|
||||||
if archetype == nil or archetype == ROOT_ARCHETYPE then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
moveEntity(world.entityIndex, entityId, record, ROOT_ARCHETYPE)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function ensureArchetype(world: World, types, prev): Archetype
|
local function ensureArchetype(world: World, types, prev): Archetype
|
||||||
if #types < 1 then
|
if #types < 1 then
|
||||||
return world.ROOT_ARCHETYPE
|
return world.ROOT_ARCHETYPE
|
||||||
|
@ -547,7 +451,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)
|
local function 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
|
||||||
|
@ -562,7 +466,7 @@ function World.add(world: World, entityId: i53, componentId: i53)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Symmetric like `World.add` but idempotent
|
-- Symmetric like `World.add` but idempotent
|
||||||
function World.set(world: World, entityId: i53, componentId: i53, data: unknown)
|
local function set(world: World, entityId: i53, componentId: i53, data: unknown)
|
||||||
local record = world.entityIndex.sparse[entityId]
|
local record = world.entityIndex.sparse[entityId]
|
||||||
local from = record.archetype
|
local from = record.archetype
|
||||||
local to = archetypeTraverseAdd(world, componentId, from)
|
local to = archetypeTraverseAdd(world, componentId, from)
|
||||||
|
@ -590,6 +494,20 @@ function World.set(world: World, entityId: i53, componentId: i53, data: unknown)
|
||||||
to.columns[archetypeRecord][record.row] = data
|
to.columns[archetypeRecord][record.row] = data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function newComponent(world: World): i53
|
||||||
|
local componentId = world.nextComponentId + 1
|
||||||
|
if componentId > HI_COMPONENT_ID then
|
||||||
|
-- IDs are partitioned into ranges because component IDs are not nominal,
|
||||||
|
-- so it needs to error when IDs intersect into the entity range.
|
||||||
|
error("Too many components, consider using world:entity() instead to create components.")
|
||||||
|
end
|
||||||
|
world.nextComponentId = componentId
|
||||||
|
local id = nextEntityId(world.entityIndex, componentId)
|
||||||
|
add(world, id, EcsComponent)
|
||||||
|
return id
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local function archetypeTraverseRemove(world: World, componentId: i53, from: Archetype): Archetype
|
local function archetypeTraverseRemove(world: World, componentId: i53, from: Archetype): Archetype
|
||||||
local edge = ensureEdge(from, componentId)
|
local edge = ensureEdge(from, componentId)
|
||||||
|
|
||||||
|
@ -608,7 +526,7 @@ local function archetypeTraverseRemove(world: World, componentId: i53, from: Arc
|
||||||
return remove
|
return remove
|
||||||
end
|
end
|
||||||
|
|
||||||
function World.remove(world: World, entityId: i53, componentId: i53)
|
local function remove(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 sourceArchetype = record.archetype
|
local sourceArchetype = record.archetype
|
||||||
|
@ -619,8 +537,92 @@ function World.remove(world: World, entityId: i53, componentId: i53)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- should reuse this logic in World.set instead of swap removing in transition archetype
|
||||||
|
local function destructColumns(columns: { Column }, count: number, row: number)
|
||||||
|
if row == count then
|
||||||
|
for _, column in columns do
|
||||||
|
column[count] = nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for _, column in columns do
|
||||||
|
column[row] = column[count]
|
||||||
|
column[count] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function archetypeDelete(world: World, id: i53)
|
||||||
|
local componentIndex = world.componentIndex
|
||||||
|
local archetypesMap = componentIndex[id]
|
||||||
|
local archetypes = world.archetypes
|
||||||
|
|
||||||
|
if archetypesMap then
|
||||||
|
for archetypeId in archetypesMap.cache do
|
||||||
|
for _, entity in archetypes[archetypeId].entities do
|
||||||
|
remove(world, entity, id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
componentIndex[id] = nil :: any
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function delete(world: World, entityId: i53)
|
||||||
|
local record = world.entityIndex.sparse[entityId]
|
||||||
|
if not record then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local entityIndex = world.entityIndex
|
||||||
|
local sparse, dense = entityIndex.sparse, entityIndex.dense
|
||||||
|
local archetype = record.archetype
|
||||||
|
local row = record.row
|
||||||
|
|
||||||
|
archetypeDelete(world, entityId)
|
||||||
|
-- TODO: should traverse linked )component records to pairs including entityId
|
||||||
|
archetypeDelete(world, ECS_PAIR(entityId, EcsWildcard))
|
||||||
|
archetypeDelete(world, ECS_PAIR(EcsWildcard, entityId))
|
||||||
|
|
||||||
|
if archetype then
|
||||||
|
local entities = archetype.entities
|
||||||
|
local last = #entities
|
||||||
|
|
||||||
|
if row ~= last then
|
||||||
|
local entityToMove = entities[last]
|
||||||
|
dense[record.dense] = entityToMove
|
||||||
|
sparse[entityToMove] = record
|
||||||
|
end
|
||||||
|
|
||||||
|
entities[row], entities[last] = entities[last], nil :: any
|
||||||
|
|
||||||
|
local columns = archetype.columns
|
||||||
|
|
||||||
|
destructColumns(columns, last, row)
|
||||||
|
end
|
||||||
|
|
||||||
|
sparse[entityId] = nil :: any
|
||||||
|
dense[#dense] = nil :: any
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clear(world: World, entityId: i53)
|
||||||
|
--TODO: use sparse_get (stashed)
|
||||||
|
local record = world.entityIndex.sparse[entityId]
|
||||||
|
if not record then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local ROOT_ARCHETYPE = world.ROOT_ARCHETYPE
|
||||||
|
local archetype = record.archetype
|
||||||
|
|
||||||
|
if archetype == nil or archetype == ROOT_ARCHETYPE then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
moveEntity(world.entityIndex, entityId, record, ROOT_ARCHETYPE)
|
||||||
|
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): any
|
local function fetch(record: Record, componentId: i24): any
|
||||||
local archetype = record.archetype
|
local archetype = record.archetype
|
||||||
if not archetype then
|
if not archetype then
|
||||||
return nil
|
return nil
|
||||||
|
@ -635,23 +637,23 @@ local function get(record: Record, componentId: i24): any
|
||||||
return archetype.columns[archetypeRecord][record.row]
|
return archetype.columns[archetypeRecord][record.row]
|
||||||
end
|
end
|
||||||
|
|
||||||
function World.get(world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any
|
local function get(world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any
|
||||||
local id = entityId
|
local id = entityId
|
||||||
local record = world.entityIndex.sparse[id]
|
local record = world.entityIndex.sparse[id]
|
||||||
if not record then
|
if not record then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local va = get(record, a)
|
local va = fetch(record, a)
|
||||||
|
|
||||||
if b == nil then
|
if b == nil then
|
||||||
return va
|
return va
|
||||||
elseif c == nil then
|
elseif c == nil then
|
||||||
return va, get(record, b)
|
return va, fetch(record, b)
|
||||||
elseif d == nil then
|
elseif d == nil then
|
||||||
return va, get(record, b), get(record, c)
|
return va, fetch(record, b), fetch(record, c)
|
||||||
elseif e == nil then
|
elseif e == nil then
|
||||||
return va, get(record, b), get(record, c), get(record, d)
|
return va, fetch(record, b), fetch(record, c), fetch(record, d)
|
||||||
else
|
else
|
||||||
error("args exceeded")
|
error("args exceeded")
|
||||||
end
|
end
|
||||||
|
@ -696,11 +698,13 @@ local function preparedQuery(compatibleArchetypes: { Archetype },
|
||||||
while entityId == nil do
|
while entityId == nil do
|
||||||
lastArchetype += 1
|
lastArchetype += 1
|
||||||
archetype = compatibleArchetypes[lastArchetype]
|
archetype = compatibleArchetypes[lastArchetype]
|
||||||
|
|
||||||
if not archetype then
|
if not archetype then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
i = 1
|
i = 1
|
||||||
entityId = archetype.entities[i]
|
entityId = archetype.entities[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
local row = i
|
local row = i
|
||||||
|
@ -782,7 +786,7 @@ local function preparedQuery(compatibleArchetypes: { Archetype },
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
local query = {
|
local it = {
|
||||||
__iter = function()
|
__iter = function()
|
||||||
i = 1
|
i = 1
|
||||||
lastArchetype = 1
|
lastArchetype = 1
|
||||||
|
@ -794,10 +798,10 @@ local function preparedQuery(compatibleArchetypes: { Archetype },
|
||||||
without = without
|
without = without
|
||||||
}
|
}
|
||||||
|
|
||||||
return setmetatable(query, query) :: any
|
return setmetatable(it, it) :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
function World.query(world: World, ...: number): Query
|
local function query(world: World, ...: number): Query
|
||||||
-- breaking?
|
-- breaking?
|
||||||
if (...) == nil then
|
if (...) == nil then
|
||||||
error("Missing components")
|
error("Missing components")
|
||||||
|
@ -854,46 +858,6 @@ function World.query(world: World, ...: number): Query
|
||||||
end
|
end
|
||||||
|
|
||||||
type WorldIterator = (() -> (i53, { [unknown]: unknown? })) & (() -> ()) & (() -> i53)
|
type WorldIterator = (() -> (i53, { [unknown]: unknown? })) & (() -> ()) & (() -> i53)
|
||||||
|
|
||||||
function World.__iter(world: World): WorldIterator
|
|
||||||
local entityIndex = world.entityIndex
|
|
||||||
local sparse = entityIndex.sparse
|
|
||||||
local last
|
|
||||||
|
|
||||||
-- new solver doesnt like the world iterator type even tho its correct
|
|
||||||
-- so any cast here i come
|
|
||||||
local i = 0
|
|
||||||
local function iterator()
|
|
||||||
i+=1
|
|
||||||
local entityId, record = next(sparse, last)
|
|
||||||
if not entityId then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
last = entityId
|
|
||||||
|
|
||||||
local archetype = record.archetype
|
|
||||||
if not archetype then
|
|
||||||
-- 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.
|
|
||||||
return entityId
|
|
||||||
end
|
|
||||||
|
|
||||||
local row = record.row
|
|
||||||
local types = archetype.types
|
|
||||||
local columns = archetype.columns
|
|
||||||
local entityData = {}
|
|
||||||
for i, column in columns do
|
|
||||||
-- We use types because the key should be the component ID not the column index
|
|
||||||
entityData[types[i]] = column[row]
|
|
||||||
end
|
|
||||||
|
|
||||||
return entityId, entityData
|
|
||||||
end
|
|
||||||
|
|
||||||
return iterator :: any
|
|
||||||
end
|
|
||||||
|
|
||||||
-- __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 & { __nominal_type_dont_use: T }
|
||||||
|
@ -908,6 +872,7 @@ export type QueryShim<T...> = typeof(setmetatable({
|
||||||
return nil :: any
|
return nil :: any
|
||||||
end,
|
end,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export type WorldShim = typeof(setmetatable(
|
export type WorldShim = typeof(setmetatable(
|
||||||
{} :: {
|
{} :: {
|
||||||
|
|
||||||
|
@ -1023,16 +988,57 @@ export type WorldShim = typeof(setmetatable(
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
||||||
|
local World = {}
|
||||||
|
World.__index = World
|
||||||
|
|
||||||
|
function World.new()
|
||||||
|
local self = setmetatable({
|
||||||
|
archetypeIndex = {} :: { [string]: Archetype },
|
||||||
|
archetypes = {} :: Archetypes,
|
||||||
|
componentIndex = {} :: ComponentIndex,
|
||||||
|
entityIndex = {
|
||||||
|
dense = {} :: { [i24]: i53 },
|
||||||
|
sparse = {} :: { [i53]: Record },
|
||||||
|
} :: EntityIndex,
|
||||||
|
hooks = {
|
||||||
|
[EcsOnAdd] = {},
|
||||||
|
},
|
||||||
|
nextArchetypeId = 0,
|
||||||
|
nextComponentId = 0,
|
||||||
|
nextEntityId = 0,
|
||||||
|
ROOT_ARCHETYPE = (nil :: any) :: Archetype,
|
||||||
|
}, World)
|
||||||
|
self.ROOT_ARCHETYPE = archetypeOf(self, {})
|
||||||
|
|
||||||
|
-- Initialize built-in components
|
||||||
|
nextEntityId(self.entityIndex, EcsChildOf)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
World.entity = entity
|
||||||
|
World.query = query
|
||||||
|
World.remove = remove
|
||||||
|
World.clear = clear
|
||||||
|
World.delete = delete
|
||||||
|
World.component = newComponent
|
||||||
|
World.add = add
|
||||||
|
World.set = set
|
||||||
|
World.get = get
|
||||||
|
World.target = target
|
||||||
|
World.parent = parent
|
||||||
|
|
||||||
return {
|
return {
|
||||||
World = (World :: any) :: { new: () -> WorldShim },
|
World = World :: { new: () -> WorldShim },
|
||||||
|
|
||||||
OnAdd = (EcsOnAdd :: any) :: Entity,
|
OnAdd = EcsOnAdd :: Entity,
|
||||||
OnRemove = (EcsOnRemove :: any) :: Entity,
|
OnRemove = EcsOnRemove :: Entity,
|
||||||
OnSet = (EcsOnSet :: any) :: Entity,
|
OnSet = EcsOnSet :: Entity,
|
||||||
|
|
||||||
Wildcard = (EcsWildcard :: any) :: Entity,
|
Wildcard = EcsWildcard :: Entity,
|
||||||
w = (EcsWildcard :: any) :: Entity,
|
w = EcsWildcard :: Entity,
|
||||||
ChildOf = EcsChildOf,
|
ChildOf = EcsChildOf,
|
||||||
|
Component = EcsComponent,
|
||||||
|
|
||||||
Rest = EcsRest,
|
Rest = EcsRest,
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue