mirror of
https://github.com/Keyslam-Group/Concord.git
synced 2025-09-02 12:24:11 -04:00
Add World:query
This method allows you to query the World in order to find a set of Entities that matches a specific Filter.
This commit is contained in:
parent
a4ae392341
commit
3d195c790f
3 changed files with 53 additions and 25 deletions
|
@ -19,20 +19,25 @@ Filter.__mt = {
|
||||||
-- @string name Name for the Filter.
|
-- @string name Name for the Filter.
|
||||||
-- @tparam table definition Table containing the Filter Definition
|
-- @tparam table definition Table containing the Filter Definition
|
||||||
-- @tparam onComponent Optional function, called when a component is valid.
|
-- @tparam onComponent Optional function, called when a component is valid.
|
||||||
function Filter.validate (name, def, onComponent)
|
function Filter.validate (errorLevel, name, def, onComponent)
|
||||||
|
local filter = "World:query filter"
|
||||||
|
if name then
|
||||||
|
filter = ("filter '%s'"):format(name)
|
||||||
|
end
|
||||||
|
|
||||||
if type(def) ~= 'table' then
|
if type(def) ~= 'table' then
|
||||||
Utils.error(3, "invalid component list for filter '%s' (table expected, got %s)", name, type(def))
|
Utils.error(3 + errorLevel, "invalid component list for %s (table expected, got %s)", filter, type(def))
|
||||||
end
|
end
|
||||||
|
|
||||||
if not onComponent and def.constructor and not Type.isCallable(def.constructor) then
|
if not onComponent and def.constructor and not Type.isCallable(def.constructor) then
|
||||||
Utils.error(3, "invalid pool constructor for filter '%s' (callable expected, got %s)", name, type(def.constructor))
|
Utils.error(3 + errorLevel, "invalid pool constructor for %s (callable expected, got %s)", filter, type(def.constructor))
|
||||||
end
|
end
|
||||||
|
|
||||||
for n, component in ipairs(def) do
|
for n, component in ipairs(def) do
|
||||||
local ok, err, reject = Components.try(component, true)
|
local ok, err, reject = Components.try(component, true)
|
||||||
|
|
||||||
if not ok then
|
if not ok then
|
||||||
Utils.error(3, "invalid component for filter '%s' at position #%d (%s)", name, n, err)
|
Utils.error(3 + errorLevel, "invalid component for %s at position #%d (%s)", filter, n, err)
|
||||||
end
|
end
|
||||||
|
|
||||||
if onComponent then
|
if onComponent then
|
||||||
|
@ -49,17 +54,30 @@ end
|
||||||
-- @treturn table required
|
-- @treturn table required
|
||||||
-- @treturn table rejected
|
-- @treturn table rejected
|
||||||
function Filter.parse (name, def)
|
function Filter.parse (name, def)
|
||||||
local required, rejected = {}, {}
|
local filter = {}
|
||||||
|
|
||||||
Filter.validate(name, def, function (component, reject)
|
Filter.validate(1, name, def, function (component, reject)
|
||||||
if reject then
|
if reject then
|
||||||
table.insert(rejected, reject)
|
table.insert(filter, reject)
|
||||||
|
table.insert(filter, false)
|
||||||
else
|
else
|
||||||
table.insert(required, component)
|
table.insert(filter, component)
|
||||||
|
table.insert(filter, true)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
return required, rejected
|
return filter
|
||||||
|
end
|
||||||
|
|
||||||
|
function Filter.match (e, filter)
|
||||||
|
for i=#filter, 2, -2 do
|
||||||
|
local match = filter[i - 0]
|
||||||
|
local name = filter[i - 1]
|
||||||
|
|
||||||
|
if (not e[name]) == match then return false end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local REQUIRED_METHODS = {"add", "remove", "has", "clear"}
|
local REQUIRED_METHODS = {"add", "remove", "has", "clear"}
|
||||||
|
@ -95,14 +113,12 @@ function Filter.new (name, def)
|
||||||
pool = List()
|
pool = List()
|
||||||
end
|
end
|
||||||
|
|
||||||
local required, rejected = Filter.parse(name, def)
|
local filter = Filter.parse(name, def)
|
||||||
|
|
||||||
local filter = setmetatable({
|
local filter = setmetatable({
|
||||||
pool = pool,
|
pool = pool,
|
||||||
|
|
||||||
__required = required,
|
__filter = filter,
|
||||||
__rejected = rejected,
|
|
||||||
|
|
||||||
__name = name,
|
__name = name,
|
||||||
|
|
||||||
__isFilter = true,
|
__isFilter = true,
|
||||||
|
@ -115,17 +131,7 @@ end
|
||||||
-- @tparam Entity e Entity to check
|
-- @tparam Entity e Entity to check
|
||||||
-- @treturn boolean
|
-- @treturn boolean
|
||||||
function Filter:eligible(e)
|
function Filter:eligible(e)
|
||||||
for i=#self.__required, 1, -1 do
|
return Filter.match(e, self.__filter)
|
||||||
local name = self.__required[i]
|
|
||||||
if not e[name] then return false end
|
|
||||||
end
|
|
||||||
|
|
||||||
for i=#self.__rejected, 1, -1 do
|
|
||||||
local name = self.__rejected[i]
|
|
||||||
if e[name] then return false end
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Filter:evaluate (e)
|
function Filter:evaluate (e)
|
||||||
|
|
|
@ -53,7 +53,7 @@ function System.new(definition)
|
||||||
Utils.error(2, "invalid name for filter (string key expected, got %s)", type(name))
|
Utils.error(2, "invalid name for filter (string key expected, got %s)", type(name))
|
||||||
end
|
end
|
||||||
|
|
||||||
Filter.validate(name, def)
|
Filter.validate(0, name, def)
|
||||||
end
|
end
|
||||||
|
|
||||||
local systemClass = setmetatable({
|
local systemClass = setmetatable({
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
local PATH = (...):gsub('%.[^%.]+$', '')
|
local PATH = (...):gsub('%.[^%.]+$', '')
|
||||||
|
|
||||||
|
local Filter = require(PATH..".filter")
|
||||||
local Entity = require(PATH..".entity")
|
local Entity = require(PATH..".entity")
|
||||||
local Type = require(PATH..".type")
|
local Type = require(PATH..".type")
|
||||||
local List = require(PATH..".list")
|
local List = require(PATH..".list")
|
||||||
|
@ -71,6 +72,27 @@ function World:newEntity()
|
||||||
return Entity(self)
|
return Entity(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function World:query(def, onMatch)
|
||||||
|
local filter = Filter.parse(nil, def)
|
||||||
|
|
||||||
|
local list = nil
|
||||||
|
if not Type.isCallable(onMatch) then
|
||||||
|
list = type(onMatch) == "table" and onMatch or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, e in ipairs(self.__entities) do
|
||||||
|
if Filter.match(e, filter) then
|
||||||
|
if list then
|
||||||
|
table.insert(list, e)
|
||||||
|
else
|
||||||
|
onMatch(e)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return list
|
||||||
|
end
|
||||||
|
|
||||||
--- Removes an Entity from the World.
|
--- Removes an Entity from the World.
|
||||||
-- @tparam Entity e Entity to remove
|
-- @tparam Entity e Entity to remove
|
||||||
-- @treturn World self
|
-- @treturn World self
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue