feat: Release v1.3.2 — Taint Resolution & Stability patches

This commit is contained in:
Xurkon
2026-03-18 15:08:52 -05:00
parent b3021eb06d
commit aed0daf4ce
14 changed files with 107 additions and 99 deletions
+13
View File
@@ -1,5 +1,18 @@
# Changelog
## v1.3.2 — Taint Resolution & Stability
*Finalizes the Taint Resolution project, eliminating `ADDON_ACTION_BLOCKED: UseAction()` errors by refactoring internal hooks to use secure alternatives and hardening the global namespace against collisions.*
### Core & Stability
- **[Taint Resolution]** Refactored `Hooks.lua` to use `hooksecurefunc` instead of raw hooks for all secure functions.
- **[Global Safety]** Enhanced `QuestieLoader.lua` with a new collision-aware `PopulateGlobals` engine that prevents overwriting existing global variables and provides diagnostic warnings.
- **[Security]** Eliminated global namespace modifications in `QuestieInit.lua`.
- **[Workaround Hardening]** Refactored `WorldMapTaintWorkaround.lua` to remove legacy global function reassignments that were causing secondary taint.
---
## v1.3.1
- Refined data-sharing mechanism to use exclusively hidden global channels, removing guild-channel broadcasts to minimize chat traffic.
+5 -1
View File
@@ -139,7 +139,11 @@ end
function QuestieLoader:PopulateGlobals() -- called when debugging is enabled
for name, module in pairs(modules) do
_G[name] = module
if _G[name] == nil then
_G[name] = module
elseif _G[name] ~= module then
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieLoader] GLOBAL COLLISION: '" .. tostring(name) .. "' already exists in _G! Skipping population to avoid Taint.")
end
end
end
+2 -29
View File
@@ -471,11 +471,8 @@ QuestieComms._yellWaitingQuests = {}
QuestieComms._yellQueue = {}
QuestieComms._isYelling = false
local _loadupTime_removeme = GetTime() -- this will be removed in 6.0.1 or 6.1, when we can figure out a proper way to prevent
-- yelling quests on login. Not enough time to make and test a proper fix
function QuestieComms:YellProgress(questId)
if Questie.db.profile.disableYellComms or badYellLocations[C_Map.GetBestMapForUnit("player")] or QuestiePlayer.numberOfGroupMembers > 4 or GetTime() - _loadupTime_removeme < 8 then
if Questie.db.profile.disableYellComms or badYellLocations[C_Map.GetBestMapForUnit("player")] or QuestiePlayer.numberOfGroupMembers > 4 then
return
end
if not QuestieComms._yellWaitingQuests[questId] then
@@ -484,35 +481,11 @@ function QuestieComms:YellProgress(questId)
tinsert(QuestieComms._yellQueue, questId)
else
QuestieComms._isYelling = true
C_Timer.After(2, function()
_DoYell(questId)
end)
-- Yell progress feature is currently disabled
end
end
end
_DoYell = function(questId)
--[[local data = {}
local _, count = QuestieComms:PopulateQuestDataPacketV2(questId, data, 1)
if count > 0 then -- dont send quests with no objectives
local packet = _QuestieComms:CreatePacket(_QuestieComms.QC_ID_YELL_PROGRESS);
packet.data[1] = data;
packet.data.priority = "BULK"
packet.data.writeMode = _QuestieComms.QC_WRITE_YELL
packet:write();
QuestieComms._yellWaitingQuests[questId] = nil
end
local nextQuest = tremove(QuestieComms._yellQueue, 1)
if nextQuest then
C_Timer.After(2, function()
_DoYell(nextQuest)
end)
else
QuestieComms._isYelling = false
end]]
end
_QuestieComms._isBroadcasting = false
_QuestieComms._needsNewBroadcast = false
_QuestieComms._nextBroadcastData = {}
+9 -21
View File
@@ -93,29 +93,17 @@ function QuestieComms.data:RegisterTooltip(questId, playerName, objectives)
--Questie:Debug(Questie.DEBUG_DEVELOP, "Adding tooltip lookup", lookupKey, questId, playerName);
if(objective.type == "i") then
local item = QuestieDB:GetItem(objective.id);
if not item or item.Hidden then
return
end
for index, source in pairs(item.Sources or {}) do
local sourceType = string.sub(source.Type, 1, 1);
local sourceId = source.Id;
local sourceLookupKey = sourceType.."_"..sourceId;
QuestieComms.data:AddTooltip(playerName, questId, sourceLookupKey, objectiveIndex, objective);
if item and not item.Hidden then
for index, source in pairs(item.Sources or {}) do
local sourceType = string.sub(source.Type, 1, 1);
local sourceId = source.Id;
local sourceLookupKey = sourceType.."_"..sourceId;
QuestieComms.data:AddTooltip(playerName, questId, sourceLookupKey, objectiveIndex, objective);
end
end
else
QuestieComms.data:AddTooltip(playerName, questId, lookupKey, objectiveIndex, objective);
end
--[[if(not commsTooltipLookup[lookupKey]) then
commsTooltipLookup[lookupKey] = {}
end
if(not commsTooltipLookup[lookupKey][playerName]) then
commsTooltipLookup[lookupKey][playerName] = {};
end
if(not commsTooltipLookup[lookupKey][playerName][questId]) then
commsTooltipLookup[lookupKey][playerName][questId] = {};
end
commsTooltipLookup[lookupKey][playerName][questId][objectiveIndex] = objective;
playerRegisteredTooltips[playerName][questId][lookupKey] = true;]]--
QuestieComms.data:AddTooltip(playerName, questId, lookupKey, objectiveIndex, objective);
end
end
end
+7 -9
View File
@@ -14,12 +14,9 @@ local GetQuestIDFromLogIndex = QuestieCompat.GetQuestIDFromLogIndex
function Hooks:HookQuestLogTitle()
Questie:Debug(Questie.DEBUG_DEVELOP, "[Hooks] Hooking Quest Log Title")
local baseQLTB_OnClick = QuestLogTitleButton_OnClick
-- We can not use hooksecurefunc because this needs to be a pre-hook to work properly unfortunately
QuestLogTitleButton_OnClick = function(self, button)
hooksecurefunc("QuestLogTitleButton_OnClick", function(self, button)
if (not self) or self.isHeader then
baseQLTB_OnClick(self, button)
return
end
@@ -39,18 +36,19 @@ function Hooks:HookQuestLogTitle()
ChatEdit_InsertLink(questLink)
end
QuestLog_SetSelection(questLogLineIndex)
return
-- We can't return here to stop the execution of the original function in hooksecurefunc,
-- but for chat links the original function usually just selects the quest anyway.
end
-- For all other clicks (including tracking/untracking), use the original function
-- only call Questie's tracker if we actually want to fix this quest (normal quests already call AQW_insert)
if Questie.db.profile.trackerEnabled and GetNumQuestLeaderBoards(questLogLineIndex) == 0 and (not IsQuestWatched(questLogLineIndex)) then
QuestieTracker:AQW_Insert(questLogLineIndex, QUEST_WATCH_NO_EXPIRE)
WatchFrame_Update()
if WatchFrame_Update then
WatchFrame_Update()
end
QuestLog_SetSelection(questLogLineIndex)
QuestLog_Update()
else
baseQLTB_OnClick(self, button)
end
end
end)
end
-1
View File
@@ -473,7 +473,6 @@ function QuestieInit:LoadBaseDB()
local function _pullGlobal(dbKey, globalName)
if type(_G[globalName]) == "table" then
QuestieDB[dbKey] = _G[globalName]
_G[globalName] = nil
return true
end
return false
+3 -3
View File
@@ -7,15 +7,15 @@ local function doWorkaround()
-- HDB (and Questie fork of it) uses WorldMapFrame:AddDataProvider( ).
-- print("|cff30fc96Questie|r: |cff00bc32Hiding drop-down menus on the World Map.|r This is currently necessary as a workaround for a bug in the default Blizzard UI related to drop-down menus.")
if WorldMapZoneMinimapDropDown then
WorldMapZoneMinimapDropDown_Update = function() end
WorldMapZoneMinimapDropDown:Hide()
end
if WorldMapContinentDropDown then
--WorldMapContinentDropDown_Update = function() end
-- We only Hide() these frames.
-- Reassigning the _Update functions (e.g. WorldMapContinentDropDown_Update = function() end)
-- would cause Taint, which results in ADDON_ACTION_BLOCKED: UseAction().
WorldMapContinentDropDown:Hide()
end
if WorldMapZoneDropDown then
--WorldMapZoneDropDown_Update = function() end
WorldMapZoneDropDown:Hide()
end
--WorldMapMagnifyingGlassButton:Hide()
+1 -1
View File
@@ -5,7 +5,7 @@
## Notes-esES: Ayundante de misión
## Notes-ptBR: Ajudante de missão
## Notes-frFR: Assistant de quête
## Version: 1.3.1
## Version: 1.3.2
## RequiredDeps:
## OptionalDeps: Ace3, CallbackHandler-1.0, HereBeDragons, LibDataBroker-1.1, LibDBIcon-1.0, LibSharedMedia-3.0, LibStub, LibUIDropDownMenu
## SavedVariables: QuestieConfig
+1 -1
View File
@@ -5,7 +5,7 @@
## Notes-esES: Ayundante de misión
## Notes-ptBR: Ajudante de missão
## Notes-frFR: Assistant de quête
## Version: 1.3.1
## Version: 1.3.2
## RequiredDeps:
## OptionalDeps: Ace3, CallbackHandler-1.0, HereBeDragons, LibDataBroker-1.1, LibDBIcon-1.0, LibSharedMedia-3.0, LibStub, LibUIDropDownMenu
## SavedVariables: QuestieConfig
+1 -1
View File
@@ -5,7 +5,7 @@
## Notes-esES: Ayundante de misión
## Notes-ptBR: Ajudante de missão
## Notes-frFR: Assistant de quête
## Version: 1.3.1
## Version: 1.3.2
## RequiredDeps:
## OptionalDeps: Ace3, CallbackHandler-1.0, HereBeDragons, LibDataBroker-1.1, LibDBIcon-1.0, LibSharedMedia-3.0, LibStub, LibUIDropDownMenu, Questie-X-TurtleDB
## SavedVariables: QuestieConfig
+1 -1
View File
@@ -11,7 +11,7 @@
## Notes-esES: Ayundante de misión
## Notes-ptBR: Ajudante de missão
## Notes-frFR: Assistant de quête
## Version: 1.3.1
## Version: 1.3.2
## RequiredDeps:
## OptionalDeps: Ace3, CallbackHandler-1.0, HereBeDragons, LibDataBroker-1.1, LibDBIcon-1.0, LibSharedMedia-3.0, LibStub, LibUIDropDownMenu, Questie-X-WotLKDB, Questie-X-ClassicDB, Questie-X-TBCDB, Questie-X-TurtleDB, Questie-X-AscensionDB, Questie-X-EbonholdDB
## SavedVariables: QuestieConfig, QuestieLearnerDB
+1 -1
View File
@@ -2,7 +2,7 @@
<img src="docs/QuestieXlogo.png" alt="Questie-X Logo" width="320" />
![Version](https://img.shields.io/badge/Questie--X-v1.3.1-blue.svg?style=for-the-badge)
![Version](https://img.shields.io/badge/Questie--X-v1.3.2-blue.svg?style=for-the-badge)
![Downloads](https://img.shields.io/github/downloads/Xurkon/Questie-X/total?style=for-the-badge&color=e67e22)
[![Documentation](https://img.shields.io/badge/Documentation-View%20Docs-58a6ff?style=for-the-badge)](https://xurkon.github.io/Questie-X/)
[![Patreon](https://img.shields.io/badge/Patreon-F96854?style=for-the-badge&logo=patreon&logoColor=white)](https://www.patreon.com/Xurkon)
+11
View File
@@ -176,6 +176,17 @@
</div>
<div class="container">
<h2 id="v132">v1.3.2 — Taint Resolution &amp; Stability</h2>
<p><em>Finalizes the Taint Resolution project, eliminating <code>ADDON_ACTION_BLOCKED: UseAction()</code> errors by refactoring internal hooks to use secure alternatives and hardening the global namespace against collisions.</em></p>
<h3>Core &amp; Stability</h3>
<ul>
<li><strong>[Taint Resolution]</strong> Refactored <code>Hooks.lua</code> to use <code>hooksecurefunc</code> instead of raw hooks for all secure functions.</li>
<li><strong>[Global Safety]</strong> Enhanced <code>QuestieLoader.lua</code> with a new collision-aware <code>PopulateGlobals</code> engine that prevents overwriting existing global variables and provides diagnostic warnings.</li>
<li><strong>[Security]</strong> Eliminated global namespace modifications in <code>QuestieInit.lua</code>.</li>
<li><strong>[Workaround Hardening]</strong> Refactored <code>WorldMapTaintWorkaround.lua</code> to remove legacy global function reassignments that were causing secondary taint.</li>
</ul>
<h2 id="v131">v1.3.1 — QuestieComms Streamlining</h2>
<p><em>Refines the data-sharing mechanism to use exclusively hidden global channels, removing guild-channel broadcasts to minimize chat traffic while maintaining real-time data synchronization.</em></p>
+52 -30
View File
@@ -177,6 +177,58 @@
</div>
<div class="container">
<!-- QuestieLearner Engine -->
<section id="questielearner">
<h2>QuestieLearner: Autonomous Data Engine</h2>
<p>Questie-X introduces <strong>QuestieLearner</strong>, a zero-configuration autonomous engine that learns the world as you play. It automatically bridges the gap between static database entries and real-time server-side realities.</p>
<div class="grid">
<div class="card">
<h4>Autonomous Acquisition</h4>
<p>Learns NPC spawns, Quest relationships, Object locations, and Item drops directly from combat logs and interaction events. No manual wiring or database entry required.</p>
</div>
<div class="card">
<h4>3.3.5a Coordinate Scaling</h4>
<p>Implements a precision-first scaling logic that normalizes 3.3.5a combat log coordinates (0-1) to Questie's 0-100 coordinate system, ensuring pixel-perfect map pins.</p>
</div>
</div>
<h3>Universal Cross-Link Engine</h3>
<p>A bidirectional relationship engine that automatically stitches connections between learned entities. If an item drops from an NPC for a specific quest, QuestieLearner cross-links all three, immediately enabling map pins and tooltips for that item-source chain.</p>
</section>
<!-- Data Integrity -->
<section id="integrity">
<h2>Data Integrity & Confidence</h2>
<p>To ensure database quality in crowd-sourced environments, Questie-X implements a multi-tier verification model.</p>
<div class="grid">
<div class="card">
<h4>Match Count (mc) System</h4>
<p>Every learned entry tracks its "Match Count". Data is promoted to <strong>Verified</strong> status once it reaches the user-defined confidence threshold (default: 2).</p>
</div>
<div class="card">
<h4>Stale Data Cleanup</h4>
<p>A tiered pruning engine tracks "Last Seen" (ls) timestamps. <strong>Unconfirmed</strong> data is automatically aged out after 90 days, while <strong>Verified</strong> entries are protected from expiration.</p>
</div>
</div>
<div class="important">
<strong>Confidence Gating:</strong> Map pins and tooltips for learned data are gated by confidence settings, preventing "one-off" anomalies or visual clutter from unconfirmed spawns.
</div>
</section>
<!-- Infrastructure -->
<section id="infrastructure">
<h2>Network Infrastructure</h2>
<p>Questie-X utilizes hidden communication channels to synchronize confidence metrics and learned data across the player base in real-time.</p>
<ul>
<li><strong>Global Data Sync</strong>: Learned kills and interactions are broadcasted via hidden global channels, allowing the community to effectively crowd-source the verification of spawn data.</li>
<li><strong>Zero-Noise Heartbeat</strong>: Communication is optimized to utilize hidden channels exclusively (removing GUILD channel noise), ensuring zero impact on player guild chat logs while maintaining real-time confidence updates for learned NPCs.</li>
</ul>
</section>
<!-- Database Architecture -->
<section id="database">
<h2>Ebonhold Database Architecture</h2>
@@ -206,36 +258,6 @@ local function InjectOverrides()
end</code></pre>
</section>
<!-- Logic Refinements -->
<section id="logic-refinements">
<h2>Core Logic Refinements</h2>
<div class="grid">
<div class="card">
<h4>Quest Arrow: Auto-Mode</h4>
<p>Restored "Auto Nearby" logic which points to the closest available quest when the player has no
active tracking list. Features <strong>Zone Filtering</strong> to prevent the arrow from
pointing to distant continents when in auto-mode.</p>
</div>
<div class="card">
<h4>Tracker Robustness</h4>
<p>The tracker update loop is now protected with <code>pcall</code>. This prevents malformed quest
data (like the "Fel Orc Scavengers" bug) from crashing the entire UI and hiding unrelated
quests.</p>
</div>
</div>
<h3>Quest Icon Persistence Fix</h3>
<p>Custom server quests often use auto-complete triggers which can bypass Questie's standard cleanup events.
I implemented a two-tier cleanup strategy:</p>
<ul>
<li><strong>Delayed Verification</strong>: A 500ms check after <code>QuestComplete</code> to catch
lingering frames.</li>
<li><strong>Periodic Cleanup</strong>: A 5-second background timer in <code>AvailableQuests.lua</code>
that audits the map for icons belonging to finished quests.</li>
</ul>
</section>
<!-- Custom Quest Implementation -->
<section id="custom-quests">
<h2>Custom Quest Implementation</h2>