local obj_proto = {} local obj_mt = {__newindex = function()assert(false)end} function obj_proto:get(ct) assert(ct, "component type") return self.components[ct] end function obj_proto:all_components() local k, v return function() k, v = next(self.components, k) return v end end function obj_proto:call(method, ...) for c in self:all_components() do if c[method] then c[method](c, ...) end end end function obj_proto:enable() self.world:registered(self, nil, true) for c in self:all_components() do self.world:registered(self, c.component_type, true) if c.enable then c:enable() end end end function obj_proto:disable() self.world:registered(self, nil, false) for c in self:all_components() do self.world:registered(self, c.component_type, false) if c.disable then c:disable() end end end function obj_mt:__index(k) return obj_proto[k] or self:get(k) end local function init_cmp(obj, c) assert(not c.inited) c.obj = obj for _, dep in ipairs(c.deps) do local ct, inst = unpack(dep) assert(ct, "component type") obj:require(ct, inst) end c:init(c.i) if c.enable then c:enable() end c.inited = true end function obj_proto:add(c) assert(not self.components[c.component_type]) self.components[c.component_type] = c init_cmp(self, c) return c end function obj_proto:remove(ct) local c = assert(self:get(ct)) for oc in self:all_components() do for _, d in ipairs(oc.deps) do assert(d[1] ~= ct, "dependency") end end self.world:registered(self, ct, false) self.components[ct] = nil if c.disable then c:disable() end if c.remove then c:remove() end end function obj_proto:require(ct, instance) if self:get(ct) then return end return self:add(ct(instance)) end local world_proto = {} local world_mt = {__index = world_proto} local function world() local w = setmetatable({objects = {}, components = {}}, world_mt) return w end -- create an object in the world with the components specified in the arguments function world_proto:object(...) local components = {...} local o = setmetatable({world = self, components = {}}, obj_mt) for _, c in ipairs(components) do assert(type(c) == 'table') o.components[c.component_type] = c end for _, c in pairs(o.components) do if not c.inited then init_cmp(o, c) end end o:enable() return o end function world_proto:registered(object, ct, is_reg) if ct then self.components[ct] = self.components[ct] or {} self.components[ct][object] = is_reg and true or nil else self.objects[object] = is_reg and true or nil end end function world_proto:iterate(ct) if ct then return pairs(self.components[ct] or {}) else return pairs(self.objects) end end return world