Fix Combat Text Font never applying for SharedMedia fonts - #1262
Open
dfrisone wants to merge 2 commits into
Open
Fix Combat Text Font never applying for SharedMedia fonts#1262dfrisone wants to merge 2 commits into
dfrisone wants to merge 2 commits into
Conversation
Bundled fonts store a direct file path and worked. A SharedMedia font stores "smf:<name>" and resolved it at startup, which failed twice over: The earliest apply with SavedVariables available is our own ADDON_LOADED, and external SharedMedia packs load after us, so at that moment the font name is not registered yet. LSM:Fetch without its noDefault flag does not return nil for an unregistered name, it substitutes the DEFAULT font, Friz Quadrata. So the "skip if unavailable" guard never fired and DAMAGE_TEXT_FONT was set to the font damage numbers already use, right in the window where the engine caches it. The PLAYER_LOGIN re-apply resolved the real path but landed after the cache. Net effect: the dropdown showed the chosen font, the damage numbers never changed. Fix mirrors the Name Font pattern already in this codebase: cache the resolved path (fctFontPath) at selection time, when the pack is necessarily loaded because its font is in the dropdown. Startup applies the cached path in the early window, fetches with noDefault so a missing name can never silently become Friz, refreshes the cache once login completes, and clears it when the providing pack is gone so a later login never points the engine at a missing file. Profiles saved before this fix have no cache; their first login populates it and the second login shows the font. Also keep the ADDON_LOADED watch alive until Blizzard_CombatText actually loads: our own addon always fired first and unregistered it, so the load-on-demand CombatTextFont object was never restyled at its real load moment.
Review findings on the first commit, worst first: with the providing pack uninstalled, the early window applied the cached path blindly, leaving DAMAGE_TEXT_FONT pointed at a missing file for the whole session, which disables floating combat text entirely. And the login-complete cache clear treated "not registered by PLAYER_LOGIN" as "pack gone", so a single login with the pack disabled (an alt, a troubleshooting session, out-of-date after a patch) or a pack that registers its fonts late wiped the account-wide cache and cost an extra default-font login after recovery. Replace the event-driven state machine with a probe: SetFont returns a success boolean, so both the LSM result and the cached path are verified loadable before either reaches an engine global or stays in the cache. That single invariant covers every reviewed scenario: an uninstalled pack clears the cache and leaves the default intact, a disabled-but-on-disk pack keeps working from the cache (font files load regardless of addon enable state), late-registering packs lose nothing, and a registration pointing at a moved file is refused. The loginComplete parameter goes away entirely. The cache also records which key it was resolved for (fctFontPathFor), so a fctFont written by any future non-dropdown path cannot silently apply a stale path for a different font, and it is only written for smf: keys, where the key is not already the path. ApplyUnitNameFont gets the same probe on its cached path: unitNameFontPath rides profile export, so an import from someone with a pack the importer lacks pointed UNIT_NAME_FONT at a missing file permanently. It now falls back to ResolveFontName and skips the write rather than apply a dead path. The ADDON_LOADED watch retires at our own load when no combat text font is configured (a mid-session pick needs a relog regardless) or when Blizzard_CombatText already loaded, so only enabled-feature sessions that still await that addon keep listening.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reported on 8.6.3: setting Combat Text Font to a SharedMedia font (e.g. "Numbers"), following the logout prompt, and logging back in shows the font selected in Global Settings, but the damage numbers never change. Bundled fonts work; only SharedMedia picks fail.
Cause
Two defects stacked in
ApplyCombatTextFont(EllesmereUI_Startup.lua).Load order. A SharedMedia font is stored as
smf:<name>and resolved at startup. The earliest apply with SavedVariables available is our ownADDON_LOADED, and external SharedMedia packs load after us, so at that moment the name is not registered yet. The engine cachesDAMAGE_TEXT_FONTbefore thePLAYER_LOGINre-apply (the feature's own "logout required" popup documents that cache), so the later correct write is invisible.Silent substitution.
LSM:Fetch("font", name)without itsnoDefaultflag does not return nil for an unregistered name. It returns the default font, Friz Quadrata, the same face damage numbers already use. So the "skip if unavailable" guard never fired, and the engine cached "no change" every login.Bundled fonts store a direct file path and skip resolution entirely, which is why they always worked.
Change
Mirrors the Name Font pattern already in this codebase (
unitNameFontPath):setValuealso stores the resolved path (EllesmereUIDB.fctFontPath). At selection time the providing pack is necessarily loaded, since its font is in the dropdown.noDefaultso a missing name can never silently become Friz, refreshes the cache once login completes, and clears it when the providing pack is gone, so no later login points the engine at a missing file.Also fixed in the same block: the
ADDON_LOADEDwatch was unregistered on the first matching addon, which is always ours, so the load-on-demandCombatTextFontobject (scrolling combat text) was never restyled at its actual load moment. OnlyBlizzard_CombatText's load retires the watch now.Testing
luac -ppasses on both files. The resolve logic was exercised offline across all five timing windows (bundled early, cached early, pre-fix profile early, login-complete refresh, pack removed), plus a demonstration that the old code fetched Friz Quadrata for an unregistered name.Verified in game by the original reporter on a test build of this branch: SharedMedia font selected, logout to character select, damage numbers render in the chosen font on a training dummy. Bundled fonts and Blizzard Default unchanged.
Update after review
A multi-angle review of the first commit surfaced two real defects in its failure paths, both fixed in the second commit:
DAMAGE_TEXT_FONTpointed at a missing file for the whole session, which disables floating combat text entirely (worse than the original bug).The revision replaces the event-driven branching with a single invariant: every candidate path (LSM result or cache) is probed with
SetFont, which returns a success boolean (perSimpleFontStringAPIDocumentation), before it reaches an engine global or stays cached. An uninstalled pack reverts to Blizzard default with the cache cleared; a disabled-but-on-disk pack keeps working, since font files load regardless of addon enable state. The cache also records which key produced it, so a desyncedfctFontcan never apply a stale path, andApplyUnitNameFontgets the same probe (itsunitNameFontPathrides profile export, where an import could carry a path the importer's machine does not have). TheADDON_LOADEDwatch now retires when the feature is unconfigured, keeping the unused-feature cost at zero.All eight resolve scenarios (healthy, uninstalled, disabled, late-registering, key-mismatch, dead registration, pre-fix profile, bundled) pass an offline simulation of the new logic. The reporter-verified happy path is preserved by construction; a re-test of the pack-uninstalled path in game is welcome but the failure it guards against was never reachable in the verified flow.