mirror of
https://github.com/Keyslam-Group/Concord.git
synced 2025-09-02 04:13:58 -04:00
Entity's Keys
You can now give the 'key' component to Entities. A key will be generated automatically and stored in Entity.key.value. You can then use this key to fetch the Entity from the World with World:getEntityByKey(key) The keys are generated with a generator function that can be overriden.
This commit is contained in:
parent
3d195c790f
commit
a55efd042a
6 changed files with 148 additions and 15 deletions
|
@ -2,4 +2,5 @@ local PATH = (...):gsub("(%.init)$", "")
|
|||
|
||||
return {
|
||||
serializable = require(PATH..".serializable"),
|
||||
key = require(PATH..".key"),
|
||||
}
|
||||
|
|
37
concord/builtins/key.lua
Normal file
37
concord/builtins/key.lua
Normal file
|
@ -0,0 +1,37 @@
|
|||
local PATH = (...):gsub('%.builtins%.[^%.]+$', '')
|
||||
|
||||
local Component = require(PATH..".component")
|
||||
|
||||
local getKey = function (self, key)
|
||||
local entity = self.__entity
|
||||
|
||||
if not entity:inWorld() then
|
||||
error("entity needs to belong to a world")
|
||||
end
|
||||
|
||||
local world = entity:getWorld()
|
||||
|
||||
return world:__assignKey(entity, key)
|
||||
end
|
||||
|
||||
local Key = Component("key", function (self, key)
|
||||
self.value = getKey(self, key)
|
||||
end)
|
||||
|
||||
function Key:deserialize (data)
|
||||
self.value = getKey(self, data.value)
|
||||
end
|
||||
|
||||
function Key:removed (replaced)
|
||||
if not replaced then
|
||||
local entity = self.__entity
|
||||
|
||||
if entity:inWorld() then
|
||||
local world = entity:getWorld()
|
||||
|
||||
return world:__clearKey(entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Key
|
|
@ -74,6 +74,7 @@ function Component:deserialize(data)
|
|||
end
|
||||
|
||||
-- Internal: Creates a new Component.
|
||||
-- @param entity The Entity that will receive this Component.
|
||||
-- @return A new Component
|
||||
function Component:__new(entity)
|
||||
local component = setmetatable({
|
||||
|
@ -88,6 +89,7 @@ function Component:__new(entity)
|
|||
end
|
||||
|
||||
-- Internal: Creates and populates a new Component.
|
||||
-- @param entity The Entity that will receive this Component.
|
||||
-- @param ... Varargs passed to the populate function
|
||||
-- @return A new populated Component
|
||||
function Component:__initialize(entity, ...)
|
||||
|
|
|
@ -9,7 +9,8 @@ local Type = require(PATH..".type")
|
|||
local Utils = require(PATH..".utils")
|
||||
|
||||
-- Initialize built-in Components (as soon as possible)
|
||||
local Builtins = require(PATH..".builtins")
|
||||
local Builtins = require(PATH..".builtins.init") --luacheck: ignore
|
||||
-- Builtins is unused but the require already registers the Components
|
||||
|
||||
local Entity = {
|
||||
SERIALIZE_BY_DEFAULT = true,
|
||||
|
@ -49,7 +50,7 @@ local function give(e, name, componentClass, ...)
|
|||
local hadComponent = not not e[name]
|
||||
|
||||
if hadComponent then
|
||||
e[name]:removed()
|
||||
e[name]:removed(true)
|
||||
end
|
||||
|
||||
e[name] = component
|
||||
|
@ -61,7 +62,7 @@ end
|
|||
|
||||
local function remove(e, name)
|
||||
if e[name] then
|
||||
e[name]:removed()
|
||||
e[name]:removed(false)
|
||||
|
||||
e[name] = nil
|
||||
|
||||
|
@ -207,11 +208,16 @@ function Entity:getWorld()
|
|||
return self.__world
|
||||
end
|
||||
|
||||
function Entity:serialize()
|
||||
function Entity:serialize(ignoreKey)
|
||||
local data = {}
|
||||
|
||||
for name, component in pairs(self) do
|
||||
if name ~= "__world" and name ~= "__isEntity" and component.__name == name then
|
||||
-- The key component needs to be treated separately.
|
||||
if name == "key" and component.__name == "key" then
|
||||
if not ignoreKey then
|
||||
data.key = component.value
|
||||
end
|
||||
elseif (name ~= "__world") and (name ~= "__isEntity") and (component.__name == name) then
|
||||
local componentData = component:serialize()
|
||||
|
||||
if componentData ~= nil then
|
||||
|
@ -234,7 +240,7 @@ function Entity:deserialize(data)
|
|||
|
||||
local componentClass = Components[componentData.__name]
|
||||
|
||||
local component = componentClass:__new()
|
||||
local component = componentClass:__new(self)
|
||||
component:deserialize(componentData)
|
||||
|
||||
self[componentData.__name] = component
|
||||
|
|
|
@ -48,6 +48,8 @@ System.mt = {
|
|||
-- @param table filters A table containing filters (name = {components...})
|
||||
-- @treturn System A new SystemClass
|
||||
function System.new(definition)
|
||||
definition = definition or {}
|
||||
|
||||
for name, def in pairs(definition) do
|
||||
if type(name) ~= 'string' then
|
||||
Utils.error(2, "invalid name for filter (string key expected, got %s)", type(name))
|
||||
|
|
|
@ -19,6 +19,12 @@ World.__mt = {
|
|||
__index = World,
|
||||
}
|
||||
|
||||
local defaultGenerator = function (state)
|
||||
local current = state
|
||||
state = state +1
|
||||
return string.format("%d", current), state
|
||||
end
|
||||
|
||||
--- Creates a new World.
|
||||
-- @treturn World The new World
|
||||
function World.new()
|
||||
|
@ -29,6 +35,13 @@ function World.new()
|
|||
__events = {},
|
||||
__emitSDepth = 0,
|
||||
|
||||
__hash = {
|
||||
state = -2^53,
|
||||
generator = defaultGenerator,
|
||||
keys = {},
|
||||
entities = {}
|
||||
},
|
||||
|
||||
__added = List(), __backAdded = List(),
|
||||
__removed = List(), __backRemoved = List(),
|
||||
__dirty = List(), __backDirty = List(),
|
||||
|
@ -101,6 +114,14 @@ function World:removeEntity(e)
|
|||
Utils.error(2, "bad argument #1 to 'World:removeEntity' (Entity expected, got %s)", type(e))
|
||||
end
|
||||
|
||||
if e.__world ~= self then
|
||||
error("trying to remove an Entity from a World it doesn't belong to", 2)
|
||||
end
|
||||
|
||||
if e:has("key") then
|
||||
e:remove("key")
|
||||
end
|
||||
|
||||
self.__removed:add(e)
|
||||
|
||||
return self
|
||||
|
@ -343,16 +364,16 @@ function World:getSystems()
|
|||
return self.__systems
|
||||
end
|
||||
|
||||
function World:serialize()
|
||||
function World:serialize(ignoreKeys)
|
||||
self:__flush()
|
||||
|
||||
local data = {}
|
||||
local data = { generator = self.__hash.state }
|
||||
|
||||
for i = 1, self.__entities.size do
|
||||
local entity = self.__entities[i]
|
||||
|
||||
if entity.serializable then
|
||||
local entityData = entity:serialize()
|
||||
local entityData = entity:serialize(ignoreKeys)
|
||||
table.insert(data, entityData)
|
||||
end
|
||||
end
|
||||
|
@ -360,21 +381,85 @@ function World:serialize()
|
|||
return data
|
||||
end
|
||||
|
||||
function World:deserialize(data, append)
|
||||
if (not append) then
|
||||
function World:deserialize(data, startClean, ignoreGenerator)
|
||||
if startClean then
|
||||
self:clear()
|
||||
end
|
||||
|
||||
if (not ignoreGenerator) then
|
||||
self.__hash.state = data.generator
|
||||
end
|
||||
|
||||
local entities = {}
|
||||
|
||||
for i = 1, #data do
|
||||
local entityData = data[i]
|
||||
local entity = Entity(self)
|
||||
|
||||
local entity = Entity()
|
||||
entity:deserialize(entityData)
|
||||
if data[i].key then
|
||||
local component = Components.key:__new()
|
||||
entity.key = component:deserialize(data[i].key)
|
||||
|
||||
self:addEntity(entity)
|
||||
entity:__dirty()
|
||||
end
|
||||
|
||||
entities[i] = entity
|
||||
end
|
||||
|
||||
for i = 1, #data do
|
||||
entity[i]:deserialize(data[i])
|
||||
end
|
||||
|
||||
self:__flush()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function World:setKeyGenerator(generator, initialState)
|
||||
if not Type.isCallable(generator) then
|
||||
Utils.error(2, "bad argument #1 to 'World:setKeyGenerator' (function expected, got %s)", type(generator))
|
||||
end
|
||||
|
||||
self.__hash.generator = generator
|
||||
self.__hash.state = initialState
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function World:__clearKey(e)
|
||||
local key = self.__hash.keys[e]
|
||||
|
||||
if key then
|
||||
self.__hash.keys[e] = nil
|
||||
self.__hash.entities[key] = nil
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function World:__assignKey(e, key)
|
||||
local hash = self.__hash
|
||||
|
||||
if not key then
|
||||
key = hash.keys[e]
|
||||
if key then return key end
|
||||
|
||||
key, hash.state = hash.generator(hash.state)
|
||||
end
|
||||
|
||||
if hash.entities[key] and hash.entities[key] ~= e then
|
||||
Utils.error(4, "Trying to assign a key that is already taken (key: '%s').", key)
|
||||
elseif hash.keys[e] and hash.keys[e] ~= key then
|
||||
Utils.error(4, "Trying to assign more than one key to an Entity. (old: '%s', new: '%s')", hash.keys[e], key)
|
||||
end
|
||||
|
||||
hash.keys[e] = key
|
||||
hash.entities[key] = e
|
||||
|
||||
return key
|
||||
end
|
||||
|
||||
function World:getEntityByKey(key)
|
||||
return self.__hash.entities[key]
|
||||
end
|
||||
|
||||
--- Callback for when an Entity is added to the World.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue