diff --git a/CHANGELOG.md b/CHANGELOG.md index e6cd8e0..ac88644 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## v9.7.2 +## v9.7.3 ### New Features - **[Database]** Implemented **Ebonhold Database Module**. @@ -37,3 +37,6 @@ - **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). - **[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). diff --git a/Database/Zones/zoneDB.lua b/Database/Zones/zoneDB.lua index f6e65c0..54c5fa7 100644 --- a/Database/Zones/zoneDB.lua +++ b/Database/Zones/zoneDB.lua @@ -46,7 +46,7 @@ local UiMapIdOverrides = { [246] = 3713 } local parentZoneToSubZone = {} -- Generated -local zoneMap = {} -- Generated +local zoneMap = {} -- Generated function ZoneDB:Initialize() @@ -96,15 +96,16 @@ function ZoneDB:GetAreaIdByUiMapId(uiMapId) -- 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") + --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 return foundId else @@ -115,15 +116,20 @@ function ZoneDB:GetAreaIdByUiMapId(uiMapId) 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 - 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 - ---@param areaId AreaId function ZoneDB:GetDungeonLocation(areaId) return dungeonLocations[areaId] @@ -154,7 +160,6 @@ function ZoneDB:GetParentZoneId(areaId) return dungeonParentZones[areaId] or subZoneToParentZone[areaId] end - -- We keep localized variables outside of the function only used by GetZonesWithQuests do -- 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 ----@param yield boolean? ----@return table -function ZoneDB:GetZonesWithQuests(yield) - local count = 0 + ---@param yield boolean? + ---@return table + function ZoneDB:GetZonesWithQuests(yield) + local count = 0 - local function ProcessQuestId(questId) - if (not QuestieCorrections.hiddenQuests[questId]) then - if QuestiePlayer.HasRequiredRace(QuestieDB.QueryQuestSingle(questId, "requiredRaces")) - and QuestiePlayer.HasRequiredClass(QuestieDB.QueryQuestSingle(questId, "requiredClasses")) then + local function ProcessQuestId(questId) + if (not QuestieCorrections.hiddenQuests[questId]) then + if QuestiePlayer.HasRequiredRace(QuestieDB.QueryQuestSingle(questId, "requiredRaces")) + 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") - local requiredSkill = QuestieDB.QueryQuestSingle(questId, "requiredSkill") + if type(requiredSkill) == "table" + 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" - and requiredSkill[1] - and requiredSkill[1] ~= QuestieProfessions.professionKeys.RIDING then + if (not zoneMap[zoneOrSort]) then zoneMap[zoneOrSort] = {} end + zoneMap[zoneOrSort][questId] = true + elseif type(zoneOrSort) == "number" and zoneOrSort > 0 then + local parentZoneId = ZoneDB:GetParentZoneId(zoneOrSort) - local sortId = QuestieProfessions:GetSortIdByProfessionId(requiredSkill[1]) - zoneOrSort = sortId or QuestieDB.sortKeys.SPECIAL + if parentZoneId then + 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 - zoneMap[zoneOrSort][questId] = true + 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 - elseif type(zoneOrSort) == "number" and zoneOrSort > 0 then - local parentZoneId = ZoneDB:GetParentZoneId(zoneOrSort) - - if parentZoneId then - 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 - - 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 + if yield then + count = count + 1 + if count >= yieldAmount then + count = 0 + coroutine.yield() + end end end - if yield then - count = count + 1 - if count >= yieldAmount then - count = 0 - coroutine.yield() + -- 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) end end - 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) + -- 2) Ascension custom quests (from overrides list) + if type(QuestieDB.ascensionQuestIds) == "table" then + for questId in pairs(QuestieDB.ascensionQuestIds) do + 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 - ProcessQuestId(questId) - end + if yield then coroutine.yield() end + zoneMap = _ZoneDB:SplitSeasonalQuests() + return zoneMap end - - if yield then coroutine.yield() end - zoneMap = _ZoneDB:SplitSeasonalQuests() - return zoneMap -end end @@ -354,8 +354,6 @@ function ZoneDB:GetRelevantZones() return zones end - - ----- Tests ----- 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 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) + Questie:Error("[ZoneDBTests] ZoneDB.GetAreaIdByUiMapId fails for " .. + map.name .. " (" .. map.mapID .. "). Result: " .. result) end - end end Questie:Debug(Questie.DEBUG_CRITICAL, "[" .. Questie:Colorize("ZoneDBTests", "yellow") .. "] Testing ZoneDB done") end -return ZoneDB \ No newline at end of file +return ZoneDB diff --git a/Modules/Arrow/QuestieArrow.lua b/Modules/Arrow/QuestieArrow.lua index 4a0c4bf..d3f6463 100644 --- a/Modules/Arrow/QuestieArrow.lua +++ b/Modules/Arrow/QuestieArrow.lua @@ -483,8 +483,8 @@ function QuestieArrow:UpdateNearestTargets() local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone) if uiMapId and x and y then local targetX, targetY, targetInstance = HBD - :GetWorldCoordinatesFromZone( - x / 100.0, y / 100.0, uiMapId) + :GetWorldCoordinatesFromZone( + x / 100.0, y / 100.0, uiMapId) if targetX and targetY and targetInstance then local dist = HBD:GetWorldDistance(targetInstance, playerX, playerY, @@ -547,6 +547,7 @@ function QuestieArrow:UpdateNearestTargets() end end + if finisher.waypoints then for zone, waypoints in pairs(finisher.waypoints) do -- Auto Logic: Hide distant quests (different zone) @@ -596,47 +597,47 @@ function QuestieArrow:UpdateNearestTargets() return end + end - local function _CollectObjective(objective) - if not objective or not objective.spawnList then - return - end + local function _CollectObjective(objective) + if not objective or not objective.spawnList then + return + end - if objective.Completed == true or objective.Completed == 1 then - return - end + if objective.Completed == true or objective.Completed == 1 then + return + end - for _, spawnData in pairs(objective.spawnList) do - if spawnData and spawnData.Spawns then - for zone, spawns in pairs(spawnData.Spawns) do - -- Auto Logic: Hide distant quests (different zone) - if usingAutoLogic and zone ~= playerZoneId then - -- continue - else - for _, spawn in pairs(spawns) do - local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone) - if uiMapId then - local targetX, targetY, targetInstance = HBD:GetWorldCoordinatesFromZone( - spawn[1] / 100.0, spawn[2] / 100.0, uiMapId) - if targetX and targetY and targetInstance then - local dist = HBD:GetWorldDistance(targetInstance, playerX, playerY, targetX, - targetY) - if dist then - if targetInstance ~= playerInstance then - 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, - }) + for _, spawnData in pairs(objective.spawnList) do + if spawnData and spawnData.Spawns then + for zone, spawns in pairs(spawnData.Spawns) do + -- Auto Logic: Hide distant quests (different zone) + if usingAutoLogic and zone ~= playerZoneId then + -- continue + else + for _, spawn in pairs(spawns) do + local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone) + if uiMapId then + local targetX, targetY, targetInstance = HBD:GetWorldCoordinatesFromZone( + spawn[1] / 100.0, spawn[2] / 100.0, uiMapId) + if targetX and targetY and targetInstance then + local dist = HBD:GetWorldDistance(targetInstance, playerX, playerY, targetX, + targetY) + if dist then + if targetInstance ~= playerInstance then + 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 end @@ -647,6 +648,8 @@ function QuestieArrow:UpdateNearestTargets() end end + + if quest.Objectives then for _, objective in pairs(quest.Objectives) do _CollectObjective(objective) @@ -728,7 +731,7 @@ function QuestieArrow:SetTarget(title, zoneOrUiMapId, x, y) y = y, uiMapId = uiMapId, title = title, - distance = 0, -- Manual targets always go first + distance = 0, -- Manual targets always go first } } EnsureArrowFrame() diff --git a/Questie-335.toc b/Questie-335.toc index 087b050..c5a3c95 100644 --- a/Questie-335.toc +++ b/Questie-335.toc @@ -6,7 +6,7 @@ ## Notes-esES: Ayundante de misión ## Notes-ptBR: Ajudante de missão ## Notes-frFR: Assistant de quête -## Version: 9.7.2 beta +## Version: 9.7.3 ## RequiredDeps: ## OptionalDeps: Ace3, CallbackHandler-1.0, HereBeDragons, LibDataBroker-1.1, LibDBIcon-1.0, LibSharedMedia-3.0, LibStub, LibUIDropDownMenu ## SavedVariables: QuestieConfig