mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Change casing
This commit is contained in:
parent
1b6cdd4791
commit
459e670ce9
5 changed files with 319 additions and 158 deletions
1
.luaurc
1
.luaurc
|
@ -2,6 +2,5 @@
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"jecs": "src",
|
"jecs": "src",
|
||||||
"testkit": "testkit",
|
"testkit": "testkit",
|
||||||
"mirror": "mirror"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
161
benches/cached.luau
Normal file
161
benches/cached.luau
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
|
||||||
|
local jecs = require("@jecs")
|
||||||
|
local mirror = require("../mirror/init")
|
||||||
|
|
||||||
|
type i53 = number
|
||||||
|
|
||||||
|
do
|
||||||
|
TITLE(testkit.color.white_underline("Jecs query"))
|
||||||
|
local ecs = jecs.World.new()
|
||||||
|
do
|
||||||
|
TITLE("one component in common")
|
||||||
|
|
||||||
|
local function view_bench(world: jecs.World, A: i53, B: i53, C: i53, D: i53, E: i53, F: i53, G: i53, H: i53)
|
||||||
|
BENCH("4 component", function()
|
||||||
|
for _ in world:query(D, C, B, A) do
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local D1 = ecs:component()
|
||||||
|
local D2 = ecs:component()
|
||||||
|
local D3 = ecs:component()
|
||||||
|
local D4 = ecs:component()
|
||||||
|
local D5 = ecs:component()
|
||||||
|
local D6 = ecs:component()
|
||||||
|
local D7 = ecs:component()
|
||||||
|
local D8 = ecs:component()
|
||||||
|
|
||||||
|
local function flip()
|
||||||
|
return math.random() >= 0.15
|
||||||
|
end
|
||||||
|
|
||||||
|
local added = 0
|
||||||
|
local archetypes = {}
|
||||||
|
for i = 1, 2 ^ 16 - 2 do
|
||||||
|
local entity = ecs:entity()
|
||||||
|
|
||||||
|
local combination = ""
|
||||||
|
|
||||||
|
if flip() then
|
||||||
|
combination ..= "B"
|
||||||
|
ecs:set(entity, D2, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "C"
|
||||||
|
ecs:set(entity, D3, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "D"
|
||||||
|
ecs:set(entity, D4, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "E"
|
||||||
|
ecs:set(entity, D5, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "F"
|
||||||
|
ecs:set(entity, D6, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "G"
|
||||||
|
ecs:set(entity, D7, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "H"
|
||||||
|
ecs:set(entity, D8, {value = true})
|
||||||
|
end
|
||||||
|
|
||||||
|
if #combination == 7 then
|
||||||
|
added += 1
|
||||||
|
ecs:set(entity, D1, {value = true})
|
||||||
|
end
|
||||||
|
archetypes[combination] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local a = 0
|
||||||
|
for _ in archetypes do
|
||||||
|
a += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
view_bench(ecs, D1, D2, D3, D4, D5, D6, D7, D8)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
TITLE(testkit.color.white_underline("Mirror query"))
|
||||||
|
local ecs = mirror.World.new()
|
||||||
|
do
|
||||||
|
TITLE("one component in common")
|
||||||
|
|
||||||
|
local function view_bench(world: jecs.World, A: i53, B: i53, C: i53, D: i53, E: i53, F: i53, G: i53, H: i53)
|
||||||
|
BENCH("4 component", function()
|
||||||
|
for _ in world:query(D, C, B, A) do
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local D1 = ecs:component()
|
||||||
|
local D2 = ecs:component()
|
||||||
|
local D3 = ecs:component()
|
||||||
|
local D4 = ecs:component()
|
||||||
|
local D5 = ecs:component()
|
||||||
|
local D6 = ecs:component()
|
||||||
|
local D7 = ecs:component()
|
||||||
|
local D8 = ecs:component()
|
||||||
|
|
||||||
|
local function flip()
|
||||||
|
return math.random() >= 0.15
|
||||||
|
end
|
||||||
|
|
||||||
|
local added = 0
|
||||||
|
local archetypes = {}
|
||||||
|
for i = 1, 2 ^ 16 - 2 do
|
||||||
|
local entity = ecs:entity()
|
||||||
|
|
||||||
|
local combination = ""
|
||||||
|
|
||||||
|
if flip() then
|
||||||
|
combination ..= "B"
|
||||||
|
ecs:set(entity, D2, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "C"
|
||||||
|
ecs:set(entity, D3, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "D"
|
||||||
|
ecs:set(entity, D4, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "E"
|
||||||
|
ecs:set(entity, D5, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "F"
|
||||||
|
ecs:set(entity, D6, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "G"
|
||||||
|
ecs:set(entity, D7, {value = true})
|
||||||
|
end
|
||||||
|
if flip() then
|
||||||
|
combination ..= "H"
|
||||||
|
ecs:set(entity, D8, {value = true})
|
||||||
|
end
|
||||||
|
|
||||||
|
if #combination == 7 then
|
||||||
|
added += 1
|
||||||
|
ecs:set(entity, D1, {value = true})
|
||||||
|
end
|
||||||
|
archetypes[combination] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local a = 0
|
||||||
|
for _ in archetypes do
|
||||||
|
a += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
view_bench(ecs, D1, D2, D3, D4, D5, D6, D7, D8)
|
||||||
|
end
|
||||||
|
end
|
|
@ -52,7 +52,7 @@ local E8 = mcs:entity()
|
||||||
|
|
||||||
local registry2 = ecr.registry()
|
local registry2 = ecr.registry()
|
||||||
|
|
||||||
local function flip()
|
local function flip()
|
||||||
return math.random() >= 0.15
|
return math.random() >= 0.15
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -61,80 +61,80 @@ local N = 2^16-2
|
||||||
local archetypes = {}
|
local archetypes = {}
|
||||||
|
|
||||||
local hm = 0
|
local hm = 0
|
||||||
for i = 1, N do
|
for i = 1, N do
|
||||||
local id = registry2.create()
|
local id = registry2.create()
|
||||||
local combination = ""
|
local combination = ""
|
||||||
local n = newWorld:spawn()
|
local n = newWorld:spawn()
|
||||||
local entity = ecs:entity()
|
local entity = ecs:entity()
|
||||||
local m = mcs:entity()
|
local m = mcs:entity()
|
||||||
|
|
||||||
if flip() then
|
if flip() then
|
||||||
combination ..= "B"
|
combination ..= "B"
|
||||||
registry2:set(id, B2, {value = true})
|
registry2:set(id, B2, {value = true})
|
||||||
ecs:set(entity, D2, { value = true})
|
ecs:set(entity, D2, { value = true})
|
||||||
mcs:set(m, E2, { value = 2})
|
mcs:set(m, E2, { value = 2})
|
||||||
newWorld:insert(n, A2({value = true}))
|
newWorld:insert(n, A2({value = true}))
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
combination ..= "C"
|
combination ..= "C"
|
||||||
registry2:set(id, B3, {value = true})
|
registry2:set(id, B3, {value = true})
|
||||||
ecs:set(entity, D3, { value = true})
|
ecs:set(entity, D3, { value = true})
|
||||||
mcs:set(m, E3, { value = 2})
|
mcs:set(m, E3, { value = 2})
|
||||||
newWorld:insert(n, A3({value = true}))
|
newWorld:insert(n, A3({value = true}))
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
combination ..= "D"
|
combination ..= "D"
|
||||||
registry2:set(id, B4, {value = true})
|
registry2:set(id, B4, {value = true})
|
||||||
ecs:set(entity, D4, { value = true})
|
ecs:set(entity, D4, { value = true})
|
||||||
mcs:set(m, E4, { value = 2})
|
mcs:set(m, E4, { value = 2})
|
||||||
|
|
||||||
newWorld:insert(n, A4({value = true}))
|
newWorld:insert(n, A4({value = true}))
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
combination ..= "E"
|
combination ..= "E"
|
||||||
registry2:set(id, B5, {value = true})
|
registry2:set(id, B5, {value = true})
|
||||||
ecs:set(entity, D5, { value = true})
|
ecs:set(entity, D5, { value = true})
|
||||||
mcs:set(m, E5, { value = 2})
|
mcs:set(m, E5, { value = 2})
|
||||||
|
|
||||||
newWorld:insert(n, A5({value = true}))
|
newWorld:insert(n, A5({value = true}))
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
combination ..= "F"
|
combination ..= "F"
|
||||||
registry2:set(id, B6, {value = true})
|
registry2:set(id, B6, {value = true})
|
||||||
ecs:set(entity, D6, { value = true})
|
ecs:set(entity, D6, { value = true})
|
||||||
mcs:set(m, E6, { value = 2})
|
mcs:set(m, E6, { value = 2})
|
||||||
newWorld:insert(n, A6({value = true}))
|
newWorld:insert(n, A6({value = true}))
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
combination ..= "G"
|
combination ..= "G"
|
||||||
registry2:set(id, B7, {value = true})
|
registry2:set(id, B7, {value = true})
|
||||||
ecs:set(entity, D7, { value = true})
|
ecs:set(entity, D7, { value = true})
|
||||||
mcs:set(m, E7, { value = 2})
|
mcs:set(m, E7, { value = 2})
|
||||||
newWorld:insert(n, A7({value = true}))
|
newWorld:insert(n, A7({value = true}))
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
combination ..= "H"
|
combination ..= "H"
|
||||||
registry2:set(id, B8, {value = true})
|
registry2:set(id, B8, {value = true})
|
||||||
newWorld:insert(n, A8({value = true}))
|
newWorld:insert(n, A8({value = true}))
|
||||||
ecs:set(entity, D8, { value = true})
|
ecs:set(entity, D8, { value = true})
|
||||||
mcs:set(m, E8, { value = 2})
|
mcs:set(m, E8, { value = 2})
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if #combination == 7 then
|
if #combination == 7 then
|
||||||
combination = "A" .. combination
|
combination = "A" .. combination
|
||||||
common += 1
|
common += 1
|
||||||
registry2:set(id, B1, {value = true})
|
registry2:set(id, B1, {value = true})
|
||||||
ecs:set(entity, D1, { value = true})
|
ecs:set(entity, D1, { value = true})
|
||||||
newWorld:insert(n, A1({value = true}))
|
newWorld:insert(n, A1({value = true}))
|
||||||
mcs:set(m, E1, { value = 2})
|
mcs:set(m, E1, { value = 2})
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if combination:find("BCDF") then
|
if combination:find("BCDF") then
|
||||||
if not archetypes[combination] then
|
if not archetypes[combination] then
|
||||||
print(combination)
|
print(combination)
|
||||||
end
|
end
|
||||||
hm += 1
|
hm += 1
|
||||||
end
|
end
|
||||||
archetypes[combination] = true
|
archetypes[combination] = true
|
||||||
|
@ -149,7 +149,7 @@ local green = rgb.green
|
||||||
local WALL = gray(" │ ")
|
local WALL = gray(" │ ")
|
||||||
|
|
||||||
local numberOfArchetypes = 0
|
local numberOfArchetypes = 0
|
||||||
for _ in archetypes do
|
for _ in archetypes do
|
||||||
numberOfArchetypes += 1
|
numberOfArchetypes += 1
|
||||||
end
|
end
|
||||||
print(common)
|
print(common)
|
||||||
|
@ -167,36 +167,22 @@ print(
|
||||||
return {
|
return {
|
||||||
ParameterGenerator = function()
|
ParameterGenerator = function()
|
||||||
return
|
return
|
||||||
end,
|
end,
|
||||||
|
|
||||||
Functions = {
|
Functions = {
|
||||||
Mirror = function()
|
ECR = function()
|
||||||
local matched = 0
|
local matched = 0
|
||||||
for entityId, firstComponent in mcs:query(E1, E4, E6, E8) do
|
for entityId, firstComponent in registry2:view(B1, B4) do
|
||||||
matched += 1
|
matched += 1
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
Matter = function()
|
Jecs = function()
|
||||||
local matched = 0
|
local matched = 0
|
||||||
for entityId, firstComponent in newWorld:query(A1, A4, A6, A8) do
|
for entityId, firstComponent in ecs:query(D1, D4) do
|
||||||
matched += 1
|
matched += 1
|
||||||
end
|
end
|
||||||
end,
|
|
||||||
|
|
||||||
ECR = function()
|
|
||||||
local matched = 0
|
|
||||||
for entityId, firstComponent in registry2:view(B1, B4, B6, B8) do
|
|
||||||
matched += 1
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
Jecs = function()
|
|
||||||
local matched = 0
|
|
||||||
for entityId, firstComponent in ecs:query(D1, D4, D6, D8) do
|
|
||||||
matched += 1
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
|
|
184
src/init.luau
184
src/init.luau
|
@ -142,7 +142,7 @@ end
|
||||||
local ERROR_ENTITY_NOT_ALIVE = "Entity is not alive"
|
local ERROR_ENTITY_NOT_ALIVE = "Entity is not alive"
|
||||||
local ERROR_GENERATION_INVALID = "INVALID GENERATION"
|
local ERROR_GENERATION_INVALID = "INVALID GENERATION"
|
||||||
|
|
||||||
local function getAlive(index: EntityIndex, e: i24): i53
|
local function entity_index_get_alive(index: EntityIndex, e: i24): i53
|
||||||
local denseArray = index.dense
|
local denseArray = index.dense
|
||||||
local id = denseArray[ECS_ENTITY_T_LO(e)]
|
local id = denseArray[ECS_ENTITY_T_LO(e)]
|
||||||
|
|
||||||
|
@ -159,18 +159,18 @@ local function getAlive(index: EntityIndex, e: i24): i53
|
||||||
error(ERROR_ENTITY_NOT_ALIVE)
|
error(ERROR_ENTITY_NOT_ALIVE)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function sparseGet(entityIndex, id)
|
local function entity_index_sparse_get(entityIndex, id)
|
||||||
return entityIndex.sparse[getAlive(entityIndex, id)]
|
return entityIndex.sparse[entity_index_get_alive(entityIndex, id)]
|
||||||
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)
|
||||||
return getAlive(entityIndex, ECS_ENTITY_T_HI(e))
|
return entity_index_get_alive(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)
|
||||||
return getAlive(entityIndex, ECS_ENTITY_T_LO(e))
|
return entity_index_get_alive(entityIndex, ECS_ENTITY_T_LO(e))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function entity_index_new_id(entityIndex: EntityIndex, index: i24): i53
|
local function entity_index_new_id(entityIndex: EntityIndex, index: i24): i53
|
||||||
|
@ -300,8 +300,8 @@ local function archetype_of(world: any, types: { i24 }, prev: Archetype?): Arche
|
||||||
idr.size += 1
|
idr.size += 1
|
||||||
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 r = ECS_PAIR(relation, EcsWildcard)
|
local r = ECS_PAIR(relation, EcsWildcard)
|
||||||
local idr_r = id_record_ensure(componentIndex, r)
|
local idr_r = id_record_ensure(componentIndex, r)
|
||||||
|
@ -375,7 +375,7 @@ local function world_target(world: World, entity: i53, relation: i24--[[, nth: n
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
return ECS_PAIR_OBJECT(entityIndex, archetype.types[archetypeRecord])
|
return ecs_pair_object(entityIndex, archetype.types[archetypeRecord])
|
||||||
end
|
end
|
||||||
|
|
||||||
local function world_parent(world: World, entity: i53)
|
local function world_parent(world: World, entity: i53)
|
||||||
|
@ -408,22 +408,22 @@ local function find_insert(types: { i53 }, toAdd: i53): number
|
||||||
return #types + 1
|
return #types + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local function find_archetype_with(world: World, node: Archetype, componentId: i53): Archetype
|
local function find_archetype_with(world: World, node: Archetype, id: i53): Archetype
|
||||||
local types = node.types
|
local types = node.types
|
||||||
-- 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) :: { i53 }
|
local dst_type = table.clone(node.types) :: { i53 }
|
||||||
local at = find_insert(types, componentId)
|
local at = find_insert(types, id)
|
||||||
if at == -1 then
|
if at == -1 then
|
||||||
-- If it finds a duplicate, it just means it is the same archetype so it can return it
|
-- If it finds a duplicate, it just means it is the same archetype so it can return it
|
||||||
-- directly instead of needing to hash types for a lookup to the archetype.
|
-- directly instead of needing to hash types for a lookup to the archetype.
|
||||||
return node
|
return node
|
||||||
end
|
end
|
||||||
table.insert(destinationType, at, componentId)
|
table.insert(dst_type, at, id)
|
||||||
|
|
||||||
return archetype_ensure(world, destinationType, node)
|
return archetype_ensure(world, dst_type, node)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function edge_ensure(archetype: Archetype, componentId: i53): ArchetypeEdge
|
local function edge_ensure(archetype: Archetype, componentId: i53): ArchetypeEdge
|
||||||
|
@ -624,42 +624,49 @@ local function world_clear(world: World, entityId: i53)
|
||||||
entity_move(world.entityIndex, entityId, record, ROOT_ARCHETYPE)
|
entity_move(world.entityIndex, entityId, record, ROOT_ARCHETYPE)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Keeping the function as small as possible to enable inlining
|
local world_get: (world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?) -> (...any)
|
||||||
local function fetch(record: Record, componentId: i24): any
|
do
|
||||||
local archetype = record.archetype
|
-- Keeping the function as small as possible to enable inlining
|
||||||
if not archetype then
|
local function fetch(id: i24, records, columns, row): any
|
||||||
return nil
|
local tr = records[id]
|
||||||
end
|
|
||||||
|
|
||||||
local archetypeRecord = archetype.records[componentId]
|
if not tr then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
if not archetypeRecord then
|
return columns[tr][row]
|
||||||
return nil
|
end
|
||||||
end
|
|
||||||
|
|
||||||
return archetype.columns[archetypeRecord][record.row]
|
function world_get(world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any
|
||||||
end
|
local id = entityId
|
||||||
|
local record = world.entityIndex.sparse[id]
|
||||||
|
if not record then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
local function world_get(world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any
|
local archetype = record.archetype
|
||||||
local id = entityId
|
if not archetype then
|
||||||
local record = world.entityIndex.sparse[id]
|
return nil
|
||||||
if not record then
|
end
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local va = fetch(record, a)
|
local records = archetype.records
|
||||||
|
local columns = archetype.records
|
||||||
|
local row = record.row
|
||||||
|
|
||||||
if b == nil then
|
local va = fetch(a, tr, columns, row)
|
||||||
return va
|
|
||||||
elseif c == nil then
|
if b == nil then
|
||||||
return va, fetch(record, b)
|
return va
|
||||||
elseif d == nil then
|
elseif c == nil then
|
||||||
return va, fetch(record, b), fetch(record, c)
|
return va, fetch(b, tr, columns, row)
|
||||||
elseif e == nil then
|
elseif d == nil then
|
||||||
return va, fetch(record, b), fetch(record, c), fetch(record, d)
|
return va, fetch(b, tr, columns, row), fetch(c, tr, columns, row)
|
||||||
else
|
elseif e == nil then
|
||||||
error("args exceeded")
|
return va, fetch(b, tr, columns, row), fetch(c, tr, columns, row), fetch(d, tr, columns, row)
|
||||||
end
|
else
|
||||||
|
error("args exceeded")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
type Item = () -> (number, ...any)
|
type Item = () -> (number, ...any)
|
||||||
|
@ -848,58 +855,66 @@ do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local cache
|
||||||
|
|
||||||
function world_query(world: World, ...: number): Query
|
function world_query(world: World, ...: number): Query
|
||||||
-- breaking?
|
-- breaking?
|
||||||
if (...) == nil then
|
if (...) == nil then
|
||||||
error("Missing components")
|
error("Missing components")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
indices = {}
|
indices = {}
|
||||||
compatibleArchetypes = {}
|
|
||||||
length = 0
|
length = 0
|
||||||
components = { ... }
|
components = { ... }
|
||||||
|
|
||||||
local archetypes: { Archetype } = world.archetypes :: any
|
if cache then
|
||||||
local firstArchetypeMap: ArchetypeMap
|
compatibleArchetypes = cache
|
||||||
local componentIndex = world.componentIndex
|
else
|
||||||
|
compatibleArchetypes = {}
|
||||||
|
local archetypes: { Archetype } = world.archetypes :: any
|
||||||
|
local firstArchetypeMap: ArchetypeMap
|
||||||
|
local componentIndex = world.componentIndex
|
||||||
|
|
||||||
for _, componentId in components do
|
for _, componentId in components do
|
||||||
local map: ArchetypeMap = componentIndex[componentId] :: any
|
local map: ArchetypeMap = componentIndex[componentId] :: any
|
||||||
if not map then
|
if not map then
|
||||||
return EmptyQuery
|
return EmptyQuery
|
||||||
end
|
end
|
||||||
|
|
||||||
if (firstArchetypeMap :: any) == nil or firstArchetypeMap.size > map.size then
|
if (firstArchetypeMap :: any) == nil or firstArchetypeMap.size > map.size then
|
||||||
firstArchetypeMap = map
|
firstArchetypeMap = map
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for id in firstArchetypeMap.cache do
|
for id in firstArchetypeMap.cache do
|
||||||
local compatibleArchetype = archetypes[id]
|
local compatibleArchetype = archetypes[id]
|
||||||
local archetypeRecords = compatibleArchetype.records
|
local archetypeRecords = compatibleArchetype.records
|
||||||
|
|
||||||
local records: { number } = {}
|
local records: { number } = {}
|
||||||
local skip = false
|
local skip = false
|
||||||
|
|
||||||
for i, componentId in components do
|
for i, componentId in components do
|
||||||
local index = archetypeRecords[componentId]
|
local index = archetypeRecords[componentId]
|
||||||
if not index then
|
if not index then
|
||||||
skip = true
|
skip = true
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
-- index should be index.offset
|
-- index should be index.offset
|
||||||
records[i] = index
|
records[i] = index
|
||||||
end
|
end
|
||||||
|
|
||||||
if skip then
|
if skip then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
|
|
||||||
length += 1
|
length += 1
|
||||||
compatibleArchetypes[length] = compatibleArchetype
|
compatibleArchetypes[length] = compatibleArchetype
|
||||||
indices[length] = records
|
indices[length] = records
|
||||||
end
|
end
|
||||||
|
|
||||||
|
cache = compatibleArchetypes
|
||||||
|
end
|
||||||
lastArchetype = 1
|
lastArchetype = 1
|
||||||
archetype = compatibleArchetypes[lastArchetype]
|
archetype = compatibleArchetypes[lastArchetype]
|
||||||
|
|
||||||
|
@ -1113,14 +1128,15 @@ return {
|
||||||
|
|
||||||
Rest = EcsRest,
|
Rest = EcsRest,
|
||||||
|
|
||||||
|
pair = (ECS_PAIR :: any) :: <R, T>(pred: Entity, obj: Entity) -> number,
|
||||||
|
|
||||||
|
-- Inwards facing API for testing
|
||||||
IS_PAIR = ECS_IS_PAIR,
|
IS_PAIR = ECS_IS_PAIR,
|
||||||
ECS_ID = ECS_ENTITY_T_LO,
|
ECS_ID = ECS_ENTITY_T_LO,
|
||||||
ECS_PAIR = ECS_PAIR,
|
|
||||||
ECS_GENERATION_INC = ECS_GENERATION_INC,
|
ECS_GENERATION_INC = ECS_GENERATION_INC,
|
||||||
ECS_GENERATION = ECS_GENERATION,
|
ECS_GENERATION = ECS_GENERATION,
|
||||||
ECS_PAIR_RELATION = ECS_PAIR_RELATION,
|
|
||||||
ECS_PAIR_OBJECT = ECS_PAIR_OBJECT,
|
|
||||||
|
|
||||||
pair = (ECS_PAIR :: any) :: <R, T>(pred: Entity, obj: Entity) -> number,
|
ecs_pair_relation = ecs_pair_relation,
|
||||||
getAlive = getAlive,
|
ecs_pair_object = ecs_pair_object,
|
||||||
|
entity_index_get_alive = entity_index_get_alive,
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@ local __ = jecs.Wildcard
|
||||||
local ECS_ID, ECS_GENERATION = jecs.ECS_ID, jecs.ECS_GENERATION
|
local ECS_ID, ECS_GENERATION = jecs.ECS_ID, jecs.ECS_GENERATION
|
||||||
local ECS_GENERATION_INC = jecs.ECS_GENERATION_INC
|
local ECS_GENERATION_INC = jecs.ECS_GENERATION_INC
|
||||||
local IS_PAIR = jecs.IS_PAIR
|
local IS_PAIR = jecs.IS_PAIR
|
||||||
local ECS_PAIR = jecs.ECS_PAIR
|
local pair = jecs.pair
|
||||||
local getAlive = jecs.getAlive
|
local getAlive = jecs.entity_index_get_alive
|
||||||
local ECS_PAIR_RELATION = jecs.ECS_PAIR_RELATION
|
local ecs_pair_relation = jecs.ecs_pair_relation
|
||||||
local ECS_PAIR_OBJECT = jecs.ECS_PAIR_OBJECT
|
local ecs_pair_object = jecs.ecs_pair_object
|
||||||
|
|
||||||
local TEST, CASE, CHECK, FINISH, SKIP = testkit.test()
|
local TEST, CASE, CHECK, FINISH, SKIP = testkit.test()
|
||||||
local function CHECK_NO_ERR<T...>(s: string, fn: (T...) -> (), ...: T...)
|
local function CHECK_NO_ERR<T...>(s: string, fn: (T...) -> (), ...: T...)
|
||||||
|
@ -256,11 +256,11 @@ TEST("world", function()
|
||||||
|
|
||||||
CHECK(IS_PAIR(world:entity()) == false)
|
CHECK(IS_PAIR(world:entity()) == false)
|
||||||
|
|
||||||
local pair = ECS_PAIR(e2, e3)
|
local pair = pair(e2, e3)
|
||||||
CHECK(IS_PAIR(pair) == true)
|
CHECK(IS_PAIR(pair) == true)
|
||||||
|
|
||||||
CHECK(ECS_PAIR_RELATION(world.entityIndex, pair) == e2)
|
CHECK(ecs_pair_relation(world.entityIndex, pair) == e2)
|
||||||
CHECK(ECS_PAIR_OBJECT(world.entityIndex, pair) == e3)
|
CHECK(ecs_pair_object(world.entityIndex, pair) == e3)
|
||||||
end
|
end
|
||||||
|
|
||||||
do CASE("should allow querying for relations")
|
do CASE("should allow querying for relations")
|
||||||
|
@ -269,8 +269,8 @@ TEST("world", function()
|
||||||
local Apples = world:entity()
|
local Apples = world:entity()
|
||||||
local bob = world:entity()
|
local bob = world:entity()
|
||||||
|
|
||||||
world:set(bob, ECS_PAIR(Eats, Apples), true)
|
world:set(bob, pair(Eats, Apples), true)
|
||||||
for e, bool in world:query(ECS_PAIR(Eats, Apples)) do
|
for e, bool in world:query(pair(Eats, Apples)) do
|
||||||
CHECK(e == bob)
|
CHECK(e == bob)
|
||||||
CHECK(bool)
|
CHECK(bool)
|
||||||
end
|
end
|
||||||
|
@ -282,14 +282,14 @@ TEST("world", function()
|
||||||
local Apples = world:entity()
|
local Apples = world:entity()
|
||||||
local bob = world:entity()
|
local bob = world:entity()
|
||||||
|
|
||||||
world:set(bob, ECS_PAIR(Eats, Apples), "bob eats apples")
|
world:set(bob, pair(Eats, Apples), "bob eats apples")
|
||||||
|
|
||||||
local w = jecs.Wildcard
|
local w = jecs.Wildcard
|
||||||
for e, data in world:query(ECS_PAIR(Eats, w)) do
|
for e, data in world:query(pair(Eats, w)) do
|
||||||
CHECK(e == bob)
|
CHECK(e == bob)
|
||||||
CHECK(data == "bob eats apples")
|
CHECK(data == "bob eats apples")
|
||||||
end
|
end
|
||||||
for e, data in world:query(ECS_PAIR(w, Apples)) do
|
for e, data in world:query(pair(w, Apples)) do
|
||||||
CHECK(e == bob)
|
CHECK(e == bob)
|
||||||
CHECK(data == "bob eats apples")
|
CHECK(data == "bob eats apples")
|
||||||
end
|
end
|
||||||
|
@ -303,12 +303,12 @@ TEST("world", function()
|
||||||
local bob = world:entity()
|
local bob = world:entity()
|
||||||
local alice = world:entity()
|
local alice = world:entity()
|
||||||
|
|
||||||
world:set(bob, ECS_PAIR(Eats, Apples), "bob eats apples")
|
world:set(bob, pair(Eats, Apples), "bob eats apples")
|
||||||
world:set(alice, ECS_PAIR(Eats, Oranges), "alice eats oranges")
|
world:set(alice, pair(Eats, Oranges), "alice eats oranges")
|
||||||
|
|
||||||
local w = jecs.Wildcard
|
local w = jecs.Wildcard
|
||||||
local count = 0
|
local count = 0
|
||||||
for e, data in world:query(ECS_PAIR(Eats, w)) do
|
for e, data in world:query(pair(Eats, w)) do
|
||||||
count += 1
|
count += 1
|
||||||
if e == bob then
|
if e == bob then
|
||||||
CHECK(data == "bob eats apples")
|
CHECK(data == "bob eats apples")
|
||||||
|
@ -320,7 +320,7 @@ TEST("world", function()
|
||||||
CHECK(count == 2)
|
CHECK(count == 2)
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
for e, data in world:query(ECS_PAIR(w, Apples)) do
|
for e, data in world:query(pair(w, Apples)) do
|
||||||
count += 1
|
count += 1
|
||||||
CHECK(data == "bob eats apples")
|
CHECK(data == "bob eats apples")
|
||||||
end
|
end
|
||||||
|
@ -337,21 +337,21 @@ TEST("world", function()
|
||||||
local alice = world:entity()
|
local alice = world:entity()
|
||||||
|
|
||||||
world:set(bob, Apples, "apples")
|
world:set(bob, Apples, "apples")
|
||||||
world:set(bob, ECS_PAIR(Eats, Apples), "bob eats apples")
|
world:set(bob, pair(Eats, Apples), "bob eats apples")
|
||||||
world:set(alice, ECS_PAIR(Eats, Oranges), "alice eats oranges")
|
world:set(alice, pair(Eats, Oranges), "alice eats oranges")
|
||||||
|
|
||||||
world:delete(Apples)
|
world:delete(Apples)
|
||||||
local Wildcard = jecs.Wildcard
|
local Wildcard = jecs.Wildcard
|
||||||
|
|
||||||
local count = 0
|
local count = 0
|
||||||
for _, data in world:query(ECS_PAIR(Wildcard, Apples)) do
|
for _, data in world:query(pair(Wildcard, Apples)) do
|
||||||
count += 1
|
count += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
world:delete(ECS_PAIR(Eats, Apples))
|
world:delete(pair(Eats, Apples))
|
||||||
|
|
||||||
CHECK(count == 0)
|
CHECK(count == 0)
|
||||||
CHECK(world:get(bob, ECS_PAIR(Eats, Apples)) == nil)
|
CHECK(world:get(bob, pair(Eats, Apples)) == nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
do CASE("should error when setting invalid pair")
|
do CASE("should error when setting invalid pair")
|
||||||
|
@ -362,13 +362,12 @@ TEST("world", function()
|
||||||
|
|
||||||
world:delete(Apples)
|
world:delete(Apples)
|
||||||
|
|
||||||
world:set(bob, ECS_PAIR(Eats, Apples), "bob eats apples")
|
world:set(bob, pair(Eats, Apples), "bob eats apples")
|
||||||
end
|
end
|
||||||
|
|
||||||
do CASE("should find target for ChildOf")
|
do CASE("should find target for ChildOf")
|
||||||
local world = jecs.World.new()
|
local world = jecs.World.new()
|
||||||
local ChildOf = jecs.ChildOf
|
local ChildOf = jecs.ChildOf
|
||||||
local pair = ECS_PAIR
|
|
||||||
|
|
||||||
local Name = world:component()
|
local Name = world:component()
|
||||||
|
|
||||||
|
@ -383,7 +382,7 @@ TEST("world", function()
|
||||||
CHECK(world:parent(bob) == alice) -- O(1)
|
CHECK(world:parent(bob) == alice) -- O(1)
|
||||||
|
|
||||||
local count = 0
|
local count = 0
|
||||||
for _, name in world:query(Name, ECS_PAIR(ChildOf, alice)) do
|
for _, name in world:query(Name, pair(ChildOf, alice)) do
|
||||||
count += 1
|
count += 1
|
||||||
end
|
end
|
||||||
CHECK(count == 2)
|
CHECK(count == 2)
|
||||||
|
@ -521,11 +520,11 @@ TEST("world", function()
|
||||||
local Bob = world:component()
|
local Bob = world:component()
|
||||||
|
|
||||||
local helloBob = world:entity()
|
local helloBob = world:entity()
|
||||||
world:add(helloBob, ECS_PAIR(Hello, Bob))
|
world:add(helloBob, pair(Hello, Bob))
|
||||||
world:add(helloBob, Bob)
|
world:add(helloBob, Bob)
|
||||||
|
|
||||||
local withoutCount = 0
|
local withoutCount = 0
|
||||||
for _ in world:query(ECS_PAIR(Hello, Bob)):without(Bob) do
|
for _ in world:query(pair(Hello, Bob)):without(Bob) do
|
||||||
withoutCount += 1
|
withoutCount += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue