feat(D.2b): run importer-built vitals window under ACDREAM_RETAIL_UI_IMPORTER (A/B)
Adds RuntimeOptions.RetailUiImporter (ACDREAM_RETAIL_UI_IMPORTER=1) — a new opt-in flag that runs the LayoutImporter-built vitals window ALONGSIDE the hand-authored vitals panel for pixel-for-pixel A/B comparison. The importer window is placed at x=200, y=30 so both render simultaneously within the same ACDREAM_RETAIL_UI=1 session. The hand-authored path is entirely untouched and remains the default; the importer path is the eventual switch-over target. Also adds two RuntimeOptionsRetailUiTests covering the new flag: value "1" → true, unset/other → false. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e8ddb68801
commit
ab3ab79380
3 changed files with 57 additions and 0 deletions
|
|
@ -1794,6 +1794,36 @@ public sealed class GameWindow : IDisposable
|
|||
_uiHost.Root.AddChild(panel);
|
||||
Console.WriteLine("[D.2b] retail UI active — vitals panel from vitals.xml markup.");
|
||||
|
||||
// Phase D.2b — LayoutDesc importer A/B harness. When ACDREAM_RETAIL_UI_IMPORTER=1,
|
||||
// build the SAME vitals window (0x2100006C) data-driven from the dat and place it beside
|
||||
// the hand-authored one so the two can be compared pixel-for-pixel before the importer
|
||||
// becomes the default. The hand-authored path above is untouched.
|
||||
if (_options.RetailUiImporter)
|
||||
{
|
||||
AcDream.App.UI.Layout.ImportedLayout? imported;
|
||||
lock (_datLock)
|
||||
imported = AcDream.App.UI.Layout.LayoutImporter.Import(
|
||||
_dats!, 0x2100006Cu, ResolveChrome, vitalsDatFont);
|
||||
if (imported is not null)
|
||||
{
|
||||
AcDream.App.UI.Layout.VitalsController.Bind(imported,
|
||||
healthPct: () => _vitalsVm!.HealthPercent,
|
||||
staminaPct: () => _vitalsVm!.StaminaPercent ?? 0f,
|
||||
manaPct: () => _vitalsVm!.ManaPercent ?? 0f,
|
||||
healthText: () => (_vitalsVm!.HealthCurrent, _vitalsVm.HealthMax) is (uint c, uint m) ? $"{c}/{m}" : "",
|
||||
staminaText: () => (_vitalsVm!.StaminaCurrent, _vitalsVm.StaminaMax) is (uint c, uint m) ? $"{c}/{m}" : "",
|
||||
manaText: () => (_vitalsVm!.ManaCurrent, _vitalsVm.ManaMax) is (uint c, uint m) ? $"{c}/{m}" : "");
|
||||
// Offset beside the hand-authored window (at x=10) for an A/B visual comparison.
|
||||
imported.Root.Left = 200; imported.Root.Top = 30;
|
||||
_uiHost.Root.AddChild(imported.Root);
|
||||
Console.WriteLine("[D.2b] importer vitals window active (A/B vs hand-authored).");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("[D.2b] importer vitals: LayoutDesc 0x2100006C not found.");
|
||||
}
|
||||
}
|
||||
|
||||
// Retail chat window — a draggable/resizable nine-slice frame hosting a
|
||||
// scrollable transcript (UiChatView). Read-only + wheel-scroll for now;
|
||||
// drag-select + Ctrl+C copy land in the next D.2b sub-step. A dedicated
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ public sealed record RuntimeOptions(
|
|||
bool DumpLiveSpawns,
|
||||
int? LegacyStreamRadius,
|
||||
bool RetailUi,
|
||||
bool RetailUiImporter,
|
||||
string? AcDir)
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -85,6 +86,7 @@ public sealed record RuntimeOptions(
|
|||
// top of the quality preset's radii. Null when unset or invalid.
|
||||
LegacyStreamRadius: TryParseNonNegativeInt(env("ACDREAM_STREAM_RADIUS")),
|
||||
RetailUi: IsExactlyOne(env("ACDREAM_RETAIL_UI")),
|
||||
RetailUiImporter: IsExactlyOne(env("ACDREAM_RETAIL_UI_IMPORTER")),
|
||||
AcDir: NullIfEmpty(env("ACDREAM_AC_DIR")));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,4 +25,29 @@ public class RuntimeOptionsRetailUiTests
|
|||
Assert.False(opts.RetailUi);
|
||||
Assert.Null(opts.AcDir);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_ReadsRetailUiImporter_WhenSetToOne()
|
||||
{
|
||||
var env = new Dictionary<string, string?>
|
||||
{
|
||||
["ACDREAM_RETAIL_UI_IMPORTER"] = "1",
|
||||
};
|
||||
var opts = RuntimeOptions.Parse("dats", k => env.GetValueOrDefault(k));
|
||||
Assert.True(opts.RetailUiImporter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_DefaultsRetailUiImporterOff_WhenUnsetOrOtherValue()
|
||||
{
|
||||
// Unset → false.
|
||||
Assert.False(RuntimeOptions.Parse("dats", _ => null).RetailUiImporter);
|
||||
|
||||
// Non-"1" values → false (mirrors RetailUi / other IsExactlyOne flags).
|
||||
var envOther = new Dictionary<string, string?>
|
||||
{
|
||||
["ACDREAM_RETAIL_UI_IMPORTER"] = "true",
|
||||
};
|
||||
Assert.False(RuntimeOptions.Parse("dats", k => envOther.GetValueOrDefault(k)).RetailUiImporter);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue