fix #213: complete suicide and framerate presentation
Translate suicide response 0x004A as retail's successful self-kill notice. Port /framerate onto the authored SmartBox FPS element with live two-decimal FPS and DEG values, keep diagnostic window chrome independent, and synchronize command-driven settings without discarding panel drafts. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
9ea579bdd0
commit
43f7c7807c
17 changed files with 729 additions and 39 deletions
79
src/AcDream.App/UI/Layout/RetailFpsController.cs
Normal file
79
src/AcDream.App/UI/Layout/RetailFpsController.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
using System.Globalization;
|
||||
|
||||
namespace AcDream.App.UI.Layout;
|
||||
|
||||
/// <summary>
|
||||
/// Binds retail's SmartBox frame-rate display to the authored text element from
|
||||
/// <c>LayoutDesc 0x2100000F</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Faithful port of <c>gmSmartBoxUI::RecvNotice_SetFramerateDisplay @ 0x004D65E0</c>,
|
||||
/// <c>gmSmartBoxUI::UpdateFPSMeter @ 0x004D63A0</c>, and
|
||||
/// <c>gmSmartBoxUI::UseTime @ 0x004D6E30</c>. Portal string table 0x23000001,
|
||||
/// string 0x0DCFFF73 supplies the two labels <c>FPS:</c> and <c>DEG:</c>;
|
||||
/// retail inserts both floating-point values with two decimal places.
|
||||
/// </remarks>
|
||||
public sealed class RetailFpsController
|
||||
{
|
||||
public const uint LayoutId = 0x2100000Fu;
|
||||
public const uint DisplayElementId = 0x10000047u;
|
||||
|
||||
private readonly UiText _display;
|
||||
private readonly Func<double> _framesPerSecond;
|
||||
private readonly Func<double> _degradeMultiplier;
|
||||
private readonly Func<bool> _isVisible;
|
||||
|
||||
private RetailFpsController(
|
||||
UiText display,
|
||||
Func<double> framesPerSecond,
|
||||
Func<double> degradeMultiplier,
|
||||
Func<bool> isVisible)
|
||||
{
|
||||
_display = display;
|
||||
_framesPerSecond = framesPerSecond;
|
||||
_degradeMultiplier = degradeMultiplier;
|
||||
_isVisible = isVisible;
|
||||
|
||||
// The selected catalog element is authored at (1,1) inside gmSmartBoxUI.
|
||||
// Selective LayoutDesc import makes it a root, so restore that parent-relative
|
||||
// placement explicitly instead of letting it drift to (0,0).
|
||||
_display.Left = 1f;
|
||||
_display.Top = 1f;
|
||||
_display.Padding = 1f;
|
||||
_display.Selectable = false;
|
||||
_display.LinesProvider = BuildLines;
|
||||
Tick();
|
||||
}
|
||||
|
||||
public UiText Display => _display;
|
||||
|
||||
public static RetailFpsController? Bind(
|
||||
ImportedLayout layout,
|
||||
Func<double> framesPerSecond,
|
||||
Func<double> degradeMultiplier,
|
||||
Func<bool> isVisible)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(layout);
|
||||
ArgumentNullException.ThrowIfNull(framesPerSecond);
|
||||
ArgumentNullException.ThrowIfNull(degradeMultiplier);
|
||||
ArgumentNullException.ThrowIfNull(isVisible);
|
||||
|
||||
return layout.FindElement(DisplayElementId) is UiText display
|
||||
? new RetailFpsController(display, framesPerSecond, degradeMultiplier, isVisible)
|
||||
: null;
|
||||
}
|
||||
|
||||
/// <summary>Mirrors the retail notice-driven show/hide state each UI tick.</summary>
|
||||
public void Tick() => _display.Visible = _isVisible();
|
||||
|
||||
private IReadOnlyList<UiText.Line> BuildLines()
|
||||
{
|
||||
string fps = _framesPerSecond().ToString("F2", CultureInfo.InvariantCulture);
|
||||
string degrade = _degradeMultiplier().ToString("F2", CultureInfo.InvariantCulture);
|
||||
return
|
||||
[
|
||||
new UiText.Line($"FPS: {fps}", _display.DefaultColor),
|
||||
new UiText.Line($"DEG: {degrade}", _display.DefaultColor),
|
||||
];
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue