Files
Endfield-Data/LuaScripts/Common/Core/Coroutine.lua
2025-12-02 20:37:18 +07:00

256 lines
6.0 KiB
Lua

local create = coroutine.create
local running = coroutine.running
local resume = coroutine.resume
local yield = coroutine.yield
local getinfo = debug.getinfo
local corTimers = {}
local corUpdates = {}
local corInRequest = {}
local stoppedCor = {}
local waitStepCors = {}
local waitStepCorCount = 0
local corToDebugInfo = {}
setmetatable(corToDebugInfo, {
__mode = "kv"
})
setmetatable(stoppedCor, {
__mode = "k"
})
local emptyFun = function() end
local begin_unity_sample = emptyFun
local end_unity_sample = emptyFun
local getFileInfo = emptyFun
if unity_sample and unity_sample.begin_unity_sample then
if DEVELOPMENT_BUILD or UNITY_EDITOR then
getFileInfo = function (co)
local info = getinfo(4,"Sl")
corToDebugInfo[co] = (info.short_src..":"..info.currentline):match("([^\\/]+)$")
end
begin_unity_sample = unity_sample.begin_unity_sample
end_unity_sample = unity_sample.end_unity_sample
end
end
function coroutine.start(f)
local co = create(f)
getFileInfo(co)
if running() == nil then
begin_unity_sample(corToDebugInfo[co])
local flag, msg = resume(co)
end_unity_sample()
if not flag then
logger.error(debug.traceback(co, msg), corToDebugInfo[co])
end
else
local action = function()
if not corTimers[co] then
return
end
corTimers[co] = nil
begin_unity_sample(corToDebugInfo[co])
local flag, msg = resume(co)
end_unity_sample()
if not flag then
logger.error(debug.traceback(co, msg), corToDebugInfo[co])
end
end
local timer = TimerManager:StartFrameTimer(0, action)
corTimers[co] = timer
end
return co
end
function coroutine.wait(t, co)
co = co or running()
if stoppedCor[co] then
return yield()
end
local action = function()
if not corTimers[co] then
return
end
corTimers[co] = nil
begin_unity_sample(corToDebugInfo[co])
local flag, msg = resume(co)
end_unity_sample()
if not flag then
logger.error(debug.traceback(co, msg), corToDebugInfo[co])
return
end
end
local timer = TimerManager:StartTimer(t, action)
corTimers[co] = timer
return yield()
end
local stepUpdateKey
function coroutine.step(co)
co = co or running()
if stoppedCor[co] then
return yield()
end
if not stepUpdateKey then
stepUpdateKey = LuaUpdate:Add("Tick", coroutine._stepUpdate)
end
waitStepCorCount = waitStepCorCount + 1
waitStepCors[waitStepCorCount] = co
return yield()
end
function coroutine.waitForRenderDone(co)
co = co or running()
if stoppedCor[co] then
return yield()
end
local key = LuaUpdate:Add("RenderDone", function()
LuaUpdate:Remove(corUpdates[co])
corUpdates[co] = nil
begin_unity_sample(corToDebugInfo[co])
local flag, msg = resume(co)
end_unity_sample()
if not flag then
logger.error(debug.traceback(co, msg), corToDebugInfo[co])
end
return true
end)
corUpdates[co] = key
return yield()
end
function coroutine._stepUpdate()
local count = waitStepCorCount
waitStepCorCount = 0
local cors = waitStepCors
waitStepCors = {}
for k = 1, count do
local stepCo = cors[k]
if stepCo and not stoppedCor[stepCo] then
begin_unity_sample(corToDebugInfo[stepCo])
local flag, msg = resume(stepCo)
end_unity_sample()
if not flag then
logger.error(debug.traceback(stepCo, msg), corToDebugInfo[stepCo])
end
end
end
end
function coroutine.stop(co)
stoppedCor[co] = true
local timer = corTimers[co]
if timer ~= nil then
TimerManager:ClearTimer(timer)
corTimers[co] = nil
end
corInRequest[co] = nil
local updateKey = corUpdates[co]
if updateKey then
LuaUpdate:Remove(updateKey)
end
for k = 1, waitStepCorCount do
if waitStepCors[k] == co then
waitStepCors[k] = nil
end
end
end
function coroutine.waitAsyncRequest(request, co)
co = co or running()
if stoppedCor[co] then
return yield()
end
corInRequest[co] = true
local action = function()
if not corInRequest[co] then
return
end
corInRequest[co] = nil
corTimers[co] = nil
begin_unity_sample(corToDebugInfo[co])
local flag, msg = resume(co)
end_unity_sample()
if not flag then
logger.error(debug.traceback(co, msg), corToDebugInfo[co])
return
end
end
local timer = TimerManager:StartFrameTimer(0, function()
request(action)
end)
corTimers[co] = timer
return yield()
end
coroutine.Tick = -1
coroutine.LateTick = -2
coroutine.TailTick = -3
function coroutine.waitCondition(condition, checkInterval, co)
co = co or running()
if stoppedCor[co] then
return yield()
end
checkInterval = checkInterval or coroutine.Tick
local tickName
if checkInterval == coroutine.Tick then
tickName = "Tick"
elseif checkInterval == coroutine.LateTick then
tickName = "LateTick"
elseif checkInterval == coroutine.TailTick then
tickName = "TailTick"
end
local key = LuaUpdate:Add(tickName, function()
if condition() then
LuaUpdate:Remove(corUpdates[co])
corUpdates[co] = nil
begin_unity_sample(corToDebugInfo[co])
local flag, msg = resume(co)
end_unity_sample()
if not flag then
logger.error(debug.traceback(co, msg), corToDebugInfo[co])
end
return true
end
end)
corUpdates[co] = key
return yield()
end