Complete history of changes, fixes, and additions.
Version: v1.6.0
← Back to Documentation
QuestieDB:GetObject, GetNPC, and GetItem to prioritize manual corrections (overrides) over the compiled database. This ensures human-verified data is always used when available.objectData) instead of the active override table (objectDataOverrides), causing overrides to be ignored by the rendering engine.nil errors on legacy clients while maintaining performance.QuestieQuest:killcredit path.debugstack() calls in ERR_FUNCTION with Questie:Error. This prevents the error handler from causing secondary crashes when generating stacks on older WoW clients.LibSharedMedia-3.0 registered fonts.ipairs to pairs for SharedMedia hash-table iteration.nil value error in AddToBlizOptions affecting 3.3.5a clients.
AceConfigDialog-3.0 shim in !X-Libs to correctly bridge modern Ace3 options calls to the legacy 3.3.5a InterfaceOptions_AddCategory API.Questie-X.toc and !X-Libs to ensure the compatibility suite initializes before BugSack and other diagnostic tools, preventing interleaved error reporting.GetPlayerWorldPosition and GetPlayerZonePosition in Compat/HBD.lua. This drastically reduces C API overhead which was the #1 hotspot, with automatic cache invalidation on zone transitions.ZoneDB:GetAreaIdByUiMapId to use an O(1) reverse-mapping cache instead of an O(n) linear scan, eliminating a significant CPU bottleneck triggered hundreds of times per minute by the directional arrow.GameTooltip OnUpdate hook to run at 10Hz (100ms) and added a text-change cache, preventing redundant and expensive tooltip recalculations every single frame.QuestieLearnerComms: reduced compression overhead (negligible size difference but massive CPU savings), slowed processing ticker to match output rate limits, and optimized duplicate detection to O(1).QuestieArrow:UpdateNearestTargets loop to module-level functions, eliminating persistent memory allocation spikes and Garbage Collection (GC) pressure.QuestieProfiler UI. Function names are now properly left-aligned, and horizontal spacing ensures metrics remain legible regardless of function name length.QuestieLib:Euclid function call overhead from the minimap icon FadeLogic hot loop in favor of an inline Pythagorean distance check, reducing micro-stutters during movement.TrackerLinePool:SetItem and QuestieQuest:CheckQuestSourceItem, replacing them with native O(1) GetItemCount(itemId) queries. Completely eliminated thousands of GetContainerItemInfo calls.btn.OnUpdate frame handler, dropping baseline GetItemCooldown API polls from over 6000 checks every few minutes down to a fraction of that load.GetItemSpell), checks which ones are in the player's bags using QuestieCompat.GetContainerItemInfo, calculates proximity to quest objectives using HBD:GetWorldDistance, and uses the nearest one via UseItemByName. Configurable via Tracker options tab under "Use Quest Item (Nearest)".QuestieCompat.UiMapData before HBD initialized its map cache. Added ZoneDB:ApplyCustomZones() function that hooks ZoneDB.Initialize to inject custom zones BEFORE the original initialization runs. This ensures HBD's mapData table (which references QuestieCompat.UiMapData) contains custom zone entries like 1244 (Valley of Trials). Also modified QuestiePluginAPI:InjectUiMapData() to call ZoneDB:ApplyCustomZones() after injecting custom zone data.GetZoneNameByID fails for custom zone IDs (like 1244), the system now falls back to GetQuestLogZoneName which reads the zone header directly from the quest log where custom zone names are properly displayed.QuestieCompat.GetCurrentUiMapID() to check QuestieCompat.UiMapData directly for custom zone IDs. Previously, only mapIdToUiMapId was checked, which doesn't contain custom zones. Added fallback: if QuestieCompat.UiMapData and QuestieCompat.UiMapData[mapID] then return mapID endzone ~= playerZoneId), but custom zones use different IDs (e.g., 1244 for Valley of Trials) than their parent zones (e.g., 14 for Durotar). Added QuestiePlayer:GetCurrentUiMapId() function and updated arrow zone filtering to compare both playerZoneId AND playerUiMapId against objective zone IDs in all 4 zone filter locations within _CollectObjective, _CollectFinisherSpawns, and finisher waypoint loops.objective.Description when rendering quest objectives in QuestieTracker.lua. Custom server quests may have objectives without a Description field, which would previously cause "attempt to index field 'Description' (a nil value)" crash.QuestiePluginAPI:InjectUiMapData() to call ZoneDB:ApplyCustomZones() after injecting custom zone data, ensuring the zone mappings are properly registered with both ZoneDB and QuestieCompat.UiMapData.AscensionUiMapData.lua (Questie-X-AscensionDB) to use string.find() instead of exact string comparison. Realms like "Bronzebeard - Warcraft Reborn" now properly match the "Bronzebeard" pattern, allowing custom zone data to load on all Ascension server variants.PrintDifficultyColor when quest name is nil. Added defensive nil check in GetColoredQuestName to return early if QuestieDB.QueryQuestSingle returns nil for a quest, preventing "attempt to concatenate local 'text' (a nil value)" errors.uiMapId > 1000 restriction in ZoneDB:ApplyCustomZones() that was preventing custom zone IDs below 1000 from being registered as self-mappings. This caused some Townsfolk NPCs with zone IDs < 1000 to fail UiMapId lookups and not display on the map.QuestieDB.npcData and QuestieDB.npcDataOverrides / QuestieDB.objectDataOverrides. On custom servers (Ebonhold, Ascension), the database is loaded via plugins into overrides tables, but Townsfolk.Initialize() was only checking the base database tables which are empty until Stage 3 compilation. This affected Flight Masters, Auctioneers, Innkeepers, Repair Vendors, Class Trainers, and Mailboxes.QuestieCompat.UiMapData before HBD initialized its map cache. Added ZoneDB:ApplyCustomZones() function that hooks ZoneDB.Initialize to inject custom zones BEFORE the original initialization runs. This ensures HBD's mapData table (which references QuestieCompat.UiMapData) contains custom zone entries like 1244 (Valley of Trials). Also modified QuestiePluginAPI:InjectUiMapData() to call ZoneDB:ApplyCustomZones() after injecting custom zone data.GetZoneNameByID fails for custom zone IDs (like 1244), the system now falls back to GetQuestLogZoneName which reads the zone header directly from the quest log where custom zone names are properly displayed.QuestieCompat.GetCurrentUiMapID() to check QuestieCompat.UiMapData directly for custom zone IDs. Previously, only mapIdToUiMapId was checked, which doesn't contain custom zones. Added fallback: if QuestieCompat.UiMapData and QuestieCompat.UiMapData[mapID] then return mapID endzone ~= playerZoneId), but custom zones use different IDs (e.g., 1244 for Valley of Trials) than their parent zones (e.g., 14 for Durotar). Added QuestiePlayer:GetCurrentUiMapId() function and updated arrow zone filtering to compare both playerZoneId AND playerUiMapId against objective zone IDs in all 4 zone filter locations within _CollectObjective, _CollectFinisherSpawns, and finisher waypoint loops.objective.Description when rendering quest objectives in QuestieTracker.lua. Custom server quests may have objectives without a Description field, which would previously cause "attempt to index field 'Description' (a nil value)" crash.QuestiePluginAPI:InjectUiMapData() to call ZoneDB:ApplyCustomZones() after injecting custom zone data, ensuring the zone mappings are properly registered with both ZoneDB and QuestieCompat.UiMapData.AscensionUiMapData.lua (Questie-X-AscensionDB) to use string.find() instead of exact string comparison. Realms like "Bronzebeard - Warcraft Reborn" now properly match the "Bronzebeard" pattern, allowing custom zone data to load on all Ascension server variants.GetItemSpell), checks which ones are in the player's bags using QuestieCompat.GetContainerItemInfo, calculates proximity to quest objectives using HBD:GetWorldDistance, and uses the nearest one via UseItemByName. Configurable via Tracker options tab under "Use Quest Item (Nearest)".QuestieFrameGroup container that is ignored by these addons while maintaining correct spatial anchoring via HereBeDragons.QuestieDB lookup functions (GetNPC, GetObject, GetItem). This prevents the "rawdata is nil" debug spam that occurred when custom plugins attempted to access uninitialized or malformed entity data.QuestieDB override handling to support both numeric and string keys simultaneously. This ensures that custom server data (e.g., Ascension, Ebonhold) is correctly resolved regardless of how the third-party plugin formats its internal IDs.QuestieLearner:InjectLearnedData to enforce numeric key normalization. All dynamically learned spawn data is now strictly indexed by numeric IDs, preventing type-mismatch collisions during database merging.DEVELOP log.QuestieCompat where uiMapData for Ascension-specific zones was not correctly propagating to the global mapping table, restoring map pin functionality for seasonal and custom zones.l10n module to prevent GetAreaIdByLocalName nil errors (Fixes Project Ebonhold runtime crash).session_export skill for standardized documentation and session artifact exports.QuestiePluginAPI:InjectZoneTables(). This caused zone lookups to fail, resulting in "No UiMapID or fitting parentAreaId" errors for custom zone IDs._QuestEventHandler:InitQuestLog and refactored QuestLogCache.GetQuest and GetQuestObjectives to fail gracefully.DecodePointerMap when compiled database pointer map was empty or corrupted. Added defensive check to return empty table instead of crashing.ValidateObjects and ValidateQuests when compiled binary data is missing, preventing validation failures on cached databases from incomplete previous sessions.QuestieInit to skip validation in Stage 1 when plugins are pending, since plugins inject data after compilation and validation would compare stale pre-plugin data against post-plugin data.ChatEdit_InsertLink call from QuestLogTitleButton_OnClick hook.QuestieProfiler. Added early-exit logic in HookTable to skip large pure-data tables that don't benefit from profiling.QuestieValidateGameCache to silently skip "ghost quests" instead of failing validation, resolving infinite retry loops on servers with custom quest content.AscensionNpcDB_2.lua (missing closing } at end of NPC entry for ID 3287).QuestiePluginAPI:FinishLoading() and a registration handshake to resolve race conditions during addon initialization. By ensuring that database plugins report their data-injection status before QuestieInit Stage 3 completes, we eliminated "ghost maps" where pins and statistics would fail to render until a manual /reload.pairs() and ipairs() to next() and numeric loops. This refactor targets the Lua 5.0 engine used by legacy clients (e.g., Turtle WoW), which can exhibit inconsistent behavior or performance degradation when using standard iterators in high-frequency database sweeps. This change guarantees stable, universal performance across all WoW versions from 1.12 to 3.3.5+.MapIconTooltip.lua at line 239. A malformed if statement was trapping execution, preventing tooltips from updating when hovering over Quest objectives on the World Map.AscensionLoader.lua. The loader now utilizes an pattern-matching check against GetRealmName() to correctly identify and apply custom database overrides for all Project Ascension realms, including seasonal and specialized rule-set servers.QuestieInit. The initialization sequence now yields more efficiently to the main UI thread during massive database injections, reducing "frame-stutter" during the initial login sequence while strictly maintaining loading priority for essential UI modules.Questie-X-WotLKDB database files from monolithic global definitions into smaller, manageable chunks using addonTable to prevent memory allocation failures during LoadAddOn() and eliminate global namespace pollution.Loader.lua now explicitly exports WotLKDB data to _G.QuestieX_WotLKDB_* with proper capitalization to match QuestieInit expectations, fully resolving database loading failures and taint vectors.Usage: AceSerializer:Deserialize(str): str must be a string, got table") occurring in QuestieLearnerComms and Export functions. This was caused by a lightweight, customized AceSerializer-3.0.lua implementation in Questie-X that lacked proper self parameter handling for standard colon-syntax method calls (:). As a result, method calls were serializing/deserializing the library table itself instead of the intended payload string. We patched AceSerializer natively to dynamically support both dot (.) and colon (:) syntax seamlessly without dropping arguments, while ensuring Deserialize correctly yields (success, result) tuples expected by the calling functions.# -> table.getn replacements injected by earlier vanilla compatibility automation throughout LibDeflate.lua. These have been wrapped with a custom dual-typed safe access function that flawlessly determines whether to compute properties natively via string.len(x) for strings or the standard table.getn(x) for structured tables—guaranteeing 100% stable networking cross-client from 1.12 to 3.3.5 and upwards.bad argument #1 to 'getn' (table expected, got string)) occurring during data-sharing via the hidden questiecomm addon channel. A legacy string length method (table.getn) was mistakenly used in LibDeflate string decoding; this has been restored to the universally compatible string.len.isModernClient safeguard now uses a bulletproof tocversion range check to flawlessly differentiate between original legacy engines and modern Classic counterparts.attempt to index global 'l10n' (a nil value) error that triggered when accepting a new quest, caused by a missing module import at the top of QuestieLearner.lua.ADDON_ACTION_BLOCKED taint on ActionButton and StaticPopup that occurred when Questie loaded data from its cache rather than manually recompiling. The _G namespace cleanup for Questie-X-WotLKDB globals now runs accurately during cached loads (via UpdateWotLKDBStats), ensuring the taint vector is closed and additionally freeing ~20MB of redundant cached memory.ADDON_ACTION_BLOCKED errors caused by Questie-X-WotLKDB leaving tainted global variables in _G after initialization. QuestieInit._pullGlobal now sets _G[globalName] = nil immediately after copying each WotLKDB table reference into QuestieDB, removing the taint vector while keeping all data fully accessible through QuestieDB. QuestieLearner real-time updates are unaffected — they write exclusively to QuestieDB.*Overrides and learnedData.Compat/embeds.xml to load Wrath-compatible Ace library versions from Libs/ (AceGUI-3.0 v34, AceConfigDialog-3.0 v66) instead of newer versions from ..\Libs/ that caused widget pool corruption.Create, Release, WidgetBase.Fire, WidgetContainerBase methods) to prevent crashes when pooled widgets have corrupted/nil properties.content is nil during layout.Compat/Libs/AceGUI-3.0/AceGUI-3.0.lua for consistency.message parameter in QuestieEventHandler:ChatMsgSystem to prevent "bad argument #1 to 'find'" errors.level parameter in QuestiePlayer:SetPlayerLevel to prevent "number expected, got nil" errors.SanitizeData function with depth limiting and proper key/value filtering to remove functions, userdata, and thread values from learned data before network serialization.AceSerializer:Serialize to catch and log any remaining serialization errors instead of crashing.BroadcastLearnedData when data is nil or sanitization produces empty results.container in HandleTabChange to prevent "attempt to index local 'container'" errors.translationValue in l10n:translate to prevent "bad argument #2 to 'format'" errors when translation is not a string or when format arguments are missing.Hooks.lua that was instantly reverting tracker states when shift-clicking a quest in the Quest Log._G = _G or {} from WotLKDB data file that could contribute to namespace pollution._G.xpcall to QuestieCompat.xpcall namespace to prevent polluting the global table.GetCurrentRegion and GetCurrentRegionName for AceDB-3.0 compatibility on WotLK/Classic.Ambiguate and RegisterAddonMessagePrefix for AceComm-3.0 compatibility on WotLK/Classic.DialogBorderOpaqueTemplate and SetFixedFrameStrata in AceConfigDialog for WotLK/Classic.SetColorTexture using SetTexture + SetVertexColor..history/ and Research/ folders from repository tracking.Tests/ folder from repository tracking.tests/ to .gitignore.C_Timer OnUpdate to use precise (self, elapsed) parameter instead of 1/GetFramerate().IsAchievementCompleted to properly check completion boolean via select(4, GetAchievementInfo(...)).C_Map.GetPlayerMapPosition to use correct legacy API.GetNpcIdFromGUID and GetObjectIdFromGUID being called before definition.InCombatLockdown() guards and pcall wrappers to secure hooks to prevent protected function access errors.QuestieTracker to safely handle nil returns from the WoW API (GetQuestLogTitle), preventing potential "attempt to compare number with nil" errors during rapid quest log updates.QuestieCompat.lua.WorldMapTaintWorkaround for older WoW clients (3.3.5) by correcting the IsAddOnLoaded detection timing and adding explicit empty-function stubs to blocked dropdowns.A comprehensive update resolving 13 distinct issues related to global environment taint, unsafe polyfills, and module stability across all supported Lua environments (5.0, 5.1, 5.2).
function Questie:Warning(...) global monkey-patching in QuestieTracker.lua (_InstallMissingQuestLogWarningFilter deleted). Ghost quest iterations now use a safe, two-phase collection and deletion pattern to prevent warning generation upfront.hooksecurefunc polyfill in QuestieCompat.lua no longer pollutes the global _G namespace. It runs strictly as a local fallback when the native function is absent._G writes for C_Seasons and C_Timer._G.QuestieX_WotLKDB_Counts from writing to the global namespace in QuestieInit.lua. Counts are now cleanly stored directly on the plugin object (plugin.stats).CreateModule function in QuestieLoader.lua now guards against double-registration of modules, preventing accidental aliasing and overwriting.string.match, select) from QuestieCompat.lua that were already provided canonically by QuestieLoader.lua.while n > 0 structures in select polyfills with standard do...end blocks.loadstring execution in QuestieInit:LoadDatabase. On modern clients, it now safely blocks and logs an error instead of executing potentially tainted legacy string DBs at runtime.Resolves the initialization error in GameVersionError.lua and implements a version guard to support Classic-era private servers. Also confirms the integrity of the WotLKDB module after a deep taint analysis.
attempt to call local 'l10n' (a table value) in GameVersionError.lua and implemented a tocVersion guard to prevent the "unsupported client" error on Classic-era private servers (e.g., Turtle WoW).GameVersionError.lua strings to correctly identify Questie-X as supporting Classic and private servers.Questie-X-WotLKDB. No direct taint vectors or secure function overrides were found.Addresses the missing WorldMapTaintWorkaround module that was excluded from previous releases, finally enabling the intended seat-of-pants taint mitigation strategy.
Modules\WorldMapTaintWorkaround.lua in all TOC files to ensure it's loaded and executed.Modules\GameVersionError.lua in all TOC files for better unsupported client detection.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.
Hooks.lua to use hooksecurefunc instead of raw hooks for all secure functions.QuestieLoader.lua with a new collision-aware PopulateGlobals engine that prevents overwriting existing global variables and provides diagnostic warnings.QuestieInit.lua.WorldMapTaintWorkaround.lua to remove legacy global function reassignments that were causing secondary taint.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.
AceComm:SendCommMessage targeting the GUILD channel in QuestieLearnerComms.lua. All background data synchronization now travels exclusively via the questiecomm hidden global channel.Implements a robust verification model for learned data, introducing a tiered confidence system (Verified vs Unconfirmed), automated stale data cleanup with protection for high-confidence entries, and a critical correction to coordinate scaling logic for 3.3.5a combat log events. Refactors global data sharing to utilize hidden chat channels for community-wide confidence calculation.
OnCombatLogEvent now explicitly scales player position coordinates by 100 before recording. Previously, C_Map.GetPlayerMapPosition returned values on a 0-1 range, while Questie's internal modules and map pins expect 0-100. This fix resolves the "pins in the top-left corner" bug for all learned data.mc (Match Count) field as a primary confidence metric. Data is promoted to "Verified" status once mc >= minConfidencePins (default: 2). Verified data is exempt from automatic time-based pruning.ls key to the learned data schema for NPCs, Objects, Quests, and Items. Updated on every kill, interaction, or network confirmation. This provides the temporal baseline for the new stale data cleanup engine.minConfidencePins setting. Pins only appear on the map/minimap if the learned data has been confirmed by multiple kills (either local or received via network).PARTY/RAID channels to a hidden global channel for learned data broadcast. This allows kills by any Questie-X user in the vicinity to contribute to local data confidence, effectively crowd-sourcing verification in real-time.mc count for learned entries and displays it alongside the "Learned" label (e.g., (Learned - Confidence: 3)), providing immediate visual feedback on data reliability.Cleanup function. Only entries marked as "Unconfirmed" (low confidence) are subject to expiration. The expiration logic uses (time() - entry.ls) > staleThreshold (default: 90 days).pruneVerified setting is manually enabled by the user.Introduces a universal bidirectional cross-link engine in QuestieLearner that automatically stitches relationships between all four entity types (NPCs, Quests, Objects, Items) as data is learned — no manual wiring needed. Fixes the tracker's persistent "Unknown Zone" header for custom/unknown quests by replacing unreliable map API calls with the canonical 3.3.5a quest log header walk. Fixes a logic inversion in UntrackQuestId that prevented shift-click untacking from working.
_AddToArray(tbl, key, value, ovrTable, ovrId) adds a value to an array field and mirrors it to the live *DataOverrides table in the same call; _AddToNestedArray does the same for two-level nested arrays (used for quest starters/finishers sub-slots quest[2][1], quest[2][2], etc.); _AddToQuestObjective inserts {entityId, text} pairs into quest[10][slot] with the same dual-write pattern. Every write is idempotent — a no-op if the value is already present. All three primitives write to both learnedData (SavedVariables, persistent) and the live *DataOverrides tables (in-memory, immediate effect on map pins and tooltips).learnedData.npcs. Performs three scans across all learned quests: (a) if quest[2][1] contains this npcId → adds questId to npc[10] (questStarts); (b) if quest[3][1] contains this npcId → adds questId to npc[11] (questEnds); (c) walks quest[10][3] (item objectives) — for each item whose item[2] (npcDrops) already references this NPC, the NPC is injected into quest[10][1] as a creature objective so it receives map pins and tooltip kill-count text.learnedData.quests. Links all referenced entities in one pass: starter NPCs (quest[2][1]) → each known NPC's npc[10]; starter objects (quest[2][2]) → each known object's obj[2]; finisher NPCs (quest[3][1]) → npc[11]; finisher objects (quest[3][2]) → obj[3]; source item (quest[11]) → item[5] (startQuest key per itemDB schema); item drop chain: for each item in quest[10][3] whose item[2] lists known NPCs, those NPCs are injected into quest[10][1] as creature objectives.learnedData.objects. Scans all learned quests: if quest[2][2] references this objectId → adds questId to obj[2] (questStarts); if quest[3][2] references it → adds questId to obj[3] (questEnds).learnedData.items AND whenever a new drop-NPC relationship is added via LearnItemDrop. Two passes: (1) scan all learned quests for quest[11] == itemId → set item[5] = questId (this item starts that quest); (2) scan all learned quests for quest[10][3] entries matching itemId — for each such quest, every NPC in item[2] (drop sources) is injected into quest[10][1] as a creature objective. Practical example: accept a quest needing "Wolf Pelt" → wolf is killed and the pelt drops → LearnItemDrop fires → CrossLinkAfterItem runs → the wolf NPC is immediately added as a creature objective for the pelt quest with active map pins, no reload.npc[10/11] ↔ quest[2/3][1] bidirectionally. For typeSlot=2: stitches obj[2/3] ↔ quest[2/3][2]. For typeSlot=3: adds itemId to quest[2][3] (item starters sub-slot). Called by LearnQuestGiver for all typeSlots, replacing the previous NPC-only check.CrossLinkAfterItem(itemId) every time a new NPC is added to an item's drop list, not only on initial item creation. This retroactively propagates the drop→quest objective chain for previously learned items.CrossLinkAfterX function on first creation of the entity record. Subsequent updates to an existing record skip the cross-link scan (already linked on creation).[9] (which maps to itemLevel in QuestieDB.itemKeys) for quest-source storage. The correct key is [5] (startQuest). Affects CrossLinkAfterQuest and CrossLinkAfterItem.UnitReaction < 4 early-return guard that blocked learning hostile or neutral NPCs via mouseover. The existing QUESTGIVER NPC-flag bitmask check (0x02) remains as the primary filter, ensuring only NPCs with a quest-giver relationship are stored. Hostile quest objective NPCs are now captured on any hover, target, or kill and are correctly cross-linked to their quests.GetQuestLogZoneName(questId). Implements the only fully reliable zone resolution method in 3.3.5a: iterates the quest log from index 1 to GetNumQuestLogEntries() to locate the target quest's log index, then walks backwards from that index until an entry where isHeader=true is found. That header's title string is the zone name (e.g. "Shadowmoon Valley"). GetRealZoneText() and GetCurrentMapAreaID() were previously used but are unreliable because they reflect the currently viewed map, not the quest's zone. The 3.3.5a client places zone header entries directly above their child quests in the flat quest log list — this is guaranteed by the client and is the same method Blizzard's own UI uses to render the zone groups.GetRealZoneText() call with the inline header walk. The loop that already iterates the quest log to find the fallback quest's entry now continues backwards from that same index to find the header. GetAreaIdByZoneName() converts the string to an area ID for zoneOrSort; the raw string is stored as quest.zoneName for display. If no header is found (e.g. "Special" category with no zone header), zoneName remains nil and the tracker falls back to the _GetZoneName(zoneOrSort) path.QuestLogCache fallback objects (identified by _isLogFallback=true and absence of an IsComplete method) now calls GetQuestLogZoneName(capturedId) immediately after patching Objectives, SpecialObjectives, and ExtraObjectives. If a zone name is returned, both quest.zoneName and quest.zoneOrSort are set on the object in-place. Previously this block left both values at their QuestLogCache defaults (zoneOrSort=0, zoneName=nil), which caused every fallback quest to group under "Unknown Zone" in the tracker regardless of where the quest was accepted._fallbackQuests[qid] is now evicted and unconditionally rebuilt if the cached entry has no zoneName. This handles the race condition where BuildFallbackQuest was called during addon initialization before the quest log entries were populated, caching a zoneless entry that would persist for the entire session.UntrackQuestId previously set AutoUntrackedQuests[questId] = nil when the player untracks a quest. The tracker filter expression is not Questie.db.char.AutoUntrackedQuests[questId] — when the value is nil, not nil is true, meaning "show this quest". Clearing the entry on untrack therefore immediately re-showed the quest on the very next tracker update tick, making untacking appear completely broken. Fix: in autoTrackQuests mode, UntrackQuestId now sets AutoUntrackedQuests[questId] = true (evaluated as "hide"). In manual-track mode, it clears TrackedQuests[questId] as before, and AutoUntrackedQuests is cleared instead of being incorrectly toggled. The two tracking modes are now cleanly separated within the function.IsShiftKeyDown() and QuestLogFrame:IsShown() inside AQW_Insert was blocking the re-tracking path (clearing AutoUntrackedQuests[questId]) whenever the quest log frame was not open. Since untacking fires RemoveQuestWatch → UntrackQuestId directly, this AQW_Insert branch was only ever reached for re-tracking — yet the gate required the quest log to be open. The gate has been removed; re-tracking now works from any UI context.Rewrote QuestieLearner from scratch to fix all known data-capture deficiencies. Adds full quest field coverage, grid-based coordinate clustering, quest-giver-only mouseover filtering, async item-info retry, object loot detection, and live inject-on-import so imported data takes effect without a reload.
LearnQuest now accepts a generic data table keyed by Questie wiki array indices rather than individual positional arguments. OnQuestDetail captures title, objectives text block, quest description body, and current zone as zoneOrSort[8]. OnQuestAccepted fills quest level from GetQuestLogTitle, per-objective text from GetQuestLogLeaderBoard, and required money from GetQuestLogRequiredMoney. OnQuestComplete captures finish/reward text via GetRewardText.OnMouseoverUnit now only learns an NPC if its UnitNPCFlags bitmask includes the QUESTGIVER bit (0x02), OR if the NPC already exists in QuestieDB as a known quest starter/finisher. All other NPCs are silently ignored — this eliminates the flood of irrelevant NPC entries the learner previously accumulated.OnTargetChanged no longer calls LearnNPC on every target switch. It now only populates the guidNpcCache for kill-tracking purposes, avoiding recording non-quest NPCs.COORD_GRID = 2.0). A new point is inserted only when no existing point shares the same grid cell. This prevents coordinate scatter across a kill area while still preserving distinct spawn clusters. The InsertIfNewBucket helper is shared across NPC, Object, and all merge paths (including InjectLearnedData and HandleNetworkData).OnLootOpened now checks whether the loot source GUID is a GameObject. If so, LearnObject is called with the object's ID and name. OnGossipShow records both objects and NPCs via GetIdAndTypeFromGUID. OnQuestDetail and OnQuestComplete also record the interacting object when the quest giver/finisher is a GameObject.OnLootOpened queues unresolved item links (where GetItemInfo returns nil because the item is not yet in the client cache) into _Learner.pendingItemLinks. A new OnGetItemInfoReceived(itemId) handler fires on the GET_ITEM_INFO_RECEIVED event, resolves queued links for that item ID, and calls LearnItem/LearnItemDrop once the data is available. This fixes silent data loss on first-encounter loots.LearnQuestGiver now accepts an entityType argument (1=NPC, 2=GameObject, 3=item) and stores starters/finishers in the correct sub-array slot matching the Questie wiki spec { [1]={npcIds}, [2]={objIds}, [3]={itemIds} }.OnCombatLogEvent retains all three GUID-resolution paths (dash-split, GUID cache, hex-prefix) with a 10-minute TTL cache cleanup. Uses CombatLogGetCurrentEventInfo() with fallback to varargs for cross-client compatibility.InsertIfNewBucket instead of the old radius check.MergeImport immediately calls QuestieLearner:InjectLearnedData(). Imported data is pushed into QuestieDB.*DataOverrides in the same frame — override-driven map pins update without a /reload. A full reload is still needed to pick up newly imported quest starters/finishers for quests already in the player's quest log./reload is beneficial.Fixed a fatal load-time crash in all four Ebonhold DB files (and identically in the Ascension DB files) caused by calling GetRealmName() and QuestieLoader:CreateModule() at file scope — before WoW's API is fully available. Switched to plain global table population; realm-gating and injection remain safely deferred to the loader's PLAYER_LOGIN handler.
EbonholdNpcDB.lua, EbonholdObjectDB.lua, EbonholdItemDB.lua, and EbonholdQuestDB.lua each began with if GetRealmName() ~= "Rogue-Lite (Live)" then return end followed immediately by QuestieLoader:CreateModule("EbonholdDB"). Both calls execute at file-load time (during LoadAddOn()), before PLAYER_LOGIN has fired and before QuestieLoader is guaranteed to be populated. This produced attempt to index global 'QuestieLoader' (a nil value) on every load.Bronzebeard/AscensionXxxDB.lua files had the same pattern with a different realm guard. Same crash, same fix applied.QuestieLoader:CreateModule call. Replaced with _G.EbonholdDB = _G.EbonholdDB or {} and a local alias. Data is now populated unconditionally into the global at load time.QuestieLoader:ImportModule("EbonholdDB") with _G.EbonholdDB or {}. The loader's existing PLAYER_LOGIN handler with realm check remains intact as the sole gate for injection into Questie-X.QuestieLoader:CreateModule call. Replaced with _G.AscensionDB = _G.AscensionDB or {}.QuestieLoader:ImportModule("AscensionDB") with _G.AscensionDB or {}.Questie-Ascension to Questie-X-AscensionDB to match the folder name and plugin naming convention.table.getn(str), which expects a table — passing a string (e.g. a player name like "MooeshaLC@Asc.BB25") caused a crash: bad argument #1 to 'getn' (table expected, got string). Fixed by replacing all string-length calls with string.len(str) (universal across Lua 5.0 and 5.1). Table-length calls restored to table.getn(t) for the same universal coverage — the # length operator is only available in Lua 5.1+ and would break on WoW 1.12 vanilla clients..gitattributes to all five repos with export-ignore for dev-only files (.gitattributes, .gitignore, Tools/, docs/, .git_disabled/). Release archives are now generated from tags — named RepoName-vX.Y.Z.zip rather than RepoName-main.zip.Deleted all Season of Discovery, Season of Mastery, and Hardcore correction files. These were retail-specific and never referenced by the TOC. Cleaned up all dead imports, constants, and code branches they left behind in QuestieCorrections.lua.
Database/Corrections/SeasonOfDiscovery.lua — SoD base quest/NPC/object/item overridesDatabase/Corrections/sodQuestFixes.lua — SoD quest correctionsDatabase/Corrections/sodNPCFixes.lua — SoD NPC correctionsDatabase/Corrections/sodItemFixes.lua — SoD item correctionsDatabase/Corrections/sodObjectFixes.lua — SoD object correctionsDatabase/Corrections/Automatic/sodBaseQuests.lua — SoD auto-generated base questsDatabase/Corrections/Automatic/sodBaseNPCs.lua — SoD auto-generated base NPCsDatabase/Corrections/Automatic/sodBaseItems.lua — SoD auto-generated base itemsDatabase/Corrections/Automatic/sodBaseObjects.lua — SoD auto-generated base objectsDatabase/Corrections/HardcoreBlacklist.lua — Hardcore mode quest blacklistDatabase/Corrections/SoMPhases.lua — Season of Mastery phase data (was already commented out in TOC)HardcoreBlacklist and SeasonOfDiscovery ImportModule calls deleted.SOD_ONLY = 5 and HIDE_SOD = 6 deleted from the expansion filter enum. Remaining constants (TBC_ONLY, CLASSIC_ONLY, WOTLK_ONLY, TBC_AND_WOTLK, CLASSIC_AND_TBC) are unchanged.filterExpansion: Removed the isSoD local and the two SOD_ONLY / HIDE_SOD branches.MinimalInit: Removed the if Questie.IsSoD then addOverride(...SeasonOfDiscovery...) end block and the if Questie.IsHardcore then HardcoreBlacklist:Load() end block.Initialize: Removed the 8-call if Questie.IsSoD then SeasonOfDiscovery:LoadBase*/Load*() end block covering quest/NPC/item/object base data and fixes.#Database\Corrections\SoMPhases.lua line.Moved all DB init diagnostics out of chat and into the Develop debug level. Replaced hardcoded quest-ID spot-checks with generic per-table stats. Removed the stale monolithic database folders fully superseded by the DB plugin architecture (~30 MB removed).
_dbStats helper] Added a local _dbStats(t) function returning count=N minID=X maxID=Y for any table. Used at every checkpoint so diagnostic output is meaningful for any server's dataset without hardcoding expansion-specific IDs._dbDiag removed] Eliminated the local _dbDiag = {} accumulator and the deferred C_Timer.After(6, ...) print block. Diagnostics are now emitted inline as Questie:Debug(Questie.DEBUG_DEVELOP, "[DBDiag] ...") calls at the exact point each stage completes — visible in real time when Develop logging is enabled, not as a delayed flood 6 seconds post-load.DEBUG_DEVELOP.DEBUG_DEVELOP with generic _dbStats output: After LoadBaseDB, After Corrections, Before Compile, After Compile.loadstring parse errors and pcall execution errors converted to DEBUG_DEVELOP.DB was CACHED (no recompile) line converted to DEBUG_DEVELOP.countTable / quest+npc+obj+item count block and the DEBUG_CRITICAL "questData is empty" warning that fired at PLAYER_LOGIN. This check always reported zero counts because it ran before QuestieInit's loading coroutine had started. Loader.lua is now a minimal registration stub.classicQuestDB.lua (1.0 MB), classicNpcDB.lua (2.0 MB), classicObjectDB.lua (1.0 MB), classicItemDB.lua (2.1 MB). Never listed in Questie-X.toc. Classic data is now provided exclusively by the ClassicDB plugin.tbcQuestDB.lua (1.6 MB), tbcNpcDB.lua (3.5 MB), tbcObjectDB.lua (1.6 MB), tbcItemDB.lua (3.3 MB). TBC data is now provided exclusively by the TBCDB plugin.wotlkQuestDB.lua (2.3 MB), wotlkNpcDB.lua (5.2 MB), wotlkObjectDB.lua (2.0 MB), wotlkItemDB.lua (4.4 MB). WotLK data is now provided exclusively by the WotLKDB plugin. Combined removal: ~30 MB of dead weight from the core repository.Overhauled the DB plugin loading pipeline from a fragile push/bridge pattern to a direct pull at init time. Fixed a long-standing compiler bug that silently dropped extraobjective condition data. Removed all DevTools_Dump calls that were printing raw Lua table syntax to chat during validation.
QuestieX_CoreDB bridge mechanism with a direct pull of DB plugin globals at init time. LoadBaseDB() now checks for QuestieX_WotLKDB_quest, QuestieX_WotLKDB_npc, QuestieX_WotLKDB_object, and QuestieX_WotLKDB_item globals and assigns them directly to QuestieDB.*Data. Globals are cleared (= nil) after transfer to free memory. This runs inside Questie-X's own init coroutine at a known point in the load sequence, with no dependency on cross-addon module references._G.QuestieX_CoreDB = QuestieDB export. The CoreDB bridge global is no longer needed and was never reliably accessible from DB plugin Loader.lua files due to module-registry timing.if not QuestieX_CoreDB then return end guard and subsequent QuestieX_CoreDB.*Data = ... assignments). The file is now a PLAYER_LOGIN handler that registers the plugin with QuestiePluginAPI, logs absorbed table sizes, and emits a DEBUG_CRITICAL warning if questData is still empty after init.data[6] (conditions table). After writing the 5 existing fields per entry, the writer now writes a WriteByte(n) count followed by WriteShortString(key) + WriteInt24(value) for each condition entry. If data[6] is nil, writes 0.ReadByte() condition count; if non-zero, reconstructs the conditions table as {[key]=value} and assigns it to entry[6].ShortString + Int24 per condition.QuestieDB.lua:1443 reads HideCondition = o[6] from each extraobjective. Before this fix, compiled data always produced o[6] = nil, so ShouldHideObjective() never activated. The hideIfQuestActive / hideIfQuestComplete conditions were silently ignored post-compilation. Validation also flagged the mismatch every load, which triggered DevTools_Dump to flood chat with raw Lua table syntax.DevTools_Dump({["Compiled Table:"]=a, ["Base Table:"]=b}) calls from table-mismatch branches. These calls serialized full Lua tables to the chat frame as raw source code, appearing to users as a syntax error or data corruption. The preceding Questie:Warning(...) line already captures the mismatch identity. DevTools_Dump is a retail WoW debugging API unavailable or unreliable on private/custom servers and should never be called in production validation paths.Ongoing stability pass. Hardened the entire database loading pipeline, wired up the live quest-log fallback for quests missing from the DB, and fixed a chain of nil-guard crashes across corrections, map, and tracker modules.
loadstring() / fn() calls with proper error capture (local fn, err = loadstring(...) + pcall(fn)). Errors now print to chat with the failing key and string length instead of silently falling back to {}.hasData guard in QuestieDBCompiler:Compile() — now accepts type == "table" in addition to "string", preventing the compiler from silently aborting when LoadDatabase has already decoded the string to a table before compilation.questData overwrites. On WotLK servers only Questie-X-WotLKDB should be enabled alongside the server-specific plugin.rawdata is nil, a minimal quest object is now built from QuestLogCache instead of returning nil. The fallback populates name, level, isComplete, and an empty Objectives table with _isLogFallback = true.Objectives table from QuestLogCache.GetQuestObjectives on first call, then call obj:Update() on each to refresh progress from the live quest log.objectiveSpawnListCallTable), preventing "Corrupted objective data" errors caused by nil NPC IDs.name — returns quest ID string as fallback.objectData[id] before clearing spawn keys in prune loop (attempt to index nil at QuestieDB:1715).objectiveSpawnListCallTable result in nil-guard before iterating — prevents pairs(nil) when a referenced NPC/object is missing from the loaded DB.monster(killCreditNpcId) result nil-guarded before indexing — prevents crash for kill-credit NPCs absent from npcData.flags nil-guard added before bitband(flags, VENDOR) call.quest.SpecialObjectives nil-guard before next() call.quest.SpecialObjectives nil-guard before next() call.Minimap button overhaul and second pass of P2 bug fixes.
mmapIcon.tga. Applied SetMask for circular clip on WotLK+ clients with SetTexCoord fallback for 1.12 vanilla clients.C_QuestLog/C_Map shims, and QuestieServer init sequence.select() polyfill to not use arg table.plugin.stats nil access.Major expansion of the data-learning system and a new Database options tab.
QuestieLearnerDB to separate retail/private/custom content.This release marks the official rebranding from Questie-335 / PE-Questie to Questie-X and introduces the new plugin architecture. Additionally, this version includes significant UI enhancements, core compatibility refinements for legacy clients, and critical database corrections.
Xurkon/Questie-X. Remote updated from PE-Questie to Questie-X.QuestiePluginAPI (Modules/Libs/QuestiePluginAPI.lua). Plugins register themselves and inject quest, NPC, object, item, and zone data without modifying core files.QuestieServer module (Modules/QuestieServer.lua) for improved runtime server environment detection.QuestieLearnerComms module (Modules/Network/QuestieLearnerComms.lua) for cross-client quest data sharing.Database/Ascension/ and Database/Ebonhold/ folders. All custom server data is now distributed via separate plugin addons.string.match and string.gmatch using string.find and string.gfind to ensure universal compatibility with legacy WoW clients (e.g., Turtle WoW).AceTimer-3.0 instances in ElvUI and OG-RaidHelper to resolve math.mod errors on Lua 5.0 clients.CreateColor polyfill with SetRGB, SetRGBA, SetColor, and GetColor methods.[QuestieTooltips:GetTooltip] m_20509 debug log spam..toc files updated to Questie-X title and v1.1.4 version.LibDeflate, XXH_Lua_Lib, LibDBIcon-1.0, and LibDataBroker-1.1 to the Libs directory.QuestieDB.IsComplete to accurately verify all objectives are finished using numFulfilled == numRequired instead of the unreliable server-side finished flag.HideCondition mechanism for objectives, allowing specific spawns to be hidden based on quest log status (hideIfQuestActive / hideIfQuestComplete).⚠️ This is the final stable release before a major architectural refactoring. All active features and quest data from previous releases are preserved.
creatureObjective to killCreditObjective, allowing Questie to correctly
resolve Dune Smasher spawn locations from the NPC database.
BAG_UPDATE_DELAYED strategy: immediate scan, 0.3s
debounce scan, and a 2s follow-up scan to allow the server's quest-objective cache to flush batch loot
counts.