diff options
Diffstat (limited to 'honey.bak/ecs.lua')
-rw-r--r-- | honey.bak/ecs.lua | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/honey.bak/ecs.lua b/honey.bak/ecs.lua new file mode 100644 index 0000000..0672efe --- /dev/null +++ b/honey.bak/ecs.lua @@ -0,0 +1,234 @@ +local module = {} +setmetatable(module, {__index=_G}) +setfenv(1, module) + + +--===== filters =====-- + + +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) + 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}) + + +function Level.getEntity(self, id) + return self.entities[id] +end + + +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 = {} + system.level = self + 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) + 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) + end + 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 + end + end +end + + +return module |