Release v9.7.3

This commit is contained in:
Xurkon
2026-02-15 09:08:51 -06:00
parent 0a1bc74f45
commit a113070b7d
4 changed files with 126 additions and 122 deletions
+4 -1
View File
@@ -1,6 +1,6 @@
# Changelog # Changelog
## v9.7.2 ## v9.7.3
### New Features ### New Features
- **[Database]** Implemented **Ebonhold Database Module**. - **[Database]** Implemented **Ebonhold Database Module**.
@@ -37,3 +37,6 @@
- **Instance Filter**: Arrow explicitly hides if the target is in a different instance. - **Instance Filter**: Arrow explicitly hides if the target is in a different instance.
- **[Map]** Fixed an issue where completed quest icons would persist on the map (`RequestMapUpdate` logic). - **[Map]** Fixed an issue where completed quest icons would persist on the map (`RequestMapUpdate` logic).
- **[Database]** Updated `wotlkNpcDB.lua` with scraped spawn data for 12 key beast NPCs in Terokkar Forest to ensure accuracy. - **[Database]** Updated `wotlkNpcDB.lua` with scraped spawn data for 12 key beast NPCs in Terokkar Forest to ensure accuracy.
- **[Arrow]** Fixed a nil function error for `_CollectObjective` when processing incomplete quests.
- **[Arrow]** Fixed syntax issues that prevented `QuestieArrow` module from initializing correctly.
- **[Database]** Fixed a runtime crash in `ZoneDB` when encountering maps with no AreaId mapping (e.g., Kalimdor).
+78 -80
View File
@@ -46,7 +46,7 @@ local UiMapIdOverrides = {
[246] = 3713 [246] = 3713
} }
local parentZoneToSubZone = {} -- Generated local parentZoneToSubZone = {} -- Generated
local zoneMap = {} -- Generated local zoneMap = {} -- Generated
function ZoneDB:Initialize() function ZoneDB:Initialize()
@@ -96,15 +96,16 @@ function ZoneDB:GetAreaIdByUiMapId(uiMapId)
-- Only print if debug is enabled. -- Only print if debug is enabled.
if Questie.db.profile.debugEnabled then 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 end
end end
if foundId then -- debug --TechnoHunter adding debug print to report found AreaId if foundId then -- debug --TechnoHunter adding debug print to report found AreaId
--if Questie.db.profile.debugEnabled then --if Questie.db.profile.debugEnabled then
--local uiMapInfo = C_Map.GetMapInfo(uiMapId) --local uiMapInfo = C_Map.GetMapInfo(uiMapId)
--local foundName = C_Map.GetAreaInfo(foundId) --local foundName = C_Map.GetAreaInfo(foundId)
--Questie:Debug(Questie.DEBUG_DEVELOP, "[ZoneDB:GetAreaIdByUiMapId] : ", "Found AreaId", foundName, ":", foundId, " for UiMapId", uiMapInfo.name, ":", uiMapId, "direct match") --Questie:Debug(Questie.DEBUG_DEVELOP, "[ZoneDB:GetAreaIdByUiMapId] : ", "Found AreaId", foundName, ":", foundId, " for UiMapId", uiMapInfo.name, ":", uiMapId, "direct match")
--end --end
return foundId return foundId
else else
@@ -115,15 +116,20 @@ function ZoneDB:GetAreaIdByUiMapId(uiMapId)
local mapInfo = C_Map.GetMapInfo(uiMapId) local mapInfo = C_Map.GetMapInfo(uiMapId)
local areaName = C_Map.GetAreaInfo(areaId) local areaName = C_Map.GetAreaInfo(areaId)
if mapInfo and mapInfo.name == areaName then 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 return areaId
end end
end end
error("No AreaId found for UiMapId: " .. uiMapId .. ":" .. C_Map.GetMapInfo(uiMapId).name) if Questie.db.profile.debugEnabled then
Questie:Debug(Questie.DEBUG_CRITICAL,
"No AreaId found for UiMapId: " ..
uiMapId .. ":" .. (C_Map.GetMapInfo(uiMapId) and C_Map.GetMapInfo(uiMapId).name or "nil"))
end
return nil
end end
end end
---@param areaId AreaId ---@param areaId AreaId
function ZoneDB:GetDungeonLocation(areaId) function ZoneDB:GetDungeonLocation(areaId)
return dungeonLocations[areaId] return dungeonLocations[areaId]
@@ -154,7 +160,6 @@ function ZoneDB:GetParentZoneId(areaId)
return dungeonParentZones[areaId] or subZoneToParentZone[areaId] return dungeonParentZones[areaId] or subZoneToParentZone[areaId]
end end
-- We keep localized variables outside of the function only used by GetZonesWithQuests -- We keep localized variables outside of the function only used by GetZonesWithQuests
do do
-- This is for yielding -- This is for yielding
@@ -163,87 +168,82 @@ do
--Keep yield here as there is potentially a case where this wants to be run outside of a coroutine --Keep yield here as there is potentially a case where this wants to be run outside of a coroutine
---@param yield boolean? ---@param yield boolean?
---@return table ---@return table
function ZoneDB:GetZonesWithQuests(yield) function ZoneDB:GetZonesWithQuests(yield)
local count = 0 local count = 0
local function ProcessQuestId(questId) local function ProcessQuestId(questId)
if (not QuestieCorrections.hiddenQuests[questId]) then if (not QuestieCorrections.hiddenQuests[questId]) then
if QuestiePlayer.HasRequiredRace(QuestieDB.QueryQuestSingle(questId, "requiredRaces")) if QuestiePlayer.HasRequiredRace(QuestieDB.QueryQuestSingle(questId, "requiredRaces"))
and QuestiePlayer.HasRequiredClass(QuestieDB.QueryQuestSingle(questId, "requiredClasses")) then and QuestiePlayer.HasRequiredClass(QuestieDB.QueryQuestSingle(questId, "requiredClasses")) then
local zoneOrSort = QuestieDB.QueryQuestSingle(questId, "zoneOrSort")
local requiredSkill = QuestieDB.QueryQuestSingle(questId, "requiredSkill")
local zoneOrSort = QuestieDB.QueryQuestSingle(questId, "zoneOrSort") if type(requiredSkill) == "table"
local requiredSkill = QuestieDB.QueryQuestSingle(questId, "requiredSkill") and requiredSkill[1]
and requiredSkill[1] ~= QuestieProfessions.professionKeys.RIDING then
local sortId = QuestieProfessions:GetSortIdByProfessionId(requiredSkill[1])
zoneOrSort = sortId or QuestieDB.sortKeys.SPECIAL
if type(requiredSkill) == "table" if (not zoneMap[zoneOrSort]) then zoneMap[zoneOrSort] = {} end
and requiredSkill[1] zoneMap[zoneOrSort][questId] = true
and requiredSkill[1] ~= QuestieProfessions.professionKeys.RIDING then elseif type(zoneOrSort) == "number" and zoneOrSort > 0 then
local parentZoneId = ZoneDB:GetParentZoneId(zoneOrSort)
local sortId = QuestieProfessions:GetSortIdByProfessionId(requiredSkill[1]) if parentZoneId then
zoneOrSort = sortId or QuestieDB.sortKeys.SPECIAL if (not zoneMap[parentZoneId]) then zoneMap[parentZoneId] = {} end
zoneMap[parentZoneId][questId] = true
else
if (not zoneMap[zoneOrSort]) then zoneMap[zoneOrSort] = {} end
zoneMap[zoneOrSort][questId] = true
end
elseif type(zoneOrSort) == "number" and _ZoneDB:IsSpecialQuest(zoneOrSort) then
if (not zoneMap[zoneOrSort]) then zoneMap[zoneOrSort] = {} end
zoneMap[zoneOrSort][questId] = true
else
local startedBy = QuestieDB.QueryQuestSingle(questId, "startedBy")
if startedBy then
zoneMap = _ZoneDB:GetZonesWithQuestsFromNPCs(zoneMap, startedBy[1], questId)
zoneMap = _ZoneDB:GetZonesWithQuestsFromObjects(zoneMap, startedBy[2], questId)
end
if (not zoneMap[zoneOrSort]) then zoneMap[zoneOrSort] = {} end local finishedBy = QuestieDB.QueryQuestSingle(questId, "finishedBy")
zoneMap[zoneOrSort][questId] = true if finishedBy then
zoneMap = _ZoneDB:GetZonesWithQuestsFromNPCs(zoneMap, finishedBy[1], questId)
zoneMap = _ZoneDB:GetZonesWithQuestsFromObjects(zoneMap, finishedBy[2], questId)
end
end
end
end
elseif type(zoneOrSort) == "number" and zoneOrSort > 0 then if yield then
local parentZoneId = ZoneDB:GetParentZoneId(zoneOrSort) count = count + 1
if count >= yieldAmount then
if parentZoneId then count = 0
if (not zoneMap[parentZoneId]) then zoneMap[parentZoneId] = {} end coroutine.yield()
zoneMap[parentZoneId][questId] = true end
else
if (not zoneMap[zoneOrSort]) then zoneMap[zoneOrSort] = {} end
zoneMap[zoneOrSort][questId] = true
end
elseif type(zoneOrSort) == "number" and _ZoneDB:IsSpecialQuest(zoneOrSort) then
if (not zoneMap[zoneOrSort]) then zoneMap[zoneOrSort] = {} end
zoneMap[zoneOrSort][questId] = true
else
local startedBy = QuestieDB.QueryQuestSingle(questId, "startedBy")
if startedBy then
zoneMap = _ZoneDB:GetZonesWithQuestsFromNPCs(zoneMap, startedBy[1], questId)
zoneMap = _ZoneDB:GetZonesWithQuestsFromObjects(zoneMap, startedBy[2], questId)
end
local finishedBy = QuestieDB.QueryQuestSingle(questId, "finishedBy")
if finishedBy then
zoneMap = _ZoneDB:GetZonesWithQuestsFromNPCs(zoneMap, finishedBy[1], questId)
zoneMap = _ZoneDB:GetZonesWithQuestsFromObjects(zoneMap, finishedBy[2], questId)
end
end
end end
end end
if yield then -- 1) Base Questie quests (QuestPointers values must be numbers; ignore anything weird)
count = count + 1 for questId, ptr in pairs(QuestieDB.QuestPointers) do
if count >= yieldAmount then if type(ptr) == "number" then
count = 0 ProcessQuestId(questId)
coroutine.yield()
end end
end end
end
-- 1) Base Questie quests (QuestPointers values must be numbers; ignore anything weird) -- 2) Ascension custom quests (from overrides list)
for questId, ptr in pairs(QuestieDB.QuestPointers) do if type(QuestieDB.ascensionQuestIds) == "table" then
if type(ptr) == "number" then for questId in pairs(QuestieDB.ascensionQuestIds) do
ProcessQuestId(questId) ProcessQuestId(questId)
end
end end
end
-- 2) Ascension custom quests (from overrides list) if yield then coroutine.yield() end
if type(QuestieDB.ascensionQuestIds) == "table" then zoneMap = _ZoneDB:SplitSeasonalQuests()
for questId in pairs(QuestieDB.ascensionQuestIds) do return zoneMap
ProcessQuestId(questId)
end
end end
if yield then coroutine.yield() end
zoneMap = _ZoneDB:SplitSeasonalQuests()
return zoneMap
end
end end
@@ -354,8 +354,6 @@ function ZoneDB:GetRelevantZones()
return zones return zones
end end
----- Tests ----- ----- Tests -----
function _ZoneDB:RunTests() function _ZoneDB:RunTests()
@@ -373,12 +371,12 @@ function _ZoneDB:RunTests()
if map.mapType ~= Enum.UIMapType.World and map.mapType ~= Enum.UIMapType.Continent and map.mapType ~= Enum.UIMapType.Cosmic then 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) local success, result = pcall(ZoneDB.GetAreaIdByUiMapId, ZoneDB, map.mapID)
if not success and not buggedMaps[map.mapID] then if not success and not buggedMaps[map.mapID] then
Questie:Error("[ZoneDBTests] ZoneDB.GetAreaIdByUiMapId fails for " .. map.name .. " (" .. map.mapID .. "). Result: " .. result) Questie:Error("[ZoneDBTests] ZoneDB.GetAreaIdByUiMapId fails for " ..
map.name .. " (" .. map.mapID .. "). Result: " .. result)
end end
end end
end end
Questie:Debug(Questie.DEBUG_CRITICAL, "[" .. Questie:Colorize("ZoneDBTests", "yellow") .. "] Testing ZoneDB done") Questie:Debug(Questie.DEBUG_CRITICAL, "[" .. Questie:Colorize("ZoneDBTests", "yellow") .. "] Testing ZoneDB done")
end end
return ZoneDB return ZoneDB
+43 -40
View File
@@ -483,8 +483,8 @@ function QuestieArrow:UpdateNearestTargets()
local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone) local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone)
if uiMapId and x and y then if uiMapId and x and y then
local targetX, targetY, targetInstance = HBD local targetX, targetY, targetInstance = HBD
:GetWorldCoordinatesFromZone( :GetWorldCoordinatesFromZone(
x / 100.0, y / 100.0, uiMapId) x / 100.0, y / 100.0, uiMapId)
if targetX and targetY and targetInstance then if targetX and targetY and targetInstance then
local dist = HBD:GetWorldDistance(targetInstance, playerX, local dist = HBD:GetWorldDistance(targetInstance, playerX,
playerY, playerY,
@@ -547,6 +547,7 @@ function QuestieArrow:UpdateNearestTargets()
end end
end end
if finisher.waypoints then if finisher.waypoints then
for zone, waypoints in pairs(finisher.waypoints) do for zone, waypoints in pairs(finisher.waypoints) do
-- Auto Logic: Hide distant quests (different zone) -- Auto Logic: Hide distant quests (different zone)
@@ -596,47 +597,47 @@ function QuestieArrow:UpdateNearestTargets()
return return
end end
end
local function _CollectObjective(objective) local function _CollectObjective(objective)
if not objective or not objective.spawnList then if not objective or not objective.spawnList then
return return
end end
if objective.Completed == true or objective.Completed == 1 then if objective.Completed == true or objective.Completed == 1 then
return return
end end
for _, spawnData in pairs(objective.spawnList) do for _, spawnData in pairs(objective.spawnList) do
if spawnData and spawnData.Spawns then if spawnData and spawnData.Spawns then
for zone, spawns in pairs(spawnData.Spawns) do for zone, spawns in pairs(spawnData.Spawns) do
-- Auto Logic: Hide distant quests (different zone) -- Auto Logic: Hide distant quests (different zone)
if usingAutoLogic and zone ~= playerZoneId then if usingAutoLogic and zone ~= playerZoneId then
-- continue -- continue
else else
for _, spawn in pairs(spawns) do for _, spawn in pairs(spawns) do
local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone) local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone)
if uiMapId then if uiMapId then
local targetX, targetY, targetInstance = HBD:GetWorldCoordinatesFromZone( local targetX, targetY, targetInstance = HBD:GetWorldCoordinatesFromZone(
spawn[1] / 100.0, spawn[2] / 100.0, uiMapId) spawn[1] / 100.0, spawn[2] / 100.0, uiMapId)
if targetX and targetY and targetInstance then if targetX and targetY and targetInstance then
local dist = HBD:GetWorldDistance(targetInstance, playerX, playerY, targetX, local dist = HBD:GetWorldDistance(targetInstance, playerX, playerY, targetX,
targetY) targetY)
if dist then if dist then
if targetInstance ~= playerInstance then if targetInstance ~= playerInstance then
dist = 500000 + dist * 100 dist = 500000 + dist * 100
end
table.insert(sortedTargets, {
x = spawn[1],
y = spawn[2],
uiMapId = uiMapId,
title = quest.name,
questLevel = quest.level,
iconPath = ResolveIconTexture(objective.Icon) or
ResolveIconTexture(spawnData and spawnData.Icon),
distance = dist,
})
end end
table.insert(sortedTargets, {
x = spawn[1],
y = spawn[2],
uiMapId = uiMapId,
title = quest.name,
questLevel = quest.level,
iconPath = ResolveIconTexture(objective.Icon) or
ResolveIconTexture(spawnData and spawnData.Icon),
distance = dist,
})
end end
end end
end end
@@ -647,6 +648,8 @@ function QuestieArrow:UpdateNearestTargets()
end end
end end
if quest.Objectives then if quest.Objectives then
for _, objective in pairs(quest.Objectives) do for _, objective in pairs(quest.Objectives) do
_CollectObjective(objective) _CollectObjective(objective)
@@ -728,7 +731,7 @@ function QuestieArrow:SetTarget(title, zoneOrUiMapId, x, y)
y = y, y = y,
uiMapId = uiMapId, uiMapId = uiMapId,
title = title, title = title,
distance = 0, -- Manual targets always go first distance = 0, -- Manual targets always go first
} } } }
EnsureArrowFrame() EnsureArrowFrame()
+1 -1
View File
@@ -6,7 +6,7 @@
## Notes-esES: Ayundante de misión ## Notes-esES: Ayundante de misión
## Notes-ptBR: Ajudante de missão ## Notes-ptBR: Ajudante de missão
## Notes-frFR: Assistant de quête ## Notes-frFR: Assistant de quête
## Version: 9.7.2 beta ## Version: 9.7.3
## RequiredDeps: ## RequiredDeps:
## OptionalDeps: Ace3, CallbackHandler-1.0, HereBeDragons, LibDataBroker-1.1, LibDBIcon-1.0, LibSharedMedia-3.0, LibStub, LibUIDropDownMenu ## OptionalDeps: Ace3, CallbackHandler-1.0, HereBeDragons, LibDataBroker-1.1, LibDBIcon-1.0, LibSharedMedia-3.0, LibStub, LibUIDropDownMenu
## SavedVariables: QuestieConfig ## SavedVariables: QuestieConfig