test(app): freeze GameWindow lifecycle boundaries

Pin the accepted startup, input, frame, resize, shutdown, and native-window order before Slice 8 moves those edges, while deleting only unread duplicate state and test-only GameWindow facades.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-22 09:27:55 +02:00
parent 20ebf217e2
commit 476c2e6de1
7 changed files with 380 additions and 56 deletions

View file

@ -30,7 +30,6 @@ public sealed class GameWindow : IDisposable
/// <see cref="_terrain"/> at draw time but allocated + disposed here.</summary>
private Shader? _terrainModernShader;
private CameraController? _cameraController;
private IMouse? _capturedMouse;
private IDatReaderWriter? _dats;
private readonly AcDream.App.Input.PointerPositionState _pointerPosition = new();
private float _lastMouseX
@ -118,7 +117,6 @@ public sealed class GameWindow : IDisposable
_localPlayerTeleportSink = new();
private AcDream.App.Streaming.LocalPlayerTeleportController?
_localPlayerTeleport;
private int _streamingRadius = 2; // default 5×5 (kept for debug overlay getStreamingRadius callback)
private readonly AcDream.App.Rendering.WorldRenderRangeState _renderRange =
new(nearRadius: 4, farRadius: 12);
private int _nearRadius
@ -317,37 +315,6 @@ public sealed class GameWindow : IDisposable
private AcDream.App.World.LiveEntityRuntime? _liveEntities;
private AcDream.App.World.LiveEntityLivenessController? _liveEntityLiveness;
/// <summary>Soft-snap decay rate (1/sec). At this rate the residual
/// halves every 1/rate seconds. 8.0 → ~100ms half-life, so even a
/// 2m residual fades within ~300ms without visible snap.</summary>
private const float SnapResidualDecayRate = 8.0f;
/// <summary>
/// When the prediction error exceeds this many meters, we treat the
/// update as a teleport / rubber-band and hard-snap (no soft lerp).
/// Prevents the soft-snap logic from trying to smooth a genuine portal
/// or force-move event.
///
/// <para>
/// Matches retail's <c>GetAutonomyBlipDistance</c> (ACE
/// <c>PhysicsObj.cs:545</c>): 20m for creatures, 25m for players.
/// We use 20m as a conservative default — any delta larger than this
/// must be a teleport (portal, recall, spawn). A running character
/// with 1-second UpdatePosition cadence at 9.5 m/s produces deltas
/// of ~9.5m, well below this threshold, so normal movement flows
/// through the interpolation queue instead of hard-snapping.
/// </para>
/// </summary>
private const float SnapHardSnapThreshold = 20.0f;
/// <summary>
/// Soft-snap window in seconds: after an UpdatePosition arrives for a
/// remote entity, dead-reckoning continues but the "origin" for
/// predicted position is the server pos. This matches retail's snap
/// behavior — the server is authoritative, we just interpolate between
/// authoritative samples.
/// </summary>
private const float DeadReckonMaxPredictSeconds = 1.0f;
// Phase F.1-H.1 — client-side state classes fed by GameEventWiring.
// Exposed publicly so plugins + UI panels can bind directly.
public readonly AcDream.Core.Chat.ChatLog Chat = new();
@ -611,8 +578,6 @@ public sealed class GameWindow : IDisposable
// path. Populated for remotes plus the PlayerModeController local entry
// (player); pruned only by logical LiveEntityRuntime teardown.
private static bool IsPlayerGuid(uint guid) => (guid & 0xFF000000u) == 0x50000000u;
private static bool IsDoorName(string? name) => name == "Door";
// ServerControlledVelocityStaleSeconds moved to RemotePhysicsUpdater (#184
// Slice 2a — the DR tick's stale-velocity anim-stop was its only user).
public GameWindow(
@ -2349,7 +2314,6 @@ public sealed class GameWindow : IDisposable
if (_options.LegacyStreamRadius is { } sr)
{
_nearRadius = sr;
_streamingRadius = sr; // keep debug overlay in sync
_farRadius = System.Math.Max(sr, _farRadius);
}
Console.WriteLine(
@ -3340,8 +3304,6 @@ public sealed class GameWindow : IDisposable
session.SendTurbineChatTo(
roomId, chatType, dispatchType, senderGuid, text, cookie),
Log: Console.WriteLine);
internal static uint ParticleEntityKey(AcDream.Core.World.WorldEntity entity) =>
entity.Id;
/// <summary>
/// Phase 5d — retail <c>AdminEnvirons</c> (0xEA60) dispatcher.
/// Routes fog presets into the weather system's sticky override
@ -3427,7 +3389,6 @@ public sealed class GameWindow : IDisposable
// held is handled separately by the gameplay input owner.
bool needsRawCursor = _cameraController?.IsFlyMode == true;
mouse.Cursor.CursorMode = needsRawCursor ? CursorMode.Raw : CursorMode.Normal;
_capturedMouse = needsRawCursor ? mouse : null;
}
// Performance overlay state — updated every ~0.5s and written to the
@ -4217,10 +4178,6 @@ public sealed class GameWindow : IDisposable
_debugVm?.AddToast(text);
}
internal static AcDream.Core.Physics.RawMotionState BuildOutboundRawMotionState(
AcDream.App.Input.MovementResult result) =>
AcDream.App.Input.LocalPlayerOutboundController.BuildRawMotionState(result);
/// <summary>
/// Item-target-mode world pick at the current cursor. The renderer supplies the
/// exact visible CPhysicsPart equivalents and RetailWorldPicker performs