From aca4b4645a3f2dcb92d38a3ab9cb440c578260e1 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 13 Jun 2026 17:11:40 +0200 Subject: [PATCH] refactor(G.3a): Place flips Idle before delegate; test mid-hold reset (#133) Co-Authored-By: Claude Opus 4.8 (1M context) --- .../World/TeleportArrivalController.cs | 4 +++- .../World/TeleportArrivalControllerTests.cs | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/AcDream.App/World/TeleportArrivalController.cs b/src/AcDream.App/World/TeleportArrivalController.cs index d6538533..096f0cce 100644 --- a/src/AcDream.App/World/TeleportArrivalController.cs +++ b/src/AcDream.App/World/TeleportArrivalController.cs @@ -97,7 +97,9 @@ public sealed class TeleportArrivalController private void Place(bool forced) { - _place(_destPos, _destCell, forced); + // Flip to Idle BEFORE invoking the placement delegate so the machine + // reflects "done holding" even if the delegate were to re-enter Tick. Phase = TeleportArrivalPhase.Idle; + _place(_destPos, _destCell, forced); } } diff --git a/tests/AcDream.App.Tests/World/TeleportArrivalControllerTests.cs b/tests/AcDream.App.Tests/World/TeleportArrivalControllerTests.cs index fbf8727f..54a23f2f 100644 --- a/tests/AcDream.App.Tests/World/TeleportArrivalControllerTests.cs +++ b/tests/AcDream.App.Tests/World/TeleportArrivalControllerTests.cs @@ -120,4 +120,28 @@ public class TeleportArrivalControllerTests Assert.Equal(2, placed.Count); Assert.Equal(0x01250127u, placed[1].Cell); } + + [Fact] + public void BeginArrival_DuringHold_ResetsTimeoutCounter() + { + var placed = new List(); + var c = Make(ArrivalReadiness.NotReady, placed, maxHoldFrames: 3); + + c.BeginArrival(new Vector3(1, 0, 0), 0x01250126u); + c.Tick(); // held=1 + c.Tick(); // held=2 (one short of the timeout) + + // Re-arm mid-hold with a fresh destination: the counter must restart. + c.BeginArrival(new Vector3(2, 0, 0), 0x01250199u); + c.Tick(); // held=1 again (NOT 3 -> no placement yet) + c.Tick(); // held=2 + Assert.Empty(placed); + Assert.Equal(TeleportArrivalPhase.Holding, c.Phase); + + c.Tick(); // held=3 -> timeout, forced place of the SECOND destination + var call = Assert.Single(placed); + Assert.True(call.Forced); + Assert.Equal(0x01250199u, call.Cell); + Assert.Equal(new Vector3(2, 0, 0), call.Pos); + } }