jecs/test/btree.luau
2024-10-12 22:18:11 +02:00

152 lines
2.8 KiB
Text

-- original author @centauri
local bt
do
local FAILURE = 0
local SUCCESS = 1
local RUNNING = 2
local function SEQUENCE(nodes)
return function(...)
for _, node in nodes do
local status = node(...)
if status == FAILURE or status == RUNNING then
return status
end
end
return SUCCESS
end
end
local function FALLBACK(nodes)
return function(...)
for _, node in nodes do
local status = node(...)
if status == SUCCESS or status == RUNNING then
return status
end
end
return FAILURE
end
end
bt = {
SEQUENCE = SEQUENCE,
FALLBACK = FALLBACK,
RUNNING = RUNNING,
SUCCESS = SUCCESS,
FAILURE = FAILURE,
}
end
local SEQUENCE, FALLBACK = bt.SEQUENCE, bt.FALLBACK
local RUNNING, SUCCESS, FAILURE = bt.FAILURE, bt.SUCCESS, bt.FAILURE
local btree = FALLBACK({
SEQUENCE({
function()
return 1
end,
function()
return 0
end,
}),
SEQUENCE({
function()
print(3)
local start = os.clock()
local now = os.clock()
while os.clock() - now < 4 do
print("yielding")
coroutine.yield()
end
return 0
end,
}),
function()
return 1
end,
})
function wait(seconds)
local start = os.clock()
while os.clock() - start < seconds do
end
return os.clock() - start
end
local function panic(str)
-- We don't want to interrupt the loop when we error
coroutine.resume(coroutine.create(function()
error(str)
end))
end
local jecs = require("@jecs")
local world = jecs.World.new()
local function Scheduler(world, ...)
local systems = { ... }
local systemsNames = {}
local N = #systems
local system
local dt
for i, module in systems do
local sys = if typeof(module) == "function" then module else require(module)
systems[i] = sys
local file, line = debug.info(2, "sl")
systemsNames[sys] = `{file}->::{line}::->{debug.info(sys, "n")}`
end
local function run()
local name = systemsNames[system]
--debug.profilebegin(name)
--debug.setmemorycategory(name)
system(world, dt)
--debug.profileend()
end
local function loop(sinceLastFrame)
--debug.profilebegin("loop()")
local start = os.clock()
for i = N, 1, -1 do
system = systems[i]
dt = sinceLastFrame
local didNotYield, why = xpcall(function()
for _ in run do
end
end, debug.traceback)
if didNotYield then
continue
end
if string.find(why, "thread is not yieldable") then
N -= 1
local name = table.remove(systems, i)
panic("Not allowed to yield in the systems." .. "\n" .. `System: {name} has been ejected`)
else
panic(why)
end
end
--debug.profileend()
--debug.resetmemorycategory()
return os.clock() - start
end
return loop
end
local co = coroutine.create(btree)
local function ai(world, dt)
coroutine.resume(co)
end
local loop = Scheduler(world, ai)
while wait(0.2) do
print("frame time: ", loop(0.2))
end