-- Callback Lib -- Dependencies: lib/EventRegistration local _, app = ...; -- Global locals local After, max, unpack = C_Timer.After, math.max, unpack; -- Setup the callback tables since they are heavily used local __callbacks = {}; local CallbackMethodCache = setmetatable({}, { -- Gets or Creates the actual method which runs as a callback to execute the specified method __index = function(t, method) -- app.PrintDebug("CB:New",method) local callbackMethod = function() local args = __callbacks[method]; __callbacks[method] = nil; -- callback with args/void if args ~= true then -- app.PrintDebug("CB:Run/args",method,unpack(args)) method(unpack(args)); else -- app.PrintDebug("CB:Run/void",method) method(); end -- app.PrintDebug("CB:Done",method) end; t[method] = callbackMethod; return callbackMethod; end }); local function Callback(method, ...) -- Triggers a timer callback method to run on the next game frame with the provided params; the method can only be set to run once per frame if not __callbacks[method] then __callbacks[method] = ... and {...} or true; After(0, CallbackMethodCache[method]); -- else app.PrintDebug("CB:Skip",method) end end local function DelayedCallback(method, delaySec, ...) -- Triggers a timer callback method to run after the provided number of seconds with the provided params; the method can only be set to run once per delay if not __callbacks[method] then __callbacks[method] = ... and {...} or true; After(max(0, delaySec or 0), CallbackMethodCache[method]); -- else app.PrintDebug("DCB:Skip",method) end end -- Callbacks to trigger after combat has ended! local __combatcallbacks = {}; local InCombatLockdown = InCombatLockdown; local function AfterCombatCallback(method, ...) -- Triggers a timer callback method to run on the next game frame or following combat if in combat currently with the provided params; the method can only be set to run once per frame if not InCombatLockdown() then Callback(method, ...); return; end if not __callbacks[method] then __callbacks[method] = ... and {...} or true; -- TODO: convert to a CallbackRunner? __combatcallbacks[#__combatcallbacks + 1] = CallbackMethodCache[method]; app:RegisterEvent("PLAYER_REGEN_ENABLED"); -- else app.PrintDebug("ACCB:Skip",method) end end local function AfterCombatOrDelayedCallback(method, delaySec, ...) -- Triggers a timer callback method to run either when current combat ends, or after the provided delay; the method can only be set to run once until it has been run if InCombatLockdown() then AfterCombatCallback(method, ...); else DelayedCallback(method, delaySec, ...); end end app:RegisterFuncEvent("PLAYER_REGEN_ENABLED", function() app:UnregisterEvent("PLAYER_REGEN_ENABLED"); -- print("PLAYER_REGEN_ENABLED:Begin") local callbacks = __combatcallbacks; local count = #callbacks; if count > 0 then __combatcallbacks = {}; for i=count,1,-1 do -- print(" callback:",i) callbacks[i](); end end -- print("PLAYER_REGEN_ENABLED:End") end) -- External API app.CallbackHandlers = { Callback = Callback, DelayedCallback = DelayedCallback, AfterCombatCallback = AfterCombatCallback, AfterCombatOrDelayedCallback = AfterCombatOrDelayedCallback };