diff options
author | sanine-a <sanine.not@pm.me> | 2023-05-09 11:31:17 -0500 |
---|---|---|
committer | sanine-a <sanine.not@pm.me> | 2023-05-09 11:31:17 -0500 |
commit | a2ae7aae8357c8c2684d85fd58b0c5a0563ebab9 (patch) | |
tree | 5050161547408c80b521c9f4708bb9f7a9d0fa71 /honey/ecs.lua | |
parent | 2a14abecaee073aef1f1966bb397d6086b2e4785 (diff) |
refactor: split ecs systems into multiple files
Diffstat (limited to 'honey/ecs.lua')
-rw-r--r-- | honey/ecs.lua | 277 |
1 files changed, 6 insertions, 271 deletions
diff --git a/honey/ecs.lua b/honey/ecs.lua index b0409e4..82fd877 100644 --- a/honey/ecs.lua +++ b/honey/ecs.lua @@ -1,274 +1,9 @@ -math.randomseed(os.time()) - -local glm = require 'honey.glm' - -local module = {} -setmetatable(module, {__index=_G}) -setfenv(1, module) - - ---===== EntityDb =====-- - - --- EntityDb is a database of entities and their associated components --- it should be quite efficient to query for all entities with a given component, and reasonably --- efficient to query for all components of a given entity - - -EntityDb = {} -EntityDb.__index = EntityDb - - -function EntityDb.new(_) - local self = { - entities = {}, - components = {}, - } - setmetatable(self, EntityDb) - return self -end -setmetatable(EntityDb, {__call=EntityDb.new}) - - -local function serialize(tbl) - local tostr = function(x, value) - if type(x) == "table" then - if x.__tostring then - return tostring(x) - else - return serialize(x) - end - elseif type(x) == "string" then - if value then - return string.format("\"%s\"", x) - else - return x - end - else - return tostring(x) - end - end - local str = "{" - for key, value in pairs(tbl) do - if type(key) == "string" and string.match(key, "^_") then - -- ignore keys starting with an underscore - else - str = str .. string.format("%s=%s,", tostr(key), tostr(value, true)) - end - end - str = string.sub(str, 1, -2) .. "}" - return str -end - - --- save current database to file -function EntityDb.save(self, filename) - local file, err = io.open(filename, "w") - if not file then error(err) end - - for entity in pairs(self.entities) do - local components = self:queryEntity(entity) - file:write(string.format("Entity(\"%s\", %s)\n", entity, serialize(components))) - end - - file:close() -end - - --- load database from file -function EntityDb.load(self, filename) - print(collectgarbage("count")) - self.entities = {} - self.components = {} - collectgarbage() - print(collectgarbage("count")) - local env = { - Entity = function(id, components) - self:createEntity(id) - self:addComponents(id, components) - end, - Vec3 = glm.Vec3, - Mat4 = glm.Mat4, - } - local f, err = loadfile(filename) - if not f then error(err) end - setfenv(f, env) - f() -end - - --- check if a given entity id is legitimate -function EntityDb.checkIsValid(self, id) - if not self.entities[id] then - error(string.format("invalid entity id: %s", tostring(id))) - end -end - - -local random = math.random -local function uuid() - local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' - return string.gsub(template, '[xy]', function (c) - local v = (c == 'x') and random(0, 0xf) or random(8, 0xb) - return string.format('%x', v) - end) -end - - --- create a new entity -function EntityDb.createEntity(self, id) - local id = id or uuid() -- allow inserting entities at preset ids for loading - self.entities[id] = true - return id -end - - --- add a component to an entity -function EntityDb.addComponent(self, id, name, value) - self:checkIsValid(id) - - -- create the relevant component table if it doesn't exist - if not self.components[name] then - self.components[name] = { count=0, data={} } - end - - local component = self.components[name] - component.data[id] = value - component.count = component.count + 1 -end - - --- add multiple components at once, for convenience -function EntityDb.addComponents(self, id, components) - for name, value in pairs(components) do - self:addComponent(id, name, value) - end -end - - --- create an entity with components -function EntityDb.createEntityWithComponents(self, components) - local id = self:createEntity() - self:addComponents(id, components) - return id -end - - --- get all entities with a given component -function EntityDb.queryComponent(self, name) - local component = self.components[name] - if component then - return component.data - else - return {} - end -end - - --- get all components associated with an entity -function EntityDb.queryEntity(self, id) - self:checkIsValid(id) - local query = {} - for name, component in pairs(self.components) do - query[name] = component.data[id] - end - return query -end - - --- get a specific component from an entity -function EntityDb.getComponent(self, id, name) - self:checkIsValid(id) - return self.components[name].data[id] -end - - --- remove a component from an entity -function EntityDb.removeComponent(self, id, name) - self:checkIsValid(id) - local component = self.components[name] - if component.data[id] ~= nil then - component.data[id] = nil - component.count = component.count - 1 - if component.count == 0 then - self.components[name] = nil - end - end -end - - --- remove an entity from the db -function EntityDb.deleteEntity(self, id) - self:checkIsValid(id) - for name in pairs(self.components) do - self:removeComponent(id, name) - end - self.entities[id] = nil -end - - ---===== SystemDb =====-- - -SystemDb = {} -SystemDb.__index = SystemDb - - -function SystemDb.new(_, entityDb) - local self = { - systems = {}, - sorted = {}, - entityDb = entityDb, - } - setmetatable(self, SystemDb) - return self -end -setmetatable(SystemDb, {__call=SystemDb.new}) - - -local function systemId() - local template = "xx:xx:xx" - return string.gsub(template, "x", function(c) - return string.format("%x", random(0, 0xf)) - end) -end - - -function SystemDb.addSystem(self, systemFunc, params) - local system - if type(systemFunc) == "table" then - system = systemFunc - else - local params = params or {} - params.db = self.entityDb - system = systemFunc(params) - end - - local id = systemId() - self.systems[id] = system - table.insert(self.sorted, id) - self:sort() - return id -end - - -function SystemDb.sort(self) - table.sort(self.sorted, function(a, b) return (self.systems[a].priority or 100) < (self.systems[b].priority or 100) end) -end - - -function SystemDb.update(self, dt) - for _, system in ipairs(self.sorted) do - self.systems[system]:update(dt) - end -end - - -function SystemDb.removeSystem(self, id) - self.systems[id] = nil - for i=#self.sorted,1,-1 do - if self.sorted[i] == id then table.remove(self.sorted, i) end - end -end +local module = require 'honey.ecs.ecs' +module.collision = require 'honey.ecs.collision' +module.node = require 'honey.ecs.node' +module.physics = require 'honey.ecs.physics' +module.render = require 'honey.ecs.render' +module.script = require 'honey.ecs.script' return module |