mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-25 01:20:04 +00:00
Improve types for SolverV2
This commit is contained in:
parent
4fc36261c2
commit
ec91a5d1e9
1 changed files with 83 additions and 59 deletions
142
src/init.luau
142
src/init.luau
|
@ -58,6 +58,11 @@ type IdRecord = {
|
||||||
cache: { ArchetypeRecord },
|
cache: { ArchetypeRecord },
|
||||||
flags: number,
|
flags: number,
|
||||||
size: number,
|
size: number,
|
||||||
|
hooks: {
|
||||||
|
on_add: ((entity: i53) -> ())?,
|
||||||
|
on_set: ((entity: i53, data: any) -> ())?,
|
||||||
|
on_remove: ((entity: i53) -> ())?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ComponentIndex = Map<i53, IdRecord>
|
type ComponentIndex = Map<i53, IdRecord>
|
||||||
|
@ -96,7 +101,7 @@ local ECS_ID_HAS_ON_SET = 0b0000_1000
|
||||||
local ECS_ID_HAS_ON_REMOVE = 0b0001_0000
|
local ECS_ID_HAS_ON_REMOVE = 0b0001_0000
|
||||||
local ECS_ID_MASK = 0b0000_0000
|
local ECS_ID_MASK = 0b0000_0000
|
||||||
|
|
||||||
local NULL_ARRAY = table.freeze({})
|
local NULL_ARRAY = table.freeze({}) :: Column
|
||||||
|
|
||||||
local function FLAGS_ADD(is_pair: boolean): number
|
local function FLAGS_ADD(is_pair: boolean): number
|
||||||
local flags = 0x0
|
local flags = 0x0
|
||||||
|
@ -287,11 +292,11 @@ end
|
||||||
local world_get: (world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?) -> ...any
|
local world_get: (world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?) -> ...any
|
||||||
do
|
do
|
||||||
-- Keeping the function as small as possible to enable inlining
|
-- Keeping the function as small as possible to enable inlining
|
||||||
local records
|
local records: { ArchetypeRecord }
|
||||||
local columns
|
local columns: {{ any }}
|
||||||
local row
|
local row: number
|
||||||
|
|
||||||
local function fetch(id)
|
local function fetch(id): any
|
||||||
local tr = records[id]
|
local tr = records[id]
|
||||||
|
|
||||||
if not tr then
|
if not tr then
|
||||||
|
@ -332,7 +337,7 @@ do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function world_get_one_inline(world: World, entity: i53, id: i53)
|
local function world_get_one_inline(world: World, entity: i53, id: i53): any
|
||||||
local record = world.entityIndex.sparse[entity]
|
local record = world.entityIndex.sparse[entity]
|
||||||
if not record then
|
if not record then
|
||||||
return nil
|
return nil
|
||||||
|
@ -388,10 +393,8 @@ local function world_has(world: World, entity: number, ...: i53): boolean
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function world_target(world: World, entity: i53, relation: i24, index): i24?
|
local function world_target(world: World, entity: i53, relation: i24, index: number?): i24?
|
||||||
if index == nil then
|
local nth = index or 0
|
||||||
index = 0
|
|
||||||
end
|
|
||||||
local record = world.entityIndex.sparse[entity]
|
local record = world.entityIndex.sparse[entity]
|
||||||
local archetype = record.archetype
|
local archetype = record.archetype
|
||||||
if not archetype then
|
if not archetype then
|
||||||
|
@ -409,11 +412,11 @@ local function world_target(world: World, entity: i53, relation: i24, index): i2
|
||||||
end
|
end
|
||||||
|
|
||||||
local count = tr.count
|
local count = tr.count
|
||||||
if index >= count then
|
if nth >= count then
|
||||||
index = index + count + 1
|
nth = nth + count + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local nth = archetype.types[index + tr.column]
|
nth = archetype.types[nth + tr.column]
|
||||||
|
|
||||||
if not nth then
|
if not nth then
|
||||||
return nil
|
return nil
|
||||||
|
@ -612,7 +615,7 @@ local function archetype_init_edge(archetype: Archetype, edge: GraphEdge, id: i5
|
||||||
edge.id = id
|
edge.id = id
|
||||||
end
|
end
|
||||||
|
|
||||||
local function archetype_ensure_edge(world, edges, id): GraphEdge
|
local function archetype_ensure_edge(world, edges: GraphEdges, id): GraphEdge
|
||||||
local edge = edges[id]
|
local edge = edges[id]
|
||||||
if not edge then
|
if not edge then
|
||||||
edge = {} :: GraphEdge
|
edge = {} :: GraphEdge
|
||||||
|
@ -639,7 +642,8 @@ local function init_edge_for_add(world, archetype, edge: GraphEdge, id, to)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function init_edge_for_remove(world, archetype, edge, id, to)
|
local function init_edge_for_remove(world: World, archetype: Archetype,
|
||||||
|
edge: GraphEdge, id: number, to: Archetype)
|
||||||
archetype_init_edge(archetype, edge, id, to)
|
archetype_init_edge(archetype, edge, id, to)
|
||||||
archetype_ensure_edge(world, archetype.node.remove, id)
|
archetype_ensure_edge(world, archetype.node.remove, id)
|
||||||
if archetype ~= to then
|
if archetype ~= to then
|
||||||
|
@ -668,7 +672,7 @@ local function create_edge_for_remove(world: World, node: Archetype, edge: Graph
|
||||||
return to
|
return to
|
||||||
end
|
end
|
||||||
|
|
||||||
local function archetype_traverse_add(world: World, id: i53, from: Archetype): Archetype
|
local function archetype_traverse_add(world: World, id: i53, from: Archetype?): Archetype
|
||||||
from = from or world.ROOT_ARCHETYPE
|
from = from or world.ROOT_ARCHETYPE
|
||||||
local edge = archetype_ensure_edge(world, from.node.add, id)
|
local edge = archetype_ensure_edge(world, from.node.add, id)
|
||||||
|
|
||||||
|
@ -717,15 +721,15 @@ local function world_add(world: World, entity: i53, id: i53): ()
|
||||||
local on_add = idr.hooks.on_add
|
local on_add = idr.hooks.on_add
|
||||||
|
|
||||||
if on_add then
|
if on_add then
|
||||||
invoke_hook(on_add, entity)
|
on_add(entity)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function world_set(world: World, entity: i53, id: i53, data: unknown): ()
|
local function world_set(world: World, entity: i53, id: i53, data: unknown): ()
|
||||||
local entityIndex = world.entityIndex
|
local entityIndex = world.entityIndex
|
||||||
local record = entityIndex.sparse[entity]
|
local record = entityIndex.sparse[entity]
|
||||||
local from = record.archetype
|
local from: Archetype = record.archetype
|
||||||
local to = archetype_traverse_add(world, id, from)
|
local to: Archetype = archetype_traverse_add(world, id, from)
|
||||||
local idr = world.componentIndex[id]
|
local idr = world.componentIndex[id]
|
||||||
local flags = idr.flags
|
local flags = idr.flags
|
||||||
local is_tag = bit32.band(flags, ECS_ID_IS_TAG) ~= 0
|
local is_tag = bit32.band(flags, ECS_ID_IS_TAG) ~= 0
|
||||||
|
@ -741,7 +745,7 @@ local function world_set(world: World, entity: i53, id: i53, data: unknown): ()
|
||||||
from.columns[tr.column][record.row] = data
|
from.columns[tr.column][record.row] = data
|
||||||
local on_set = idr_hooks.on_set
|
local on_set = idr_hooks.on_set
|
||||||
if on_set then
|
if on_set then
|
||||||
invoke_hook(on_set, entity, data)
|
on_set(entity, data)
|
||||||
end
|
end
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -759,7 +763,7 @@ local function world_set(world: World, entity: i53, id: i53, data: unknown): ()
|
||||||
|
|
||||||
local on_add = idr_hooks.on_add
|
local on_add = idr_hooks.on_add
|
||||||
if on_add then
|
if on_add then
|
||||||
invoke_hook(on_add, entity)
|
on_add(entity)
|
||||||
end
|
end
|
||||||
|
|
||||||
if is_tag then
|
if is_tag then
|
||||||
|
@ -803,7 +807,7 @@ local function world_remove(world: World, entity: i53, id: i53)
|
||||||
local idr = world.componentIndex[id]
|
local idr = world.componentIndex[id]
|
||||||
local on_remove = idr.hooks.on_remove
|
local on_remove = idr.hooks.on_remove
|
||||||
if on_remove then
|
if on_remove then
|
||||||
invoke_hook(on_remove, entity)
|
on_remove(entity)
|
||||||
end
|
end
|
||||||
|
|
||||||
entity_move(entity_index, entity, record, to)
|
entity_move(entity_index, entity, record, to)
|
||||||
|
@ -837,7 +841,7 @@ local function archetype_delete(world: World, archetype: Archetype, row: number,
|
||||||
local move = entities[last]
|
local move = entities[last]
|
||||||
local delete = entities[row]
|
local delete = entities[row]
|
||||||
entities[row] = move
|
entities[row] = move
|
||||||
entities[last] = nil
|
entities[last] = nil :: any
|
||||||
|
|
||||||
if row ~= last then
|
if row ~= last then
|
||||||
-- TODO: should be "entity_index_sparse_get(entityIndex, move)"
|
-- TODO: should be "entity_index_sparse_get(entityIndex, move)"
|
||||||
|
@ -850,7 +854,7 @@ local function archetype_delete(world: World, archetype: Archetype, row: number,
|
||||||
-- TODO: if last == 0 then deactivate table
|
-- TODO: if last == 0 then deactivate table
|
||||||
|
|
||||||
for _, id in types do
|
for _, id in types do
|
||||||
local on_remove = world_get_one_inline(world, id, EcsOnRemove)
|
local on_remove: (entity: i53) -> () = world_get_one_inline(world, id, EcsOnRemove)
|
||||||
if on_remove then
|
if on_remove then
|
||||||
on_remove(delete)
|
on_remove(delete)
|
||||||
end
|
end
|
||||||
|
@ -879,8 +883,8 @@ local function world_clear(world: World, entity: i53)
|
||||||
archetype_delete(world, archetype, row)
|
archetype_delete(world, archetype, row)
|
||||||
end
|
end
|
||||||
|
|
||||||
record.archetype = nil
|
record.archetype = nil :: any
|
||||||
record.row = nil
|
record.row = nil :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
local function archetype_disconnect_edge(edge: GraphEdge)
|
local function archetype_disconnect_edge(edge: GraphEdge)
|
||||||
|
@ -896,26 +900,26 @@ end
|
||||||
|
|
||||||
local function archetype_remove_edge(edges: Map<i53, GraphEdge>, id: i53, edge: GraphEdge)
|
local function archetype_remove_edge(edges: Map<i53, GraphEdge>, id: i53, edge: GraphEdge)
|
||||||
archetype_disconnect_edge(edge)
|
archetype_disconnect_edge(edge)
|
||||||
edges[id] = nil
|
edges[id] = nil :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
local function archetype_clear_edges(archetype: Archetype)
|
local function archetype_clear_edges(archetype: Archetype)
|
||||||
local node = archetype.node
|
local node: GraphNode = archetype.node
|
||||||
local add = node.add
|
local add: GraphEdges = node.add
|
||||||
local remove = node.remove
|
local remove: GraphEdges = node.remove
|
||||||
local node_refs = node.refs
|
local node_refs: GraphEdge = node.refs
|
||||||
for id, edge in add do
|
for id, edge in add do
|
||||||
archetype_disconnect_edge(edge)
|
archetype_disconnect_edge(edge)
|
||||||
add[id] = nil
|
add[id] = nil :: any
|
||||||
end
|
end
|
||||||
for id, edge in remove do
|
for id, edge in remove do
|
||||||
archetype_disconnect_edge(edge)
|
archetype_disconnect_edge(edge)
|
||||||
remove[id] = nil
|
remove[id] = nil :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
local cur = node_refs.next
|
local cur = node_refs.next
|
||||||
while cur do
|
while cur do
|
||||||
local edge = cur
|
local edge: GraphEdge = cur
|
||||||
local next_edge = edge.next
|
local next_edge = edge.next
|
||||||
archetype_remove_edge(edge.from.node.add, edge.id, edge)
|
archetype_remove_edge(edge.from.node.add, edge.id, edge)
|
||||||
cur = next_edge
|
cur = next_edge
|
||||||
|
@ -923,7 +927,7 @@ local function archetype_clear_edges(archetype: Archetype)
|
||||||
|
|
||||||
cur = node_refs.prev
|
cur = node_refs.prev
|
||||||
while cur do
|
while cur do
|
||||||
local edge = cur
|
local edge: GraphEdge = cur
|
||||||
local next_edge = edge.prev
|
local next_edge = edge.prev
|
||||||
archetype_remove_edge(edge.from.node.remove, edge.id, edge)
|
archetype_remove_edge(edge.from.node.remove, edge.id, edge)
|
||||||
cur = next_edge
|
cur = next_edge
|
||||||
|
@ -941,22 +945,22 @@ local function archetype_destroy(world: World, archetype: Archetype)
|
||||||
local component_index = world.componentIndex
|
local component_index = world.componentIndex
|
||||||
archetype_clear_edges(archetype)
|
archetype_clear_edges(archetype)
|
||||||
local archetype_id = archetype.id
|
local archetype_id = archetype.id
|
||||||
world.archetypes[archetype_id] = nil
|
world.archetypes[archetype_id] = nil :: any
|
||||||
world.archetypeIndex[archetype.type] = nil
|
world.archetypeIndex[archetype.type] = nil :: any
|
||||||
local records = archetype.records
|
local records = archetype.records
|
||||||
|
|
||||||
for id in records do
|
for id in records do
|
||||||
local idr = component_index[id]
|
local idr = component_index[id]
|
||||||
idr.cache[archetype_id] = nil
|
idr.cache[archetype_id] = nil :: any
|
||||||
idr.size -= 1
|
idr.size -= 1
|
||||||
records[id] = nil
|
records[id] = nil :: any
|
||||||
if idr.size == 0 then
|
if idr.size == 0 then
|
||||||
component_index[id] = nil
|
component_index[id] = nil :: any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function world_cleanup(world)
|
local function world_cleanup(world: World)
|
||||||
local archetypes = world.archetypes
|
local archetypes = world.archetypes
|
||||||
|
|
||||||
for _, archetype in archetypes do
|
for _, archetype in archetypes do
|
||||||
|
@ -965,7 +969,7 @@ local function world_cleanup(world)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local new_archetypes = table.create(#archetypes)
|
local new_archetypes = table.create(#archetypes) :: { Archetype }
|
||||||
local new_archetype_map = {}
|
local new_archetype_map = {}
|
||||||
|
|
||||||
for index, archetype in archetypes do
|
for index, archetype in archetypes do
|
||||||
|
@ -1045,12 +1049,12 @@ do
|
||||||
if object == delete then
|
if object == delete then
|
||||||
local id_record = component_index[id]
|
local id_record = component_index[id]
|
||||||
local flags = id_record.flags
|
local flags = id_record.flags
|
||||||
if bit32.band(flags, ECS_ID_DELETE) ~= 0 then
|
local flags_delete_mask: number = bit32.band(flags, ECS_ID_DELETE)
|
||||||
|
if flags_delete_mask ~= 0 then
|
||||||
for _, child in children do
|
for _, child in children do
|
||||||
-- Cascade deletions of it has Delete as component trait
|
-- Cascade deletions of it has Delete as component trait
|
||||||
world_delete(world, child, destruct)
|
world_delete(world, child, destruct)
|
||||||
end
|
end
|
||||||
|
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
for _, child in children do
|
for _, child in children do
|
||||||
|
@ -1065,7 +1069,7 @@ do
|
||||||
end
|
end
|
||||||
|
|
||||||
record.archetype = nil :: any
|
record.archetype = nil :: any
|
||||||
sparse_array[entity] = nil
|
sparse_array[entity] = nil :: any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1096,14 +1100,14 @@ local EMPTY_QUERY = {
|
||||||
|
|
||||||
setmetatable(EMPTY_QUERY, EMPTY_QUERY)
|
setmetatable(EMPTY_QUERY, EMPTY_QUERY)
|
||||||
|
|
||||||
local function query_iter_init(query)
|
local function query_iter_init(query): () -> (number, ...any)
|
||||||
local world_query_iter_next
|
local world_query_iter_next
|
||||||
|
|
||||||
local compatible_archetypes = query.compatible_archetypes
|
local compatible_archetypes = query.compatible_archetypes
|
||||||
local lastArchetype = 1
|
local lastArchetype = 1
|
||||||
local archetype = compatible_archetypes[1]
|
local archetype = compatible_archetypes[1]
|
||||||
if not archetype then
|
if not archetype then
|
||||||
return EMPTY_QUERY
|
return NOOP :: () -> (number, ...any)
|
||||||
end
|
end
|
||||||
local columns = archetype.columns
|
local columns = archetype.columns
|
||||||
local entities = archetype.entities
|
local entities = archetype.entities
|
||||||
|
@ -1112,7 +1116,8 @@ local function query_iter_init(query)
|
||||||
|
|
||||||
local ids = query.ids
|
local ids = query.ids
|
||||||
local A, B, C, D, E, F, G, H, I = unpack(ids)
|
local A, B, C, D, E, F, G, H, I = unpack(ids)
|
||||||
local a, b, c, d, e, f, g, h
|
local a: Column, b: Column, c: Column, d: Column
|
||||||
|
local e: Column, f: Column, g: Column, h: Column
|
||||||
|
|
||||||
if not B then
|
if not B then
|
||||||
a = columns[records[A].column]
|
a = columns[records[A].column]
|
||||||
|
@ -1334,7 +1339,7 @@ local function query_iter_init(query)
|
||||||
return world_query_iter_next
|
return world_query_iter_next
|
||||||
end
|
end
|
||||||
|
|
||||||
local function query_iter(query)
|
local function query_iter(query): () -> (number, ...any)
|
||||||
local query_next = query.next
|
local query_next = query.next
|
||||||
if not query_next then
|
if not query_next then
|
||||||
query_next = query_iter_init(query)
|
query_next = query_iter_init(query)
|
||||||
|
@ -1342,7 +1347,7 @@ local function query_iter(query)
|
||||||
return query_next
|
return query_next
|
||||||
end
|
end
|
||||||
|
|
||||||
local function query_without(query, ...)
|
local function query_without(query: { compatible_archetypes: { Archetype } }, ...)
|
||||||
local compatible_archetypes = query.compatible_archetypes
|
local compatible_archetypes = query.compatible_archetypes
|
||||||
local N = select("#", ...)
|
local N = select("#", ...)
|
||||||
for i = #compatible_archetypes, 1, -1 do
|
for i = #compatible_archetypes, 1, -1 do
|
||||||
|
@ -1363,7 +1368,7 @@ local function query_without(query, ...)
|
||||||
if last ~= i then
|
if last ~= i then
|
||||||
compatible_archetypes[i] = compatible_archetypes[last]
|
compatible_archetypes[i] = compatible_archetypes[last]
|
||||||
end
|
end
|
||||||
compatible_archetypes[last] = nil
|
compatible_archetypes[last] = nil :: any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1371,10 +1376,10 @@ local function query_without(query, ...)
|
||||||
return EMPTY_QUERY
|
return EMPTY_QUERY
|
||||||
end
|
end
|
||||||
|
|
||||||
return query
|
return query :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
local function query_with(query, ...)
|
local function query_with(query: { compatible_archetypes: { Archetype } }, ...)
|
||||||
local compatible_archetypes = query.compatible_archetypes
|
local compatible_archetypes = query.compatible_archetypes
|
||||||
local N = select("#", ...)
|
local N = select("#", ...)
|
||||||
for i = #compatible_archetypes, 1, -1 do
|
for i = #compatible_archetypes, 1, -1 do
|
||||||
|
@ -1395,13 +1400,13 @@ local function query_with(query, ...)
|
||||||
if last ~= i then
|
if last ~= i then
|
||||||
compatible_archetypes[i] = compatible_archetypes[last]
|
compatible_archetypes[i] = compatible_archetypes[last]
|
||||||
end
|
end
|
||||||
compatible_archetypes[last] = nil
|
compatible_archetypes[last] = nil :: any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if #compatible_archetypes == 0 then
|
if #compatible_archetypes == 0 then
|
||||||
return EMPTY_QUERY
|
return EMPTY_QUERY
|
||||||
end
|
end
|
||||||
return query
|
return query :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Meant for directly iterating over archetypes to minimize
|
-- Meant for directly iterating over archetypes to minimize
|
||||||
|
@ -1427,7 +1432,7 @@ local function world_query(world: World, ...)
|
||||||
|
|
||||||
local archetypes = world.archetypes
|
local archetypes = world.archetypes
|
||||||
|
|
||||||
local idr: IdRecord
|
local idr: IdRecord?
|
||||||
local componentIndex = world.componentIndex
|
local componentIndex = world.componentIndex
|
||||||
|
|
||||||
for _, id in ids do
|
for _, id in ids do
|
||||||
|
@ -1441,6 +1446,10 @@ local function world_query(world: World, ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not idr then
|
||||||
|
return EMPTY_QUERY
|
||||||
|
end
|
||||||
|
|
||||||
for archetype_id in idr.cache do
|
for archetype_id in idr.cache do
|
||||||
local compatibleArchetype = archetypes[archetype_id]
|
local compatibleArchetype = archetypes[archetype_id]
|
||||||
if #compatibleArchetype.entities == 0 then
|
if #compatibleArchetype.entities == 0 then
|
||||||
|
@ -1647,13 +1656,28 @@ function World.new()
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
export type Id<T = nil> = Entity<T> | Pair
|
export type Id<T = nil> = Entity<T> | Pair<Entity<T>, Entity<unknown>>
|
||||||
|
|
||||||
export type Pair = number
|
export type Pair<First, Second> = number & {
|
||||||
|
__relation: First
|
||||||
|
}
|
||||||
|
|
||||||
|
-- type function _Pair(first, second)
|
||||||
|
-- local thing = first:components()[2]
|
||||||
|
|
||||||
|
-- if thing:readproperty(types.singleton("__T")):is("nil") then
|
||||||
|
-- return second
|
||||||
|
-- else
|
||||||
|
-- return first
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
|
|
||||||
|
-- type TestPair = _Pair<Entity<nil>, Entity<Vector3>>
|
||||||
|
|
||||||
type Item<T...> = (self: Query<T...>) -> (Entity, T...)
|
type Item<T...> = (self: Query<T...>) -> (Entity, T...)
|
||||||
|
|
||||||
export type Entity<T = nil> = number & { __T: T }
|
export type Entity<T = nil> = number & { read __T: T }
|
||||||
|
|
||||||
type Iter<T...> = (query: Query<T...>) -> () -> (Entity, T...)
|
type Iter<T...> = (query: Query<T...>) -> () -> (Entity, T...)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue