fix #380: Chat tab opacity sliders were missing their retail row captions

Root cause: PlayerOptionPage::AddSliderOption never sets a row's own
name-label text — the "Inactive Opacity"/"Active Opacity" caption comes
from a SEPARATE DAT-resident runtime catalog (DID 0x78000000, resolved
via the same two-level DBCache::GetDIDFromEnumStatic master-map/submap
lookup ChatOptionsDatDefaults already uses for enum 0x16/category 2,
here for enum 0x15/category 2) that nothing in the codebase ever
queried, so both slider rows rendered with no caption at all.

Fix: new ChatOptionsDatCaptions.TryRead resolves the DID-0x78000000
catalog's per-property name/tooltip entries (matched by the same
owning-property enum ChatOptionsDatDefaults already keys its defaults
by) and ChatOptionsPageController.BuildOpacitySliders stamps each
slider's own row caption/tooltip from it — falling back to no text
(never invented English) if resolution fails. Regressed by
ChatOptionsPageControllerTests.
Bind_WiresEachSlidersOwnRowCaption_FromTheResolvedDatCatalog and the
companion Bind_MissingCaption_RendersNoText_NeverInventsEnglish case,
plus a live-mount probe (OptionsPanelLiveMountProbeTests.
ProbeChatOpacityCaptions) confirming the production TryRead call
resolves "Inactive Opacity"/"Active Opacity" against the real DAT.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-11 23:01:22 +02:00
parent c0b3d8f233
commit 2a248c0d48
8 changed files with 415 additions and 10 deletions

View file

@ -293,6 +293,43 @@ public sealed class OptionsPanelLiveMountProbeTests
return null;
}
/// <summary>#380 (gate 4): exercises the PRODUCTION
/// <see cref="ChatOptionsDatCaptions.TryRead"/> mechanism against the real
/// DAT and asserts the two resolved captions match the user's own
/// complaint ("Inactive Opacity" / "Active Opacity") — live-mount proof
/// that #380's fix reads the SAME two strings the fixture-driven
/// regression tests (<c>ChatOptionsPageControllerTests</c>) only assume
/// via a fake.</summary>
[Fact]
public void ProbeChatOpacityCaptions()
{
if (Environment.GetEnvironmentVariable("ACDREAM_PROBE_LIVE_MOUNT") != "1")
return;
var datDir = Environment.GetEnvironmentVariable("ACDREAM_DAT_DIR")
?? Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"Documents",
"Asheron's Call");
using var dats = new DatCollection(datDir, DatAccessType.Read);
var strings = new DatStringResolver(dats);
bool ok = ChatOptionsDatCaptions.TryRead(
dats, strings,
out ChatOptionsDatCaptions.Caption defaultOpacity,
out ChatOptionsDatCaptions.Caption activeOpacity);
Console.WriteLine($"[probe380] TryRead ok={ok}");
Console.WriteLine($"[probe380] Default: Name='{defaultOpacity.Name}' Tooltip='{defaultOpacity.Tooltip}'");
Console.WriteLine($"[probe380] Active: Name='{activeOpacity.Name}' Tooltip='{activeOpacity.Tooltip}'");
Assert.True(ok);
Assert.Equal("Inactive Opacity", defaultOpacity.Name);
Assert.Equal("Active Opacity", activeOpacity.Name);
Assert.False(string.IsNullOrEmpty(defaultOpacity.Tooltip));
Assert.False(string.IsNullOrEmpty(activeOpacity.Tooltip));
}
/// <summary>#372 minor half: the 13 ID_ChatOption_TextFilter_* labels fail
/// to resolve in table 0x23000003 — sweep the plausible tables and key
/// spellings against the live DAT to find their real home.</summary>