ee0b350aba
- Dungeon followers now correctly show into the damage done section. - Fixed an error while statusbar plugin options. - Framework update. - Mythic Dungeon Plus code has been separated into six files (was just 2), this will help with the organization and maintenance of the code.
277 lines
9.5 KiB
Lua
277 lines
9.5 KiB
Lua
|
|
local detailsFramework = _G["DetailsFramework"]
|
|
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
|
return
|
|
end
|
|
|
|
local C_Timer = _G.C_Timer
|
|
local unpack = table.unpack or _G.unpack
|
|
local GetTime = GetTime
|
|
|
|
local CONST_DEBUG_ENABLED = false
|
|
|
|
--make a namespace for schedules
|
|
detailsFramework.Schedules = detailsFramework.Schedules or {}
|
|
|
|
detailsFramework.Schedules.AfterCombatSchedules = {
|
|
withId = {},
|
|
withoutId = {},
|
|
}
|
|
|
|
---@class df_schedule : table
|
|
---@field NewTicker fun(time: number, callback: function, ...: any): timer
|
|
---@field NewLooper fun(time: number, callback: function, loopAmount: number, loopEndCallback: function?, checkPointCallback: function?, ...: any): timer
|
|
---@field NewTimer fun(time: number, callback: function, ...: any): timer
|
|
---@field Cancel fun(ticker: timer)
|
|
---@field After fun(time: number, callback: function)
|
|
---@field SetName fun(object: timer, name: string)
|
|
---@field RunNextTick fun(callback: function)
|
|
---@field AfterCombat fun(callback:function, id:any, ...: any)
|
|
---@field CancelAfterCombat fun(id: any)
|
|
---@field CancelAllAfterCombat fun()
|
|
---@field IsAfterCombatScheduled fun(id: any): boolean
|
|
---@field LazyExecute fun(callback: function, payload: table?, maxIterations: number?, onEndCallback: function?): table
|
|
---@field AfterById fun(time: number, callback: function, id: any, ...: any): timer
|
|
|
|
---@class df_looper : table
|
|
---@field payload table
|
|
---@field callback function
|
|
---@field loopEndCallback function?
|
|
---@field checkPointCallback function?
|
|
---@field nextCheckPoint number
|
|
---@field lastLoop number
|
|
---@field currentLoop number
|
|
---@field Cancel fun()
|
|
---@field IsCancelled fun(): boolean
|
|
|
|
local eventFrame = CreateFrame("frame")
|
|
eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
|
|
eventFrame:SetScript("OnEvent", function(self, event)
|
|
if (event == "PLAYER_REGEN_ENABLED") then
|
|
for _, schedule in ipairs(detailsFramework.Schedules.AfterCombatSchedules.withoutId) do
|
|
xpcall(schedule.callback, geterrorhandler(), unpack(schedule.payload))
|
|
end
|
|
|
|
for _, schedule in pairs(detailsFramework.Schedules.AfterCombatSchedules.withId) do
|
|
xpcall(schedule.callback, geterrorhandler(), unpack(schedule.payload))
|
|
end
|
|
|
|
table.wipe(detailsFramework.Schedules.AfterCombatSchedules.withoutId)
|
|
table.wipe(detailsFramework.Schedules.AfterCombatSchedules.withId)
|
|
end
|
|
end)
|
|
|
|
local triggerScheduledLoop = function(tickerObject)
|
|
if (tickerObject:IsCancelled()) then
|
|
return
|
|
end
|
|
|
|
local payload = tickerObject.payload
|
|
local callback = tickerObject.callback
|
|
|
|
--local result, errortext = pcall(callback, unpack(payload))
|
|
local runOkay, result = xpcall(callback, geterrorhandler(), unpack(payload))
|
|
--if (not result) then
|
|
-- detailsFramework:Msg("error on scheduler: ",tickerObject.path , tickerObject.name, errortext)
|
|
--end
|
|
|
|
local checkPointCallback = tickerObject.checkPointCallback
|
|
if (checkPointCallback) then
|
|
if (GetTime() >= tickerObject.nextCheckPoint) then
|
|
local checkPointResult = checkPointCallback(unpack(payload))
|
|
if (not checkPointResult) then
|
|
tickerObject:Cancel()
|
|
if (tickerObject.loopEndCallback) then
|
|
tickerObject.loopEndCallback()
|
|
end
|
|
return
|
|
end
|
|
tickerObject.nextCheckPoint = GetTime() + 1
|
|
end
|
|
end
|
|
|
|
tickerObject.currentLoop = tickerObject.currentLoop + 1
|
|
|
|
if (tickerObject.currentLoop == tickerObject.lastLoop) then
|
|
tickerObject:Cancel()
|
|
if (tickerObject.loopEndCallback) then
|
|
tickerObject.loopEndCallback()
|
|
end
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
---start a loop which will tick @loopAmount of times, then call @loopEndCallback if exists
|
|
---checkPointCallback will be called every time the loop ticks, if it returns false, the loop will be cancelled
|
|
---@param time number
|
|
---@param callback function
|
|
---@param loopAmount number
|
|
---@param loopEndCallback function?
|
|
---@param checkPointCallback function?
|
|
---@vararg any
|
|
---@return df_looper
|
|
function detailsFramework.Schedules.NewLooper(time, callback, loopAmount, loopEndCallback, checkPointCallback, ...)
|
|
local payload = {...}
|
|
---@type df_looper
|
|
local newLooper = C_Timer.NewTicker(time, triggerScheduledLoop, loopAmount)
|
|
newLooper.payload = payload
|
|
newLooper.callback = callback
|
|
newLooper.loopEndCallback = loopEndCallback
|
|
newLooper.checkPointCallback = checkPointCallback
|
|
newLooper.nextCheckPoint = GetTime() + 1
|
|
newLooper.lastLoop = loopAmount
|
|
newLooper.currentLoop = 1
|
|
return newLooper
|
|
end
|
|
|
|
--run a scheduled function with its payload
|
|
local triggerScheduledTick = function(tickerObject)
|
|
local payload = tickerObject.payload
|
|
local callback = tickerObject.callback
|
|
|
|
local runOkay, result = xpcall(callback, geterrorhandler(), unpack(payload))
|
|
--local result, errortext = pcall(callback, unpack(payload))
|
|
--if (not result) then
|
|
-- detailsFramework:Msg("error on scheduler: ",tickerObject.path , tickerObject.name, errortext)
|
|
--end
|
|
return result
|
|
end
|
|
|
|
--schedule to repeat a task with an interval of @time, keep ticking until cancelled
|
|
function detailsFramework.Schedules.NewTicker(time, callback, ...)
|
|
local payload = {...}
|
|
local newTicker = C_Timer.NewTicker(time, triggerScheduledTick)
|
|
newTicker.payload = payload
|
|
newTicker.callback = callback
|
|
|
|
--debug
|
|
newTicker.path = CONST_DEBUG_ENABLED and debugstack() or ""
|
|
|
|
return newTicker
|
|
end
|
|
|
|
--schedule a task with an interval of @time
|
|
function detailsFramework.Schedules.NewTimer(time, callback, ...)
|
|
local payload = {...}
|
|
local newTimer = C_Timer.NewTimer(time, triggerScheduledTick)
|
|
newTimer.payload = payload
|
|
newTimer.callback = callback
|
|
newTimer.expireAt = GetTime() + time
|
|
|
|
--debug
|
|
newTimer.path = CONST_DEBUG_ENABLED and debugstack() or ""
|
|
|
|
return newTimer
|
|
end
|
|
|
|
--cancel an ongoing ticker, the native call tickerObject:Cancel() also works with no problem
|
|
function detailsFramework.Schedules.Cancel(tickerObject)
|
|
--ignore if there's no ticker object
|
|
if (tickerObject) then
|
|
return tickerObject:Cancel()
|
|
end
|
|
end
|
|
|
|
--schedule a task to be executed when the player leaves combat
|
|
function detailsFramework.Schedules.AfterCombat(callback, id, ...)
|
|
local bInCombatLockdown = UnitAffectingCombat("player") or InCombatLockdown()
|
|
|
|
if (not bInCombatLockdown) then
|
|
xpcall(callback, geterrorhandler(), ...)
|
|
return
|
|
end
|
|
|
|
local payload = {...}
|
|
|
|
if (id) then
|
|
detailsFramework.Schedules.AfterCombatSchedules.withId[id] = {
|
|
callback = callback,
|
|
payload = payload,
|
|
id = id,
|
|
}
|
|
else
|
|
table.insert(detailsFramework.Schedules.AfterCombatSchedules.withoutId, {
|
|
callback = callback,
|
|
payload = payload,
|
|
})
|
|
end
|
|
end
|
|
|
|
function detailsFramework.Schedules.CancelAfterCombat(id)
|
|
detailsFramework.Schedules.AfterCombatSchedules.withId[id] = nil
|
|
end
|
|
|
|
function detailsFramework.Schedules.CancelAllAfterCombat()
|
|
table.wipe(detailsFramework.Schedules.AfterCombatSchedules.withId)
|
|
table.wipe(detailsFramework.Schedules.AfterCombatSchedules.withoutId)
|
|
end
|
|
|
|
function detailsFramework.Schedules.IsAfterCombatScheduled(id)
|
|
return detailsFramework.Schedules.AfterCombatSchedules.withId[id] ~= nil
|
|
end
|
|
|
|
---execute each frame a small portion of a big task
|
|
---the callback function receives a payload, the current iteration index and the max iterations
|
|
---if the callback function return true, the task is finished
|
|
---@param callback function
|
|
---@param payload table?
|
|
---@param maxIterations number?
|
|
---@param onEndCallback function?
|
|
function detailsFramework.Schedules.LazyExecute(callback, payload, maxIterations, onEndCallback)
|
|
assert(type(callback) == "function", "DetailsFramework.Schedules.LazyExecute() param #1 'callback' must be a function.")
|
|
maxIterations = maxIterations or 100000
|
|
payload = payload or {}
|
|
local iterationIndex = 1
|
|
|
|
local function wrapFunc()
|
|
local bIsFinished = callback(payload, iterationIndex, maxIterations)
|
|
if (not bIsFinished) then
|
|
iterationIndex = iterationIndex + 1
|
|
if (iterationIndex > maxIterations) then
|
|
detailsFramework:QuickDispatch(onEndCallback, payload)
|
|
return
|
|
end
|
|
C_Timer.After(0, function() wrapFunc() end)
|
|
else
|
|
detailsFramework:QuickDispatch(onEndCallback, payload)
|
|
return
|
|
end
|
|
end
|
|
|
|
wrapFunc()
|
|
|
|
return payload
|
|
end
|
|
|
|
--Schedules a callback function to be executed after a specified time delay.
|
|
--It uniquely identifies each scheduled task by an ID, cancel and replace any existing schedules with the same ID.
|
|
function detailsFramework.Schedules.AfterById(time, callback, id, ...)
|
|
if (not detailsFramework.Schedules.ExecuteTimerTable) then
|
|
detailsFramework.Schedules.ExecuteTimerTable = {}
|
|
end
|
|
|
|
local alreadyHaveTimer = detailsFramework.Schedules.ExecuteTimerTable[id]
|
|
if (alreadyHaveTimer) then
|
|
alreadyHaveTimer:Cancel()
|
|
end
|
|
|
|
local newTimer = detailsFramework.Schedules.NewTimer(time, callback, ...)
|
|
detailsFramework.Schedules.ExecuteTimerTable[id] = newTimer
|
|
|
|
return newTimer
|
|
end
|
|
|
|
|
|
--schedule a task with an interval of @time without payload
|
|
function detailsFramework.Schedules.After(time, callback)
|
|
C_Timer.After(time, callback)
|
|
end
|
|
|
|
function detailsFramework.Schedules.SetName(object, name)
|
|
object.name = name
|
|
end
|
|
|
|
function detailsFramework.Schedules.RunNextTick(callback)
|
|
return detailsFramework.Schedules.After(0, callback)
|
|
end |