From 4f450ca94522f5c26a631fc4d19bd6eec420cbec Mon Sep 17 00:00:00 2001 From: sanine-a Date: Tue, 28 Mar 2023 13:15:27 -0500 Subject: implement EntityDb --- honey/ecs.lua | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) (limited to 'honey/ecs.lua') diff --git a/honey/ecs.lua b/honey/ecs.lua index b4def84..62acce0 100644 --- a/honey/ecs.lua +++ b/honey/ecs.lua @@ -5,28 +5,41 @@ setfenv(1, module) --===== Components =====-- +-- Components provide a kind-of-type-safe way of storing values, since they are +-- guaranteed to have a specific set of keys and no other values in them. They also serialize +-- nicely for storage. + Component = {} function Component.newFactory(name, params, serialize) + -- create the metatable for this component type local metatable = {} - metatable.__tostring = serialize or Component.serialize + metatable.__tostring = serialize or Component.serialize -- nice serialization metatable.__newindex = function(tbl, index, value) if params[index] ~= nil then tbl[index] = value else + -- throw an error if we try to set a key that is not in the valid set error(string.format("%q is not a valid key for a component of type %q", index, name)) end end + + -- the factory function for creating components return function(tbl) local tbl = tbl or {} local self = { __type=name } + + -- ensure that all keys are present for k, v in pairs(params) do self[k] = v end setmetatable(self, metatable) + + -- set the keys from the factory call for k, v in pairs(tbl) do self[k] = v end + return self end end @@ -45,4 +58,97 @@ function Component.serialize(self) return str end + +--===== EntityDb =====-- + +EntityDb = {} +EntityDb.__index = EntityDb + + +function EntityDb.new(_) + local self = { + entities = {}, + components = {}, + } + setmetatable(self, EntityDb) + return self +end +setmetatable(EntityDb, {__call=EntityDb.new}) + + +function EntityDb.checkIsValid(self, id) + if not self.entities[id] then + error(string.format("invalid entity id: 0x%x", id)) + end +end + + +local guid = (function() + local id = 0 + return function() id=id+1 return id end +end)() +function EntityDb.createEntity(self) + local id = guid() + self.entities[id] = true + return id +end + + +function EntityDb.addComponent(self, id, name, value) + self:checkIsValid(id) + if not self.components[name] then + self.components[name] = { count=0 } + end + + local component = self.components[name] + component[id] = value + component.count = component.count + 1 +end + + +local function shallowCopy(tbl) + local copy = {} + for k, v in pairs(tbl) do copy[k] = v end + return copy +end + + +function EntityDb.queryComponent(self, name) + local query = shallowCopy(self.components[name]) + query.count = nil + return query +end + + +function EntityDb.queryEntity(self, id) + self:checkIsValid(id) + local query = {} + for name, component in pairs(self.components) do + query[name] = component[id] + end + return query +end + + +function EntityDb.removeComponent(self, id, name) + self:checkIsValid(id) + local component = self.components[name] + if component[id] ~= nil then + component[id] = nil + component.count = component.count - 1 + if component.count == 0 then + self.components[name] = nil + end + end +end + + +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 + return module -- cgit v1.2.1