fix: suppress duplicate native quest POIs

This commit is contained in:
Xurkon
2026-06-12 22:32:24 -05:00
parent a7de3eccb4
commit 70a99346e6
5 changed files with 174 additions and 22 deletions
+145 -5
View File
@@ -587,18 +587,158 @@ function QuestieCompat.GetQuestIDFromLogIndex(questLogIndex)
return select(8, QuestieCompat.GetQuestLogTitle(questLogIndex))
end
---Keeps Blizzard/server objective POIs from drawing over Questie's objective icons.
---@param useQuestieObjectives boolean
function QuestieCompat.SyncBlizzardObjectivePOIs(useQuestieObjectives)
local QUESTIE_DUPLICATE_POI_ICON_TYPES = {
complete = true,
monster = true,
object = true,
item = true,
event = true,
}
local BLIZZARD_POI_QUEST_ID_FIELDS = {
"questID",
"questId",
"questIDNumber",
"questIDNum",
"questLogID",
"id",
}
local BLIZZARD_POI_QUEST_LOG_INDEX_FIELDS = {
"questLogIndex",
"questIndex",
"logIndex",
}
local function _ToPositiveNumber(value)
if type(value) == "number" or type(value) == "string" then
local number = tonumber(value)
if number and number > 0 then
return number
end
end
return nil
end
---Enables Blizzard/server objective POIs without globally disabling them when Questie objectives are on.
function QuestieCompat.EnableBlizzardObjectivePOIs()
if GetCVar and GetCVar("questPOI") ~= nil and SetCVar then
SetCVar("questPOI", useQuestieObjectives and "0" or "1")
SetCVar("questPOI", "1")
end
if WorldMapQuestShowObjectives and WorldMapQuestShowObjectives.SetChecked then
WorldMapQuestShowObjectives:SetChecked(not useQuestieObjectives)
WorldMapQuestShowObjectives:SetChecked(true)
end
end
---@param frame table
---@return boolean
local function _IsVisibleQuestiePOIFrame(frame)
if (not frame) or (not frame.data) or (not QUESTIE_DUPLICATE_POI_ICON_TYPES[frame.data.Type]) then
return false
end
if frame.ShouldBeHidden then
return not frame:ShouldBeHidden()
end
return not frame.hidden
end
---@param questId number
---@return boolean
function QuestieCompat.HasVisibleQuestiePOIForQuest(questId)
if (not questId) or questId <= 0 then
return false
end
local QuestieMap = QuestieLoader:ImportModule("QuestieMap")
local questFrames = QuestieMap.questIdFrames and QuestieMap.questIdFrames[questId]
if not questFrames then
return false
end
for _, frameName in pairs(questFrames) do
if _IsVisibleQuestiePOIFrame(_G[frameName]) then
return true
end
end
return false
end
---@param poiButton table
---@return number|nil
function QuestieCompat.GetQuestIDFromBlizzardPOIButton(poiButton)
if not poiButton then
return nil
end
for _, field in ipairs(BLIZZARD_POI_QUEST_ID_FIELDS) do
local questId = _ToPositiveNumber(poiButton[field])
if questId then
return questId
end
end
for _, field in ipairs(BLIZZARD_POI_QUEST_LOG_INDEX_FIELDS) do
local questLogIndex = _ToPositiveNumber(poiButton[field])
if questLogIndex then
local questId = QuestieCompat.GetQuestIDFromLogIndex(questLogIndex)
if questId and questId > 0 then
return questId
end
end
end
return nil
end
---@param poiButton table
function QuestieCompat.SuppressDuplicateBlizzardPOIButton(poiButton)
local questId = QuestieCompat.GetQuestIDFromBlizzardPOIButton(poiButton)
if questId and QuestieCompat.HasVisibleQuestiePOIForQuest(questId) then
poiButton.questieDuplicateSuppressed = true
poiButton:Hide()
end
end
function QuestieCompat.SuppressDuplicateBlizzardPOI(parentName, buttonType, buttonIndex)
local poiButton = _G[string.format(
"poi%s%s_%d",
tostring(parentName or ""),
tostring(buttonType or ""),
_ToPositiveNumber(buttonIndex) or 0
)]
if poiButton then
QuestieCompat.SuppressDuplicateBlizzardPOIButton(poiButton)
end
end
function QuestieCompat.InitializeBlizzardPOISuppression()
if QuestieCompat._blizzardPOISuppressionHooked then
return
end
local hooked = false
if QuestPOI_DisplayButton then
hooksecurefunc("QuestPOI_DisplayButton", function(parentName, buttonType, buttonIndex)
QuestieCompat.SuppressDuplicateBlizzardPOI(parentName, buttonType, buttonIndex)
end)
hooked = true
end
if QuestPOI_SelectButton then
hooksecurefunc("QuestPOI_SelectButton", function(poiButton)
QuestieCompat.SuppressDuplicateBlizzardPOIButton(poiButton)
end)
hooked = true
end
QuestieCompat._blizzardPOISuppressionHooked = hooked
end
-- https://wowpedia.fandom.com/wiki/API_GetQuestLink
-- Returns a QuestLink for a quest.
-- Between patches 6.2 and 7.3.2 argument was changed to take a QuestID instead of a quest log index.
@@ -266,7 +266,6 @@ function QuestieOptions.tabs.icons:Initialize()
get = function() return Questie.db.profile.enableObjectives; end,
set = function(info, value)
Questie.db.profile.enableObjectives = value
QuestieCompat.SyncBlizzardObjectivePOIs(value)
QuestieQuest:ToggleNotes(value)
QuestieOptionsUtils.DetermineTheme()
end,
@@ -1335,7 +1334,6 @@ end
function QuestieOptionsUtils.ExecuteTheme(info, value)
Questie.db.profile.iconTheme = value
if value == 'questie' then
QuestieCompat.SyncBlizzardObjectivePOIs(true)
Questie.db.profile.enableObjectives = true
Questie.db.profile.ICON_SLAY = Questie.icons["slay"]
Questie.db.profile.ICON_LOOT = Questie.icons["loot"]
@@ -1348,7 +1346,6 @@ function QuestieOptionsUtils.ExecuteTheme(info, value)
Questie.db.profile.alwaysGlowMinimap = optionsDefaults.profile.alwaysGlowMinimap
Questie.db.profile.clusterLevelHotzone = optionsDefaults.profile.clusterLevelHotzone
elseif value == 'pfquest' then
QuestieCompat.SyncBlizzardObjectivePOIs(true)
Questie.db.profile.enableObjectives = true
Questie.db.profile.ICON_SLAY = Questie.icons["node"]
Questie.db.profile.ICON_LOOT = Questie.icons["node"]
@@ -1361,7 +1358,7 @@ function QuestieOptionsUtils.ExecuteTheme(info, value)
Questie.db.profile.alwaysGlowMinimap = false
Questie.db.profile.clusterLevelHotzone = 1
elseif value == 'blizzard' then
QuestieCompat.SyncBlizzardObjectivePOIs(false)
QuestieCompat.EnableBlizzardObjectivePOIs()
Questie.db.profile.enableObjectives = false
Questie.db.profile.ICON_SLAY = Questie.icons["slay"]
Questie.db.profile.ICON_LOOT = Questie.icons["loot"]
+1 -1
View File
@@ -226,7 +226,7 @@ QuestieInit.Stages[1] = function() -- run as a coroutine
end
Questie:SetIcons()
QuestieCompat.SyncBlizzardObjectivePOIs(Questie.db.profile.enableObjectives)
QuestieCompat.InitializeBlizzardPOISuppression()
if QUESTIE_LOCALES_OVERRIDE ~= nil then
l10n:InitializeLocaleOverride()
-1
View File
@@ -302,7 +302,6 @@ function QuestieMenu:Show(hideDelay)
tinsert(menuTable, { text= l10n("Objective"), func = function()
local value = not Questie.db.profile.enableObjectives
Questie.db.profile.enableObjectives = value
QuestieCompat.SyncBlizzardObjectivePOIs(value)
QuestieQuest:ToggleNotes(value)
QuestieQuest:SmoothReset()
end, icon=QuestieLib.AddonPath.."Icons\\event.blp", notCheckable=false, checked=Questie.db.profile.enableObjectives, isNotRadio=true, keepShownOnClick=true})
+27 -11
View File
@@ -9,26 +9,42 @@ local function has(content, needle)
return content:find(needle, 1, true) ~= nil
end
describe("Blizzard objective POI sync", function()
describe("Blizzard objective POI suppression", function()
local compat = read("Compat/Compat.lua")
local init = read("Modules/QuestieInit.lua")
local iconOptions = read("Modules/Options/IconsTab/QuestieOptionsIcons.lua")
local questieMenu = read("Modules/QuestieMenu/QuestieMenu.lua")
it("disables native quest POIs when Questie objective icons are enabled", function()
local helperStart = assert(compat:find("function QuestieCompat.SyncBlizzardObjectivePOIs", 1, true))
it("suppresses only native POI buttons that duplicate visible Questie quest icons", function()
local helperStart = assert(compat:find("function QuestieCompat.HasVisibleQuestiePOIForQuest", 1, true))
local helperEnd = assert(compat:find("-- https://wowpedia.fandom.com/wiki/API_GetQuestLink", helperStart, true))
local helper = compat:sub(helperStart, helperEnd)
assert.is_true(has(helper, "SetCVar(\"questPOI\", useQuestieObjectives and \"0\" or \"1\")"))
assert.is_true(has(helper, "WorldMapQuestShowObjectives:SetChecked(not useQuestieObjectives)"))
assert.is_true(has(compat, "complete = true"))
assert.is_true(has(compat, "monster = true"))
assert.is_true(has(compat, "object = true"))
assert.is_true(has(compat, "item = true"))
assert.is_true(has(compat, "event = true"))
assert.is_true(has(compat, "frame:ShouldBeHidden()"))
assert.is_true(has(helper, "QuestieMap.questIdFrames and QuestieMap.questIdFrames[questId]"))
assert.is_true(has(helper, "poiButton:Hide()"))
end)
it("syncs native POIs on startup and objective ownership changes", function()
assert.is_true(has(init, "QuestieCompat.SyncBlizzardObjectivePOIs(Questie.db.profile.enableObjectives)"))
assert.is_true(has(iconOptions, "QuestieCompat.SyncBlizzardObjectivePOIs(value)"))
assert.is_true(has(iconOptions, "QuestieCompat.SyncBlizzardObjectivePOIs(true)"))
assert.is_true(has(iconOptions, "QuestieCompat.SyncBlizzardObjectivePOIs(false)"))
assert.is_true(has(questieMenu, "QuestieCompat.SyncBlizzardObjectivePOIs(value)"))
it("hooks Blizzard POI display without globally disabling native POIs", function()
local helperStart = assert(compat:find("function QuestieCompat.InitializeBlizzardPOISuppression", 1, true))
local helperEnd = assert(compat:find("-- https://wowpedia.fandom.com/wiki/API_GetQuestLink", helperStart, true))
local helper = compat:sub(helperStart, helperEnd)
assert.is_true(has(helper, "hooksecurefunc(\"QuestPOI_DisplayButton\""))
assert.is_true(has(helper, "hooksecurefunc(\"QuestPOI_SelectButton\""))
assert.is_true(has(compat, "\"poi%s%s_%d\""))
assert.is_false(has(compat, "SetCVar(\"questPOI\", useQuestieObjectives and \"0\" or \"1\")"))
end)
it("initializes duplicate suppression but leaves objective toggles in control of Questie icons only", function()
assert.is_true(has(init, "QuestieCompat.InitializeBlizzardPOISuppression()"))
assert.is_false(has(iconOptions, "QuestieCompat.SyncBlizzardObjectivePOIs"))
assert.is_true(has(iconOptions, "QuestieCompat.EnableBlizzardObjectivePOIs()"))
assert.is_false(has(questieMenu, "QuestieCompat.SyncBlizzardObjectivePOIs"))
end)
end)