mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Please the type solver overlord
This commit is contained in:
parent
a62cb370cf
commit
1553362014
1 changed files with 108 additions and 38 deletions
146
lib/init.lua
146
lib/init.lua
|
@ -23,7 +23,7 @@ type Archetype = {
|
||||||
type: string | number,
|
type: string | number,
|
||||||
entities: { number },
|
entities: { number },
|
||||||
columns: { Column },
|
columns: { Column },
|
||||||
records: {},
|
records: { [number]: number },
|
||||||
}
|
}
|
||||||
|
|
||||||
type Record = {
|
type Record = {
|
||||||
|
@ -47,7 +47,7 @@ TODO:
|
||||||
]]
|
]]
|
||||||
|
|
||||||
type ArchetypeMap = {
|
type ArchetypeMap = {
|
||||||
cache: { [number]: ArchetypeRecord },
|
cache: { ArchetypeRecord },
|
||||||
first: ArchetypeMap,
|
first: ArchetypeMap,
|
||||||
second: ArchetypeMap,
|
second: ArchetypeMap,
|
||||||
parent: ArchetypeMap,
|
parent: ArchetypeMap,
|
||||||
|
@ -136,7 +136,7 @@ local function ECS_ENTITY_T_HI(e: i53): i24
|
||||||
end
|
end
|
||||||
|
|
||||||
-- SECOND
|
-- SECOND
|
||||||
local function ECS_ENTITY_T_LO(e: i53)
|
local function ECS_ENTITY_T_LO(e: i53): i24
|
||||||
if e > ECS_ENTITY_MASK then
|
if e > ECS_ENTITY_MASK then
|
||||||
e = e // 0x10
|
e = e // 0x10
|
||||||
return e // ECS_ENTITY_MASK
|
return e // ECS_ENTITY_MASK
|
||||||
|
@ -145,7 +145,7 @@ local function ECS_ENTITY_T_LO(e: i53)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ECS_PAIR(pred: i53, obj: i53): i53
|
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)
|
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)
|
local function getAlive(entityIndex: EntityIndex, id: i24)
|
||||||
|
@ -163,7 +163,7 @@ local function ECS_PAIR_OBJECT(entityIndex, 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: EntityIndex, index: i24): i53
|
||||||
--local id = ECS_COMBINE(index, 0)
|
--local id = ECS_COMBINE(index, 0)
|
||||||
local id = index
|
local id = index
|
||||||
entityIndex.sparse[id] = {
|
entityIndex.sparse[id] = {
|
||||||
|
@ -219,7 +219,7 @@ local function transitionArchetype(
|
||||||
sourceEntities[sourceRow] = e2
|
sourceEntities[sourceRow] = e2
|
||||||
end
|
end
|
||||||
|
|
||||||
sourceEntities[movedAway] = nil
|
sourceEntities[movedAway] = nil :: any
|
||||||
destinationEntities[destinationRow] = e1
|
destinationEntities[destinationRow] = e1
|
||||||
|
|
||||||
local record1 = sparse[e1]
|
local record1 = sparse[e1]
|
||||||
|
@ -265,7 +265,7 @@ local function ensureComponentRecord(
|
||||||
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 = {} }
|
||||||
componentIndex[componentId] = archetypesMap
|
componentIndex[componentId] = archetypesMap
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ local function archetypeOf(world: any, types: { i24 }, prev: Archetype?): Archet
|
||||||
world.nextArchetypeId = id
|
world.nextArchetypeId = id
|
||||||
|
|
||||||
local length = #types
|
local length = #types
|
||||||
local columns = table.create(length)
|
local columns = (table.create(length) :: any) :: { Column }
|
||||||
local componentIndex = world.componentIndex
|
local componentIndex = world.componentIndex
|
||||||
|
|
||||||
local records = {}
|
local records = {}
|
||||||
|
@ -311,7 +311,7 @@ local function archetypeOf(world: any, types: { i24 }, prev: Archetype?): Archet
|
||||||
columns[i] = {}
|
columns[i] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
local archetype = {
|
local archetype: Archetype = {
|
||||||
columns = columns,
|
columns = columns,
|
||||||
edges = {},
|
edges = {},
|
||||||
entities = {},
|
entities = {},
|
||||||
|
@ -320,6 +320,7 @@ local function archetypeOf(world: any, types: { i24 }, prev: Archetype?): Archet
|
||||||
type = ty,
|
type = ty,
|
||||||
types = types,
|
types = types,
|
||||||
}
|
}
|
||||||
|
|
||||||
world.archetypeIndex[ty] = archetype
|
world.archetypeIndex[ty] = archetype
|
||||||
world.archetypes[id] = archetype
|
world.archetypes[id] = archetype
|
||||||
|
|
||||||
|
@ -330,12 +331,12 @@ local World = {}
|
||||||
World.__index = World
|
World.__index = World
|
||||||
function World.new()
|
function World.new()
|
||||||
local self = setmetatable({
|
local self = setmetatable({
|
||||||
archetypeIndex = {},
|
archetypeIndex = {} :: { [string]: Archetype },
|
||||||
archetypes = {} :: Archetypes,
|
archetypes = {} :: Archetypes,
|
||||||
componentIndex = {} :: ComponentIndex,
|
componentIndex = {} :: ComponentIndex,
|
||||||
entityIndex = {
|
entityIndex = {
|
||||||
dense = {},
|
dense = {} :: { [i24]: i53 },
|
||||||
sparse = {},
|
sparse = {} :: { [i53]: Record },
|
||||||
} :: EntityIndex,
|
} :: EntityIndex,
|
||||||
hooks = {
|
hooks = {
|
||||||
[ON_ADD] = {},
|
[ON_ADD] = {},
|
||||||
|
@ -349,6 +350,8 @@ function World.new()
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
export type World = typeof(World.new())
|
||||||
|
|
||||||
function World.component(world: World)
|
function World.component(world: World)
|
||||||
local componentId = world.nextComponentId + 1
|
local componentId = world.nextComponentId + 1
|
||||||
if componentId > HI_COMPONENT_ID then
|
if componentId > HI_COMPONENT_ID then
|
||||||
|
@ -391,7 +394,7 @@ 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: { Column }, count: number, row: number)
|
||||||
if row == count then
|
if row == count then
|
||||||
for _, column in columns do
|
for _, column in columns do
|
||||||
column[count] = nil
|
column[count] = nil
|
||||||
|
@ -415,7 +418,7 @@ local function archetypeDelete(world: World, id: i53)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
componentIndex[id] = nil
|
componentIndex[id] = nil :: any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -444,20 +447,18 @@ function World.delete(world: World, entityId: i53)
|
||||||
sparse[entityToMove] = record
|
sparse[entityToMove] = record
|
||||||
end
|
end
|
||||||
|
|
||||||
entities[row], entities[last] = entities[last], nil
|
entities[row], entities[last] = entities[last], nil :: any
|
||||||
|
|
||||||
local columns = archetype.columns
|
local columns = archetype.columns
|
||||||
|
|
||||||
destructColumns(columns, last, row)
|
destructColumns(columns, last, row)
|
||||||
end
|
end
|
||||||
|
|
||||||
sparse[entityId] = nil
|
sparse[entityId] = nil :: any
|
||||||
dense[#dense] = nil
|
dense[#dense] = nil :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
export type World = typeof(World.new())
|
local function ensureArchetype(world: World, types, prev): Archetype
|
||||||
|
|
||||||
local function ensureArchetype(world: World, types, prev)
|
|
||||||
if #types < 1 then
|
if #types < 1 then
|
||||||
return world.ROOT_ARCHETYPE
|
return world.ROOT_ARCHETYPE
|
||||||
end
|
end
|
||||||
|
@ -853,17 +854,17 @@ 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 }
|
||||||
export type Pair = number
|
export type Pair = number
|
||||||
|
|
||||||
export type QueryShim<T...> = typeof(setmetatable({
|
export type QueryShim<T...> = typeof(setmetatable({
|
||||||
without = function(...): QueryShim<T...>
|
without = function(...): QueryShim<T...>
|
||||||
return nil :: any
|
return nil :: any
|
||||||
end
|
end,
|
||||||
}, {
|
}, {
|
||||||
__iter = function(): () -> (number, T...)
|
__iter = function(): () -> (number, T...)
|
||||||
return nil :: any
|
return nil :: any
|
||||||
end
|
end,
|
||||||
}))
|
}))
|
||||||
export type WorldShim = typeof(setmetatable(
|
export type WorldShim = typeof(setmetatable(
|
||||||
{} :: {
|
{} :: {
|
||||||
|
@ -878,7 +879,7 @@ export type WorldShim = typeof(setmetatable(
|
||||||
target: (WorldShim, id: Entity, relation: Entity) -> Entity?,
|
target: (WorldShim, id: Entity, relation: Entity) -> Entity?,
|
||||||
--- Deletes an entity and all it's related components and relationships.
|
--- Deletes an entity and all it's related components and relationships.
|
||||||
delete: (WorldShim, id: Entity) -> (),
|
delete: (WorldShim, id: Entity) -> (),
|
||||||
|
|
||||||
--- Adds a component to the entity with no value
|
--- Adds a component to the entity with no value
|
||||||
add: <T>(WorldShim, id: Entity, component: Entity<T>) -> (),
|
add: <T>(WorldShim, id: Entity, component: Entity<T>) -> (),
|
||||||
--- Assigns a value to a component on the given entity
|
--- Assigns a value to a component on the given entity
|
||||||
|
@ -886,33 +887,102 @@ export type WorldShim = typeof(setmetatable(
|
||||||
--- Removes a component from the given entity
|
--- Removes a component from the given entity
|
||||||
remove: (WorldShim, id: Entity, component: Entity) -> (),
|
remove: (WorldShim, id: Entity, component: Entity) -> (),
|
||||||
--- Retrieves the value of up to 4 components. These values may be nil.
|
--- Retrieves the value of up to 4 components. These values may be nil.
|
||||||
get:
|
get: (<A>(WorldShim, id: any, Entity<A>) -> A)
|
||||||
(<A>(WorldShim, id: any, Entity<A>) -> A)
|
|
||||||
& (<A, B>(WorldShim, id: Entity, Entity<A>, Entity<B>) -> (A, B))
|
& (<A, B>(WorldShim, id: Entity, Entity<A>, Entity<B>) -> (A, B))
|
||||||
& (<A, B, C>(WorldShim, id: Entity, Entity<A>, Entity<B>, Entity<C>) -> (A, B, C))
|
& (<A, B, C>(WorldShim, id: Entity, Entity<A>, Entity<B>, Entity<C>) -> (A, B, C))
|
||||||
& <A, B, C, D>(WorldShim, id: Entity, Entity<A>, Entity<B>, Entity<C>, Entity<D>) -> (A, B, C, D),
|
& <A, B, C, D>(WorldShim, id: Entity, Entity<A>, Entity<B>, Entity<C>, Entity<D>) -> (A, B, C, D),
|
||||||
|
|
||||||
--- Searches the world for entities that match a given query
|
--- Searches the world for entities that match a given query
|
||||||
query: (<A>(WorldShim, Entity<A>) -> QueryShim<A>)
|
query: (<A>(WorldShim, Entity<A>) -> QueryShim<A>)
|
||||||
& (<A, B>(WorldShim, Entity<A>, Entity<B>) -> QueryShim<A, B>)
|
& (<A, B>(WorldShim, Entity<A>, Entity<B>) -> QueryShim<A, B>)
|
||||||
& (<A, B, C>(WorldShim, Entity<A>, Entity<B>, Entity<C>) -> QueryShim<A, B, C>)
|
& (<A, B, C>(WorldShim, Entity<A>, Entity<B>, Entity<C>) -> QueryShim<A, B, C>)
|
||||||
& (<A, B, C, D>(WorldShim, Entity<A>, Entity<B>, Entity<C>, Entity<D>) -> QueryShim<A, B, C, D>)
|
& (<A, B, C, D>(WorldShim, Entity<A>, Entity<B>, Entity<C>, Entity<D>) -> QueryShim<A, B, C, D>)
|
||||||
& (<A, B, C, D, E>(WorldShim, Entity<A>, Entity<B>, Entity<C>, Entity<D>, Entity<E>) -> QueryShim<A, B, C, D, E>)
|
& (<A, B, C, D, E>(
|
||||||
& (<A, B, C, D, E, F>(WorldShim, Entity<A>, Entity<B>, Entity<C>, Entity<D>, Entity<E>, Entity<F>) -> QueryShim<A, B, C, D, E, F>)
|
WorldShim,
|
||||||
& (<A, B, C, D, E, F, G>(WorldShim, Entity<A>, Entity<B>, Entity<C>, Entity<D>, Entity<E>, Entity<F>, Entity<G>) -> QueryShim<A, B, C, D, E, F, G>)
|
Entity<A>,
|
||||||
& (<A, B, C, D, E, F, G, H>(WorldShim, Entity<A>, Entity<B>, Entity<C>, Entity<D>, Entity<E>, Entity<F>, Entity<G>, Entity<H>) -> QueryShim<A, B, C, D, E, F, G, H>)
|
Entity<B>,
|
||||||
& (<A, B, C, D, E, F, G, H, I>(WorldShim, Entity<A>, Entity<B>, Entity<C>, Entity<D>, Entity<E>, Entity<F>, Entity<G>, Entity<H>, Entity<I>) -> QueryShim<A, B, C, D, E, F, G, H, I>)
|
Entity<C>,
|
||||||
& (<A, B, C, D, E, F, G, H, I, J>(WorldShim, Entity<A>, Entity<B>, Entity<C>, Entity<D>, Entity<E>, Entity<F>, Entity<G>, Entity<H>, Entity<I>, Entity<J>) -> QueryShim<A, B, C, D, E, F, G, H, I, J>)
|
Entity<D>,
|
||||||
& (<A, B, C, D, E, F, G, H, I, J, K>(WorldShim, Entity<A>, Entity<B>, Entity<C>, Entity<D>, Entity<E>, Entity<F>, Entity<G>, Entity<H>, Entity<I>, Entity<J>, Entity<K>, ...Entity<any>) -> QueryShim<A, B, C, D, E, F, G, H, I, J, K>)
|
Entity<E>
|
||||||
|
) -> QueryShim<A, B, C, D, E>)
|
||||||
|
& (<A, B, C, D, E, F>(
|
||||||
|
WorldShim,
|
||||||
|
Entity<A>,
|
||||||
|
Entity<B>,
|
||||||
|
Entity<C>,
|
||||||
|
Entity<D>,
|
||||||
|
Entity<E>,
|
||||||
|
Entity<F>
|
||||||
|
) -> QueryShim<A, B, C, D, E, F>)
|
||||||
|
& (<A, B, C, D, E, F, G>(
|
||||||
|
WorldShim,
|
||||||
|
Entity<A>,
|
||||||
|
Entity<B>,
|
||||||
|
Entity<C>,
|
||||||
|
Entity<D>,
|
||||||
|
Entity<E>,
|
||||||
|
Entity<F>,
|
||||||
|
Entity<G>
|
||||||
|
) -> QueryShim<A, B, C, D, E, F, G>)
|
||||||
|
& (<A, B, C, D, E, F, G, H>(
|
||||||
|
WorldShim,
|
||||||
|
Entity<A>,
|
||||||
|
Entity<B>,
|
||||||
|
Entity<C>,
|
||||||
|
Entity<D>,
|
||||||
|
Entity<E>,
|
||||||
|
Entity<F>,
|
||||||
|
Entity<G>,
|
||||||
|
Entity<H>
|
||||||
|
) -> QueryShim<A, B, C, D, E, F, G, H>)
|
||||||
|
& (<A, B, C, D, E, F, G, H, I>(
|
||||||
|
WorldShim,
|
||||||
|
Entity<A>,
|
||||||
|
Entity<B>,
|
||||||
|
Entity<C>,
|
||||||
|
Entity<D>,
|
||||||
|
Entity<E>,
|
||||||
|
Entity<F>,
|
||||||
|
Entity<G>,
|
||||||
|
Entity<H>,
|
||||||
|
Entity<I>
|
||||||
|
) -> QueryShim<A, B, C, D, E, F, G, H, I>)
|
||||||
|
& (<A, B, C, D, E, F, G, H, I, J>(
|
||||||
|
WorldShim,
|
||||||
|
Entity<A>,
|
||||||
|
Entity<B>,
|
||||||
|
Entity<C>,
|
||||||
|
Entity<D>,
|
||||||
|
Entity<E>,
|
||||||
|
Entity<F>,
|
||||||
|
Entity<G>,
|
||||||
|
Entity<H>,
|
||||||
|
Entity<I>,
|
||||||
|
Entity<J>
|
||||||
|
) -> QueryShim<A, B, C, D, E, F, G, H, I, J>)
|
||||||
|
& (<A, B, C, D, E, F, G, H, I, J, K>(
|
||||||
|
WorldShim,
|
||||||
|
Entity<A>,
|
||||||
|
Entity<B>,
|
||||||
|
Entity<C>,
|
||||||
|
Entity<D>,
|
||||||
|
Entity<E>,
|
||||||
|
Entity<F>,
|
||||||
|
Entity<G>,
|
||||||
|
Entity<H>,
|
||||||
|
Entity<I>,
|
||||||
|
Entity<J>,
|
||||||
|
Entity<K>,
|
||||||
|
...Entity<any>
|
||||||
|
) -> QueryShim<A, B, C, D, E, F, G, H, I, J, K>),
|
||||||
},
|
},
|
||||||
{} :: {
|
{} :: {
|
||||||
__iter: (world: WorldShim) -> () -> (number, {[unknown]: unknown?})
|
__iter: (world: WorldShim) -> () -> (number, { [unknown]: unknown? }),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
||||||
return table.freeze({
|
return table.freeze({
|
||||||
World = (World :: any) :: {new: () -> WorldShim},
|
World = (World :: any) :: { new: () -> WorldShim },
|
||||||
|
|
||||||
OnAdd = (ON_ADD :: any) :: Entity,
|
OnAdd = (ON_ADD :: any) :: Entity,
|
||||||
OnRemove = (ON_REMOVE :: any) :: Entity,
|
OnRemove = (ON_REMOVE :: any) :: Entity,
|
||||||
|
@ -930,5 +1000,5 @@ return table.freeze({
|
||||||
ECS_PAIR_OBJECT = ECS_PAIR_OBJECT,
|
ECS_PAIR_OBJECT = ECS_PAIR_OBJECT,
|
||||||
|
|
||||||
pair = (ECS_PAIR :: any) :: <R, T>(pred: Entity, obj: Entity) -> number,
|
pair = (ECS_PAIR :: any) :: <R, T>(pred: Entity, obj: Entity) -> number,
|
||||||
getAlive = getAlive
|
getAlive = getAlive,
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue