Replace tiny-ecs with the version I've been using + my own tweaks

This commit is contained in:
Sage Vaillancourt 2025-03-05 00:23:19 -05:00
parent f2ff35daec
commit f570a4a966
1 changed files with 59 additions and 37 deletions

View File

@ -19,6 +19,16 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
---@class System
---@field world World field points to the World that the System belongs to. Useful for adding and removing Entities from the world dynamically via the System.
---@field active boolean flag for whether or not the System is updated automatically. Inactive Systems should be updated manually or not at all via system:update(dt). Defaults to true.
---@field entities table[] is an ordered list of Entities in the System. This list can be used to quickly iterate through all Entities in a System.
---@field interval number is an optional field that makes Systems update at certain intervals using buffered time, regardless of World update frequency. For example, to make a System update once a second, set the System's interval to 1.
---@field index number is the System's index in the World. Lower indexed Systems are processed before higher indices. The index is a read only field; to set the index, use tiny.setSystemIndex(world, system).
---@field indices table<any, any> field is a table of Entity keys to their indices in the entities list. Most Systems can ignore this.
---@field modified boolean indicator for if the System has been modified in the last update. If so, the onModify callback will be called on the System in the next update, if it has one. This is usually managed by tiny-ecs, so users should mostly ignore this, too.
--- @module tiny-ecs
-- @author Calvin Rose
-- @license MIT
@ -91,40 +101,49 @@ local filterJoin
-- A helper function to filters from string
local filterBuildString
do
local loadstring = loadstring or load
local function getchr(c)
return "\\" .. c:byte()
end
local function make_safe(text)
return ("%q"):format(text):gsub('\n', 'n'):gsub("[\128-\255]", getchr)
end
local function filterJoinRaw(invert, joining_op, ...)
local _args = {...}
local function filterJoinRaw(prefix, seperator, ...)
local accum = {}
local build = {}
for i = 1, select('#', ...) do
local item = select(i, ...)
if type(item) == 'string' then
accum[#accum + 1] = ("(e[%s] ~= nil)"):format(make_safe(item))
elseif type(item) == 'function' then
build[#build + 1] = ('local subfilter_%d_ = select(%d, ...)')
:format(i, i)
accum[#accum + 1] = ('(subfilter_%d_(system, e))'):format(i)
else
error 'Filter token must be a string or a filter function.'
return function(system, e)
local acc
local args = _args
if joining_op == 'or' then
acc = false
for i = 1, #args do
local v = args[i]
if type(v) == "string" then
acc = acc or (e[v] ~= nil)
elseif type(v) == "function" then
acc = acc or v(system, e)
else
error 'Filter token must be a string or a filter function.'
end
end
else
acc = true
for i = 1, #args do
local v = args[i]
if type(v) == "string" then
acc = acc and (e[v] ~= nil)
elseif type(v) == "function" then
acc = acc and v(system, e)
else
error 'Filter token must be a string or a filter function.'
end
end
end
local source = ('%s\nreturn function(system, e) return %s(%s) end')
:format(
table.concat(build, '\n'),
prefix,
table.concat(accum, seperator))
local loader, err = loadstring(source)
if err then error(err) end
return loader(...)
-- computes a simple xor
if invert then
return not acc
else
return acc
end
end
end
do
function filterJoin(...)
local state, value = pcall(filterJoinRaw, ...)
@ -169,25 +188,25 @@ end
--- Makes a Filter that selects Entities with all specified Components and
-- Filters.
function tiny.requireAll(...)
return filterJoin('', ' and ', ...)
return filterJoin(false, 'and', ...)
end
--- Makes a Filter that selects Entities with at least one of the specified
-- Components and Filters.
function tiny.requireAny(...)
return filterJoin('', ' or ', ...)
return filterJoin(false, 'or', ...)
end
--- Makes a Filter that rejects Entities with all specified Components and
-- Filters, and selects all other Entities.
function tiny.rejectAll(...)
return filterJoin('not', ' and ', ...)
return filterJoin(true, 'and', ...)
end
--- Makes a Filter that rejects Entities with at least one of the specified
-- Components and Filters, and selects all other Entities.
function tiny.rejectAny(...)
return filterJoin('not', ' or ', ...)
return filterJoin(true, 'or', ...)
end
--- Makes a Filter from a string. Syntax of `pattern` is as follows.
@ -303,11 +322,12 @@ local function processingSystemUpdate(system, dt)
local process = system.process
local postProcess = system.postProcess
local shouldSkipSystemProcess = false
if preProcess then
preProcess(system, dt)
shouldSkipSystemProcess = preProcess(system, dt)
end
if process then
if process and not shouldSkipSystemProcess then
if system.nocache then
local entities = system.world.entities
local filter = system.filter
@ -327,7 +347,7 @@ local function processingSystemUpdate(system, dt)
end
end
if postProcess then
if postProcess and not shouldSkipSystemProcess then
postProcess(system, dt)
end
end
@ -420,6 +440,7 @@ local worldMetaTable
--- Creates a new World.
-- Can optionally add default Systems and Entities. Returns the new World along
-- with default Entities and Systems.
---@return World
function tiny.world(...)
local ret = setmetatable({
@ -861,4 +882,5 @@ worldMetaTable = {
end
}
return tiny
_G.tiny = tiny
return tiny