fix(learner): harden import/merge for clean multi-player data merge

Importing learned data merged from several players must not corrupt the
store. Fixes:

- ValidateImport prefix check was a no-op:  parsed
  as  (always false), so non-Questie strings were
  never rejected. Now a proper inequality check.
- MergeImport now ensures the learner stores exist (fresh profile can
  import), merges each entry synchronously via _ApplyIncomingNetworkMerge
  (validates structure, only adopts missing fields, never overwrites good
  local data), wraps each entry in pcall so one malformed entry is
  skipped/counted rather than aborting the whole import, and returns
  accurate merged/skipped/rejected counts.
- Synchronous merge also fixes InjectLearnedData previously running before
  the async-queued merges landed.

selene 0 errors; busted 145 successes / same 7 pre-existing failures.
This commit is contained in:
Xurkon
2026-06-10 05:12:04 -05:00
parent 1b06808655
commit 2c2e4a24a7
2 changed files with 46 additions and 14 deletions
+1
View File
@@ -34,6 +34,7 @@
### Bug Fixes
- **[Learner - Hardened Import/Merge For Multi-Player Data]** Importing learned data merged from several different players is now safe and clean. Fixed a prefix-validation bug in `ValidateImport` (`not str:sub(...) == x` parsed as `(not str:sub(...)) == x`, always false, so non-Questie strings were never rejected). `MergeImport` now: ensures the learner stores exist (so a fresh profile can import), merges each entry **synchronously and defensively** via `_ApplyIncomingNetworkMerge` (which validates key/coordinate structure and only adopts fields the local store is missing — never overwriting good local data), isolates every entry in a `pcall` so one corrupt entry is skipped/counted instead of aborting the import or corrupting the store, and reports accurate `merged / skipped / rejected` counts. Merging synchronously also fixes `InjectLearnedData` previously running before the queued merges landed.
- **[Quest - Turn-In '?' Missing For Quests In The Log]** A quest in the player's log is active and not yet turned in, so its turn-in `?` finisher should always be drawable — but `AddFinisher` also required `not char.complete[questId]`, so a quest completed in a previous Ascension prestige (still flagged in `char.complete`) and then re-accepted had its finisher suppressed while standing at the turn-in NPC. `AddFinisher` now trusts the live quest log: if the quest is in `currentQuestlog` and not failed, the finisher draws regardless of the (possibly stale) completed flag. No quest-completion data is modified.
- **[Learner - Turn-In/Quest NPC Not Learned When Targeted]** In learner mode the turn-in NPC's location wasn't always recorded, so its `?` finisher couldn't draw. `OnTargetChanged` only cached the GUID and never called `LearnNPC`; it now learns the spawn of quest-giver/turn-in NPCs (gated like `OnMouseoverUnit`), so simply targeting a turn-in NPC records its position. The `QUEST_COMPLETE`/`QUEST_TURNED_IN` handlers also fall back to the `target` unit when the `npc` gossip unit is already cleared, so the finisher NPC is reliably learned on turn-in.
- **[Map - Completed Quests Still Shown As Available]** (#7) The server's completed-quest list is delivered asynchronously (the `QUEST_QUERY_COMPLETE` event), often after available quests were first drawn — so quests that were actually already complete kept showing as available `!` until something forced a redraw (e.g. `/reload`). Questie now recalculates available quests once `char.complete` is populated by that event, removing the completed ones. This also clears the "already completed" subset of the false-available pins reported in #8.