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.
|
||||
-- @tparam table definition Table containing the Filter Definition
|
||||
-- @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
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
for n, component in ipairs(def) do
|
||||
local ok, err, reject = Components.try(component, true)
|
||||
|
||||
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
|
||||
|
||||
if onComponent then
|
||||
|
@ -49,17 +54,30 @@ end
|
|||
-- @treturn table required
|
||||
-- @treturn table rejected
|
||||
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
|
||||
table.insert(rejected, reject)
|
||||
table.insert(filter, reject)
|
||||
table.insert(filter, false)
|
||||
else
|
||||
table.insert(required, component)
|
||||
table.insert(filter, component)
|
||||
table.insert(filter, true)
|
||||
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
|
||||
|
||||
local REQUIRED_METHODS = {"add", "remove", "has", "clear"}
|
||||
|
@ -95,14 +113,12 @@ function Filter.new (name, def)
|
|||
pool = List()
|
||||
end
|
||||
|
||||
local required, rejected = Filter.parse(name, def)
|
||||
local filter = Filter.parse(name, def)
|
||||
|
||||
local filter = setmetatable({
|
||||
pool = pool,
|
||||
|
||||
__required = required,
|
||||
__rejected = rejected,
|
||||
|
||||
__filter = filter,
|
||||
__name = name,
|
||||
|
||||
__isFilter = true,
|
||||
|
@ -115,17 +131,7 @@ end
|
|||
-- @tparam Entity e Entity to check
|
||||
-- @treturn boolean
|
||||
function Filter:eligible(e)
|
||||
for i=#self.__required, 1, -1 do
|
||||
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
|
||||
return Filter.match(e, self.__filter)
|
||||
end
|
||||
|
||||
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))
|
||||
end
|
||||
|
||||
Filter.validate(name, def)
|
||||
Filter.validate(0, name, def)
|
||||
end
|
||||
|
||||
local systemClass = setmetatable({
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
local PATH = (...):gsub('%.[^%.]+$', '')
|
||||
|
||||
local Filter = require(PATH..".filter")
|
||||
local Entity = require(PATH..".entity")
|
||||
local Type = require(PATH..".type")
|
||||
local List = require(PATH..".list")
|
||||
|
@ -71,6 +72,27 @@ function World:newEntity()
|
|||
return Entity(self)
|
||||
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.
|
||||
-- @tparam Entity e Entity to remove
|
||||
-- @treturn World self
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue