diff --git a/CHANGELOG.md b/CHANGELOG.md index c4ac228..4a9992b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/Modules/Network/QuestieComms.lua b/Modules/Network/QuestieComms.lua index 13857d4..8721ef2 100644 --- a/Modules/Network/QuestieComms.lua +++ b/Modules/Network/QuestieComms.lua @@ -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 diff --git a/Modules/Quest/QuestieQuest.lua b/Modules/Quest/QuestieQuest.lua index da701e2..b217ab0 100644 --- a/Modules/Quest/QuestieQuest.lua +++ b/Modules/Quest/QuestieQuest.lua @@ -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 diff --git a/Modules/QuestieEventHandler.lua b/Modules/QuestieEventHandler.lua index e067f47..b2fe0ab 100644 --- a/Modules/QuestieEventHandler.lua +++ b/Modules/QuestieEventHandler.lua @@ -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 diff --git a/Modules/QuestieInit.lua b/Modules/QuestieInit.lua index 6a496e9..26d802b 100644 --- a/Modules/QuestieInit.lua +++ b/Modules/QuestieInit.lua @@ -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() diff --git a/Modules/VersionCheck.lua b/Modules/VersionCheck.lua index 5da6706..aad5851 100644 --- a/Modules/VersionCheck.lua +++ b/Modules/VersionCheck.lua @@ -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 diff --git a/Questie.lua b/Questie.lua index e4119d6..93e5c77 100644 --- a/Questie.lua +++ b/Questie.lua @@ -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 diff --git a/Tests/QuestieError_policy_spec.lua b/Tests/QuestieError_policy_spec.lua new file mode 100644 index 0000000..13bd340 --- /dev/null +++ b/Tests/QuestieError_policy_spec.lua @@ -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) diff --git a/docs/changelog.html b/docs/changelog.html index 69b158a..4e2f238 100644 --- a/docs/changelog.html +++ b/docs/changelog.html @@ -211,6 +211,7 @@
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.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.Arrow1 through Arrow4) plus one legacy sheet arrow (arrowold). The old default arrow.tga cache path was retired in favor of the new image-specific asset names, and the generator now keeps sheet-mode detection isolated so only arrowold or an explicitly custom sheet can enter the sprite-sheet path.
Icons\\Arrows, with matching generated preview TGAs so the dropdown can show a visible swatch for each style.