fix(map): align minimap pins at non-1 UI scales

This commit is contained in:
Xurkon
2026-06-11 06:49:51 -05:00
parent d2c36a4a95
commit e755416f8a
4 changed files with 20 additions and 30 deletions
+7 -7
View File
@@ -232,21 +232,21 @@
</li>
<li><strong>[Fix &mdash; Arrow Runtime Texture Fallback]</strong> Bundled image arrows now use the generated runtime TGA as the live render source, while the preview TGA stays dedicated to the dropdown swatch. This keeps image arrows stable even when the client behaves oddly with a specific source file, while the sheet arrow stays isolated to <code>arrowold</code>.</li>
<li><strong>[Fix &mdash; Arrow2 Orientation]</strong> Rotated <code>Arrow2</code> 180 degrees so the pointed tip is the top-facing tip of the asset instead of the base. The runtime TGA and its preview stay in sync so the dropdown thumbnail and in-game arrow match exactly.</li>
<li><strong>[Fix &mdash; Minimap Pin Drift: Live View-Radius API + Corrected Pixel Math]</strong> Resolved the long-running minimap pin drift bug where quest pins appeared to &quot;follow&quot; the player or jump on every frame. Pins now stay anchored to their world positions across all minimap zoom levels (0-5+) and across both Stock UI and ElvUI.
<li><strong>[Fix &mdash; Minimap Pin Alignment At Non-1 UI Scales]</strong> Reverted the attempted pixel-snapping fix and corrected the minimap coordinate math instead. Quest pins now stay anchored to their world positions across all minimap zoom levels (0-5+) and across both Stock UI and ElvUI.
<ul>
<li><strong>Time-to-fix note</strong>: This took roughly three weeks of iteration. The first three attempts either crashed, partially fixed only some zoom levels, or regressed zoom 0. The final patch was the first one that held across the full zoom range without the pin math drifting again.</li>
<li><strong>Iteration 1 &mdash; mapRadius reuse (broken)</strong>: The first attempt reused <code>mapRadius</code> for both the radius and the pixel multiplier, which crashed on 3.3.5a because the live API fallback was not wired in yet.</li>
<li><strong>Iteration 2 &mdash; direct half-width (partial)</strong>: The second attempt used <code>GetWidth() * GetScale() / 2</code> directly and fixed low zoom levels, but higher zooms still drifted because the map radius source was still wrong.</li>
<li><strong>Iteration 2 &mdash; direct half-width (partial)</strong>: The second attempt used the unscaled minimap half-width directly and fixed low zoom levels, but higher zooms still drifted because the map radius source was still wrong.</li>
<li><strong>Iteration 3 &mdash; scaleFactor normalization (regressed)</strong>: The third attempt added a normalization factor based on a reference radius and inverted the ratio, which made zoom 0 worse and had to be backed out.</li>
<li><strong>Iteration 4 &mdash; final fix</strong>: The final patch combined the native 3.3.5a <code>Minimap:GetViewRadius()</code> API with the correct pixel half-width formula, which aligned the world-yard math with the on-screen pixel math.</li>
<li><strong>Iteration 4 &mdash; final fix</strong>: The final patch combined the native 3.3.5a <code>Minimap:GetViewRadius()</code> API with the unscaled minimap half-width formula, which kept the world-yard math aligned with the minimap frame coordinate space.</li>
<li><strong>Root Cause 1 &mdash; Hardcoded lookup table used on 3.3.5a</strong>: <code>Compat/HBD.lua</code> was reading <code>mapRadius</code> from a hardcoded <code>minimap_size</code> lookup table calibrated for stock WoW zoom levels. The API check <code>C_Minimap and C_Minimap.GetViewRadius</code> evaluated to <code>nil</code> on 3.3.5a (and Ascension), so the broken lookup table was always used. The lookup value <code>minimap_size.outdoor[5] = 250</code> produced <code>mapRadius = 125</code>, but the actual live minimap view radius at zoom 5 is <code>116.67</code> yards (from <code>Minimap:GetViewRadius()</code>). This 6.7% error compounded across all pin offsets.</li>
<li><strong>Root Cause 2 &mdash; Factor-of-2 in pixel math</strong>: <code>minimapWidth</code> was computed as <code>(GetWidth() * mapRadius / 155.52) / 2</code>, mixing pixel-half-width with a yards-based scale factor. The <code>/ 155.52</code> constant was a hardcoded normalization that did not match the live API value. The math was self-inconsistent: ratio <code>minimapWidth / mapRadius</code> was <code>0.56</code> (off by ~7% from the correct <code>0.6</code>).</li>
<li><strong>Root Cause 3 &mdash; Scale not applied to pixel dimensions</strong>: <code>minimapWidth</code> was based on <code>GetWidth()</code> alone, ignoring <code>GetScale()</code>. When UI scale changed, the pixel dimensions reported by <code>GetWidth()</code> would diverge from the actual on-screen size, while <code>mapRadius</code> (in yards) stayed fixed. This caused drift to worsen at higher zoom levels where the ratio was most sensitive.</li>
<li><strong>Root Cause 3 &mdash; Scale applied to the wrong layer</strong>: <code>SetPoint</code> offsets are expressed in the minimap parent frame's coordinate space, not physical pixels. Multiplying the offset by <code>GetScale()</code> pushed Questie pins away from that coordinate space and made them diverge from the native minimap quest blips whenever UI/minimap scale was not 1.0.</li>
<li><strong>Fix &mdash; <code>Compat/HBD.lua</code> lines 337-339</strong>: Changed the radius API detection to use the 3.3.5a-native <code>Minimap:GetViewRadius()</code> (instance method), with <code>C_Minimap.GetViewRadius</code> as secondary fallback. The new line:<pre><code>local MinimapRadiusAPI = (C_Minimap and C_Minimap.GetViewRadius) or Minimap.GetViewRadius</code></pre></li>
<li><strong>Fix &mdash; <code>Compat/HBD.lua</code> line 528 and line 639</strong>: Replaced <code>C_Minimap.GetViewRadius()</code> with <code>MinimapRadiusAPI(Minimap)</code> in both call sites, so the live API is invoked through the resolved function reference.</li>
<li><strong>Fix &mdash; <code>Compat/HBD.lua</code> lines 536-540 and lines 653-656</strong>: Replaced the <code>minimapWidth = (GetWidth() / 2) * (mapRadius / 155.52)</code> formula with <code>minimapWidth = GetWidth() * GetScale() / 2</code>. The new formula yields the actual half-width of the visible minimap in screen pixels, which is the correct multiplier for <code>diffX * minimapWidth</code> when <code>diffX</code> is normalized by <code>mapRadius</code> (yards in viewport).</li>
<li><strong>Fix (debug code preserved as comments)</strong>: All <code>QDMATH</code> / <code>UPDATE entering</code> / <code>ICON</code> debug prints and <code>_G.QuestieDebugPinMath</code> global state in <code>Compat/HBD.lua</code> are now wrapped in <code>--[[ DEBUG: ... --]]</code> block comments. The drift bug is fixed; debug output is silent in production. The commented-out blocks are preserved for future regression investigation &mdash; to re-enable, remove the <code>--[[</code> and <code>--]]</code> markers and reload.</li>
<li><strong>Verification</strong>: Live <code>Minimap:GetViewRadius()</code> returns <code>116.67</code> at zoom 5. <code>minimapWidth = 70</code> (from <code>GetWidth()=140 * GetScale()=1.0 / 2</code>). <code>diffX * minimapWidth / mapRadius</code> = <code>diffX * 0.6</code>, matching the expected 0.6 pixels-per-yard scaling. Pins now stay anchored to their world positions as the player moves; the per-frame <code>diffX</code> of ~0.35 yards during walking translates to ~0.21 pixels of pin movement per frame (correct for 1 yard of world movement).</li>
<li><strong>Fix &mdash; <code>Compat/HBD.lua</code> lines 536-540 and lines 653-656</strong>: Replaced the <code>minimapWidth = (GetWidth() / 2) * (mapRadius / 155.52)</code> formula with <code>minimapWidth = GetWidth() / 2</code>. The offset math now stays in the minimap frame's own coordinate space, which is the correct unit for <code>SetPoint</code>.</li>
<li><strong>Fix (debug code preserved as comments)</strong>: The temporary debug prints and <code>_G.QuestieDebugPinMath</code> global state in <code>Compat/HBD.lua</code> remain wrapped as comments so production chat stays clean. The commented-out blocks are preserved for future regression investigation &mdash; to re-enable, remove the comment markers and reload.</li>
<li><strong>Verification</strong>: Live <code>Minimap:GetViewRadius()</code> still returns the correct world-space radius at zoom 5. The pin offsets now use the same unscaled coordinate space as the minimap frame, so quest pins stay aligned with the native markers across fractional UI scales and window scaling combinations.</li>
</ul>
</li>
<li><strong>[Fix &mdash; MapIconTooltip _GetLevelString Guard]</strong> Resolved <code>attempt to concatenate local 'minLevel' (a nil value)</code> crash in <code>MapIconTooltip.lua:494</code> (<code>_GetLevelString</code> function). The creature name &quot;Uneasy Citizen&quot; existed in <code>creatureLevels</code> as an empty table <code>{}</code> rather than the expected <code>[1]=minLevel, [2]=maxLevel, [3]=rank</code> tuple. Added an early-return guard at the top of <code>_GetLevelString</code>: if <code>creatureLevels[name]</code> is falsy or not a table with a numeric level at index <code>[1]</code>, return the name unmodified.</li>