using AcDream.Core.Physics; using AcDream.Core.Physics.Motion; using Xunit; namespace AcDream.Core.Tests.Physics; /// /// R4-V5 door-swing fix (2026-07-03, register TS-40): CMotionInterp's /// dispatch tails strip link animations for DETACHED objects only (retail /// if (physics_obj->cell == 0) RemoveLinkAnimations, raw @305627). /// The old proxy (CellPosition.ObjCellId == 0) was seeded only by /// the local player's SnapToCell, so every REMOTE body read "detached" and /// every dispatched transition link (door open/close swings, remote /// walk↔run links) was stripped the same tick it was appended — the pose /// snapped straight to the new cycle. These pin the corrected /// guard polarity. /// public class InWorldLinkGuardTests { [Fact] public void InWorldBody_DispatchKeepsTransitionLinks() { var body = new PhysicsBody { InWorld = true, TransientState = TransientStateFlags.Contact | TransientStateFlags.OnWalkable | TransientStateFlags.Active, }; var interp = new MotionInterpreter(body); int strips = 0; interp.RemoveLinkAnimations = () => strips++; interp.DoInterpretedMotion(MotionCommand.WalkForward, new MovementParameters()); Assert.Equal(0, strips); } [Fact] public void DetachedBody_DispatchStripsLinks_RetailGuard() { var body = new PhysicsBody { // InWorld left false — retail's pre-enter_world detached state. TransientState = TransientStateFlags.Contact | TransientStateFlags.OnWalkable | TransientStateFlags.Active, }; var interp = new MotionInterpreter(body); int strips = 0; interp.RemoveLinkAnimations = () => strips++; interp.DoInterpretedMotion(MotionCommand.WalkForward, new MovementParameters()); Assert.Equal(1, strips); } [Fact] public void RemoteShapedBody_StopCompletely_KeepsLinksToo() { // The other two guard sites (StopCompletely / StopInterpretedMotion) // share the same InWorld polarity. var body = new PhysicsBody { InWorld = true, TransientState = TransientStateFlags.Contact | TransientStateFlags.OnWalkable | TransientStateFlags.Active, }; var interp = new MotionInterpreter(body); int strips = 0; interp.RemoveLinkAnimations = () => strips++; interp.StopCompletely(); Assert.Equal(0, strips); } }