diff --git a/src/ecs.lua b/src/ecs.lua new file mode 100644 index 0000000..14db8fd --- /dev/null +++ b/src/ecs.lua @@ -0,0 +1,170 @@ +local ENTITY_STORAGE = {} +local PLACEHOLDER = {} + +ecs = { } + +function ecs.addEntity(entity) + ENTITY_STORAGE[entity] = true +end + +---@return any +function ecs.field() + return PLACEHOLDER +end + +function allKeysIncluded(entity, filter) + for k, _ in pairs(filter) do + if not entity[k] then + return false + end + end + return true +end + +function allFiltersMatch(entity, filters) + for _, filter in pairs(filters) do + if not allKeysIncluded(entity, filter) then + return false + end + end + return true +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 U +---@generic V +---@generic W +---@param tShape T +---@param uShape U? +---@param vShape V? +---@param wShape W? +---@return fun(callback: fun(componentT: T, componentU: U, componentV: V, componentW: W)) +function ecs.entitiesWithShapes(tShape, uShape, vShape, wShape) + return function() + end +end + +--- Returns a function that accepts a callback. This callback will receive one argument for each Shape provided. +--- +---@generic T +---@generic TKey +---@generic U +---@generic UKey +---@generic V +---@generic VKey +---@generic W +---@generic WKey +---@param tShape { [TKey]: T } +---@param uShape { [UKey]: U }? +---@param vShape { [VKey]: V }? +---@param wShape { [WKey]: W }? +---@return fun(callback: fun(componentT: T, componentU: U, componentV: V, componentW: W)) +function ecs.entitiesWithShapes2(tShape, uShape, vShape, wShape) + local filters = {tShape, uShape, vShape, wShape} + return function(callback) + -- TODO? Cache all this? + local ret = {} + for entity,_ in pairs(ENTITY_STORAGE) do + if allFiltersMatch(entity, filters) then + callback(entity, entity, entity, entity) + end + end + return ret + end +end + +local f = ecs.field() + +---@alias XYPair { x:number, y: number } + +---@type XYPair +local XYPair = { x = f, y = f } + +local HasPosition = { position = XYPair } +local HasVelocity = { velocity = XYPair } + +local entIt = ecs.entitiesWithShapes(HasPosition, HasVelocity) +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 }, + velocity = { x = 1, y = 1 } +} + +ecs.addEntity(exampleEntity) + +---@type fun(system: fun(entity: { position: XYPair, velocity: XYPair })) +local forEachPosVel = ecs.entitiesWithFields('position', 'velocity') + +forEachPosVel(function(hasVelPos) + print(hasVelPos.velocity.x) +end) \ No newline at end of file