mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-25 09:30:03 +00:00
add replace method
This commit is contained in:
parent
ea89be96c2
commit
5e3f0485d3
2 changed files with 94 additions and 42 deletions
|
@ -8,7 +8,7 @@ local function TITLE(title: string)
|
||||||
print(testkit.color.white(title))
|
print(testkit.color.white(title))
|
||||||
end
|
end
|
||||||
|
|
||||||
local jecs = require("../lib/init")
|
local jecs = require("@jecs")
|
||||||
local mirror = require("../mirror/init")
|
local mirror = require("../mirror/init")
|
||||||
|
|
||||||
type i53 = number
|
type i53 = number
|
||||||
|
@ -50,8 +50,8 @@ do
|
||||||
world:set(e, G, true)
|
world:set(e, G, true)
|
||||||
world:set(e, H, true)
|
world:set(e, H, true)
|
||||||
|
|
||||||
BENCH("Update Data", function()
|
BENCH("Update Data", function()
|
||||||
for _ = 1, 100 do
|
for _ = 1, 100 do
|
||||||
world:set(e, A, false)
|
world:set(e, A, false)
|
||||||
world:set(e, B, false)
|
world:set(e, B, false)
|
||||||
world:set(e, C, false)
|
world:set(e, C, false)
|
||||||
|
@ -166,8 +166,8 @@ do
|
||||||
world:set(e, G, true)
|
world:set(e, G, true)
|
||||||
world:set(e, H, true)
|
world:set(e, H, true)
|
||||||
|
|
||||||
BENCH("Update Data", function()
|
BENCH("Update Data", function()
|
||||||
for _ = 1, 100 do
|
for _ = 1, 100 do
|
||||||
world:set(e, A, false)
|
world:set(e, A, false)
|
||||||
world:set(e, B, false)
|
world:set(e, B, false)
|
||||||
world:set(e, C, false)
|
world:set(e, C, false)
|
||||||
|
@ -243,4 +243,4 @@ do
|
||||||
|
|
||||||
view_bench(ecs, D1, D2, D3, D4, D5, D6, D7, D8)
|
view_bench(ecs, D1, D2, D3, D4, D5, D6, D7, D8)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
124
src/init.luau
124
src/init.luau
|
@ -42,7 +42,7 @@ TODO:
|
||||||
index: number,
|
index: number,
|
||||||
count: number,
|
count: number,
|
||||||
column: number
|
column: number
|
||||||
}
|
}
|
||||||
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ local function ECS_ENTITY_T_LO(e: i53): i24
|
||||||
return if e > ECS_ENTITY_MASK then (e // ECS_ID_FLAGS_MASK) // ECS_ENTITY_MASK else e
|
return if e > ECS_ENTITY_MASK then (e // ECS_ID_FLAGS_MASK) // ECS_ENTITY_MASK else e
|
||||||
end
|
end
|
||||||
|
|
||||||
local function STRIP_GENERATION(e: i53): i24
|
local function STRIP_GENERATION(e: i53): i24
|
||||||
return ECS_ENTITY_T_LO(e)
|
return ECS_ENTITY_T_LO(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ local function getAlive(index: EntityIndex, e: i24): i53
|
||||||
if id then
|
if id then
|
||||||
local currentGeneration = ECS_GENERATION(id)
|
local currentGeneration = ECS_GENERATION(id)
|
||||||
local gen = ECS_GENERATION(e)
|
local gen = ECS_GENERATION(e)
|
||||||
if gen == currentGeneration then
|
if gen == currentGeneration then
|
||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ 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 sparseGet(entityIndex, id)
|
||||||
return entityIndex.sparse[getAlive(entityIndex, id)]
|
return entityIndex.sparse[getAlive(entityIndex, id)]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ end
|
||||||
-- TODO:
|
-- TODO:
|
||||||
-- should have an additional `nth` parameter which selects the nth target
|
-- should have an additional `nth` parameter which selects the nth target
|
||||||
-- this is important when an entity can have multiple relationships with the same target
|
-- this is important when an entity can have multiple relationships with the same target
|
||||||
local function target(world: World, entity: i53, relation: i24--[[, nth: number]]): i24?
|
local function target(world: World, entity: i53, relation: i24--[[, nth: number]]): 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
|
||||||
|
@ -374,7 +374,7 @@ local function target(world: World, entity: i53, relation: i24--[[, nth: number]
|
||||||
return ECS_PAIR_OBJECT(entityIndex, archetype.types[archetypeRecord])
|
return ECS_PAIR_OBJECT(entityIndex, archetype.types[archetypeRecord])
|
||||||
end
|
end
|
||||||
|
|
||||||
local function parent(world: World, entity: i53)
|
local function parent(world: World, entity: i53)
|
||||||
return target(world, entity, EcsChildOf)
|
return target(world, entity, EcsChildOf)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -462,7 +462,7 @@ local function add(world: World, entityId: i53, componentId: i53)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Symmetric like `World.add` but idempotent
|
-- Symmetric like `World.add` but idempotent
|
||||||
local function 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)
|
||||||
|
@ -600,17 +600,17 @@ local function delete(world: World, entityId: i53)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function clear(world: World, entityId: i53)
|
local function clear(world: World, entityId: i53)
|
||||||
--TODO: use sparse_get (stashed)
|
--TODO: use sparse_get (stashed)
|
||||||
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 ROOT_ARCHETYPE = world.ROOT_ARCHETYPE
|
local ROOT_ARCHETYPE = world.ROOT_ARCHETYPE
|
||||||
local archetype = record.archetype
|
local archetype = record.archetype
|
||||||
|
|
||||||
if archetype == nil or archetype == ROOT_ARCHETYPE then
|
if archetype == nil or archetype == ROOT_ARCHETYPE then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -662,21 +662,29 @@ local function noop(_self: Query, ...): () -> ()
|
||||||
end
|
end
|
||||||
|
|
||||||
local EmptyQuery = {
|
local EmptyQuery = {
|
||||||
__iter = noop,
|
__iter = iterNoop,
|
||||||
without = noop,
|
next = noop,
|
||||||
|
replace = noop,
|
||||||
|
without = function()
|
||||||
|
return EmptyQuery
|
||||||
|
end
|
||||||
}
|
}
|
||||||
EmptyQuery.__index = EmptyQuery
|
|
||||||
setmetatable(EmptyQuery, EmptyQuery)
|
|
||||||
|
|
||||||
export type Query = typeof(EmptyQuery)
|
export type Query = typeof(EmptyQuery)
|
||||||
|
|
||||||
type CompatibleArchetype = { archetype: Archetype, indices: { number } }
|
type CompatibleArchetype = { archetype: Archetype, indices: { number } }
|
||||||
|
|
||||||
local function preparedQuery(compatibleArchetypes: { Archetype },
|
local function replaceColumns(row, columns, ...)
|
||||||
components: { i53? }, indices: { { number } })
|
for i, column in columns do
|
||||||
|
column[row] = select(i, ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function preparedQuery(compatibleArchetypes: { Archetype },
|
||||||
|
components: { i53? }, indices: { { number } })
|
||||||
|
|
||||||
local queryLength = #components
|
local queryLength = #components
|
||||||
|
|
||||||
local lastArchetype = 1
|
local lastArchetype = 1
|
||||||
local archetype: Archetype = compatibleArchetypes[lastArchetype]
|
local archetype: Archetype = compatibleArchetypes[lastArchetype]
|
||||||
|
|
||||||
|
@ -686,16 +694,16 @@ local function preparedQuery(compatibleArchetypes: { Archetype },
|
||||||
|
|
||||||
local queryOutput = {}
|
local queryOutput = {}
|
||||||
|
|
||||||
local entities = archetype.entities
|
local entities = archetype.entities
|
||||||
local i = #entities
|
local i = #entities
|
||||||
|
|
||||||
local function queryNext(): ...any
|
local function queryNext(): ...any
|
||||||
local entityId = entities[i]
|
local entityId = entities[i]
|
||||||
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
|
||||||
|
|
||||||
|
@ -782,34 +790,78 @@ local function preparedQuery(compatibleArchetypes: { Archetype },
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
local it = {
|
|
||||||
__iter = function()
|
|
||||||
lastArchetype = 1
|
|
||||||
archetype = compatibleArchetypes[1]
|
|
||||||
entities = archetype.entities
|
|
||||||
i = #entities
|
|
||||||
|
|
||||||
return queryNext
|
local function iter()
|
||||||
end,
|
lastArchetype = 1
|
||||||
|
archetype = compatibleArchetypes[1]
|
||||||
|
entities = archetype.entities
|
||||||
|
i = #entities
|
||||||
|
|
||||||
|
return queryNext
|
||||||
|
end
|
||||||
|
|
||||||
|
local function replace()
|
||||||
|
for _, compatibleArchetype in compatibleArchetypes do
|
||||||
|
local archetype = compatibleArchetype.archetype
|
||||||
|
local tr = compatibleArchetype.indices
|
||||||
|
local columns = archetype.columns
|
||||||
|
|
||||||
|
for row in archetype.entities do
|
||||||
|
if queryLength == 1 then
|
||||||
|
local a = columns[tr[1]]
|
||||||
|
local pa = fn(a[row])
|
||||||
|
|
||||||
|
a[row] = pa
|
||||||
|
elseif queryLength == 2 then
|
||||||
|
local a = columns[tr[1]]
|
||||||
|
local b = columns[tr[2]]
|
||||||
|
|
||||||
|
a[row], b[row] = fn(a[row], b[row])
|
||||||
|
elseif queryLength == 3 then
|
||||||
|
local a = columns[tr[1]]
|
||||||
|
local b = columns[tr[2]]
|
||||||
|
local c = columns[tr[3]]
|
||||||
|
|
||||||
|
a[row], b[row], c[row] = fn(a[row], b[row], c[row])
|
||||||
|
elseif queryLength == 4 then
|
||||||
|
local a = columns[tr[1]]
|
||||||
|
local b = columns[tr[2]]
|
||||||
|
local c = columns[tr[3]]
|
||||||
|
local d = columns[tr[4]]
|
||||||
|
|
||||||
|
a[row], b[row], c[row], d[row] = fn(
|
||||||
|
a[row], b[row], c[row], d[row])
|
||||||
|
else
|
||||||
|
for i = 1, queryLength do
|
||||||
|
queryOutput[i] = columns[tr[i]][row]
|
||||||
|
end
|
||||||
|
replace(row, columns, fn(unpack(queryOutput)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local it = {
|
||||||
|
__iter = iter,
|
||||||
next = queryNext,
|
next = queryNext,
|
||||||
without = without
|
without = without,
|
||||||
|
replace = replace
|
||||||
}
|
}
|
||||||
|
|
||||||
return setmetatable(it, it) :: any
|
return it
|
||||||
end
|
end
|
||||||
|
|
||||||
local function 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")
|
||||||
end
|
end
|
||||||
|
|
||||||
local indices: { { number } } = {}
|
local indices: { { number } } = {}
|
||||||
local compatibleArchetypes: { Archetype } = {}
|
local compatibleArchetypes: { Archetype } = {}
|
||||||
local length = 0
|
local length = 0
|
||||||
|
|
||||||
local components: { number } = { ... }
|
local components: { number } = { ... }
|
||||||
local archetypes: { Archetype } = world.archetypes :: any
|
local archetypes: { Archetype } = world.archetypes :: any
|
||||||
|
|
||||||
local firstArchetypeMap: ArchetypeMap
|
local firstArchetypeMap: ArchetypeMap
|
||||||
|
@ -989,7 +1041,7 @@ export type WorldShim = typeof(setmetatable(
|
||||||
local World = {}
|
local World = {}
|
||||||
World.__index = World
|
World.__index = World
|
||||||
|
|
||||||
function World.new()
|
function World.new()
|
||||||
local self = setmetatable({
|
local self = setmetatable({
|
||||||
archetypeIndex = {} :: { [string]: Archetype },
|
archetypeIndex = {} :: { [string]: Archetype },
|
||||||
archetypes = {} :: Archetypes,
|
archetypes = {} :: Archetypes,
|
||||||
|
|
Loading…
Reference in a new issue