Some ECS cleanup with ews() rework.

This commit is contained in:
Sage Vaillancourt 2025-01-30 12:24:10 -05:00
parent 109d67bea9
commit ff2b1d0180
1 changed files with 105 additions and 107 deletions

View File

@ -1,10 +1,29 @@
local ENTITY_STORAGE = {}
local PLACEHOLDER = {}
ecs = { } ecs = { }
local ALL_ENTITIES = {}
---@alias System { callback: fun(delta: number, a: any, b: any, c: any, d: any, e: any, any), shapes: {}, keys: string[], entityCache: table<any, boolean> }
---@type System[]
local SYSTEMS = {}
local PLACEHOLDER = {}
-- TODO: Add entity to any existing systems
function ecs.addEntity(entity) function ecs.addEntity(entity)
ENTITY_STORAGE[entity] = true ALL_ENTITIES[entity] = true
for _, system in pairs(SYSTEMS) do
if entityMatchesShapes(entity, system.shapes) then
system.entityCache[entity] = true
end
end
end
function ecs.removeEntity(entity)
ALL_ENTITIES[entity] = nil
for _, system in pairs(SYSTEMS) do
system.entityCache[entity] = nil
end
end end
---@return any ---@return any
@ -21,49 +40,15 @@ function allKeysIncluded(entity, filter)
return true return true
end end
function allFiltersMatch(entity, filters) function entityMatchesShapes(entity, shapes)
for _, filter in pairs(filters) do for _, shape in pairs(shapes) do
if not allKeysIncluded(entity, filter) then if not allKeysIncluded(entity, shape) then
return false return false
end end
end end
return true return true
end end
---@generic T
---@param shape T
---@return fun(): T[]
function ecs.buildEntityFilter(shape)
local filters = {shape}
return function()
-- TODO? Cache all this?
local ret = {}
for entity,_ in pairs(ENTITY_STORAGE) do
if allFiltersMatch(entity, filters) then
ret[#ret + 1] = entity;
end
end
return ret
end
end
---@generic T
---@return fun(): T[]
function ecs.buildRequiredFields(...)
local filters = arg
return function()
-- TODO? Cache all this?
local ret = {}
for entity,_ in pairs(ENTITY_STORAGE) do
if allKeysIncluded(entity, filters) then
ret[#ret + 1] = entity;
end
end
return ret
end
end
-- --@overload fun(tShape: `T`): fun(callback: fun(componentT: `T`))
---@generic T ---@generic T
---@generic U ---@generic U
---@generic V ---@generic V
@ -73,11 +58,55 @@ end
---@param vShape V? ---@param vShape V?
---@param wShape W? ---@param wShape W?
---@return fun(callback: fun(componentT: T, componentU: U, componentV: V, componentW: W)) ---@return fun(callback: fun(componentT: T, componentU: U, componentV: V, componentW: W))
function ecs.entitiesWithShapes(tShape, uShape, vShape, wShape) function ecs.entitiesHavingShapes(tShape, uShape, vShape, wShape)
return function() return function()
end end
end end
-- Print contents of `tbl`, with indentation.
-- `indent` sets the initial level of indentation.
function tprint (tbl, indent)
if not indent then indent = 0 end
for k, v in pairs(tbl) do
formatting = string.rep(" ", indent) .. k .. ": "
if type(v) == "table" then
print(formatting)
tprint(v, indent+1)
elseif type(v) == 'boolean' then
print(formatting .. tostring(v))
else
print(formatting .. v)
end
end
end
function addSystem(callback, keys, shapes)
SYSTEMS[#SYSTEMS + 1] = {
callback = callback,
keys = keys,
shapes = shapes,
entityCache = nil
}
end
---@param deltaSeconds number
function ecs.update(deltaSeconds)
for _,system in pairs(SYSTEMS) do
if not system.entityCache then
system.entityCache = {}
for entity,_ in pairs(ALL_ENTITIES) do
if entityMatchesShapes(entity, system.shapes) then
system.entityCache[entity] = true
end
end
end
for entity,_ in pairs(system.entityCache) do
local keys = system.keys
system.callback(deltaSeconds, entity[keys[1]], entity[keys[2]], entity[keys[3]], entity[keys[4]], entity)
end
end
end
--- Returns a function that accepts a callback. This callback will receive one argument for each Shape provided. --- Returns a function that accepts a callback. This callback will receive one argument for each Shape provided.
--- ---
---@generic T ---@generic T
@ -89,82 +118,51 @@ end
---@generic W ---@generic W
---@generic WKey ---@generic WKey
---@param tShape { [TKey]: T } ---@param tShape { [TKey]: T }
---@param uShape { [UKey]: U }? ---@param uShape { [UKey]: U } | fun(componentT: T, any) | nil
---@param vShape { [VKey]: V }? ---@param vShape { [VKey]: V } | fun(componentT: T, componentU: U, any) | nil
---@param wShape { [WKey]: W }? ---@param wShape { [WKey]: W } | fun(componentT: T, componentU: U, componentV: V, any) | nil
---@return fun(callback: fun(componentT: T, componentU: U, componentV: V, componentW: W)) ---@param finalFunc fun(componentT: T, componentU: U, componentV: V, componentW: W, any) | nil
function ecs.entitiesWithShapes2(tShape, uShape, vShape, wShape) function ecs.entitiesWithShapes(tShape, uShape, vShape, wShape, finalFunc)
local filters = {tShape, uShape, vShape, wShape} local maybeShapes = {tShape, uShape, vShape, wShape, finalFunc}
return function(callback) local shapes = {}
-- TODO? Cache all this? local callback
local ret = {}
for entity,_ in pairs(ENTITY_STORAGE) do for _,maybeShape in pairs(maybeShapes) do
if allFiltersMatch(entity, filters) then if type(maybeShape) == "table" then
callback(entity, entity, entity, entity) shapes[#shapes + 1] = maybeShape
elseif type(maybeShape) == "function" then
callback = maybeShape
end end
end end
return ret
local keys = {}
for _,shape in pairs(shapes) do
for key,_ in pairs(shape) do
keys[#keys + 1] = key
end end
end
addSystem(callback, keys, shapes)
end end
local f = ecs.field() local f = ecs.field()
---@alias XYPair { x:number, y: number } ---@type { x: number, y: number }
---@type XYPair
local XYPair = { x = f, y = f } local XYPair = { x = f, y = f }
local HasPosition = { position = XYPair } local Position = { position = XYPair }
local HasVelocity = { velocity = XYPair } local Velocity = { velocity = XYPair }
local entIt = ecs.entitiesWithShapes(HasPosition, HasVelocity) local someMovable = {
entIt(function(hasPos, hasVel)
hasPos.position.x = hasPos.position.x + hasVel.velocity.y
end)
local entIt2 = ecs.entitiesWithShapes2(HasPosition)
entIt2(function(position, velocity)
---@type number
local num = 0
num = position.x
num = velocity.z
print(num)
end)
---@return fun(callback: fun(T))
function ecs.entitiesWithFields(...)
local filters = {...}
return function(callback)
-- TODO? Cache all this?
for entity,_ in pairs(ENTITY_STORAGE) do
if allKeysIncluded(entity, filters) then
callback(entity)
end
end
end
end
---@type unknown
function ecs.shape(...)
local shape = {}
for _,incomingShape in ipairs(arg) do
for k,v in pairs(incomingShape) do
shape[k] = v
end
end
return shape
end
local exampleEntity = {
position = { x = 0, y = 0 }, position = { x = 0, y = 0 },
velocity = { x = 1, y = 1 } velocity = { x = 2, y = 1 }
} }
ecs.addEntity(exampleEntity) ecs.addEntity(someMovable)
---@type fun(system: fun(entity: { position: XYPair, velocity: XYPair })) ecs.entitiesWithShapes(Position, Velocity, function (delta, pos, vel)
local forEachPosVel = ecs.entitiesWithFields('position', 'velocity') print("position:")
tprint(pos, 1)
forEachPosVel(function(hasVelPos) pos.x = pos.x + (vel.x * delta)
print(hasVelPos.velocity.x) pos.y = pos.y + (vel.y * delta)
end) end)