You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
404 lines
12 KiB
404 lines
12 KiB
local _, addon = ...
|
|
|
|
local CallbackRegistry = {};
|
|
CallbackRegistry.events = {};
|
|
addon.CallbackRegistry = CallbackRegistry;
|
|
|
|
local tinsert = table.insert;
|
|
local tremove = table.remove;
|
|
local type = type;
|
|
local ipairs = ipairs;
|
|
|
|
--[[
|
|
callbackType:
|
|
1. Function func(owner)
|
|
2. Method owner:func()
|
|
--]]
|
|
|
|
function CallbackRegistry:Register(event, func, owner, prioritized)
|
|
if not self.events[event] then
|
|
self.events[event] = {};
|
|
end
|
|
|
|
local callbackType;
|
|
|
|
if type(func) == "string" then
|
|
callbackType = 2;
|
|
else
|
|
callbackType = 1;
|
|
end
|
|
|
|
if prioritized then
|
|
tinsert(self.events[event], 1, {callbackType, func, owner})
|
|
else
|
|
tinsert(self.events[event], {callbackType, func, owner})
|
|
end
|
|
end
|
|
|
|
function CallbackRegistry:Trigger(event, ...)
|
|
if self.events[event] then
|
|
for _, cb in ipairs(self.events[event]) do
|
|
if cb[1] == 1 then
|
|
if cb[3] then
|
|
cb[2](cb[3], ...);
|
|
else
|
|
cb[2](...);
|
|
end
|
|
else
|
|
cb[3][cb[2]](cb[3], ...);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function CallbackRegistry:UnregisterCallback(event, callback, owner)
|
|
if self.events[event] then
|
|
local callbacks = self.events[event];
|
|
local i = 1;
|
|
local cb = callbacks[i];
|
|
|
|
if type(callback) == "string" then
|
|
if owner then
|
|
while cb do
|
|
if cb[1] == 2 and cb[2] == callback and cb[3] == owner then
|
|
tremove(callbacks, i);
|
|
else
|
|
i = i + 1;
|
|
end
|
|
cb = callbacks[i];
|
|
end
|
|
else
|
|
while cb do
|
|
if cb[1] == 2 and cb[2] == callback then
|
|
tremove(callbacks, i);
|
|
else
|
|
i = i + 1;
|
|
end
|
|
cb = callbacks[i];
|
|
end
|
|
end
|
|
else
|
|
while cb do
|
|
if cb[1] == 1 and cb[2] == callback then
|
|
tremove(callbacks, i);
|
|
else
|
|
i = i + 1;
|
|
end
|
|
cb = callbacks[i];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function CallbackRegistry:UnregisterEvent(event)
|
|
self.events[event] = nil;
|
|
end
|
|
|
|
function CallbackRegistry:RegisterTutorial(tutorialFlag, func, owner)
|
|
local event = "Tutorial."..tutorialFlag;
|
|
self:Register(event, func, owner);
|
|
end
|
|
|
|
|
|
local Processor = CreateFrame("Frame");
|
|
|
|
local function Processor_OnUpdate(self, elapsed)
|
|
self:SetScript("OnUpdate", nil);
|
|
if self.triggerQueue and self.anyDelayedTrigger then
|
|
self.anyDelayedTrigger = nil;
|
|
for event, args in pairs(self.triggerQueue) do
|
|
CallbackRegistry:Trigger(event, args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
|
|
end
|
|
self.triggerQueue = nil;
|
|
end
|
|
end
|
|
|
|
function CallbackRegistry:TriggerOnNextUpdate(event, ...)
|
|
--Use Case: in case Lua error appears and clogs other important processes
|
|
--Currently used by HelpTip
|
|
if self.events[event] then
|
|
if not Processor.anyDelayedTrigger then
|
|
Processor.triggerQueue = {};
|
|
Processor.anyDelayedTrigger = true;
|
|
end
|
|
Processor.triggerQueue[event] = {...};
|
|
Processor:SetScript("OnUpdate", Processor_OnUpdate);
|
|
end
|
|
end
|
|
|
|
|
|
do --UIParent OnShow/OnHide
|
|
local frame = CreateFrame("Frame", nil, UIParent);
|
|
|
|
frame:SetScript("OnShow", function()
|
|
CallbackRegistry:Trigger("UIParent.Show");
|
|
end);
|
|
|
|
frame:SetScript("OnHide", function()
|
|
CallbackRegistry:Trigger("UIParent.Hide");
|
|
end);
|
|
end
|
|
|
|
|
|
do --AsyncCallback
|
|
local EL = CreateFrame("Frame");
|
|
|
|
--LoadQuestAPI is not available in 60 Classic
|
|
--In this case we will run all callbacks when the time is up
|
|
EL.LoadQuest = C_QuestLog.RequestLoadQuestByID;
|
|
EL.LoadItem = C_Item.RequestLoadItemDataByID;
|
|
EL.LoadSpell = C_Spell.RequestLoadSpellData;
|
|
|
|
function EL:RunAllCallbacks(list)
|
|
for id, callbacks in pairs(list) do
|
|
for _, callbackInfo in ipairs(callbacks) do
|
|
if (callbackInfo.oneTime and not callbackInfo.processed) or (callbackInfo.oneTime == false) then
|
|
callbackInfo.processed = true;
|
|
callbackInfo.func(id);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function EL:OnEvent(event, ...)
|
|
local id, success = ...
|
|
local list;
|
|
|
|
if event == "QUEST_DATA_LOAD_RESULT" then
|
|
list = self.questCallbacks;
|
|
elseif event == "ITEM_DATA_LOAD_RESULT" then
|
|
list = self.itemCallbacks;
|
|
elseif event == "SPELL_DATA_LOAD_RESULT" then
|
|
list = self.spellCallbacks;
|
|
elseif event == "TOOLTIP_DATA_UPDATE" then
|
|
list = self.npcCallbacks;
|
|
success = true;
|
|
end
|
|
|
|
if list and id and success then
|
|
if list[id] then
|
|
for _, callbackInfo in ipairs(list[id]) do
|
|
if (callbackInfo.oneTime and not callbackInfo.processed) or (callbackInfo.oneTime == false) then
|
|
callbackInfo.processed = true;
|
|
callbackInfo.func(id);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
self.t = 0; --Reset close count down
|
|
end
|
|
EL:SetScript("OnEvent", EL.OnEvent);
|
|
|
|
function EL:OnUpdate(elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t > 0.5 then
|
|
self.t = nil;
|
|
self:SetScript("OnUpdate", nil);
|
|
|
|
if self.questCallbacks then
|
|
if self.LoadQuest then
|
|
self:UnregisterEvent("QUEST_DATA_LOAD_RESULT");
|
|
end
|
|
if self.runCallbackAfter then
|
|
self:RunAllCallbacks(self.questCallbacks);
|
|
end
|
|
self.questCallbacks = nil;
|
|
end
|
|
|
|
if self.itemCallbacks then
|
|
if self.LoadItem then
|
|
self:UnregisterEvent("ITEM_DATA_LOAD_RESULT");
|
|
end
|
|
self:RunAllCallbacks(self.itemCallbacks);
|
|
self.itemCallbacks = nil;
|
|
end
|
|
|
|
if self.spellCallbacks then
|
|
if self.LoadSpell then
|
|
self:UnregisterEvent("SPELL_DATA_LOAD_RESULT");
|
|
end
|
|
self:RunAllCallbacks(self.spellCallbacks);
|
|
self.spellCallbacks = nil;
|
|
end
|
|
|
|
if self.npcCallbacks then
|
|
if self.LoadNPC then
|
|
self:UnregisterEvent("TOOLTIP_DATA_UPDATE");
|
|
end
|
|
self:RunAllCallbacks(self.npcCallbacks);
|
|
self.npcCallbacks = nil;
|
|
end
|
|
end
|
|
end
|
|
|
|
function EL:AddCallback(key, id, callback, oneTime)
|
|
if not self[key] then
|
|
self[key] = {};
|
|
end
|
|
|
|
if not self[key][id] then
|
|
self[key][id] = {};
|
|
end
|
|
|
|
if oneTime == nil then
|
|
oneTime = true;
|
|
end
|
|
|
|
local callbackInfo = {
|
|
func = callback,
|
|
oneTime = oneTime,
|
|
processed = false,
|
|
};
|
|
|
|
tinsert(self[key][id], callbackInfo);
|
|
end
|
|
|
|
|
|
function CallbackRegistry:LoadQuest(id, callback, oneTime)
|
|
EL:AddCallback("questCallbacks", id, callback, oneTime);
|
|
if EL.LoadQuest then
|
|
EL:RegisterEvent("QUEST_DATA_LOAD_RESULT");
|
|
EL.LoadQuest(id);
|
|
else
|
|
EL.runCallbackAfter = true;
|
|
end
|
|
EL.t = 0;
|
|
EL:SetScript("OnUpdate", EL.OnUpdate);
|
|
end
|
|
|
|
function CallbackRegistry:LoadItem(id, callback, oneTime)
|
|
EL:AddCallback("itemCallbacks", id, callback, oneTime);
|
|
if EL.LoadItem then
|
|
EL:RegisterEvent("ITEM_DATA_LOAD_RESULT");
|
|
EL.LoadItem(id);
|
|
else
|
|
EL.runCallbackAfter = true;
|
|
end
|
|
EL.t = 0;
|
|
EL:SetScript("OnUpdate", EL.OnUpdate);
|
|
end
|
|
|
|
function CallbackRegistry:LoadSpell(id, callback, oneTime)
|
|
EL:AddCallback("spellCallbacks", id, callback, oneTime);
|
|
if EL.LoadSpell then
|
|
EL:RegisterEvent("SPELL_DATA_LOAD_RESULT");
|
|
EL.LoadSpell(id);
|
|
else
|
|
EL.runCallbackAfter = true;
|
|
end
|
|
EL.t = 0;
|
|
EL:SetScript("OnUpdate", EL.OnUpdate);
|
|
end
|
|
|
|
|
|
if C_TooltipInfo then
|
|
function CallbackRegistry:LoadNPC(creatureID, callback, isRequery)
|
|
local tooltipData = addon.TooltipAPI.GetHyperlink("unit:Creature-0-0-0-0-"..creatureID);
|
|
local dataInstanceID, newCallback;
|
|
if tooltipData and tooltipData.lines then
|
|
local name = tooltipData.lines[1].leftText;
|
|
if name and name ~= "" then
|
|
callback(creatureID, name);
|
|
else
|
|
dataInstanceID = tooltipData.dataInstanceID;
|
|
newCallback = function()
|
|
local tooltipData = addon.TooltipAPI.GetHyperlink("unit:Creature-0-0-0-0-"..creatureID);
|
|
local name = tooltipData.lines[1].leftText;
|
|
if name and name ~= "" then
|
|
callback(creatureID, name);
|
|
end
|
|
end
|
|
end
|
|
elseif not isRequery then
|
|
dataInstanceID = 0;
|
|
newCallback = function()
|
|
local tooltipData = addon.TooltipAPI.GetHyperlink("unit:Creature-0-0-0-0-"..creatureID);
|
|
local name = tooltipData and tooltipData.lines and tooltipData.lines[1].leftText;
|
|
if name and name ~= "" then
|
|
callback(creatureID, name);
|
|
end
|
|
end
|
|
end
|
|
|
|
if dataInstanceID and newCallback then
|
|
EL:AddCallback("npcCallbacks", dataInstanceID, newCallback);
|
|
EL:RegisterEvent("TOOLTIP_DATA_UPDATE");
|
|
if not EL.t then
|
|
EL.t = 0;
|
|
end
|
|
if EL.t > 0 then
|
|
--Extend the shutdown countdown because we usually acquire NPC name during log-in
|
|
EL.t = -0.5;
|
|
end
|
|
EL:SetScript("OnUpdate", EL.OnUpdate);
|
|
end
|
|
end
|
|
else
|
|
function CallbackRegistry:LoadNPC()
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
do --Public methods for addon compatibility (NOT IMPLEMENTED)
|
|
|
|
--Private
|
|
local IsCallbackAllowed = {};
|
|
local EventObject = {};
|
|
local PublicCallbacks = {};
|
|
|
|
local function AddSupportedPublicCallback(event, objectGetter)
|
|
IsCallbackAllowed[event] = true;
|
|
if objectGetter then
|
|
if EventObject[event] then
|
|
addon.API.PrintMessage(string.format("Public Event (%s) already has a owner"));
|
|
else
|
|
EventObject[event] = objectGetter;
|
|
end
|
|
end
|
|
end
|
|
addon.AddSupportedPublicCallback = AddSupportedPublicCallback;
|
|
|
|
|
|
function CallbackRegistry:TriggerExternalEvent(event, ...)
|
|
if IsCallbackAllowed[event] and PublicCallbacks[event] then
|
|
local objectGetter = EventObject[event];
|
|
local obj;
|
|
|
|
if objectGetter then
|
|
obj = objectGetter();
|
|
end
|
|
|
|
for _, cb in ipairs(PublicCallbacks[event]) do
|
|
cb(obj, ...);
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
--Public
|
|
local function RegisterCallback(event, callback)
|
|
--payloads: isRegistered, isNew
|
|
|
|
if event and type(event) == "string" and callback and type(callback) == "function" then
|
|
if not PublicCallbacks[event] then
|
|
PublicCallbacks[event] = {};
|
|
end
|
|
|
|
for _, cb in ipairs(PublicCallbacks[event]) do
|
|
if cb == callback then
|
|
return true, false
|
|
end
|
|
end
|
|
|
|
table.insert(PublicCallbacks[event], callback);
|
|
|
|
return true, true
|
|
end
|
|
|
|
return false, false
|
|
end
|
|
--DialogueUIAPI.RegisterCallback = RegisterCallback;
|
|
end
|