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:
Erik 2026-07-13 15:50:47 +02:00
parent 9ea579bdd0
commit 43f7c7807c
17 changed files with 729 additions and 39 deletions

View file

@ -2150,6 +2150,15 @@ public sealed class GameWindow : IDisposable
SetRetailCombatGameplay),
JumpPowerbar: new AcDream.App.UI.JumpPowerbarRuntimeBindings(
() => _playerController?.JumpCharge ?? default),
Fps: new AcDream.App.UI.FpsRuntimeBindings(
() => _lastFps,
// Retail displays either the user degrade bias or the live
// distance-driven multiplier. acdream does not yet implement
// adaptive distance degradation (tracked by TS-15), so its
// effective multiplier is exactly 1.0.
() => 1.0,
() => _settingsVm?.DisplayDraft.ShowFps
?? _persistedDisplay.ShowFps),
Toolbar: new AcDream.App.UI.ToolbarRuntimeBindings(
Objects,
() => Shortcuts,
@ -9988,32 +9997,23 @@ public sealed class GameWindow : IDisposable
int entityCount = _worldState.Entities.Count;
int animatedCount = _animatedEntities.Count;
// L.0 Display tab: ShowFps gates the perf string in the
// title bar. Default is true (matches pre-L.0 behaviour);
// unchecking the toggle in Display tab collapses the title
// to just "acdream" for a cleaner alt-tab experience.
// Keep the developer diagnostic title independent from retail's
// /framerate switch. That command owns the in-world SmartBox readout;
// conflating it with window chrome was the original incomplete port.
//
// When perf is shown, also include the in-game calendar/time —
// Also include the in-game calendar/time —
// matches retail's @timestamp output ("Date: <Month> <Day>,
// PY <Year> Time: <HourName>"). Uses NowTicks (server-synced
// + wall-clock interpolation) so the user can read the same
// fields off both acdream and retail and confirm clock parity
// directly. Drift > 1 hour = real bug.
bool showFps = _settingsVm?.DisplayDraft.ShowFps ?? true;
if (showFps)
{
double tNow = WorldTime.NowTicks;
var titleCal = AcDream.Core.World.DerethDateTime.ToCalendar(tNow);
double df = WorldTime.DayFraction;
_window!.Title =
$"acdream | {fps:F0} fps | {avgFrameTime:F1} ms | "
+ $"lb {visibleLandblocks}/{totalLandblocks} | ent {entityCount}/anim {animatedCount} | "
+ $"PY{titleCal.Year} {titleCal.Month} {titleCal.Day} {titleCal.Hour} (df={df:F4})";
}
else
{
_window!.Title = "acdream";
}
double tNow = WorldTime.NowTicks;
var titleCal = AcDream.Core.World.DerethDateTime.ToCalendar(tNow);
double df = WorldTime.DayFraction;
_window!.Title =
$"acdream | {fps:F0} fps | {avgFrameTime:F1} ms | "
+ $"lb {visibleLandblocks}/{totalLandblocks} | ent {entityCount}/anim {animatedCount} | "
+ $"PY{titleCal.Year} {titleCal.Month} {titleCal.Day} {titleCal.Hour} (df={df:F4})";
_lastFps = fps;
_lastFrameMs = avgFrameTime;
_perfAccum = 0;
@ -11482,7 +11482,7 @@ public sealed class GameWindow : IDisposable
ShowFps = !_persistedDisplay.ShowFps,
};
if (_settingsVm is not null)
_settingsVm.SetDisplay(_settingsVm.DisplayDraft with
_settingsVm.ApplyExternalDisplayChange(display => display with
{
ShowFps = _persistedDisplay.ShowFps,
});