summaryrefslogtreecommitdiff
path: root/honey/ecs.lua
diff options
context:
space:
mode:
authorsanine-a <sanine.not@pm.me>2023-03-28 11:50:23 -0500
committersanine-a <sanine.not@pm.me>2023-03-28 11:50:23 -0500
commitbb019b6aad81f3dc80900f8bd6bad9ce046cf11a (patch)
tree44b738b202791af0b619175071b83c3d52f8ac1e /honey/ecs.lua
parentcd3d4706da048076375f5899b9f893e108fed7fa (diff)
begin rdb-style refactor
Diffstat (limited to 'honey/ecs.lua')
-rw-r--r--honey/ecs.lua236
1 files changed, 28 insertions, 208 deletions
diff --git a/honey/ecs.lua b/honey/ecs.lua
index 3632f34..b4def84 100644
--- a/honey/ecs.lua
+++ b/honey/ecs.lua
@@ -3,226 +3,46 @@ setmetatable(module, {__index=_G})
setfenv(1, module)
---===== filters =====--
+--===== Components =====--
+Component = {}
-Filter = {}
-
--- base filter creation
-function Filter.new(_, operation, tbl)
- local self = {}
- self.keys = {}
- self.filters = {}
- self.op = operation
-
- for _, v in ipairs(tbl) do
- if type(v) == "function" then
- table.insert(self.filters, v)
- elseif type(v) == "string" then
- table.insert(self.keys, v)
+function Component.newFactory(name, params, serialize)
+ local metatable = {}
+ metatable.__tostring = serialize or Component.serialize
+ metatable.__newindex = function(tbl, index, value)
+ if params[index] ~= nil then
+ tbl[index] = value
+ else
+ error(string.format("%q is not a valid key for a component of type %q", index, name))
end
end
-
- return function(entity, _self)
- local entity = _self or entity -- able to call as . or :
- return Filter.check(self, entity)
- end
-end
-setmetatable(Filter, {__call=Filter.new})
-
-
--- base filter checking
-function Filter.check(self, entity)
- local funcname = "check" .. self.op
- return Filter[funcname](self, entity)
-end
-
-
--- AND filter (all keys and subfilters must match)
-function Filter.AND(tbl)
- return Filter("AND", tbl)
-end
-function Filter.checkAND(self, entity)
- for _, subfilter in ipairs(self.filters) do
- if not subfilter(entity) then return false end
- end
- for _, key in ipairs(self.keys) do
- if entity[key] == nil then return false end
- end
- return true
-end
-
-
--- OR filter (at least one key or subfilter must match)
-function Filter.OR(tbl)
- return Filter("OR", tbl)
-end
-function Filter.checkOR(self, entity)
- for _, subfilter in ipairs(self.filters) do
- if subfilter(entity) then return true end
- end
- for _, key in ipairs(self.keys) do
- if entity[key] ~= nil then return true end
- end
- return false
-end
-
-
--- NAND filter (at least one key or subfilter must NOT match)
-function Filter.NAND(tbl)
- return Filter("NAND", tbl)
-end
-function Filter.checkNAND(self, entity)
- for _, subfilter in ipairs(self.filters) do
- if not subfilter(entity) then return true end
- end
- for _, key in ipairs(self.keys) do
- if entity[key] == nil then return true end
- end
- return false
-end
-
-
--- NOR filter (no keys or subfilters may match)
-function Filter.NOR(tbl)
- return Filter("NOR", tbl)
-end
-function Filter.checkNOR(self, entity)
- for _, subfilter in ipairs(self.filters) do
- if subfilter(entity) then return false end
- end
- for _, key in ipairs(self.keys) do
- if entity[key] ~= nil then return false end
- end
- return true
-end
-
-
---===== levels =====--
-
-Level = {}
-Level.__index = Level
-
-function Level.new(_)
- local self = {}
- self.systems = {}
- self.entities = {}
- self.nextId = 1
- setmetatable(self, Level)
- return self
-end
-setmetatable(Level, {__call=Level.new})
-
-
-local function systemLt(a, b)
- return (a.priority or 50) < (b.priority or 50)
-end
-function Level.addSystem(self, system)
- assert(system.update, "systems must have an 'update' key")
- assert(system.filter, "systems must have a 'filter' key")
- system.entities = {}
- table.insert(self.systems, system)
- table.sort(self.systems, systemLt)
- if system.setup then
- system.setup(system)
- end
-end
-
-
-local function addEntityToSystem(system, id, entity)
- -- check if entity is already present
- if system.entities[id] then return end
-
- if system.onAddEntity then
- system:onAddEntity(id, entity)
- end
- system.entities[id] = true
-end
-
-
-local function removeEntityFromSystem(system, id, entity)
- -- check if entity is already absent
- if not system.entities[id] then return end
-
- if system.onRemoveEntity then
- system:onRemoveEntity(id, entity)
- end
- system.entities[id] = nil
-end
-
-
-function Level.addEntity(self, entity)
- local id = self.nextId
- self.entities[id] = entity
- self.nextId = id + 1
-
- for _, system in ipairs(self.systems) do
- if system.filter(entity) then
- addEntityToSystem(system, id, entity)
+ return function(tbl)
+ local tbl = tbl or {}
+ local self = { __type=name }
+ for k, v in pairs(params) do
+ self[k] = v
end
- end
-
- return id
-end
-
-
-function Level.reconfigureEntity(self, id)
- local entity = self.entities[id]
-
- for _, system in ipairs(self.systems) do
- if system.filter(entity) then
- addEntityToSystem(system, id, entity)
- else
- removeEntityFromSystem(system, id, entity)
+ setmetatable(self, metatable)
+ for k, v in pairs(tbl) do
+ self[k] = v
end
+ return self
end
end
-function Level.removeEntity(self, id)
- local entity = self.entities[id]
- if not entity then error("bad id: "..tostring(id)) end
- for _, system in ipairs(self.systems) do
- removeEntityFromSystem(system, id, entity)
- end
- self.entities[id] = nil
-end
-
-
-function Level.reconfigureAllEntities(self)
- for id in ipairs(self.entities) do
- self:reconfigureEntity(id)
- end
-end
-
-
-function Level.update(self, dt, paused)
- local paused = paused or false
- for _, system in ipairs(self.systems) do
- if (not paused) or (paused and system.nopause) then
- if system.preUpdate then
- system:preUpdate()
- end
- if system.prepareEntity then
- for id in pairs(system.entities) do
- local entity = self.entities[id]
- if entity then
- system:prepareEntity(entity)
- end
- end
- end
- for id in pairs(system.entities) do
- local entity = self.entities[id]
- if entity then
- system:update(entity, dt)
- end
- end
- if system.postUpdate then
- system:postUpdate()
- end
+function Component.serialize(self)
+ local str = "{"
+ for k, v in pairs(self) do
+ if type(v) == "string" then
+ str = str .. string.format("%s=%q,", k, v)
+ else
+ str = str .. string.format("%s=%s,", k, tostring(v))
end
end
+ str = string.sub(str, 1, -2) .. "}"
+ return str
end
-
return module