Files

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
]]--