feat: standardize v1.5.0 and consolidate stability fixes
This commit is contained in:
@@ -115,6 +115,10 @@ function QuestieEvent:Load()
|
||||
end
|
||||
end
|
||||
|
||||
if not QuestieEvent.eventQuests then
|
||||
return
|
||||
end
|
||||
|
||||
for _, questData in pairs(QuestieEvent.eventQuests) do
|
||||
local eventName = questData[1]
|
||||
local questId = questData[2]
|
||||
|
||||
+140
-12
@@ -33,6 +33,31 @@ local l10n = QuestieLoader:ImportModule("l10n")
|
||||
---@type QuestLogCache
|
||||
local QuestLogCache = QuestieLoader:ImportModule("QuestLogCache")
|
||||
|
||||
-- Dummy handles to prevent Stage 2 crashes during deferred initialization
|
||||
local _dummyHandle = {
|
||||
QuerySingle = function() return nil end,
|
||||
Query = function() return nil end,
|
||||
pointers = {}
|
||||
}
|
||||
QuestieDB.QueryNPC = _dummyHandle.Query
|
||||
QuestieDB.QueryQuest = _dummyHandle.Query
|
||||
QuestieDB.QueryObject = _dummyHandle.Query
|
||||
QuestieDB.QueryItem = _dummyHandle.Query
|
||||
QuestieDB.QueryQuestSingle = _dummyHandle.QuerySingle
|
||||
QuestieDB.QueryNPCSingle = _dummyHandle.QuerySingle
|
||||
QuestieDB.QueryObjectSingle = _dummyHandle.QuerySingle
|
||||
QuestieDB.QueryItemSingle = _dummyHandle.QuerySingle
|
||||
QuestieDB._QueryQuestSingle = _dummyHandle.QuerySingle
|
||||
QuestieDB._QueryNPCSingle = _dummyHandle.QuerySingle
|
||||
QuestieDB._QueryObjectSingle = _dummyHandle.QuerySingle
|
||||
QuestieDB._QueryItemSingle = _dummyHandle.QuerySingle
|
||||
|
||||
-- Initialize pointers to empty tables to prevent Stage 2 crashes during deferred initialization
|
||||
QuestieDB.QuestPointers = _dummyHandle.pointers
|
||||
QuestieDB.NPCPointers = _dummyHandle.pointers
|
||||
QuestieDB.ObjectPointers = _dummyHandle.pointers
|
||||
QuestieDB.ItemPointers = _dummyHandle.pointers
|
||||
|
||||
---@type QuestieQuest
|
||||
local QuestieQuest = QuestieLoader:ImportModule("QuestieQuest")
|
||||
---@type QuestieQuestPrivate
|
||||
@@ -338,6 +363,10 @@ function QuestieDB:Initialize()
|
||||
end
|
||||
|
||||
function QuestieDB:GetObject(objectId)
|
||||
if self ~= QuestieDB then
|
||||
objectId = self
|
||||
end
|
||||
objectId = tonumber(objectId)
|
||||
if not objectId then
|
||||
return nil
|
||||
end
|
||||
@@ -348,6 +377,10 @@ function QuestieDB:GetObject(objectId)
|
||||
--local rawdata = QuestieDB.objectData[objectId];
|
||||
local rawdata = QuestieDB.QueryObject(objectId, QuestieDB._objectAdapterQueryOrder)
|
||||
|
||||
if not rawdata and QuestieDB.objectDataOverrides then
|
||||
rawdata = QuestieDB.objectDataOverrides[objectId] or QuestieDB.objectDataOverrides[tostring(objectId)]
|
||||
end
|
||||
|
||||
if not rawdata then
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieDB:GetObject] rawdata is nil for objectID:", objectId)
|
||||
return nil
|
||||
@@ -368,6 +401,10 @@ function QuestieDB:GetObject(objectId)
|
||||
end
|
||||
|
||||
function QuestieDB:GetItem(itemId)
|
||||
if self ~= QuestieDB then
|
||||
itemId = self
|
||||
end
|
||||
itemId = tonumber(itemId)
|
||||
if (not itemId) or (itemId == 0) then
|
||||
return nil
|
||||
end
|
||||
@@ -377,6 +414,10 @@ function QuestieDB:GetItem(itemId)
|
||||
|
||||
local rawdata = QuestieDB.QueryItem(itemId, QuestieDB._itemAdapterQueryOrder)
|
||||
|
||||
if not rawdata and QuestieDB.itemDataOverrides then
|
||||
rawdata = QuestieDB.itemDataOverrides[itemId] or QuestieDB.itemDataOverrides[tostring(itemId)]
|
||||
end
|
||||
|
||||
if not rawdata then
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieDB:GetItem] rawdata is nil for itemID:", itemId)
|
||||
return nil
|
||||
@@ -1210,7 +1251,16 @@ end
|
||||
|
||||
---@param questId QuestId
|
||||
---@return Quest|nil @The quest object or nil if the quest is missing
|
||||
function QuestieDB.GetQuest(questId) -- /dump QuestieDB.GetQuest(867)
|
||||
function QuestieDB.GetQuest(questId, ...) -- /dump QuestieDB.GetQuest(867)
|
||||
-- Handle colon calling QuestieDB:GetQuest(questId)
|
||||
if type(questId) == "table" and questId == QuestieDB then
|
||||
questId = select(1, ...)
|
||||
end
|
||||
-- Handle string input from console or other sources
|
||||
if type(questId) == "string" then
|
||||
questId = tonumber(questId)
|
||||
end
|
||||
|
||||
if not questId then
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieDB.GetQuest] No questId.")
|
||||
return nil
|
||||
@@ -1220,11 +1270,15 @@ function QuestieDB.GetQuest(questId) -- /dump QuestieDB.GetQuest(867)
|
||||
end
|
||||
|
||||
local rawdata = QuestieDB.QueryQuest(questId, QuestieDB._questAdapterQueryOrder)
|
||||
local overrideData = QuestieDB.questDataOverrides and (QuestieDB.questDataOverrides[questId] or QuestieDB.questDataOverrides[tostring(questId)])
|
||||
|
||||
if (not rawdata) then
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieDB.GetQuest] rawdata is nil for questID:", questId)
|
||||
if questId == 0 then
|
||||
Questie:Error("[QuestieDB.GetQuest] rawdata is nil for questID:", questId)
|
||||
rawdata = overrideData
|
||||
if (not rawdata) then
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieDB.GetQuest] rawdata is nil for questID:", questId)
|
||||
if questId == 0 then
|
||||
Questie:Error("[QuestieDB.GetQuest] rawdata is nil for questID:", questId)
|
||||
end
|
||||
print(debugstack())
|
||||
return nil
|
||||
end
|
||||
@@ -1294,6 +1348,39 @@ function QuestieDB.GetQuest(questId) -- /dump QuestieDB.GetQuest(867)
|
||||
stringKey, intKey = next(questKeys, stringKey)
|
||||
end
|
||||
|
||||
-- Support for index-aware objective mapping (QuestieLearner & custom overrides)
|
||||
if rawdata.objIndex then QO.objIndex = rawdata.objIndex end
|
||||
|
||||
|
||||
-- Apply overrides to QO directly (merging objectives if needed)
|
||||
if overrideData and rawdata ~= overrideData then
|
||||
local _sKey, _iKey = next(questKeys)
|
||||
while _sKey do
|
||||
if overrideData[_iKey] then
|
||||
if _sKey == "objectives" and QO.objectives then
|
||||
-- Merge objectives (index 10)
|
||||
local _objIdx, _objList = next(overrideData[_iKey])
|
||||
while _objIdx do
|
||||
if not QO.objectives[_objIdx] then
|
||||
QO.objectives[_objIdx] = _objList
|
||||
else
|
||||
local _id, _data = next(_objList)
|
||||
while _id do
|
||||
QO.objectives[_objIdx][_id] = _data
|
||||
_id, _data = next(_objList, _id)
|
||||
end
|
||||
end
|
||||
_objIdx, _objList = next(overrideData[_iKey], _objIdx)
|
||||
end
|
||||
else
|
||||
QO[_sKey] = overrideData[_iKey]
|
||||
end
|
||||
end
|
||||
_sKey, _iKey = next(questKeys, _sKey)
|
||||
end
|
||||
if overrideData.objIndex then QO.objIndex = overrideData.objIndex end
|
||||
end
|
||||
|
||||
local questLevel, requiredLevel = QuestieLib.GetTbcLevel(questId)
|
||||
QO.level = questLevel
|
||||
QO.requiredLevel = requiredLevel
|
||||
@@ -1357,6 +1444,25 @@ function QuestieDB.GetQuest(questId) -- /dump QuestieDB.GetQuest(867)
|
||||
---@type Objective[]
|
||||
QO.ObjectiveData = {}
|
||||
|
||||
-- Support for index-aware objective mapping (QuestieLearner & custom overrides)
|
||||
-- This handles "kill-credit" scenarios and prevents "UI swapping" by pinning
|
||||
-- entities to the specific quest log objective index 'j'.
|
||||
if QO.objIndex then
|
||||
local _index, _data = next(QO.objIndex)
|
||||
while _index do
|
||||
if _data and _data.id then
|
||||
QO.ObjectiveData[_index] = {
|
||||
Type = _data.type or "monster",
|
||||
Id = _data.id,
|
||||
Text = _data.text or "",
|
||||
-- Store original mapping for reference
|
||||
_isIndexMapped = true,
|
||||
}
|
||||
end
|
||||
_index, _data = next(QO.objIndex, _index)
|
||||
end
|
||||
end
|
||||
|
||||
---@type RawObjectives
|
||||
local objectives = QO.objectives
|
||||
if objectives then
|
||||
@@ -1364,13 +1470,26 @@ function QuestieDB.GetQuest(questId) -- /dump QuestieDB.GetQuest(867)
|
||||
local _creatureObjective, creatureObjective = next(objectives[1])
|
||||
while _creatureObjective do
|
||||
if creatureObjective then
|
||||
---@type NpcObjective
|
||||
table.insert(QO.ObjectiveData, {
|
||||
Type = "monster",
|
||||
Id = creatureObjective[1],
|
||||
Text = creatureObjective[2],
|
||||
HideCondition = creatureObjective[3],
|
||||
})
|
||||
-- Only insert if not already mapped via objIndex
|
||||
local alreadyMapped = false
|
||||
if QO.objIndex then
|
||||
for _, existing in pairs(QO.ObjectiveData) do
|
||||
if existing.Id == creatureObjective[1] then
|
||||
alreadyMapped = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not alreadyMapped then
|
||||
---@type NpcObjective
|
||||
table.insert(QO.ObjectiveData, {
|
||||
Type = "monster",
|
||||
Id = creatureObjective[1],
|
||||
Text = creatureObjective[2],
|
||||
HideCondition = creatureObjective[3],
|
||||
})
|
||||
end
|
||||
end
|
||||
_creatureObjective, creatureObjective = next(objectives[1], _creatureObjective)
|
||||
end
|
||||
@@ -1739,7 +1858,11 @@ local a = {
|
||||
---@param npcId number
|
||||
---@return table
|
||||
function QuestieDB:GetNPC(npcId)
|
||||
if not npcId then
|
||||
if self ~= QuestieDB then
|
||||
npcId = self
|
||||
end
|
||||
npcId = tonumber(npcId)
|
||||
if not npcId or npcId == 0 then
|
||||
return nil
|
||||
end
|
||||
if _QuestieDB.npcCache[npcId] then
|
||||
@@ -1747,6 +1870,11 @@ function QuestieDB:GetNPC(npcId)
|
||||
end
|
||||
|
||||
local rawdata = QuestieDB.QueryNPC(npcId, QuestieDB._npcAdapterQueryOrder)
|
||||
|
||||
if not rawdata and QuestieDB.npcDataOverrides then
|
||||
rawdata = QuestieDB.npcDataOverrides[npcId] or QuestieDB.npcDataOverrides[tostring(npcId)]
|
||||
end
|
||||
|
||||
if (not rawdata) then
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieDB:GetNPC] rawdata is nil for npcID:", npcId)
|
||||
return nil
|
||||
|
||||
+40
-52
@@ -61,7 +61,7 @@ function ZoneDB:Initialize()
|
||||
end
|
||||
|
||||
function _ZoneDB:GenerateParentZoneToStartingZoneTable()
|
||||
for startingZone, parentZone in pairs(subZoneToParentZone) do
|
||||
for startingZone, parentZone in next, subZoneToParentZone do
|
||||
parentZoneToSubZone[parentZone] = startingZone
|
||||
end
|
||||
end
|
||||
@@ -87,49 +87,32 @@ function ZoneDB:GetAreaIdByUiMapId(uiMapId)
|
||||
|
||||
local foundId
|
||||
-- First we look for a direct match
|
||||
for AreaUiMapId, lAreaId in pairs(uiMapIdToAreaId) do
|
||||
for AreaUiMapId, lAreaId in next, uiMapIdToAreaId do
|
||||
local areaId = lAreaId
|
||||
if (AreaUiMapId == uiMapId and not foundId) then
|
||||
--Questie:Debug(Questie.DEBUG_DEVELOP, "[ZoneDB:GetAreaIdByUiMapId] : ", " AreaUiMapId: ", AreaUiMapId, " == uiMapId: ", uiMapId, " and areaId = ", areaId, " foundID is nil")
|
||||
foundId = areaId
|
||||
elseif AreaUiMapId == uiMapId and foundId ~= AreaUiMapId then
|
||||
-- If we find a second match that does not match the first
|
||||
-- Print an error, but we still return the first one we found.
|
||||
|
||||
-- Only print if debug is enabled.
|
||||
if Questie.db.profile.debugEnabled then
|
||||
Questie:Error("[ZoneDB:GetAreaIdByUiMapId] : ", "UiMapId", uiMapId, "has multiple AreaIds:", foundId,
|
||||
areaId)
|
||||
Questie:Error("[ZoneDB:GetAreaIdByUiMapId] : ", "UiMapId", uiMapId, "has multiple AreaIds:", foundId, areaId)
|
||||
end
|
||||
end
|
||||
end
|
||||
if foundId then -- debug --TechnoHunter adding debug print to report found AreaId
|
||||
--if Questie.db.profile.debugEnabled then
|
||||
--local uiMapInfo = C_Map.GetMapInfo(uiMapId)
|
||||
--local foundName = C_Map.GetAreaInfo(foundId)
|
||||
--Questie:Debug(Questie.DEBUG_DEVELOP, "[ZoneDB:GetAreaIdByUiMapId] : ", "Found AreaId", foundName, ":", foundId, " for UiMapId", uiMapInfo.name, ":", uiMapId, "direct match")
|
||||
--end
|
||||
if foundId then
|
||||
return foundId
|
||||
else
|
||||
-- As a last resort we try to match AreaId and UiMapId by name
|
||||
-- uses the original table in zoneTables as the area id's are
|
||||
-- all in that and we dont care if the uiMapId is there or not
|
||||
for areaId in pairs(areaIdToUiMapId) do
|
||||
for areaId in next, areaIdToUiMapId do
|
||||
local mapInfo = C_Map.GetMapInfo(uiMapId)
|
||||
local areaName = C_Map.GetAreaInfo(areaId)
|
||||
if mapInfo and mapInfo.name == areaName then
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[ZoneDB:GetAreaIdByUiMapId] : ", "Found AreaId", areaName, ":",
|
||||
areaId, "for UiMapId", mapInfo.name, ":", uiMapId, "by name")
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[ZoneDB:GetAreaIdByUiMapId] : ", "Found AreaId", areaName, ":", areaId, "for UiMapId", mapInfo.name, ":", uiMapId, "by name")
|
||||
return areaId
|
||||
end
|
||||
end
|
||||
if Questie.db.profile.debugEnabled then
|
||||
-- NOTE: On Ascension, hub cities (Stormwind, Shattrath, etc.) may return a
|
||||
-- continent-level UiMapId from GetBestMapForUnit. This is harmless — the nil
|
||||
-- return is handled gracefully by GetCurrentZoneId's callers.
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP,
|
||||
"No AreaId found for UiMapId: " ..
|
||||
uiMapId .. ":" .. (C_Map.GetMapInfo(uiMapId) and C_Map.GetMapInfo(uiMapId).name or "nil"))
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "No AreaId found for UiMapId: " .. uiMapId .. ":" .. (C_Map.GetMapInfo(uiMapId) and C_Map.GetMapInfo(uiMapId).name or "nil"))
|
||||
end
|
||||
return nil
|
||||
end
|
||||
@@ -233,15 +216,17 @@ do
|
||||
end
|
||||
|
||||
-- 1) Base Questie quests (QuestPointers values must be numbers; ignore anything weird)
|
||||
for questId, ptr in pairs(QuestieDB.QuestPointers) do
|
||||
if type(ptr) == "number" then
|
||||
ProcessQuestId(questId)
|
||||
if type(QuestieDB.QuestPointers) == "table" then
|
||||
for questId, ptr in next, QuestieDB.QuestPointers do
|
||||
if type(ptr) == "number" then
|
||||
ProcessQuestId(questId)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 2) Ascension custom quests (from overrides list)
|
||||
if type(QuestieDB.ascensionQuestIds) == "table" then
|
||||
for questId in pairs(QuestieDB.ascensionQuestIds) do
|
||||
for questId in next, QuestieDB.ascensionQuestIds do
|
||||
ProcessQuestId(questId)
|
||||
end
|
||||
end
|
||||
@@ -255,7 +240,7 @@ end
|
||||
|
||||
---@param zoneOrSort ZoneOrSort
|
||||
function _ZoneDB:IsSpecialQuest(zoneOrSort)
|
||||
for _, v in pairs(QuestieDB.sortKeys) do
|
||||
for _, v in next, QuestieDB.sortKeys do
|
||||
if zoneOrSort == v then
|
||||
return true
|
||||
end
|
||||
@@ -272,11 +257,11 @@ function _ZoneDB:GetZonesWithQuestsFromNPCs(zones, npcIds, questId)
|
||||
return zones
|
||||
end
|
||||
|
||||
for npcId in pairs(npcIds) do
|
||||
for npcId in next, npcIds do
|
||||
local spawns = QuestieDB.QueryNPCSingle(npcId, "spawns")
|
||||
if spawns then
|
||||
for zone in pairs(spawns) do
|
||||
if not zones[zone] then zones[zone] = {} end
|
||||
for zone in next, spawns do
|
||||
if (not zones[zone]) then zones[zone] = {} end
|
||||
zones[zone][questId] = true
|
||||
end
|
||||
end
|
||||
@@ -294,11 +279,11 @@ function _ZoneDB:GetZonesWithQuestsFromObjects(zones, objectIds, questId)
|
||||
return zones
|
||||
end
|
||||
|
||||
for objectId in pairs(objectIds) do
|
||||
for objectId in next, objectIds do
|
||||
local spawns = QuestieDB.QueryObjectSingle(objectId, "spawns")
|
||||
if spawns then
|
||||
for zone in pairs(spawns) do
|
||||
if not zones[zone] then zones[zone] = {} end
|
||||
for zone in next, spawns do
|
||||
if (not zones[zone]) then zones[zone] = {} end
|
||||
zones[zone][questId] = true
|
||||
end
|
||||
end
|
||||
@@ -314,7 +299,7 @@ function _ZoneDB:SplitSeasonalQuests()
|
||||
end
|
||||
local questsToSplit = zoneMap[QuestieDB.sortKeys.SEASONAL]
|
||||
-- Merging SEASONAL and SPECIAL quests to be split into real groups
|
||||
for k, v in pairs(zoneMap[QuestieDB.sortKeys.SPECIAL]) do questsToSplit[k] = v end
|
||||
for k, v in next, zoneMap[QuestieDB.sortKeys.SPECIAL] do questsToSplit[k] = v end
|
||||
|
||||
local updatedZoneMap = zoneMap
|
||||
updatedZoneMap[-400] = {}
|
||||
@@ -323,7 +308,7 @@ function _ZoneDB:SplitSeasonalQuests()
|
||||
updatedZoneMap[-403] = {}
|
||||
updatedZoneMap[-404] = {}
|
||||
|
||||
for questId, _ in pairs(questsToSplit) do
|
||||
for questId, _ in next, questsToSplit do
|
||||
local eventName = QuestieEvent:GetEventNameFor(questId)
|
||||
if eventName == "Love is in the Air" then
|
||||
updatedZoneMap[-400][questId] = true
|
||||
@@ -345,14 +330,16 @@ end
|
||||
|
||||
function ZoneDB:GetRelevantZones()
|
||||
local zones = {}
|
||||
for category, data in pairs(l10n.zoneCategoryLookup) do
|
||||
zones[category] = {}
|
||||
for id, zoneName in pairs(data) do
|
||||
local zoneQuests = zoneMap[id]
|
||||
if (not zoneQuests) then
|
||||
zones[category][id] = nil
|
||||
else
|
||||
zones[category][id] = l10n(zoneName)
|
||||
if type(l10n.zoneCategoryLookup) == "table" then
|
||||
for category, data in next, l10n.zoneCategoryLookup do
|
||||
zones[category] = {}
|
||||
for id, zoneName in next, data do
|
||||
local zoneQuests = zoneMap[id]
|
||||
if (not zoneQuests) then
|
||||
zones[category][id] = nil
|
||||
else
|
||||
zones[category][id] = l10n(zoneName)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -372,13 +359,14 @@ function _ZoneDB:RunTests()
|
||||
[308] = true, -- ScholomanceOLD
|
||||
[309] = true, -- ScholomanceOLD
|
||||
}
|
||||
for _, map in pairs(maps) do
|
||||
--- We don't care about World, Continent or Cosmic
|
||||
if map.mapType ~= Enum.UIMapType.World and map.mapType ~= Enum.UIMapType.Continent and map.mapType ~= Enum.UIMapType.Cosmic then
|
||||
local success, result = pcall(ZoneDB.GetAreaIdByUiMapId, ZoneDB, map.mapID)
|
||||
if not success and not buggedMaps[map.mapID] then
|
||||
Questie:Error("[ZoneDBTests] ZoneDB.GetAreaIdByUiMapId fails for " ..
|
||||
map.name .. " (" .. map.mapID .. "). Result: " .. result)
|
||||
if type(maps) == "table" then
|
||||
for _, map in next, maps do
|
||||
--- We don't care about World, Continent or Cosmic
|
||||
if map.mapType ~= Enum.UIMapType.World and map.mapType ~= Enum.UIMapType.Continent and map.mapType ~= Enum.UIMapType.Cosmic then
|
||||
local success, result = pcall(ZoneDB.GetAreaIdByUiMapId, ZoneDB, map.mapID)
|
||||
if not success and not buggedMaps[map.mapID] then
|
||||
Questie:Error("[ZoneDBTests] ZoneDB.GetAreaIdByUiMapId fails for " .. map.name .. " (" .. map.mapID .. "). Result: " .. result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1075,7 +1075,7 @@ function QuestieDBCompiler:Compile()
|
||||
or type(QuestieDB.questData) == "table"
|
||||
or (type(QuestieDB.questDataOverrides) == "table" and next(QuestieDB.questDataOverrides) ~= nil)
|
||||
if not hasData then
|
||||
Questie:Print("|cFFFF4444[Questie-X]|r No database plugin loaded. Install a DB plugin for your server — see Options \226\134\146 Database.")
|
||||
Questie:Print("|cFFFF4444[Questie-X]|r No database plugin loaded. Install a DB plugin for your server — see Options ⌂ Database.")
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user