fix: suppress nonfatal errors by default

This commit is contained in:
Xurkon
2026-06-05 06:24:21 -05:00
parent a1c6a181fc
commit 1d58e3fc79
9 changed files with 83 additions and 13 deletions
+1
View File
@@ -43,6 +43,7 @@
- **[Docs - Release Metadata Sync]** Updated the README badge, documentation version badges, and in-game addon version to `v1.6.3`, then tightened the release filters so handoff notes, local dev settings, and other workspace-only artifacts stay out of the exported release archive.
- **[Docs — Minimap Range Cutoff]** Documented the new minimap icon range cutoff slider and its real-time refresh behavior so the published release notes match the current UI and runtime behavior.
- **[Fix - Debug-Only Error Policy]** Routed non-fatal addon errors through `Questie:Debug(Questie.DEBUG_CRITICAL, ...)` so normal play no longer gets spammed by red chat errors, while the small set of startup-breaking conditions still uses a separate fatal path.
- **[Fix - Arrow Asset Regression]** Restored the default `Arrow1` asset from the original `XPArrow4.png` source, renamed the bundled image arrows to `Arrow1` through `Arrow4`, regenerated the bundled arrow manifest from the actual image data, and added a busted regression test so `arrowold` remains the only bundled sprite sheet.
- **[Fix - Arrow UI / Attachment Redesign]** Reworked the Arrow tab so the arrow and objective text can be detached, reattached, locked independently, and reset independently. Added an attached-gap slider, objective transparency slider, distance-unit selector, larger font sizing, and drop-in preview support for the generated arrow swatches.
- **[Fix - Arrow Asset Size Reduction]** Rewrote the bundled image arrows to their visible bounds and saved them with TGA RLE compression, which keeps the same in-game appearance while reducing the arrow asset footprint dramatically.
+4 -4
View File
@@ -607,9 +607,9 @@ function _QuestieComms:BroadcastQuestLog(eventName, sendMode, targetPlayer) -- b
local sorted = {}
for questId, data in pairs(QuestLogCache.questLog_DO_NOT_MODIFY) do -- DO NOT MODIFY THE RETURNED TABLE
if (not QuestieDB.QuestPointers[questId]) then
if (not QuestieDB.QuestPointers[questId]) then
if not Questie._sessionWarnings[questId] then
if not Questie.IsSoD then Questie:Error(l10n("The quest %s is missing from Questie's database. Please report this on GitHub or Discord!", tostring(questId))) end
if not Questie.IsSoD then Questie:Debug(Questie.DEBUG_CRITICAL, l10n("The quest %s is missing from Questie's database. Please report this on GitHub or Discord!", tostring(questId))) end
Questie._sessionWarnings[questId] = true
end
else
@@ -730,9 +730,9 @@ function _QuestieComms:BroadcastQuestLogV2(eventName, sendMode, targetPlayer) --
local sorted = {}
for questId, data in pairs(QuestLogCache.questLog_DO_NOT_MODIFY) do -- DO NOT MODIFY THE RETURNED TABLE
if (not QuestieDB.QuestPointers[questId]) then
if (not QuestieDB.QuestPointers[questId]) then
if not Questie._sessionWarnings[questId] then
if not Questie.IsSoD then Questie:Error(l10n("The quest %s is missing from Questie's database. Please report this on GitHub or Discord!", tostring(questId))) end
if not Questie.IsSoD then Questie:Debug(Questie.DEBUG_CRITICAL, l10n("The quest %s is missing from Questie's database. Please report this on GitHub or Discord!", tostring(questId))) end
Questie._sessionWarnings[questId] = true
end
else
+2 -2
View File
@@ -953,7 +953,7 @@ function QuestieQuest:GetAllQuestIds()
if not quest then
if not Questie._sessionWarnings[questId] then
if not Questie.IsSoD then
Questie:Error(l10n(
Questie:Debug(Questie.DEBUG_CRITICAL, l10n(
"The quest %s is missing from Questie's database. Please report this on GitHub or Discord!",
tostring(questId)))
end
@@ -1150,7 +1150,7 @@ function QuestieQuest:GetAllQuestIdsNoObjectives()
if not quest then
if not Questie._sessionWarnings[questId] then
if not Questie.IsSoD then
Questie:Error(l10n(
Questie:Debug(Questie.DEBUG_CRITICAL, l10n(
"The quest %s is missing from Questie's database. Please report this on GitHub or Discord!",
tostring(questId)))
end
+1 -2
View File
@@ -232,8 +232,7 @@ function _EventHandler:PlayerLogin()
-- Check config exists
if not Questie.db or not QuestieConfig then
-- Did you move Questie.db = LibStub("AceDB-3.0"):New("QuestieConfig",.......) out of Questie:OnInitialize() ?
Questie:Error("Config DB from saved variables is not loaded and initialized. Please report this issue on Questie github or discord.")
error("Config DB from saved variables is not loaded and initialized. Please report this issue on Questie github or discord.")
Questie:Fatal("Config DB from saved variables is not loaded and initialized. Please report this issue on Questie github or discord.")
return
end
+2 -2
View File
@@ -183,7 +183,7 @@ end
---Run the validator
local function runValidator()
if type(QuestieDB.questData) == "string" or type(QuestieDB.npcData) == "string" or type(QuestieDB.objectData) == "string" or type(QuestieDB.itemData) == "string" then
Questie:Error("Cannot run the validator on string data, load database first")
Questie:Debug(Questie.DEBUG_CRITICAL, "Cannot run the validator on string data, load database first")
return
end
-- Run validator
@@ -416,7 +416,7 @@ QuestieInit.Stages[3] = function() -- run as a coroutine
if QuestieArrow and QuestieArrow.Initialize then
QuestieArrow:Initialize()
else
Questie:Error("[QuestieArrow] Module not loaded correctly (missing Initialize).")
Questie:Fatal("[QuestieArrow] Module not loaded correctly (missing Initialize).")
end
TrackerQuestTimers:Initialize()
QuestieComms:Initialize()
+1 -1
View File
@@ -27,7 +27,7 @@ local function InitializeQuestie()
LibStub("AceAddon-3.0"):NewAddon(existingQuestie, addonName, "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "AceComm-3.0", "AceBucket-3.0")
end)
if not ok then
Questie:Error("ERROR inside NewAddon: " .. tostring(err))
Questie:Fatal("ERROR inside NewAddon: " .. tostring(err))
end
-- Ensure the global reference points to our unified object
+6 -2
View File
@@ -134,10 +134,14 @@ function Questie:Print(...)
end
function Questie:Error(...)
Questie:Debug(Questie.DEBUG_CRITICAL, ...)
end
function Questie:Fatal(...)
if orig_Print then
orig_Print(Questie, "|cffff0000[ERROR]|r", ...)
orig_Print(Questie, "|cffff0000[FATAL]|r", ...)
else
print("|cffff0000[ERROR]|r", ...)
print("|cffff0000[FATAL]|r", ...)
end
end
+65
View File
@@ -0,0 +1,65 @@
local function read_file(path)
local handle = assert(io.open(path, "r"))
local content = handle:read("*a")
handle:close()
return content
end
local function find_lines(content, needle)
local lines = {}
for line in content:gmatch("[^\r\n]+") do
if line:find(needle, 1, true) then
lines[#lines + 1] = line
end
end
return lines
end
local function count_occurrences(content, needle)
local count = 0
local start = 1
while true do
local first, last = content:find(needle, start, true)
if not first then
break
end
count = count + 1
start = last + 1
end
return count
end
describe("Questie error policy", function()
it("routes Questie:Error through debug critical and keeps a fatal printer", function()
local questie = read_file("Questie.lua")
assert.is.truthy(questie:find("function Questie:Error(...)", 1, true))
assert.is.truthy(questie:find("Questie:Debug(Questie.DEBUG_CRITICAL", 1, true))
assert.is.truthy(questie:find("function Questie:Fatal(...)", 1, true))
assert.is.truthy(questie:find("[FATAL]", 1, true))
end)
it("routes missing quest spam through debug critical", function()
local quest = read_file("Modules/Quest/QuestieQuest.lua")
local comms = read_file("Modules/Network/QuestieComms.lua")
assert.are.equal(2, count_occurrences(quest, "Questie:Debug(Questie.DEBUG_CRITICAL, l10n("))
assert.are.equal(2, count_occurrences(comms, "Questie:Debug(Questie.DEBUG_CRITICAL, l10n("))
end)
it("keeps startup-breaking conditions on the fatal path", function()
local versionCheck = read_file("Modules/VersionCheck.lua")
local init = read_file("Modules/QuestieInit.lua")
local eventHandler = read_file("Modules/QuestieEventHandler.lua")
local versionLines = find_lines(versionCheck, "ERROR inside NewAddon")
local initLines = find_lines(init, "Module not loaded correctly")
local eventLines = find_lines(eventHandler, "Config DB from saved variables")
assert.are.equal(1, #versionLines)
assert.are.equal(1, #initLines)
assert.are.equal(1, #eventLines)
assert.is.truthy(versionLines[1]:find("Questie:Fatal", 1, true))
assert.is.truthy(initLines[1]:find("Questie:Fatal", 1, true))
assert.is.truthy(eventLines[1]:find("Questie:Fatal", 1, true))
end)
end)
+1
View File
@@ -211,6 +211,7 @@
<ul>
<li><strong>[Docs &mdash; Release Metadata Sync]</strong> Updated the README badge, documentation version badges, and in-game addon version to <code>v1.6.3</code>, then tightened the release filters so handoff notes, local dev settings, and other workspace-only artifacts stay out of the exported release archive.</li>
<li><strong>[Docs &mdash; Minimap Range Cutoff]</strong> Documented the new minimap icon range cutoff slider and its real-time refresh behavior so the published notes match the current UI and runtime behavior.</li>
<li><strong>[Fix &mdash; Debug-Only Error Policy]</strong> Routed non-fatal addon errors through <code>Questie:Debug(Questie.DEBUG_CRITICAL, ...)</code> so normal play no longer gets spammed by red chat errors, while the small set of startup-breaking conditions still uses a separate fatal path.</li>
<li><strong>[Fix &mdash; Arrow Asset Regression &amp; Redesign]</strong> Rebuilt the bundled arrow set so the live dropdown is backed by four image arrows (<code>Arrow1</code> through <code>Arrow4</code>) plus one legacy sheet arrow (<code>arrowold</code>). The old default <code>arrow.tga</code> cache path was retired in favor of the new image-specific asset names, and the generator now keeps sheet-mode detection isolated so only <code>arrowold</code> or an explicitly custom sheet can enter the sprite-sheet path.
<ul>
<li><strong>Bundled asset layout</strong>: The new arrow images live under <code>Icons\\Arrows</code>, with matching generated preview TGAs so the dropdown can show a visible swatch for each style.</li>