138 lines
5.2 KiB
Lua
138 lines
5.2 KiB
Lua
---@class ThreadLib
|
|
local ThreadLib = QuestieLoader:CreateModule("ThreadLib")
|
|
|
|
--- COMPATIBILITY ---
|
|
local C_Timer = QuestieCompat.C_Timer
|
|
|
|
--Coroutine functions
|
|
local coStatus, coResume, coCreate = coroutine.status, coroutine.resume, coroutine.create
|
|
local lType = type
|
|
-- local cTimer = C_Timer
|
|
local newTicker = C_Timer.NewTicker
|
|
|
|
|
|
---Thread a function, callback function is called when the thread is done.
|
|
---@param threadFunction function @The function to thread
|
|
---@param delay integer @Anything below 0.05 is each frame
|
|
---@param errorMessage string? @What is the "Prepend" of the error message
|
|
---@param callbackFunction function? @Function to call when the thread is done
|
|
---@return Ticker Timer @The WoW timer, run Timer:Cancel() and let the handle of the thread become orphaned to cancel
|
|
---@return thread Thread @The coroutine thread
|
|
function ThreadLib.Thread(threadFunction, delay, errorMessage, callbackFunction)
|
|
if lType(threadFunction) ~= "function" then
|
|
error("ThreadLib:Thread: threadFunction is not a function")
|
|
end
|
|
if lType(delay) ~= "number" then
|
|
error("ThreadLib:Thread: delay is not a number")
|
|
end
|
|
if errorMessage and lType(errorMessage) ~= "string" then
|
|
error("ThreadLib:Thread: errorMessage is not a string")
|
|
end
|
|
if callbackFunction and lType(callbackFunction) ~= "function" then
|
|
error("ThreadLib:Thread: callbackFunction is not a function")
|
|
end
|
|
|
|
local thread = coCreate(threadFunction)
|
|
|
|
local timer
|
|
timer = newTicker(delay or 0, function()
|
|
if(coStatus(thread) == "suspended") then --It's faster not to lookup the value but instead have it here
|
|
local success, ret = coResume(thread)
|
|
-- Something in the coroutine went wrong, print the error and stop the timer
|
|
if not success then
|
|
Questie:Error(errorMessage or "Error in thread", ret)
|
|
timer:Cancel();
|
|
end
|
|
elseif (coStatus(thread) == "dead") then --It's faster not to lookup the value but instead have it here
|
|
timer:Cancel();
|
|
if(callbackFunction) then
|
|
callbackFunction()
|
|
end
|
|
|
|
--? Is this needed?
|
|
timer = nil
|
|
---@diagnostic disable-next-line: cast-local-type
|
|
thread = nil
|
|
end
|
|
end)
|
|
return timer, thread
|
|
end
|
|
|
|
---Thread a function, callback function is called when the thread is done.
|
|
---@param threadFunction function @The function to thread
|
|
---@param delay integer @Anything below 0.05 is each frame
|
|
---@param callbackFunction function @Function to call when the thread is done
|
|
---@return Ticker Timer @The WoW timer, run Timer:Cancel() and let the handle of the thread become orphaned to cancel
|
|
---@return thread Thread @The coroutine thread
|
|
function ThreadLib.ThreadCallback(threadFunction, delay, callbackFunction)
|
|
return ThreadLib.Thread(threadFunction, delay, nil, callbackFunction)
|
|
end
|
|
|
|
---Thread a function, using a specific error message.
|
|
---@param threadFunction function @The function to thread
|
|
---@param delay integer @Anything below 0.05 is each frame
|
|
---@param errorMessage string @What is the "Prepend" of the error message
|
|
---@return Ticker Timer @The WoW timer, run Timer:Cancel() and let the handle of the thread become orphaned to cancel
|
|
---@return thread Thread @The coroutine thread
|
|
function ThreadLib.ThreadError(threadFunction, delay, errorMessage)
|
|
return ThreadLib.Thread(threadFunction, delay, errorMessage)
|
|
end
|
|
|
|
---Thread a function
|
|
---@param threadFunction function @The function to thread
|
|
---@param delay integer @Anything below 0.05 is each frame
|
|
---@return Ticker Timer @The WoW timer, run Timer:Cancel() and let the handle of the thread become orphaned to cancel
|
|
---@return thread Thread @The coroutine thread
|
|
function ThreadLib.ThreadSimple(threadFunction, delay)
|
|
return ThreadLib.Thread(threadFunction, delay)
|
|
end
|
|
|
|
|
|
--? This was kind of a halv baked idea, that i questioned was even good, but i don't really want to delete it yet.
|
|
--[[
|
|
|
|
---@class Thread
|
|
---@field private _thread thread
|
|
---@field private _timer Ticker
|
|
---@field private _callback function?
|
|
---@field Kill fun()
|
|
local newThread = {
|
|
_thread = coCreate(threadFunction),
|
|
_callback = callbackFunction,
|
|
|
|
Continue = ThreadContinue,
|
|
|
|
---@param self Thread
|
|
Kill = function(self)
|
|
print(Questie.DEBUG_CRITICAL, "[ThreadLib] Thread cancelled")
|
|
self._timer:Cancel()
|
|
self._thread = nil
|
|
self._timer = nil
|
|
self.Kill = nil
|
|
self.Continue = nil
|
|
end
|
|
}
|
|
|
|
newThread._timer = newTicker(delay or 0, function()
|
|
if(coStatus(newThread._thread) == "suspended") then --It's faster not to lookup the value but instead have it here
|
|
local success, ret = coResume(newThread._thread)
|
|
-- Something in the coroutine went wrong, print the error and stop the timer
|
|
if not success then
|
|
Questie:Error(errorMessage or "Error in thread", ret)
|
|
newThread._timer:Cancel();
|
|
end
|
|
elseif (coStatus(newThread._thread) == "dead") then --It's faster not to lookup the value but instead have it here
|
|
newThread._timer:Cancel();
|
|
if(newThread._callback) then
|
|
callbackFunction()
|
|
end
|
|
newThread._thread = nil
|
|
newThread._timer = nil
|
|
wipe(newThread)
|
|
end
|
|
end)
|
|
|
|
return newThread
|
|
|
|
]]--
|