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. 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 --- @module tiny-ecs
-- @author Calvin Rose -- @author Calvin Rose
-- @license MIT -- @license MIT
@ -91,40 +101,49 @@ local filterJoin
-- A helper function to filters from string -- A helper function to filters from string
local filterBuildString local filterBuildString
do
local loadstring = loadstring or load local function filterJoinRaw(invert, joining_op, ...)
local function getchr(c) local _args = {...}
return "\\" .. c:byte()
end
local function make_safe(text)
return ("%q"):format(text):gsub('\n', 'n'):gsub("[\128-\255]", getchr)
end
local function filterJoinRaw(prefix, seperator, ...) return function(system, e)
local accum = {} local acc
local build = {} local args = _args
for i = 1, select('#', ...) do if joining_op == 'or' then
local item = select(i, ...) acc = false
if type(item) == 'string' then for i = 1, #args do
accum[#accum + 1] = ("(e[%s] ~= nil)"):format(make_safe(item)) local v = args[i]
elseif type(item) == 'function' then if type(v) == "string" then
build[#build + 1] = ('local subfilter_%d_ = select(%d, ...)') acc = acc or (e[v] ~= nil)
:format(i, i) elseif type(v) == "function" then
accum[#accum + 1] = ('(subfilter_%d_(system, e))'):format(i) acc = acc or v(system, e)
else else
error 'Filter token must be a string or a filter function.' 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
end end
local source = ('%s\nreturn function(system, e) return %s(%s) end')
:format( -- computes a simple xor
table.concat(build, '\n'), if invert then
prefix, return not acc
table.concat(accum, seperator)) else
local loader, err = loadstring(source) return acc
if err then error(err) end end
return loader(...)
end end
end
do
function filterJoin(...) function filterJoin(...)
local state, value = pcall(filterJoinRaw, ...) local state, value = pcall(filterJoinRaw, ...)
@ -169,25 +188,25 @@ end
--- Makes a Filter that selects Entities with all specified Components and --- Makes a Filter that selects Entities with all specified Components and
-- Filters. -- Filters.
function tiny.requireAll(...) function tiny.requireAll(...)
return filterJoin('', ' and ', ...) return filterJoin(false, 'and', ...)
end end
--- Makes a Filter that selects Entities with at least one of the specified --- Makes a Filter that selects Entities with at least one of the specified
-- Components and Filters. -- Components and Filters.
function tiny.requireAny(...) function tiny.requireAny(...)
return filterJoin('', ' or ', ...) return filterJoin(false, 'or', ...)
end end
--- Makes a Filter that rejects Entities with all specified Components and --- Makes a Filter that rejects Entities with all specified Components and
-- Filters, and selects all other Entities. -- Filters, and selects all other Entities.
function tiny.rejectAll(...) function tiny.rejectAll(...)
return filterJoin('not', ' and ', ...) return filterJoin(true, 'and', ...)
end end
--- Makes a Filter that rejects Entities with at least one of the specified --- Makes a Filter that rejects Entities with at least one of the specified
-- Components and Filters, and selects all other Entities. -- Components and Filters, and selects all other Entities.
function tiny.rejectAny(...) function tiny.rejectAny(...)
return filterJoin('not', ' or ', ...) return filterJoin(true, 'or', ...)
end end
--- Makes a Filter from a string. Syntax of `pattern` is as follows. --- 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 process = system.process
local postProcess = system.postProcess local postProcess = system.postProcess
local shouldSkipSystemProcess = false
if preProcess then if preProcess then
preProcess(system, dt) shouldSkipSystemProcess = preProcess(system, dt)
end end
if process then if process and not shouldSkipSystemProcess then
if system.nocache then if system.nocache then
local entities = system.world.entities local entities = system.world.entities
local filter = system.filter local filter = system.filter
@ -327,7 +347,7 @@ local function processingSystemUpdate(system, dt)
end end
end end
if postProcess then if postProcess and not shouldSkipSystemProcess then
postProcess(system, dt) postProcess(system, dt)
end end
end end
@ -420,6 +440,7 @@ local worldMetaTable
--- Creates a new World. --- Creates a new World.
-- Can optionally add default Systems and Entities. Returns the new World along -- Can optionally add default Systems and Entities. Returns the new World along
-- with default Entities and Systems. -- with default Entities and Systems.
---@return World
function tiny.world(...) function tiny.world(...)
local ret = setmetatable({ local ret = setmetatable({
@ -861,4 +882,5 @@ worldMetaTable = {
end end
} }
return tiny _G.tiny = tiny
return tiny