feat: release v1.4.6 - Fix SavedVariables persistence and red textures for MafWow/3.3.5a
This commit is contained in:
@@ -65,7 +65,7 @@ function _QuestieJourney:GetJourneyEntries()
|
||||
local dateTable = {}
|
||||
-- -- Sort all of the entries by year and month
|
||||
-- ---@param v JourneyEntry
|
||||
for i, v in ipairs(Questie.db.char.journey) do
|
||||
for i, v in ipairs(Questie.dbJourney.char.journey) do
|
||||
local year = tonumber(date('%Y', v.Timestamp))
|
||||
if (not dateTable[year]) then
|
||||
dateTable[year] = {}
|
||||
|
||||
@@ -155,7 +155,7 @@ function QuestieJourney:PlayerLevelUp(level)
|
||||
Timestamp = time()
|
||||
}
|
||||
|
||||
tinsert(Questie.db.char.journey, entry)
|
||||
tinsert(Questie.dbJourney.char.journey, entry)
|
||||
end
|
||||
|
||||
function QuestieJourney:AcceptQuest(questId)
|
||||
@@ -169,16 +169,15 @@ function QuestieJourney:AcceptQuest(questId)
|
||||
Timestamp = time()
|
||||
}
|
||||
|
||||
tinsert(Questie.db.char.journey, entry)
|
||||
tinsert(Questie.dbJourney.char.journey, entry)
|
||||
end
|
||||
|
||||
function QuestieJourney:AbandonQuest(questId)
|
||||
-- Abandon Quest added to Journey
|
||||
-- first check to see if the quest has been completed already or not
|
||||
local skipAbandon = false
|
||||
for i in ipairs(Questie.db.char.journey) do
|
||||
|
||||
local entry = Questie.db.char.journey[i]
|
||||
for i in ipairs(Questie.dbJourney.char.journey) do
|
||||
local entry = Questie.dbJourney.char.journey[i]
|
||||
if entry.Event == "Quest" then
|
||||
if entry.Quest == questId then
|
||||
if entry.SubType == "Complete" then
|
||||
@@ -198,7 +197,7 @@ function QuestieJourney:AbandonQuest(questId)
|
||||
Timestamp = time()
|
||||
}
|
||||
|
||||
tinsert(Questie.db.char.journey, entry)
|
||||
tinsert(Questie.dbJourney.char.journey, entry)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -213,5 +212,5 @@ function QuestieJourney:CompleteQuest(questId)
|
||||
Timestamp = time()
|
||||
}
|
||||
|
||||
tinsert(Questie.db.char.journey, entry)
|
||||
tinsert(Questie.dbJourney.char.journey, entry)
|
||||
end
|
||||
|
||||
@@ -58,7 +58,7 @@ function _QuestieJourney.myJourney:ManageTree(container)
|
||||
local created = AceGUI:Create("Label");
|
||||
created:SetFullWidth(true);
|
||||
|
||||
local entry = Questie.db.char.journey[tonumber(e)];
|
||||
local entry = Questie.dbJourney.char.journey[tonumber(e)];
|
||||
local day = CALENDAR_WEEKDAY_NAMES[ tonumber(date('%w', entry.Timestamp)) + 1 ];
|
||||
local month = CALENDAR_FULLDATE_MONTH_NAMES[ tonumber(date('%m', entry.Timestamp)) ];
|
||||
local timestamp = Questie:Colorize(date( day ..', '.. month ..' %d @ %H:%M' , entry.Timestamp), 'blue');
|
||||
|
||||
@@ -28,7 +28,7 @@ function _QuestieJourney.myJourney:DrawTab(container)
|
||||
QuestieJourneyUtils:Spacer(container);
|
||||
|
||||
-- get last 5 elements from table for history
|
||||
local counter = #Questie.db.char.journey;
|
||||
local counter = #Questie.dbJourney.char.journey;
|
||||
local recentEvents = {};
|
||||
for i = counter, counter-4, -1 do
|
||||
if i <= 0 then
|
||||
@@ -39,30 +39,30 @@ function _QuestieJourney.myJourney:DrawTab(container)
|
||||
recentEvents[i] = AceGUI:Create("Label");
|
||||
recentEvents[i]:SetFullWidth(true);
|
||||
|
||||
local day = CALENDAR_WEEKDAY_NAMES[tonumber(date('%w', Questie.db.char.journey[i].Timestamp)) + 1];
|
||||
local month = CALENDAR_FULLDATE_MONTH_NAMES[tonumber(date('%m', Questie.db.char.journey[i].Timestamp))];
|
||||
local day = CALENDAR_WEEKDAY_NAMES[tonumber(date('%w', Questie.dbJourney.char.journey[i].Timestamp)) + 1];
|
||||
local month = CALENDAR_FULLDATE_MONTH_NAMES[tonumber(date('%m', Questie.dbJourney.char.journey[i].Timestamp))];
|
||||
|
||||
local timestamp = Questie:Colorize(date( '[ '..day ..', '.. month ..' %d @ %H:%M ] ' , Questie.db.char.journey[i].Timestamp), 'blue');
|
||||
local timestamp = Questie:Colorize(date( '[ '..day ..', '.. month ..' %d @ %H:%M ] ' , Questie.dbJourney.char.journey[i].Timestamp), 'blue');
|
||||
|
||||
-- if it's a quest event
|
||||
if Questie.db.char.journey[i].Event == "Quest" then
|
||||
local qName = QuestieDB.QueryQuestSingle(Questie.db.char.journey[i].Quest, "name");
|
||||
if Questie.dbJourney.char.journey[i].Event == "Quest" then
|
||||
local qName = QuestieDB.QueryQuestSingle(Questie.dbJourney.char.journey[i].Quest, "name");
|
||||
if qName then
|
||||
qName = Questie:Colorize(qName, 'gray');
|
||||
|
||||
if Questie.db.char.journey[i].SubType == "Accept" then
|
||||
if Questie.dbJourney.char.journey[i].SubType == "Accept" then
|
||||
recentEvents[i]:SetText(timestamp .. Questie:Colorize(l10n('You Accepted the quest %s', qName), 'yellow'));
|
||||
elseif Questie.db.char.journey[i].SubType == "Abandon" then
|
||||
elseif Questie.dbJourney.char.journey[i].SubType == "Abandon" then
|
||||
recentEvents[i]:SetText(timestamp .. Questie:Colorize(l10n('You Abandoned the quest %s', qName), 'yellow'));
|
||||
elseif Questie.db.char.journey[i].SubType == "Complete" then
|
||||
elseif Questie.dbJourney.char.journey[i].SubType == "Complete" then
|
||||
recentEvents[i]:SetText(timestamp .. Questie:Colorize(l10n('You Completed the quest %s', qName), 'yellow'));
|
||||
end
|
||||
end
|
||||
elseif Questie.db.char.journey[i].Event == "Level" then
|
||||
local level = Questie:Colorize(l10n('Level %s', Questie.db.char.journey[i].NewLevel), 'gray');
|
||||
elseif Questie.dbJourney.char.journey[i].Event == "Level" then
|
||||
local level = Questie:Colorize(l10n('Level %s', Questie.dbJourney.char.journey[i].NewLevel), 'gray');
|
||||
recentEvents[i]:SetText(timestamp .. Questie:Colorize(l10n('Congratulations! You reached %s !', level), 'yellow'));
|
||||
elseif Questie.db.char.journey[i].Event == "Note" then
|
||||
local title = Questie:Colorize(Questie.db.char.journey[i].Title, 'gray');
|
||||
elseif Questie.dbJourney.char.journey[i].Event == "Note" then
|
||||
local title = Questie:Colorize(Questie.dbJourney.char.journey[i].Title, 'gray');
|
||||
recentEvents[i]:SetText(timestamp .. Questie:Colorize(l10n('Note Created: %s', title), 'yellow'));
|
||||
end
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ _HandleNoteEntry = function ()
|
||||
data.Title = titleBox:GetText()
|
||||
data.Timestamp = time()
|
||||
|
||||
tinsert(Questie.db.char.journey, data)
|
||||
tinsert(Questie.dbJourney.char.journey, data)
|
||||
|
||||
_QuestieJourney.myJourney:ManageTree(_QuestieJourney.treeCache)
|
||||
_QuestieJourney.notePopup:Hide()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
local GetAddOnMetadata = C_AddOns and C_AddOns.GetAddOnMetadata or GetAddOnMetadata
|
||||
|
||||
|
||||
---@class QuestieLib
|
||||
local QuestieLib = QuestieLoader:CreateModule("QuestieLib")
|
||||
|
||||
@@ -13,7 +14,8 @@ local l10n = QuestieLoader:ImportModule("l10n")
|
||||
--- COMPATIBILITY ---
|
||||
local addonName = QuestieLoader.addonName
|
||||
|
||||
QuestieLib.AddonPath = "Interface\\Addons\\"..addonName.."\\"
|
||||
QuestieLib.AddonPath = "Interface\\Addons\\" .. addonName .. "\\"
|
||||
|
||||
|
||||
local math_abs = math.abs
|
||||
local math_sqrt = math.sqrt
|
||||
|
||||
@@ -76,9 +76,6 @@ function QuestieLoader:CreateModule(name)
|
||||
if modules[name] and modules[name]._defined then
|
||||
-- Print a debug message rather than hard-error so it doesn't break live servers
|
||||
-- even if another file accidentally calls CreateModule twice.
|
||||
if Questie and Questie.Debug then
|
||||
Questie:Debug(1, "[QuestieLoader] WARNING: CreateModule called twice for '" .. tostring(name) .. "'. Using existing module.")
|
||||
end
|
||||
return modules[name]
|
||||
end
|
||||
if not modules[name] then
|
||||
@@ -114,3 +111,29 @@ function QuestieLoader:PopulateGlobals() -- called when debugging is enabled
|
||||
end
|
||||
end
|
||||
|
||||
-- Initialize Questie object early to avoid nil errors during loading
|
||||
local Questie = QuestieLoader:CreateModule("Questie")
|
||||
_G.Questie = Questie
|
||||
|
||||
-- Initial stubs for Debug and Colorize so early calls don't crash
|
||||
Questie.DEBUG_CRITICAL = 1
|
||||
Questie.DEBUG_ELEVATED = 2
|
||||
Questie.DEBUG_INFO = 4
|
||||
Questie.DEBUG_DEVELOP = 8
|
||||
Questie.DEBUG_SPAM = 16
|
||||
Questie.DEBUG_LEARNER = 32
|
||||
Questie.DEBUG_COMMS = 64
|
||||
|
||||
function Questie:Debug(level, ...)
|
||||
-- Initial stub: just print to chat if it's a critical message
|
||||
-- This will be replaced by the real Questie:Debug in Questie.lua
|
||||
if level == Questie.DEBUG_CRITICAL then
|
||||
print("|cFFFFFF00[Questie-X Pre-Init Debug]|r", ...)
|
||||
end
|
||||
end
|
||||
|
||||
function Questie:Colorize(str, color)
|
||||
-- Initial stub: just return the string without color or with basic color
|
||||
return str
|
||||
end
|
||||
|
||||
|
||||
@@ -48,6 +48,14 @@ function QuestiePluginAPI:RegisterPlugin(pluginName)
|
||||
self.registeredPlugins[pluginName] = plugin
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestiePluginAPI] Successfully registered plugin: " .. pluginName)
|
||||
|
||||
if pluginName == "WotLKDB" and Questie.wotlkStatsCache then
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestiePluginAPI] Applying cached WotLK stats...")
|
||||
plugin.stats.QUEST = Questie.wotlkStatsCache.QUEST or 0
|
||||
plugin.stats.NPC = Questie.wotlkStatsCache.NPC or 0
|
||||
plugin.stats.OBJECT = Questie.wotlkStatsCache.OBJECT or 0
|
||||
plugin.stats.ITEM = Questie.wotlkStatsCache.ITEM or 0
|
||||
end
|
||||
|
||||
return plugin
|
||||
end
|
||||
|
||||
|
||||
@@ -66,6 +66,59 @@ local migrationFunctions = {
|
||||
end,
|
||||
[5] = function()
|
||||
Questie.db.profile.enableTooltipsNextInChain = true
|
||||
end,
|
||||
[6] = function()
|
||||
if Questie.dbCache and Questie.dbCache.global then
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[Migration] Offloading compiled database binary blobs to separate SavedVariable...")
|
||||
local keys = {"npcBin", "npcPtrs", "questBin", "questPtrs", "objBin", "objPtrs", "itemBin", "itemPtrs"}
|
||||
-- Handle standard keys
|
||||
for _, k in ipairs(keys) do
|
||||
if Questie.db.global[k] then
|
||||
Questie.dbCache.global[k] = Questie.db.global[k]
|
||||
Questie.db.global[k] = nil
|
||||
end
|
||||
end
|
||||
-- Handle SoD keys
|
||||
if Questie.db.global.sod then
|
||||
Questie.dbCache.global.sod = Questie.dbCache.global.sod or {}
|
||||
for _, k in ipairs(keys) do
|
||||
if Questie.db.global.sod[k] then
|
||||
Questie.dbCache.global.sod[k] = Questie.db.global.sod[k]
|
||||
Questie.db.global.sod[k] = nil
|
||||
end
|
||||
end
|
||||
-- Also move other SoD metadata
|
||||
local sodMetadata = {"dbCompiledOnVersion", "dbCompiledLang", "dbIsCompiled", "dbCompiledCount"}
|
||||
for _, k in ipairs(sodMetadata) do
|
||||
if Questie.db.global.sod[k] then
|
||||
Questie.dbCache.global.sod[k] = Questie.db.global.sod[k]
|
||||
Questie.db.global.sod[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Move global metadata
|
||||
local globalMetadata = {"dbCompiledExpansion", "dbCompiledOnVersion", "dbCompiledLang", "dbIsCompiled", "dbCompiledCount"}
|
||||
for _, k in ipairs(globalMetadata) do
|
||||
if Questie.db.global[k] then
|
||||
Questie.dbCache.global[k] = Questie.db.global[k]
|
||||
Questie.db.global[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
[7] = function()
|
||||
-- Offload Journey history to its own SavedVariable
|
||||
if Questie.dbJourney and Questie.dbJourney.char then
|
||||
if Questie.db.char and Questie.db.char.journey and (table.getn(Questie.db.char.journey) > 0) then
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[Migration] Offloading Journey history to separate SavedVariable...")
|
||||
Questie.dbJourney.char.journey = Questie.db.char.journey
|
||||
Questie.db.char.journey = nil
|
||||
end
|
||||
end
|
||||
-- Final cleanup of old learnedData from main config if still present
|
||||
if Questie.db and Questie.db.global and Questie.db.global.learnedData then
|
||||
Questie.db.global.learnedData = nil
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ local function GetServer()
|
||||
end
|
||||
|
||||
local function GetLearnedCounts()
|
||||
local ld = Questie.db and Questie.db.global and Questie.db.global.learnedData
|
||||
local ld = Questie.dbLearner and Questie.dbLearner.global
|
||||
local none = { npcs = 0, quests = 0, items = 0, objects = 0, total = 0 }
|
||||
if not ld then return none end
|
||||
local bucket = ld[GetServer()] or (ld.npcs and ld) or nil
|
||||
@@ -210,10 +210,10 @@ function QuestieOptions.tabs.database:Initialize()
|
||||
order = 2.1,
|
||||
name = function() return l10n("Learn NPCs") end,
|
||||
desc = function() return l10n("Record quest-relevant NPC positions and data.") end,
|
||||
get = function() return Questie.db.global.learnedData and Questie.db.global.learnedData.settings and Questie.db.global.learnedData.settings.learnNpcs end,
|
||||
get = function() return Questie.dbLearner.global and Questie.dbLearner.global.settings and Questie.dbLearner.global.settings.learnNpcs end,
|
||||
set = function(_, v)
|
||||
if Questie.db.global.learnedData and Questie.db.global.learnedData.settings then
|
||||
Questie.db.global.learnedData.settings.learnNpcs = v
|
||||
if Questie.dbLearner.global and Questie.dbLearner.global.settings then
|
||||
Questie.dbLearner.global.settings.learnNpcs = v
|
||||
end
|
||||
end,
|
||||
},
|
||||
@@ -223,10 +223,10 @@ function QuestieOptions.tabs.database:Initialize()
|
||||
order = 2.2,
|
||||
name = function() return l10n("Learn Quests") end,
|
||||
desc = function() return l10n("Record quest metadata, objectives, and rewards.") end,
|
||||
get = function() return Questie.db.global.learnedData and Questie.db.global.learnedData.settings and Questie.db.global.learnedData.settings.learnQuests end,
|
||||
get = function() return Questie.dbLearner.global and Questie.dbLearner.global.settings and Questie.dbLearner.global.settings.learnQuests end,
|
||||
set = function(_, v)
|
||||
if Questie.db.global.learnedData and Questie.db.global.learnedData.settings then
|
||||
Questie.db.global.learnedData.settings.learnQuests = v
|
||||
if Questie.dbLearner.global and Questie.dbLearner.global.settings then
|
||||
Questie.dbLearner.global.settings.learnQuests = v
|
||||
end
|
||||
end,
|
||||
},
|
||||
@@ -236,10 +236,10 @@ function QuestieOptions.tabs.database:Initialize()
|
||||
order = 2.3,
|
||||
name = function() return l10n("Learn Objects") end,
|
||||
desc = function() return l10n("Record interactable quest object positions.") end,
|
||||
get = function() return Questie.db.global.learnedData and Questie.db.global.learnedData.settings and Questie.db.global.learnedData.settings.learnObjects end,
|
||||
get = function() return Questie.dbLearner.global and Questie.dbLearner.global.settings and Questie.dbLearner.global.settings.learnObjects end,
|
||||
set = function(_, v)
|
||||
if Questie.db.global.learnedData and Questie.db.global.learnedData.settings then
|
||||
Questie.db.global.learnedData.settings.learnObjects = v
|
||||
if Questie.dbLearner.global and Questie.dbLearner.global.settings then
|
||||
Questie.dbLearner.global.settings.learnObjects = v
|
||||
end
|
||||
end,
|
||||
},
|
||||
@@ -249,10 +249,10 @@ function QuestieOptions.tabs.database:Initialize()
|
||||
order = 2.4,
|
||||
name = function() return l10n("Learn Items") end,
|
||||
desc = function() return l10n("Record quest item drop sources.") end,
|
||||
get = function() return Questie.db.global.learnedData and Questie.db.global.learnedData.settings and Questie.db.global.learnedData.settings.learnItems end,
|
||||
get = function() return Questie.dbLearner.global and Questie.dbLearner.global.settings and Questie.dbLearner.global.settings.learnItems end,
|
||||
set = function(_, v)
|
||||
if Questie.db.global.learnedData and Questie.db.global.learnedData.settings then
|
||||
Questie.db.global.learnedData.settings.learnItems = v
|
||||
if Questie.dbLearner.global and Questie.dbLearner.global.settings then
|
||||
Questie.dbLearner.global.settings.learnItems = v
|
||||
end
|
||||
end,
|
||||
},
|
||||
@@ -374,9 +374,9 @@ function QuestieOptions.tabs.database:Initialize()
|
||||
min = 1,
|
||||
max = 180,
|
||||
step = 1,
|
||||
get = function() return (Questie.db.global.learnedData.settings and Questie.db.global.learnedData.settings.staleThreshold) or 90 end,
|
||||
get = function() return (Questie.dbLearner.global.settings and Questie.dbLearner.global.settings.staleThreshold) or 90 end,
|
||||
set = function(_, val)
|
||||
Questie.db.global.learnedData.settings.staleThreshold = val
|
||||
Questie.dbLearner.global.settings.staleThreshold = val
|
||||
end,
|
||||
},
|
||||
|
||||
@@ -385,9 +385,9 @@ function QuestieOptions.tabs.database:Initialize()
|
||||
order = 5.3,
|
||||
name = function() return l10n("Include Verified Data in Pruning") end,
|
||||
desc = function() return l10n("If enabled, even high-confidence (Verified) data will be subject to redundancy pruning (e.g., if it's already in the official DB). Time-based pruning still only affects unconfirmed data.") end,
|
||||
get = function() return (Questie.db.global.learnedData.settings and Questie.db.global.learnedData.settings.pruneVerified) or false end,
|
||||
get = function() return (Questie.dbLearner.global.settings and Questie.dbLearner.global.settings.pruneVerified) or false end,
|
||||
set = function(_, val)
|
||||
Questie.db.global.learnedData.settings.pruneVerified = val
|
||||
Questie.dbLearner.global.settings.pruneVerified = val
|
||||
end,
|
||||
},
|
||||
|
||||
@@ -435,7 +435,7 @@ function QuestieOptions.tabs.database:Initialize()
|
||||
confirmText = "Are you sure? This cannot be undone.",
|
||||
func = function()
|
||||
if Questie.db and Questie.db.global then
|
||||
Questie.db.global.learnedData = nil
|
||||
Questie.dbLearner.global = nil
|
||||
Questie:Print("|cFFFF4444[Questie-X]|r All learned data has been reset.")
|
||||
end
|
||||
end,
|
||||
|
||||
@@ -1324,7 +1324,7 @@ function QuestieQuest:PopulateObjective(quest, objectiveIndex, objective, blockI
|
||||
end
|
||||
|
||||
-- Filter static spawns if prioritizeMyData is enabled and we have high-confidence learned data
|
||||
if Questie.db.global.learnedData and Questie.db.global.learnedData.settings and Questie.db.global.learnedData.settings.prioritizeMyData then
|
||||
if Questie.dbLearner and Questie.dbLearner.global and Questie.dbLearner.global.settings and Questie.dbLearner.global.settings.prioritizeMyData then
|
||||
for zone in pairs(zones) do
|
||||
local suppressed = (objectiveData.Type == "monster" and QuestieDB.GetSuppressedNPCs(zone)) or (objectiveData.Type == "object" and QuestieDB.GetSuppressedObjects(zone))
|
||||
if suppressed then
|
||||
|
||||
+12
-10
@@ -1,9 +1,11 @@
|
||||
---@diagnostic disable: undefined-global, return-type-mismatch, undefined-field
|
||||
---@class QuestieCompat
|
||||
---@type table|_G
|
||||
QuestieCompat = setmetatable({}, { __index = _G })
|
||||
QuestieCompat = QuestieLoader:CreateModule("QuestieCompat")
|
||||
setmetatable(QuestieCompat, { __index = _G })
|
||||
QuestieCompat.addonName = QuestieLoader.addonName
|
||||
|
||||
|
||||
------------------------------------------
|
||||
-- Lua 5.0 / 5.1 / 5.2 compatibility shims
|
||||
-- NOTE: string.match, select(), and math.mod shims live in QuestieLoader.lua
|
||||
@@ -17,8 +19,6 @@ end
|
||||
-- Polyfill for xpcall variadic arguments (missing in standard Lua 5.0/5.1 WoW clients).
|
||||
-- Modern Ace3 uses xpcall(func, err, ...) which drops arguments on legacy clients,
|
||||
-- leading to 'self' being nil in addon callbacks.
|
||||
-- Fix #14: Do NOT write to bare _G.xpcall — store in QuestieCompat namespace only.
|
||||
-- Writing to _G.xpcall pollutes the global namespace and can cause taint on protected contexts.
|
||||
local _xpcall = xpcall
|
||||
local xpcall_supported = false
|
||||
pcall(function()
|
||||
@@ -58,6 +58,9 @@ if not xpcall_supported then
|
||||
-- No extra args provided
|
||||
return _xpcall(func, err)
|
||||
end
|
||||
-- Crucial: Expose to the global environment so that unmodified Ace3 libraries (like AceGUI-3.0)
|
||||
-- will pick it up instead of using the broken native version which drops arguments causing crashes.
|
||||
_G.xpcall = QuestieCompat.xpcall
|
||||
else
|
||||
-- Native xpcall works fine, expose it
|
||||
QuestieCompat.xpcall = _xpcall
|
||||
@@ -241,6 +244,7 @@ else
|
||||
return ticker
|
||||
end
|
||||
}
|
||||
_G.C_Timer = QuestieCompat.C_Timer
|
||||
end
|
||||
|
||||
---[SetMinResize Documentation](https://wowpedia.fandom.com/wiki/API_Frame_SetMinResize)
|
||||
@@ -414,7 +418,9 @@ function QuestieCompat.GetItemCooldown(itemID)
|
||||
end
|
||||
|
||||
--- C_QuestLog Shim
|
||||
QuestieCompat.C_QuestLog = QuestieCompat.C_QuestLog or {}
|
||||
if not rawget(QuestieCompat, "C_QuestLog") then
|
||||
QuestieCompat.C_QuestLog = {}
|
||||
end
|
||||
|
||||
function QuestieCompat.C_QuestLog.GetNumQuestLogEntries()
|
||||
return GetNumQuestLogEntries()
|
||||
@@ -444,13 +450,8 @@ function QuestieCompat.C_QuestLog.GetAllQuestIDs()
|
||||
return questIDs
|
||||
end
|
||||
|
||||
function QuestieCompat.C_QuestLog.GetQuestObjectives(questID)
|
||||
local questIndex = GetQuestLogIndexByID(questID)
|
||||
if not questIndex then return nil end
|
||||
return QuestieCompat.GetQuestObjectives(questIndex)
|
||||
end
|
||||
|
||||
function QuestieCompat.C_QuestLog.IsQuestFlaggedCompleted(questID)
|
||||
|
||||
return IsQuestFlaggedCompleted(questID)
|
||||
end
|
||||
|
||||
@@ -492,3 +493,4 @@ end
|
||||
QuestieCompat.LibUIDropDownMenu = QuestieCompat.LibUIDropDownMenu or {}
|
||||
QuestieCompat.LibUIDropDownMenu.UIDropDownMenu_Menu_NewSize = function()
|
||||
end
|
||||
|
||||
|
||||
@@ -225,7 +225,10 @@ function QuestieEventHandler:RegisterLateEvents()
|
||||
end)
|
||||
end
|
||||
|
||||
local _PlayerLoginFired = false
|
||||
function _EventHandler:PlayerLogin()
|
||||
if _PlayerLoginFired then return end
|
||||
_PlayerLoginFired = true
|
||||
-- Check config exists
|
||||
if not Questie.db or not QuestieConfig then
|
||||
-- Did you move Questie.db = LibStub("AceDB-3.0"):New("QuestieConfig",.......) out of Questie:OnInitialize() ?
|
||||
|
||||
+76
-11
@@ -1,4 +1,5 @@
|
||||
---@class QuestieInit
|
||||
|
||||
local QuestieInit = QuestieLoader:CreateModule("QuestieInit")
|
||||
local _QuestieInit = QuestieInit.private
|
||||
|
||||
@@ -57,6 +58,8 @@ local QuestieValidateGameCache = QuestieLoader:ImportModule("QuestieValidateGame
|
||||
local MinimapIcon = QuestieLoader:ImportModule("MinimapIcon")
|
||||
---@type QuestieComms
|
||||
local QuestieComms = QuestieLoader:ImportModule("QuestieComms");
|
||||
---@type QuestieCompat
|
||||
local QuestieCompat = QuestieLoader:ImportModule("QuestieCompat")
|
||||
---@type QuestieOptions
|
||||
local QuestieOptions = QuestieLoader:ImportModule("QuestieOptions");
|
||||
---@type QuestieCoords
|
||||
@@ -92,7 +95,14 @@ local QuestieServer = QuestieLoader:ImportModule("QuestieServer")
|
||||
local WOW_PROJECT_ID = QuestieCompat.WOW_PROJECT_ID
|
||||
local C_Timer = QuestieCompat.C_Timer
|
||||
|
||||
local coYield = coroutine.yield
|
||||
-- Safe yield: only yields when we are actually inside a running coroutine.
|
||||
-- Without this check, coroutine.yield() throws "attempt to yield across C-call boundary"
|
||||
-- when Stage 1 runs synchronously inside AceAddon's pcall (a C stack frame).
|
||||
local function coYield()
|
||||
if coroutine.running() then
|
||||
coroutine.yield()
|
||||
end
|
||||
end
|
||||
|
||||
local function _dbStats(t)
|
||||
if type(t) ~= "table" then return "type=" .. type(t) end
|
||||
@@ -136,6 +146,29 @@ local function loadFullDatabase()
|
||||
QuestieCorrections:PreCompile()
|
||||
end
|
||||
|
||||
function QuestieInit:OnInitialize()
|
||||
if QuestieInit.initialized then return end
|
||||
QuestieInit.initialized = true
|
||||
if QuestieInit.Stages and QuestieInit.Stages[1] and (not QuestieInit.stage1Done) then
|
||||
QuestieInit.stage1Done = true
|
||||
-- Run Stage 1 inside a coroutine so that all coroutine.yield() calls
|
||||
-- in Stage 1 and its callees (Townsfolk, compiler, etc.) have a valid
|
||||
-- coroutine context. AceAddon calls OnInitialize from a C pcall boundary
|
||||
-- so calling coroutine.yield() without an enclosing coroutine crashes.
|
||||
-- We drain the coroutine synchronously (resume until dead) so that
|
||||
-- QuestieDB.QuestPointers is set before OnInitialize returns.
|
||||
local co = coroutine.create(QuestieInit.Stages[1])
|
||||
while coroutine.status(co) == "suspended" do
|
||||
local ok, err = coroutine.resume(co)
|
||||
if not ok then
|
||||
print(debugstack(co))
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
---Run the validator
|
||||
local function runValidator()
|
||||
if type(QuestieDB.questData) == "string" or type(QuestieDB.npcData) == "string" or type(QuestieDB.objectData) == "string" or type(QuestieDB.itemData) == "string" then
|
||||
@@ -226,16 +259,22 @@ QuestieInit.Stages[1] = function() -- run as a coroutine
|
||||
dbCompiledLang = Questie.db.global.dbCompiledLang
|
||||
end
|
||||
|
||||
|
||||
if Questie.IsSoD then
|
||||
coYield()
|
||||
SeasonOfDiscovery.Initialize()
|
||||
end
|
||||
|
||||
-- Check if the DB needs to be recompiled
|
||||
do
|
||||
local addonV = QuestieLib:GetAddonVersionString()
|
||||
local uiLoc = l10n:GetUILocale()
|
||||
local storedExp = Questie.db.global.dbCompiledExpansion
|
||||
end
|
||||
if (not dbIsCompiled) or (QuestieLib:GetAddonVersionString() ~= dbCompiledOnVersion) or (l10n:GetUILocale() ~= dbCompiledLang) or (Questie.db.global.dbCompiledExpansion ~= WOW_PROJECT_ID) then
|
||||
print("\124cFFAAEEFF" ..
|
||||
print("|cFFAAEEFF" ..
|
||||
l10n("Questie DB has updated!") ..
|
||||
"\124r\124cFFFF6F22 " .. l10n("Data is being processed, this may take a few moments and cause some lag..."))
|
||||
"|r|cFFFF6F22 " .. l10n("Data is being processed, this may take a few moments and cause some lag..."))
|
||||
loadFullDatabase()
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[DBDiag] Before Compile - quest:" .. _dbStats(QuestieDB.questData) .. " npc:" .. _dbStats(QuestieDB.npcData))
|
||||
QuestieDBCompiler:Compile()
|
||||
@@ -294,10 +333,15 @@ QuestieInit.Stages[2] = function()
|
||||
local keepWaiting = true
|
||||
-- We had users reporting that a quest did not reach a valid state in the game cache.
|
||||
-- In this case we still need to continue the initialization process, even though a specific quest might be bugged
|
||||
-- 3-second timeout for cache validation
|
||||
C_Timer.After(3, function()
|
||||
if keepWaiting then
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "QuestieInit: Timeout waiting for Game Cache validation. Continuing.")
|
||||
Questie:Error("[QuestieInit:Stage2] Quest cache validation timed out! Some data may be missing.")
|
||||
keepWaiting = false
|
||||
local ok, err = coroutine.resume(QuestieInit.Thread)
|
||||
if not ok then
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieInit:Stage2] Resume failed (timeout): " .. tostring(err))
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -424,6 +468,7 @@ function QuestieInit:LoadDatabase(key)
|
||||
elseif tocversion >= 20500 and tocversion < 30000 then isModernClient = true -- TBC Classic
|
||||
elseif tocversion >= 30400 and tocversion < 40000 then isModernClient = true -- WotLK Classic
|
||||
elseif tocversion >= 40400 and tocversion < 50000 then isModernClient = true -- Cata Classic
|
||||
elseif tocversion >= 50000 and tocversion < 60000 then isModernClient = true -- MoP (e.g. 50400)
|
||||
end
|
||||
end
|
||||
if isModernClient then
|
||||
@@ -473,8 +518,7 @@ function QuestieInit:UpdateWotLKDBStats()
|
||||
OBJECT = _countTable(_G["QuestieX_WotLKDB_object"]),
|
||||
ITEM = _countTable(_G["QuestieX_WotLKDB_item"]),
|
||||
}
|
||||
-- Fix #11: Do NOT write to _G.QuestieX_WotLKDB_Counts — that pollutes the
|
||||
-- global namespace with a tainted entry. Push counts only to the plugin object.
|
||||
Questie.wotlkStatsCache = counts
|
||||
local QuestiePluginAPI = QuestieLoader:ImportModule("QuestiePluginAPI")
|
||||
if QuestiePluginAPI then
|
||||
local wotlkPlugin = QuestiePluginAPI:GetPlugin("WotLKDB")
|
||||
@@ -529,7 +573,7 @@ function QuestieInit:LoadBaseDB()
|
||||
}
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[DBDiag] WotLKDB pull: quest=" .. tostring(_pulled.quest) .. " npc=" .. tostring(_pulled.npc) .. " obj=" .. tostring(_pulled.object) .. " item=" .. tostring(_pulled.item))
|
||||
|
||||
-- Fix #11: second site — push counts only to plugin object, not to _G.
|
||||
Questie.wotlkStatsCache = _counts
|
||||
local QuestiePluginAPI = QuestieLoader:ImportModule("QuestiePluginAPI")
|
||||
if QuestiePluginAPI then
|
||||
local wotlkPlugin = QuestiePluginAPI:GetPlugin("WotLKDB")
|
||||
@@ -549,15 +593,36 @@ end
|
||||
|
||||
function _QuestieInit.StartStageCoroutine()
|
||||
for i = 1, #QuestieInit.Stages do
|
||||
QuestieInit.Stages[i]()
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieInit:StartStageCoroutine] Stage " .. i .. " done.")
|
||||
if i == 1 and QuestieInit.stage1Done then
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieInit:StartStageCoroutine] Stage 1 already done, skipping.")
|
||||
else
|
||||
if i == 1 then QuestieInit.stage1Done = true end
|
||||
QuestieInit.Stages[i]()
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieInit:StartStageCoroutine] Stage " .. i .. " done.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- called by the PLAYER_LOGIN event handler
|
||||
function QuestieInit:Init()
|
||||
ThreadLib.ThreadError(_QuestieInit.StartStageCoroutine, Questie.db.profile.initDelay or 0,
|
||||
l10n("Error during initialization!"))
|
||||
QuestieInit.Thread = coroutine.create(_QuestieInit.StartStageCoroutine)
|
||||
|
||||
local function resumeInit()
|
||||
if not QuestieInit.Thread or coroutine.status(QuestieInit.Thread) == "dead" then
|
||||
return -- coroutine finished or failed
|
||||
end
|
||||
local ok, err = coroutine.resume(QuestieInit.Thread)
|
||||
if not ok then
|
||||
local stack = debugstack(QuestieInit.Thread)
|
||||
local msg = "QuestieInit Thread CRASHED: " .. tostring(err) .. "\n" .. tostring(stack)
|
||||
Questie:Error(msg)
|
||||
print("|cFFFF0000" .. msg .. "|r")
|
||||
elseif coroutine.status(QuestieInit.Thread) ~= "dead" then
|
||||
C_Timer.After(0.02, resumeInit) -- continue yielding using the timer shim
|
||||
end
|
||||
end
|
||||
|
||||
resumeInit()
|
||||
|
||||
if Questie.db.profile.trackerEnabled then
|
||||
-- This needs to be called ASAP otherwise tracked Achievements in the Blizzard WatchFrame shows upon login
|
||||
|
||||
+74
-65
@@ -146,25 +146,34 @@ end
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local function EnsureLearnedData()
|
||||
if not Questie.db then return false end
|
||||
local ld = Questie.db.global.learnedData
|
||||
if not ld then
|
||||
Questie.db.global.learnedData = {
|
||||
npcs = {},
|
||||
quests = {},
|
||||
items = {},
|
||||
objects = {},
|
||||
settings = {
|
||||
enabled = true,
|
||||
learnNpcs = true,
|
||||
learnQuests = true,
|
||||
learnItems = true,
|
||||
learnObjects = true,
|
||||
minConfidencePins = 2,
|
||||
prioritizeMyData = true,
|
||||
staleThreshold = 90, -- days
|
||||
pruneVerified = false, -- protect verified data by default
|
||||
},
|
||||
if not Questie.db or not Questie.dbLearner then return false end
|
||||
|
||||
-- Migration: If data exists in the old QuestieConfig.global.learnedData, move it to the new QuestieLearnerDB.global
|
||||
if Questie.db.global.learnedData then
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieLearner] Migrating learnedData to separate SavedVariable...")
|
||||
for k, v in pairs(Questie.db.global.learnedData) do
|
||||
Questie.dbLearner.global[k] = v
|
||||
end
|
||||
Questie.db.global.learnedData = nil
|
||||
Questie:Print("|cFF5EBAF3Questie-X:|r Learned data has been migrated to a separate SavedVariable for better performance.")
|
||||
end
|
||||
|
||||
local ld = Questie.dbLearner.global
|
||||
if (not ld.npcs) and (not ld.quests) then
|
||||
ld.npcs = {}
|
||||
ld.quests = {}
|
||||
ld.items = {}
|
||||
ld.objects = {}
|
||||
ld.settings = {
|
||||
enabled = true,
|
||||
learnNpcs = true,
|
||||
learnQuests = true,
|
||||
learnItems = true,
|
||||
learnObjects = true,
|
||||
minConfidencePins = 2,
|
||||
prioritizeMyData = true,
|
||||
staleThreshold = 90, -- days
|
||||
pruneVerified = false, -- protect verified data by default
|
||||
}
|
||||
else
|
||||
-- Backfill sub-tables that may be missing from older SavedVariables
|
||||
@@ -191,12 +200,12 @@ end
|
||||
|
||||
function QuestieLearner:IsEnabled()
|
||||
if not EnsureLearnedData() then return false end
|
||||
return Questie.db.global.learnedData.settings.enabled
|
||||
return Questie.dbLearner.global.settings.enabled
|
||||
end
|
||||
|
||||
function QuestieLearner:GetSettings()
|
||||
if not EnsureLearnedData() then return {} end
|
||||
return Questie.db.global.learnedData.settings
|
||||
return Questie.dbLearner.global.settings
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
@@ -264,7 +273,7 @@ local function _AddToQuestObjective(qData, slot, entityId, text, ovrTable, quest
|
||||
end
|
||||
end
|
||||
|
||||
local function _GetDB() return Questie.db.global.learnedData end
|
||||
local function _GetDB() return Questie.dbLearner.global end
|
||||
|
||||
-- Triggers QuestieQuest:UpdateQuest for every active quest in the player's log
|
||||
-- that is referenced in the provided set (table with questId keys).
|
||||
@@ -557,7 +566,7 @@ end
|
||||
|
||||
function QuestieLearner:LearnNPC(npcId, name, level, subName, npcFlags, factionString, spawnX, spawnY, spawnZoneId)
|
||||
if not self:IsEnabled() then return end
|
||||
if not Questie.db.global.learnedData.settings.learnNpcs then return end
|
||||
if not Questie.dbLearner.global.settings.learnNpcs then return end
|
||||
if not npcId or npcId <= 0 then return end
|
||||
|
||||
-- Use provided spawn coords (e.g. from kill event) or fall back to current player position
|
||||
@@ -569,11 +578,11 @@ function QuestieLearner:LearnNPC(npcId, name, level, subName, npcFlags, factionS
|
||||
x, y = GetPlayerCoords()
|
||||
end
|
||||
|
||||
local existing = Questie.db.global.learnedData.npcs[npcId]
|
||||
local existing = Questie.dbLearner.global.npcs[npcId]
|
||||
local isNew = existing == nil
|
||||
if not existing then
|
||||
existing = {}
|
||||
Questie.db.global.learnedData.npcs[npcId] = existing
|
||||
Questie.dbLearner.global.npcs[npcId] = existing
|
||||
end
|
||||
|
||||
if name and not existing[1] then existing[1] = name end
|
||||
@@ -593,7 +602,7 @@ function QuestieLearner:LearnNPC(npcId, name, level, subName, npcFlags, factionS
|
||||
existing.ls = time() -- Update last seen
|
||||
existing.mc = (existing.mc or 0) + 1
|
||||
|
||||
local threshold = (Questie.db.global.learnedData.settings and Questie.db.global.learnedData.settings.minConfidencePins) or MIN_CONFIDENCE_PINS
|
||||
local threshold = (Questie.dbLearner.global.settings and Questie.dbLearner.global.settings.minConfidencePins) or MIN_CONFIDENCE_PINS
|
||||
|
||||
-- Live injection: update npcDataOverrides only if confidence threshold is met
|
||||
if existing.mc >= threshold and QuestieDB and QuestieDB.npcDataOverrides then
|
||||
@@ -640,17 +649,17 @@ function QuestieLearner:LearnQuest(questId, data)
|
||||
Questie:Debug(Questie.DEBUG_LEARNER, "[QuestieLearner] LearnQuest blocked: learner not enabled")
|
||||
return
|
||||
end
|
||||
if not Questie.db.global.learnedData.settings.learnQuests then
|
||||
Questie:Debug(Questie.DEBUG_LEARNER, "[QuestieLearner] LearnQuest blocked: learnQuests=", tostring(Questie.db.global.learnedData.settings.learnQuests))
|
||||
if not Questie.dbLearner.global.settings.learnQuests then
|
||||
Questie:Debug(Questie.DEBUG_LEARNER, "[QuestieLearner] LearnQuest blocked: learnQuests=", tostring(Questie.dbLearner.global.settings.learnQuests))
|
||||
return
|
||||
end
|
||||
if not questId or questId <= 0 then return end
|
||||
|
||||
local existing = Questie.db.global.learnedData.quests[questId]
|
||||
local existing = Questie.dbLearner.global.quests[questId]
|
||||
local isNew = existing == nil
|
||||
if not existing then
|
||||
existing = {}
|
||||
Questie.db.global.learnedData.quests[questId] = existing
|
||||
Questie.dbLearner.global.quests[questId] = existing
|
||||
end
|
||||
|
||||
existing.ls = time() -- Update last seen
|
||||
@@ -685,13 +694,13 @@ end
|
||||
-- Records the NPC/object that starts or finishes a quest (array index [2] or [3])
|
||||
function QuestieLearner:LearnQuestGiver(questId, entityId, entityType, isStart)
|
||||
if not self:IsEnabled() then return end
|
||||
if not Questie.db.global.learnedData.settings.learnQuests then return end
|
||||
if not Questie.dbLearner.global.settings.learnQuests then return end
|
||||
if not questId or questId <= 0 or not entityId or entityId <= 0 then return end
|
||||
|
||||
local existing = Questie.db.global.learnedData.quests[questId]
|
||||
local existing = Questie.dbLearner.global.quests[questId]
|
||||
if not existing then
|
||||
existing = {}
|
||||
Questie.db.global.learnedData.quests[questId] = existing
|
||||
Questie.dbLearner.global.quests[questId] = existing
|
||||
end
|
||||
|
||||
-- Starters/finishers: { [1]={npcIds}, [2]={objIds}, [3]={itemIds} }
|
||||
@@ -733,12 +742,12 @@ end
|
||||
-- we only need the quest to reference it so tooltips/map-pins get registered.
|
||||
function QuestieLearner:LearnQuestObjectiveNPC(questId, npcId, objText)
|
||||
if not self:IsEnabled() then return end
|
||||
if not Questie.db.global.learnedData.settings.learnQuests then return end
|
||||
if not Questie.dbLearner.global.settings.learnQuests then return end
|
||||
if not questId or questId <= 0 or not npcId or npcId <= 0 then return end
|
||||
|
||||
-- 1. Persist to SavedVariables
|
||||
local existing = Questie.db.global.learnedData.quests[questId] or {}
|
||||
Questie.db.global.learnedData.quests[questId] = existing
|
||||
local existing = Questie.dbLearner.global.quests[questId] or {}
|
||||
Questie.dbLearner.global.quests[questId] = existing
|
||||
existing[10] = existing[10] or {}
|
||||
existing[10][1] = existing[10][1] or {} -- creatureObjective slot
|
||||
local alreadyInSV = false
|
||||
@@ -787,14 +796,14 @@ end
|
||||
|
||||
function QuestieLearner:LearnItem(itemId, name, itemLevel, requiredLevel, itemClass, itemSubClass)
|
||||
if not self:IsEnabled() then return end
|
||||
if not Questie.db.global.learnedData.settings.learnItems then return end
|
||||
if not Questie.dbLearner.global.settings.learnItems then return end
|
||||
if not itemId or itemId <= 0 then return end
|
||||
|
||||
local existing = Questie.db.global.learnedData.items[itemId]
|
||||
local existing = Questie.dbLearner.global.items[itemId]
|
||||
local isNew = existing == nil
|
||||
if not existing then
|
||||
existing = {}
|
||||
Questie.db.global.learnedData.items[itemId] = existing
|
||||
Questie.dbLearner.global.items[itemId] = existing
|
||||
end
|
||||
|
||||
if name and not existing[1] then existing[1] = name end
|
||||
@@ -826,13 +835,13 @@ end
|
||||
|
||||
function QuestieLearner:LearnItemDrop(itemId, npcId)
|
||||
if not self:IsEnabled() then return end
|
||||
if not Questie.db.global.learnedData.settings.learnItems then return end
|
||||
if not Questie.dbLearner.global.settings.learnItems then return end
|
||||
if not itemId or itemId <= 0 or not npcId or npcId <= 0 then return end
|
||||
|
||||
local existing = Questie.db.global.learnedData.items[itemId]
|
||||
local existing = Questie.dbLearner.global.items[itemId]
|
||||
if not existing then
|
||||
existing = {}
|
||||
Questie.db.global.learnedData.items[itemId] = existing
|
||||
Questie.dbLearner.global.items[itemId] = existing
|
||||
end
|
||||
|
||||
existing.ls = time() -- Update last seen
|
||||
@@ -865,17 +874,17 @@ end
|
||||
|
||||
function QuestieLearner:LearnObject(objectId, name)
|
||||
if not self:IsEnabled() then return end
|
||||
if not Questie.db.global.learnedData.settings.learnObjects then return end
|
||||
if not Questie.dbLearner.global.settings.learnObjects then return end
|
||||
if not objectId or objectId <= 0 then return end
|
||||
|
||||
local zoneId = GetZoneId()
|
||||
local x, y = GetPlayerCoords()
|
||||
|
||||
local existing = Questie.db.global.learnedData.objects[objectId]
|
||||
local existing = Questie.dbLearner.global.objects[objectId]
|
||||
local isNew = existing == nil
|
||||
if not existing then
|
||||
existing = {}
|
||||
Questie.db.global.learnedData.objects[objectId] = existing
|
||||
Questie.dbLearner.global.objects[objectId] = existing
|
||||
end
|
||||
|
||||
if name and not existing[1] then existing[1] = name end
|
||||
@@ -957,7 +966,7 @@ end
|
||||
function QuestieLearner:InjectLearnedData()
|
||||
if not EnsureLearnedData() then return end
|
||||
|
||||
local learned = Questie.db.global.learnedData
|
||||
local learned = Questie.dbLearner.global
|
||||
local npcCount, questCount, itemCount, objectCount = 0, 0, 0, 0
|
||||
|
||||
-- 1. NPCs
|
||||
@@ -1079,7 +1088,7 @@ end
|
||||
|
||||
function QuestieLearner:GetStats()
|
||||
if not EnsureLearnedData() then return 0, 0, 0, 0 end
|
||||
local learned = Questie.db.global.learnedData
|
||||
local learned = Questie.dbLearner.global
|
||||
local n, q, i, o = 0, 0, 0, 0
|
||||
for _ in pairs(learned.npcs) do n = n + 1 end
|
||||
for _ in pairs(learned.quests) do q = q + 1 end
|
||||
@@ -1090,10 +1099,10 @@ end
|
||||
|
||||
function QuestieLearner:ClearAllData()
|
||||
if not EnsureLearnedData() then return end
|
||||
Questie.db.global.learnedData.npcs = {}
|
||||
Questie.db.global.learnedData.quests = {}
|
||||
Questie.db.global.learnedData.items = {}
|
||||
Questie.db.global.learnedData.objects = {}
|
||||
Questie.dbLearner.global.npcs = {}
|
||||
Questie.dbLearner.global.quests = {}
|
||||
Questie.dbLearner.global.items = {}
|
||||
Questie.dbLearner.global.objects = {}
|
||||
Questie:Print("Cleared all learned data.")
|
||||
end
|
||||
|
||||
@@ -1113,7 +1122,7 @@ end
|
||||
|
||||
function QuestieLearner:ExportData()
|
||||
if not EnsureLearnedData() then return "" end
|
||||
local learned = Questie.db.global.learnedData
|
||||
local learned = Questie.dbLearner.global
|
||||
local lines = {}
|
||||
table.insert(lines, "-- QuestieLearner Export")
|
||||
local n, q, i, o = self:GetStats()
|
||||
@@ -1461,7 +1470,7 @@ end
|
||||
-- Fires when any quest is turned in (covers auto-complete quests that skip the QUEST_COMPLETE dialog)
|
||||
function QuestieLearner:OnQuestTurnedIn(questId, xpReward, moneyReward)
|
||||
if not self:IsEnabled() then return end
|
||||
if not Questie.db.global.learnedData.settings.learnQuests then return end
|
||||
if not Questie.dbLearner.global.settings.learnQuests then return end
|
||||
if not questId or questId <= 0 then return end
|
||||
|
||||
local data = {}
|
||||
@@ -1487,7 +1496,7 @@ end
|
||||
-- Loot handler with async GetItemInfo retry
|
||||
function QuestieLearner:OnLootOpened()
|
||||
if not self:IsEnabled() then return end
|
||||
if not Questie.db.global.learnedData.settings.learnItems then return end
|
||||
if not Questie.dbLearner.global.settings.learnItems then return end
|
||||
|
||||
local targetGuid = UnitGUID("target")
|
||||
local npcId = targetGuid and GetNpcIdFromGUID(targetGuid) or nil
|
||||
@@ -1806,7 +1815,7 @@ end
|
||||
|
||||
function QuestieLearner:Initialize()
|
||||
EnsureLearnedData()
|
||||
QuestieLearner.data = Questie.db.global.learnedData
|
||||
QuestieLearner.data = Questie.dbLearner.global
|
||||
self:RegisterEvents()
|
||||
self:InjectLearnedData()
|
||||
|
||||
@@ -1843,17 +1852,17 @@ function QuestieLearner:HandleNetworkData(typ, id, d, op)
|
||||
|
||||
local store
|
||||
if typ == "NPC" then
|
||||
if not Questie.db.global.learnedData.settings.learnNpcs then return end
|
||||
store = Questie.db.global.learnedData.npcs
|
||||
if not Questie.dbLearner.global.settings.learnNpcs then return end
|
||||
store = Questie.dbLearner.global.npcs
|
||||
elseif typ == "QUEST" then
|
||||
if not Questie.db.global.learnedData.settings.learnQuests then return end
|
||||
store = Questie.db.global.learnedData.quests
|
||||
if not Questie.dbLearner.global.settings.learnQuests then return end
|
||||
store = Questie.dbLearner.global.quests
|
||||
elseif typ == "ITEM" then
|
||||
if not Questie.db.global.learnedData.settings.learnItems then return end
|
||||
store = Questie.db.global.learnedData.items
|
||||
if not Questie.dbLearner.global.settings.learnItems then return end
|
||||
store = Questie.dbLearner.global.items
|
||||
elseif typ == "OBJECT" then
|
||||
if not Questie.db.global.learnedData.settings.learnObjects then return end
|
||||
store = Questie.db.global.learnedData.objects
|
||||
if not Questie.dbLearner.global.settings.learnObjects then return end
|
||||
store = Questie.dbLearner.global.objects
|
||||
else
|
||||
return
|
||||
end
|
||||
@@ -1863,7 +1872,7 @@ function QuestieLearner:HandleNetworkData(typ, id, d, op)
|
||||
store[id] = d
|
||||
store[id].mc = 1
|
||||
self:InjectLearnedData()
|
||||
QuestieLearner.data = Questie.db.global.learnedData
|
||||
QuestieLearner.data = Questie.dbLearner.global
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1909,7 +1918,7 @@ function QuestieLearner:HandleNetworkData(typ, id, d, op)
|
||||
if changed or (op == "NEW" or op == "UPDATE") then
|
||||
existing.ls = time() -- Refresh timestamp on network confirmation
|
||||
existing.mc = (existing.mc or 0) + 1
|
||||
QuestieLearner.data = Questie.db.global.learnedData
|
||||
QuestieLearner.data = Questie.dbLearner.global
|
||||
self:InjectLearnedData()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -48,9 +48,8 @@ local function GetServerKey()
|
||||
return realm ~= "" and realm or "unknown"
|
||||
end
|
||||
|
||||
-- Returns the learnedData sub-table for the current server, or nil
|
||||
local function GetServerBucket(serverKey)
|
||||
local ld = Questie.db and Questie.db.global and Questie.db.global.learnedData
|
||||
function QuestieLearnerExport:GetExportTable(serverKey)
|
||||
local ld = Questie.dbLearner and Questie.dbLearner.global
|
||||
if not ld then return nil end
|
||||
if ld[serverKey] then return ld[serverKey] end
|
||||
-- Fallback: flat (pre-bucket) layout still in use
|
||||
@@ -58,6 +57,11 @@ local function GetServerBucket(serverKey)
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Returns the learnedData sub-table for the current server, or nil
|
||||
local function GetServerBucket(serverKey)
|
||||
return QuestieLearnerExport:GetExportTable(serverKey)
|
||||
end
|
||||
|
||||
-- Builds a lightweight stats summary table from a bucket
|
||||
local function BuildStats(bucket)
|
||||
if not bucket then return { npcs = 0, quests = 0, items = 0, objects = 0, total = 0 } end
|
||||
@@ -127,7 +131,7 @@ end
|
||||
--- Exports ALL server buckets merged into one payload.
|
||||
---@return string|nil, table|string
|
||||
function QuestieLearnerExport:ExportAll()
|
||||
local ld = Questie.db and Questie.db.global and Questie.db.global.learnedData
|
||||
local ld = Questie.dbLearner and Questie.dbLearner.global
|
||||
if not ld then return nil, "No learned data." end
|
||||
|
||||
local merged = { npcs = {}, quests = {}, items = {}, objects = {} }
|
||||
@@ -326,7 +330,7 @@ function _Export:RunPrune(dryRun)
|
||||
local result = { npcs = 0, quests = 0, items = 0, objects = 0, total = 0, reasons = {} }
|
||||
if not bucket then return result end
|
||||
|
||||
local settings = (Questie.db.global.learnedData and Questie.db.global.learnedData.settings) or {}
|
||||
local settings = (Questie.dbLearner and Questie.dbLearner.global and Questie.dbLearner.global.settings) or {}
|
||||
local thresholdDays = settings.staleThreshold or 90
|
||||
local thresholdSeconds = thresholdDays * 86400
|
||||
local minConfidence = settings.minConfidencePins or 2
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
--[[
|
||||
|
||||
Flow:
|
||||
-> QuestieValidateGameCache.StartCheck()
|
||||
--> Wait for PLAYER_ENTERING_WORLD
|
||||
@@ -10,16 +11,9 @@ Flow:
|
||||
|
||||
---@class QuestieValidateGameCache
|
||||
local QuestieValidateGameCache = QuestieLoader:CreateModule("QuestieValidateGameCache")
|
||||
|
||||
|
||||
---@type QuestieLib
|
||||
local QuestieLib = QuestieLoader:CreateModule("QuestieLib")
|
||||
|
||||
--- COMPATIBILITY ---
|
||||
local GetNumQuestLogEntries = GetNumQuestLogEntries
|
||||
local GetQuestLogTitle = QuestieCompat.GetQuestLogTitle
|
||||
local GetQuestObjectives = QuestieCompat.C_QuestLog.GetQuestObjectives
|
||||
local HaveQuestData = QuestieCompat.HaveQuestData
|
||||
local QuestieLib = QuestieLoader:ImportModule("QuestieLib")
|
||||
local QuestieCompat = QuestieLoader:ImportModule("QuestieCompat")
|
||||
-- Defer API assignments to runtime to avoid load-order nil errors
|
||||
|
||||
local stringByte, tremove = string.byte, table.remove
|
||||
local tpack = QuestieLib.tpack
|
||||
@@ -27,148 +21,160 @@ local tunpack = QuestieLib.tunpack
|
||||
|
||||
-- 3 * (Max possible number of quests in game quest log)
|
||||
-- This is a safe value, even smaller would be enough. Too large won't effect performance
|
||||
local MAX_QUEST_LOG_INDEX = 75
|
||||
|
||||
local eventFrame
|
||||
local numberOfQuestLogUpdatesToSkip
|
||||
local numberOfQuestLogUpdatesToSkip = 0
|
||||
local checkStarted = false
|
||||
|
||||
local eventFrame = nil
|
||||
local callbacks = {}
|
||||
local isCacheGood = false
|
||||
local callbacks = {} -- example: { [1] = {func, {arg1, arg2, arg3}}, [2] = {func, {arg1, arg2}}, }
|
||||
|
||||
---@return boolean
|
||||
function QuestieValidateGameCache.IsCacheGood()
|
||||
return isCacheGood
|
||||
end
|
||||
|
||||
--- Calls the callback function imediately if the cache is already good.
|
||||
--- Otherwise adds it to list of functions called once the cache comes good.
|
||||
---@param func function @A function to call once cache is good.
|
||||
---@param ... any @Possible arguments for function.
|
||||
function QuestieValidateGameCache.AddCallback(func, ...)
|
||||
if isCacheGood then
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieValidateGameCache] Calling a callback function imediately.")
|
||||
func(...)
|
||||
else
|
||||
callbacks[#callbacks + 1] = { func, tpack(...) }
|
||||
end
|
||||
end
|
||||
|
||||
local function DestroyEventFrame()
|
||||
if eventFrame then
|
||||
eventFrame:UnregisterAllEvents()
|
||||
eventFrame:SetScript("OnEvent", nil)
|
||||
eventFrame:SetParent(nil)
|
||||
eventFrame = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Called directly and OnEvent.
|
||||
local function OnQuestLogUpdate()
|
||||
local numEntries, numQuests = GetNumQuestLogEntries()
|
||||
-- Fetch APIs at runtime with extreme defensive checks
|
||||
local qCompat = QuestieCompat or _G.QuestieCompat
|
||||
local rawCLog = qCompat and rawget(qCompat, "C_QuestLog")
|
||||
local cLog = (qCompat and qCompat.C_QuestLog) or {}
|
||||
|
||||
-- Player can have 0 quests in quest log for real OR game's cached quest log can be empty while cache is still invalid
|
||||
-- This is to wait until cache has atleast some refreshed data from a game server.
|
||||
if numberOfQuestLogUpdatesToSkip > 0 then
|
||||
numberOfQuestLogUpdatesToSkip = numberOfQuestLogUpdatesToSkip - 1
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP,
|
||||
"[QuestieValidateGameCache] Skipping a QUEST_LOG_UPDATE event. Quest log has entries, quests:", numEntries,
|
||||
numQuests)
|
||||
|
||||
local GetNumQuestLogEntries = cLog.GetNumQuestLogEntries or _G.GetNumQuestLogEntries
|
||||
local GetQuestLogTitle = cLog.GetQuestLogTitle or _G.GetQuestLogTitle
|
||||
local GetNumQuestLeaderBoards = _G.GetNumQuestLeaderBoards
|
||||
local GetQuestObjectives = cLog.GetQuestObjectives or function() return {} end
|
||||
|
||||
|
||||
|
||||
|
||||
if isCacheGood then
|
||||
DestroyEventFrame()
|
||||
return
|
||||
end
|
||||
|
||||
if numberOfQuestLogUpdatesToSkip > 0 then
|
||||
numberOfQuestLogUpdatesToSkip = numberOfQuestLogUpdatesToSkip - 1
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local isQuestLogGood = true
|
||||
local goodQuestsCount = 0 -- for debug stats
|
||||
local numQuests = select(1, GetNumQuestLogEntries()) or 0
|
||||
local goodQuestsCount = 0
|
||||
|
||||
for i = 1, MAX_QUEST_LOG_INDEX do
|
||||
local title, level, questTag, isHeader, isCollapsed, isComplete, isDaily, questId = GetQuestLogTitle(i)
|
||||
if title and questId and (not isHeader) then
|
||||
if (not HaveQuestData(questId)) then
|
||||
isQuestLogGood = false
|
||||
else
|
||||
local hasInvalidObjective -- for debug stats
|
||||
local objectiveList = GetQuestObjectives(questId, i)
|
||||
|
||||
if type(objectiveList) ~= "table" then
|
||||
-- On WotLK private servers, GetQuestObjectives can return nil for quests with
|
||||
-- no trackable objectives. This is not a broken cache state; treat it as an
|
||||
-- empty (valid) objective list so goodQuestsCount increments correctly.
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP,
|
||||
"[QuestieValidateGameCache] GetQuestObjectives returned non-table for questId:", questId,
|
||||
"- treating as empty objectives")
|
||||
objectiveList = {}
|
||||
end
|
||||
|
||||
for _, objective in pairs(objectiveList) do -- objectiveList may be {}, which is also a valid cached quest in quest log
|
||||
if (not objective.text) or (stringByte(objective.text, 1) == 32) then -- if (text starts with a space " ") then
|
||||
-- Game hasn't cached the quest fully yet
|
||||
for i = 1, numQuests do
|
||||
local status, err = pcall(function()
|
||||
local title, _, _, _, isHeader, _, _, _, questId = GetQuestLogTitle(i)
|
||||
if title and (not isHeader) and questId and questId > 0 then
|
||||
local numObjectives = GetNumQuestLeaderBoards(i) or 0
|
||||
|
||||
if numObjectives > 0 then
|
||||
local objectiveList = GetQuestObjectives(questId, i)
|
||||
if objectiveList and objectiveList[1] then
|
||||
local hasInvalidObjective = false
|
||||
for _, objective in pairs(objectiveList) do
|
||||
if (not objective.text) or (stringByte(objective.text, 1) == 32) then
|
||||
isQuestLogGood = false
|
||||
hasInvalidObjective = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not hasInvalidObjective then
|
||||
goodQuestsCount = goodQuestsCount + 1
|
||||
end
|
||||
else
|
||||
isQuestLogGood = false
|
||||
hasInvalidObjective = true
|
||||
|
||||
-- No early "return false" here to force iterate whole quest log and speed up caching
|
||||
end
|
||||
end
|
||||
|
||||
if not hasInvalidObjective then
|
||||
else
|
||||
goodQuestsCount = goodQuestsCount + 1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
|
||||
if not isQuestLogGood then
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieValidateGameCache] Quest log is NOT yet okey. Good quest:",
|
||||
goodQuestsCount .. "/" .. numQuests)
|
||||
return
|
||||
end
|
||||
|
||||
if goodQuestsCount ~= numQuests then
|
||||
-- This count mismatch can occur on WotLK private servers where GetNumQuestLogEntries
|
||||
-- returns a different value than objectives-loop counted. The cache is valid because
|
||||
-- isQuestLogGood already passed above. Log at debug level only.
|
||||
Questie:Debug(Questie.DEBUG_INFO,
|
||||
"[QuestieValidateGameCache] Quest count mismatch (expected " ..
|
||||
tostring(numQuests) .. ", validated " .. tostring(goodQuestsCount) .. "). Cache is still valid.")
|
||||
end
|
||||
|
||||
DestroyEventFrame()
|
||||
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieValidateGameCache] Quest log is ok. Good quest:",
|
||||
goodQuestsCount .. "/" .. numQuests)
|
||||
|
||||
isCacheGood = true
|
||||
|
||||
-- Call all callbacks
|
||||
while (#callbacks > 0) do
|
||||
local callback = tremove(callbacks, 1)
|
||||
local func, args = callback[1], callback[2]
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieValidateGameCache] Calling a callback.")
|
||||
func(tunpack(args))
|
||||
end
|
||||
end
|
||||
|
||||
local function OnPlayerEnteringWorld(_, _, isInitialLogin, isReloadingUi)
|
||||
-- 335 Cant find a way to distinguish between 'first login' and 'UI reload'
|
||||
if QuestieCompat.Is335 then
|
||||
isInitialLogin, isReloadingUi = false, true -- 335 Not skipping for now
|
||||
end
|
||||
assert(isInitialLogin or isReloadingUi) -- We should get to here only at login or at /reload.
|
||||
if isInitialLogin == nil then isInitialLogin = true end
|
||||
if isReloadingUi == nil then isReloadingUi = false end
|
||||
|
||||
if QuestieCompat.Is335 then
|
||||
isInitialLogin, isReloadingUi = false, true
|
||||
end
|
||||
|
||||
-- Game's quest log has still old cached data on the first QUEST_LOG_UPDATE after PLAYER_ENTERING_WORLD during login.
|
||||
-- So we need to skip that event.
|
||||
numberOfQuestLogUpdatesToSkip = isInitialLogin and 1 or 0
|
||||
|
||||
if not eventFrame then eventFrame = CreateFrame("Frame") end
|
||||
eventFrame:UnregisterAllEvents()
|
||||
eventFrame:SetScript("OnEvent", OnQuestLogUpdate)
|
||||
eventFrame:RegisterEvent("QUEST_LOG_UPDATE")
|
||||
end
|
||||
|
||||
-- MUST be started very early to count number of events firing.
|
||||
function QuestieValidateGameCache.StartCheck()
|
||||
assert(not checkStarted) -- to avoid bugging the module by wrong usage
|
||||
if checkStarted then return end
|
||||
checkStarted = true
|
||||
|
||||
eventFrame = CreateFrame("Frame")
|
||||
eventFrame:SetScript("OnEvent", OnPlayerEnteringWorld)
|
||||
if not eventFrame then eventFrame = CreateFrame("Frame") end
|
||||
eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
eventFrame:SetScript("OnEvent", OnPlayerEnteringWorld)
|
||||
|
||||
if IsLoggedIn() then
|
||||
OnPlayerEnteringWorld(eventFrame, "PLAYER_ENTERING_WORLD", true, false)
|
||||
end
|
||||
|
||||
local function backupCheck()
|
||||
if isCacheGood then return end
|
||||
OnQuestLogUpdate()
|
||||
if not isCacheGood then
|
||||
local qCompat = QuestieCompat or _G.QuestieCompat
|
||||
local timer = (qCompat and qCompat.C_QuestLog and qCompat.C_Timer) or _G.C_Timer
|
||||
if timer and timer.After then
|
||||
timer.After(2.0, backupCheck)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local qCompat = QuestieCompat or _G.QuestieCompat
|
||||
local timer = (qCompat and qCompat.C_QuestLog and qCompat.C_Timer) or _G.C_Timer
|
||||
if timer and timer.After then
|
||||
timer.After(2.0, backupCheck)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function QuestieValidateGameCache.IsCacheGood()
|
||||
return isCacheGood
|
||||
end
|
||||
|
||||
function QuestieValidateGameCache.RegisterCallback(func, ...)
|
||||
if isCacheGood then
|
||||
func(...)
|
||||
else
|
||||
table.insert(callbacks, { func, tpack(...) })
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+19
-34
@@ -12,45 +12,30 @@ local WOW_PROJECT_ID = QuestieCompat.WOW_PROJECT_ID
|
||||
local C_Seasons = QuestieCompat.C_Seasons
|
||||
|
||||
-- Check addon is not renamed to avoid conflicts in global name space.
|
||||
if (not QuestieCompat.Is335) and addonName ~= "Questie" then
|
||||
local msg = { "You have renamed Questie addon.", "This is restricted to avoid issues.", "Please remove '"..addonName.."'", "and reinstall the original version."}
|
||||
StaticPopupDialogs["QUESTIE_ADDON_NAME_ERROR"] = {
|
||||
text = "|cffff0000ERROR|r\n"..msg[1].."\n"..msg[2].."\n\n"..msg[3].."\n"..msg[4],
|
||||
button2 = "OK",
|
||||
hasEditBox = false,
|
||||
whileDead = true,
|
||||
timeout = 0 -- 335
|
||||
}
|
||||
-- (Removed because Questie-X is meant to be run universally and its folder name is Questie-X)
|
||||
|
||||
C_Timer.After(4, function()
|
||||
DEFAULT_CHAT_FRAME:AddMessage("---------------------------------")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000ERROR|r: |cff42f5ad"..msg[1].."|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000ERROR|r: |cff42f5ad"..msg[2].."|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000ERROR|r: |cff42f5ad"..msg[3].."|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000ERROR|r: |cff42f5ad"..msg[4].."|r")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("---------------------------------")
|
||||
error("ERROR: "..msg[1].." "..msg[2].." "..msg[3])
|
||||
end)
|
||||
StaticPopup_Show("QUESTIE_ADDON_NAME_ERROR")
|
||||
return
|
||||
end
|
||||
|
||||
if Questie then
|
||||
C_Timer.After(4, function()
|
||||
error("ERROR!! -> Questie already loaded! Please only have one Questie installed!")
|
||||
for _=1, 10 do
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF0000ERROR!!|r -> Questie already loaded! Please only have one Questie installed!")
|
||||
end
|
||||
end);
|
||||
error("ERROR!! -> Questie already loaded! Please only have one Questie installed!")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF0000ERROR!!|r -> Questie already loaded! Please only have one Questie installed!")
|
||||
Questie = {}
|
||||
return
|
||||
end
|
||||
|
||||
--Initialized below
|
||||
---@class Questie : AceAddon, AceConsole-3.0, AceEvent-3.0, AceTimer-3.0, AceComm-3.0, AceBucket-3.0
|
||||
Questie = LibStub("AceAddon-3.0"):NewAddon("Questie", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "AceComm-3.0", "AceBucket-3.0")
|
||||
-- In Questie-X, the Questie object is created early by QuestieLoader.
|
||||
-- We use that existing object here to ensure all modules share the same instance.
|
||||
local function InitializeQuestie()
|
||||
local existingQuestie = QuestieLoader:ImportModule("Questie")
|
||||
|
||||
local ok, err = pcall(function()
|
||||
LibStub("AceAddon-3.0"):NewAddon(existingQuestie, addonName, "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "AceComm-3.0", "AceBucket-3.0")
|
||||
end)
|
||||
if not ok then
|
||||
Questie:Error("ERROR inside NewAddon: " .. tostring(err))
|
||||
end
|
||||
|
||||
-- Ensure the global reference points to our unified object
|
||||
_G.Questie = existingQuestie
|
||||
return existingQuestie
|
||||
end
|
||||
|
||||
Questie = InitializeQuestie()
|
||||
|
||||
-- preinit placeholder to stop tukui crashing from literally force-removing one of our features no matter what users select in the config ui
|
||||
Questie.db = {profile={minimap={hide=false}}}
|
||||
|
||||
Reference in New Issue
Block a user