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:
parent
c0b3d8f233
commit
2a248c0d48
8 changed files with 415 additions and 10 deletions
|
|
@ -107,6 +107,25 @@ public static class ChatOptionsPageController
|
|||
/// <summary>The slider leaf inside either slider row template's subtree.</summary>
|
||||
private const uint SliderElementId = 0x1000021Cu;
|
||||
|
||||
/// <summary>
|
||||
/// #380 (2026-08-11, gate 4): the slider row's own NAME-CAPTION text
|
||||
/// child ("Inactive Opacity" / "Active Opacity") — present on BOTH
|
||||
/// template idx3 and idx6 (research doc §1.5's template array: "label
|
||||
/// 0x1000021B + slider 0x1000021C", the SAME id
|
||||
/// <see cref="ConfigOptionsPageController"/> already cites for its own
|
||||
/// slider rows sharing this template pool). Retail's
|
||||
/// <c>PlayerOptionPage::AddSliderOption</c> never sets this element's
|
||||
/// text itself (byte-verified — no <c>StringInfo</c> write in its
|
||||
/// pseudo-C body); the caption comes from
|
||||
/// <c>UIOption_Slider::SetGameplayOptionProperty</c>'s own
|
||||
/// <c>InqGameplayOptionNameAndTooltip</c> catalog lookup instead — see
|
||||
/// <see cref="ChatOptionsDatCaptions"/>'s own doc for the full byte
|
||||
/// trace. Nothing wired this element at all before #380 — the user's
|
||||
/// literal complaint ("I also miss the text next to the bars for
|
||||
/// Inactive and Active Opacity").
|
||||
/// </summary>
|
||||
private const uint SliderLabelElementId = 0x1000021Bu;
|
||||
|
||||
/// <summary>Labelled slider template's low/high range-caption children
|
||||
/// (research doc §1.5's template array; present only on template idx 6).</summary>
|
||||
private const uint SliderRangeMinElementId = 0x1000021Eu;
|
||||
|
|
@ -199,7 +218,17 @@ public static class ChatOptionsPageController
|
|||
float DefaultOpacityDatDefault,
|
||||
float ActiveOpacityDatDefault,
|
||||
Func<int, ulong> CurrentFilter,
|
||||
Action<int, ulong> SetFilter);
|
||||
Action<int, ulong> SetFilter,
|
||||
// #380: the two sliders' row captions/tooltips, resolved ONCE by the
|
||||
// caller (RetailUiRuntime) via ChatOptionsDatCaptions — the SAME
|
||||
// "resolve once, thread the pre-resolved value through Bindings"
|
||||
// shape DefaultOpacityDatDefault/ActiveOpacityDatDefault already
|
||||
// established for the value half of this exact DAT lookup family.
|
||||
// Null when the DAT read failed or that entry's own StringInfo did
|
||||
// not resolve — the row then renders with NO caption rather than
|
||||
// invented English, matching this codebase's uniform degrade rule.
|
||||
ChatOptionsDatCaptions.Caption DefaultOpacityCaption,
|
||||
ChatOptionsDatCaptions.Caption ActiveOpacityCaption);
|
||||
|
||||
/// <summary>
|
||||
/// Builds the General Options header + 2 sliders + 5 filter sections (header +
|
||||
|
|
@ -367,6 +396,16 @@ public static class ChatOptionsPageController
|
|||
SetRangeLabel(row2, SliderRangeMaxElementId, "ID_UI_Value_Opaque", resolveString);
|
||||
}
|
||||
|
||||
// #380: the row-name captions ("Inactive Opacity" / "Active
|
||||
// Opacity") + tooltips — resolved once by the caller via
|
||||
// ChatOptionsDatCaptions, threaded through Bindings exactly like the
|
||||
// sibling DefaultOpacityDatDefault/ActiveOpacityDatDefault values.
|
||||
// Element 0x1000021B is shared by BOTH templates (see its own doc).
|
||||
if (row1 is not null)
|
||||
SetOpacityCaption(row1, bindings.DefaultOpacityCaption, slider1);
|
||||
if (row2 is not null)
|
||||
SetOpacityCaption(row2, bindings.ActiveOpacityCaption, slider2);
|
||||
|
||||
if (slider1 is null || slider2 is null)
|
||||
return;
|
||||
|
||||
|
|
@ -431,6 +470,38 @@ public static class ChatOptionsPageController
|
|||
text.LinesProvider = () => new[] { new UiText.Line(label, text.DefaultColor) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #380: sets one opacity slider row's own name-caption (element
|
||||
/// <see cref="SliderLabelElementId"/>) + tooltip from a pre-resolved
|
||||
/// <see cref="ChatOptionsDatCaptions.Caption"/> — the DAT-catalog
|
||||
/// counterpart of <see cref="SetRangeLabel"/> (which resolves a
|
||||
/// COMPILED symbol key; this resolves a RUNTIME DAT entry, so it takes
|
||||
/// the already-resolved string rather than a key to hash). A null
|
||||
/// <see cref="ChatOptionsDatCaptions.Caption.Name"/> leaves the row with
|
||||
/// no caption rather than inventing English, matching every other
|
||||
/// resolve-miss path in this controller. The tooltip attaches to the
|
||||
/// SLIDER itself (the interactive/hoverable widget for this row — same
|
||||
/// convention <see cref="ConfigOptionsPageController"/>'s own slider
|
||||
/// rows use), not the caption text.
|
||||
/// </summary>
|
||||
private static void SetOpacityCaption(
|
||||
UiElement row, ChatOptionsDatCaptions.Caption caption, UiScrollbar? slider)
|
||||
{
|
||||
if (UiElement.FindDescendant(row, SliderLabelElementId) is UiText text)
|
||||
{
|
||||
if (caption.Name is { Length: > 0 } name)
|
||||
text.LinesProvider = () => new[] { new UiText.Line(name, text.DefaultColor) };
|
||||
else
|
||||
Console.WriteLine(
|
||||
"[D.2b] ChatOptionsPageController: opacity slider caption did not "
|
||||
+ "resolve from the DAT name/tooltip catalog — the row renders with no "
|
||||
+ "text rather than invented English.");
|
||||
}
|
||||
|
||||
if (slider is not null && caption.Tooltip is { Length: > 0 } tooltip)
|
||||
slider.TooltipText = tooltip;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// One per-window filter block: resolves the block template DIRECTLY through
|
||||
/// <paramref name="templateResolver"/> (NOT via
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue