]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Physics Assert in SharedMoverController (#37970)
authorPrincess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com>
Mon, 22 Dec 2025 02:42:39 +0000 (18:42 -0800)
committerGitHub <noreply@github.com>
Mon, 22 Dec 2025 02:42:39 +0000 (02:42 +0000)
* Physics asserts and Xenoarch fixes

* Fix blocking asserts

* Alright ready for the test fails

* Fix whitespace issues

* Fix whitespace

* Okay fix whitespace issues for real

* Fix test fails

* Temp fix

* Fix

* Whitespace

* Added a big ass comment

* Right

* A

* Should work

* Debug performance

* Mothership

* fix test fails real

* push

* fix

---------

Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
14 files changed:
Content.IntegrationTests/Tests/Buckle/BuckleTest.cs
Content.Shared/Blocking/BlockingSystem.cs
Content.Shared/Friction/TileFrictionController.cs
Content.Shared/Interaction/Components/BlockMovementComponent.cs
Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs
Content.Shared/Movement/Systems/SharedMoverController.cs
Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml
Resources/Prototypes/Entities/Mobs/Player/mothershipcore.yml
Resources/Prototypes/Entities/Mobs/Player/narsie.yml
Resources/Prototypes/Entities/Mobs/Player/ratvar.yml
Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml
Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_xenoartifacts.yml
Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_xenoartifacts.yml
Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/xenoartifacts.yml

index b90e1bd13c291e7b57a4222d993fa4674c2c8d9c..bbc8b67c53bdfede149a3254f3269773c86c565d 100644 (file)
@@ -31,6 +31,8 @@ namespace Content.IntegrationTests.Tests.Buckle
   - type: Hands
   - type: ComplexInteraction
   - type: InputMover
+  - type: Physics
+    bodyType: KinematicController
   - type: Body
     prototype: Human
   - type: StandingState
index 6223f8e840ba9e9faa5cbdcecda9af3bd48b6495..2e17485bded7b148d7271944d458acbcbd8a2732 100644 (file)
@@ -245,7 +245,7 @@ public sealed partial class BlockingSystem : EntitySystem
         if (TryComp<BlockingUserComponent>(user, out var blockingUserComponent) && TryComp<PhysicsComponent>(user, out var physicsComponent))
         {
             if (xform.Anchored)
-                _transformSystem.Unanchor(user, xform);
+                _transformSystem.Unanchor(user, xform, false);
 
             _actionsSystem.SetToggled(component.BlockingToggleActionEntity, false);
             _fixtureSystem.DestroyFixture(user, BlockingComponent.BlockFixtureID, body: physicsComponent);
index 4b29b9a9de02ec7a4d1281562fce37aecca331dc..71c51c55f1ec75f860d0ce6e118359d22cbed33b 100644 (file)
@@ -1,7 +1,9 @@
 using System.Numerics;
 using Content.Shared.CCVar;
 using Content.Shared.Gravity;
+using Content.Shared.Interaction.Components;
 using Content.Shared.Interaction.Events;
+using Content.Shared.Movement.Components;
 using Content.Shared.Movement.Events;
 using Content.Shared.Movement.Pulling.Components;
 using Content.Shared.Movement.Systems;
@@ -14,6 +16,7 @@ using Robust.Shared.Physics.Components;
 using Robust.Shared.Physics.Controllers;
 using Robust.Shared.Physics.Dynamics;
 using Robust.Shared.Physics.Systems;
+using Robust.Shared.Utility;
 
 namespace Content.Shared.Friction
 {
@@ -26,11 +29,14 @@ namespace Content.Shared.Friction
         [Dependency] private readonly SharedMapSystem _map = default!;
 
         private EntityQuery<TileFrictionModifierComponent> _frictionQuery;
-        private EntityQuery<TransformComponent> _xformQuery;
         private EntityQuery<PullerComponent> _pullerQuery;
         private EntityQuery<PullableComponent> _pullableQuery;
         private EntityQuery<MapGridComponent> _gridQuery;
 
+        // For debug purposes only
+        private EntityQuery<InputMoverComponent> _moverQuery;
+        private EntityQuery<BlockMovementComponent> _blockMoverQuery;
+
         private float _frictionModifier;
         private float _minDamping;
         private float _airDamping;
@@ -45,10 +51,11 @@ namespace Content.Shared.Friction
             Subs.CVar(_configManager, CCVars.AirFriction, value => _airDamping = value, true);
             Subs.CVar(_configManager, CCVars.OffgridFriction, value => _offGridDamping = value, true);
             _frictionQuery = GetEntityQuery<TileFrictionModifierComponent>();
-            _xformQuery = GetEntityQuery<TransformComponent>();
             _pullerQuery = GetEntityQuery<PullerComponent>();
             _pullableQuery = GetEntityQuery<PullableComponent>();
             _gridQuery = GetEntityQuery<MapGridComponent>();
+            _moverQuery = GetEntityQuery<InputMoverComponent>();
+            _blockMoverQuery = GetEntityQuery<BlockMovementComponent>();
         }
 
         public override void UpdateBeforeSolve(bool prediction, float frameTime)
@@ -107,7 +114,16 @@ namespace Content.Shared.Friction
                 PhysicsSystem.SetAngularDamping(uid, body, friction);
 
                 if (body.BodyType != BodyType.KinematicController)
+                {
+                    /*
+                     * Extra catch for input movers that may be temporarily unable to move for whatever reason.
+                     * Block movement shouldn't be added and removed frivolously so it should be reliable to use this
+                     * as a check for brains and such which have input mover purely for ghosting behavior.
+                     */
+                    DebugTools.Assert(!_moverQuery.HasComp(uid) || _blockMoverQuery.HasComp(uid),
+                        $"Input mover: {ToPrettyString(uid)} in TileFrictionController is not the correct BodyType, BodyType found: {body.BodyType}, expected: KinematicController.");
                     continue;
+                }
 
                 // Physics engine doesn't apply damping to Kinematic Controllers so we have to do it here.
                 // BEWARE YE TRAVELLER:
index 2125f16efe0e46fd5a805bf93047619ddca9e5af..a40e2b9e3cf07ad644c7340dafb40d290f049a84 100644 (file)
@@ -8,6 +8,15 @@ namespace Content.Shared.Interaction.Components;
 [RegisterComponent, NetworkedComponent]
 public sealed partial class BlockMovementComponent : Component
 {
+    /// <summary>
+    /// Blocks generic interactions such as container insertion, pick up, drop and such.
+    /// </summary>
     [DataField]
     public bool BlockInteraction = true;
+
+    /// <summary>
+    /// Blocks being able to use entities.
+    /// </summary>
+    [DataField]
+    public bool BlockUse = true;
 }
index f6f4d8605d883581b129f30705818982ab0e98c7..5d566b850e4f31d73ef6f1f22d7684d84f29e328 100644 (file)
@@ -17,10 +17,10 @@ public partial class SharedInteractionSystem
     private void InitializeBlocking()
     {
         SubscribeLocalEvent<BlockMovementComponent, UpdateCanMoveEvent>(OnMoveAttempt);
-        SubscribeLocalEvent<BlockMovementComponent, UseAttemptEvent>(CancelEvent);
+        SubscribeLocalEvent<BlockMovementComponent, UseAttemptEvent>(CancelUseEvent);
         SubscribeLocalEvent<BlockMovementComponent, InteractionAttemptEvent>(CancelInteractEvent);
-        SubscribeLocalEvent<BlockMovementComponent, DropAttemptEvent>(CancelEvent);
-        SubscribeLocalEvent<BlockMovementComponent, PickupAttemptEvent>(CancelEvent);
+        SubscribeLocalEvent<BlockMovementComponent, DropAttemptEvent>(CancellableInteractEvent);
+        SubscribeLocalEvent<BlockMovementComponent, PickupAttemptEvent>(CancellableInteractEvent);
         SubscribeLocalEvent<BlockMovementComponent, ChangeDirectionAttemptEvent>(CancelEvent);
 
         SubscribeLocalEvent<BlockMovementComponent, ComponentStartup>(OnBlockingStartup);
@@ -33,6 +33,12 @@ public partial class SharedInteractionSystem
             args.Cancelled = true;
     }
 
+    private void CancelUseEvent(Entity<BlockMovementComponent> ent, ref UseAttemptEvent args)
+    {
+        if (ent.Comp.BlockUse)
+            args.Cancel();
+    }
+
     private void OnMoveAttempt(EntityUid uid, BlockMovementComponent component, UpdateCanMoveEvent args)
     {
         // If we're relaying then don't cancel.
@@ -42,6 +48,12 @@ public partial class SharedInteractionSystem
         args.Cancel(); // no more scurrying around
     }
 
+    private void CancellableInteractEvent(EntityUid uid, BlockMovementComponent component, CancellableEntityEventArgs args)
+    {
+        if (component.BlockInteraction)
+            args.Cancel();
+    }
+
     private void CancelEvent(EntityUid uid, BlockMovementComponent component, CancellableEntityEventArgs args)
     {
         args.Cancel();
index ff034a9c07e314301e7030cd44f16953a1f7b54b..b3607b846339bb03ecf13b67616d9f8aa5cf426a 100644 (file)
@@ -20,6 +20,7 @@ using Robust.Shared.Map.Components;
 using Robust.Shared.Physics;
 using Robust.Shared.Physics.Components;
 using Robust.Shared.Physics.Controllers;
+using Robust.Shared.Physics.Events;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Timing;
 using Robust.Shared.Utility;
@@ -102,6 +103,8 @@ public abstract partial class SharedMoverController : VirtualController
 
         SubscribeLocalEvent<MovementSpeedModifierComponent, TileFrictionEvent>(OnTileFriction);
         SubscribeLocalEvent<InputMoverComponent, ComponentStartup>(OnMoverStartup);
+        SubscribeLocalEvent<InputMoverComponent, PhysicsBodyTypeChangedEvent>(OnPhysicsBodyChanged);
+        SubscribeLocalEvent<InputMoverComponent, UpdateCanMoveEvent>(OnCanMove);
 
         InitializeInput();
         InitializeRelay();
@@ -207,6 +210,21 @@ public abstract partial class SharedMoverController : VirtualController
             return;
         }
 
+        /*
+         * This assert is here because any entity using inputs to move should be a Kinematic Controller.
+         * Kinematic Controllers are not built to use the entirety of the Physics engine by intention and
+         * setting an input mover to Dynamic will cause the Physics engine to occasionally throw asserts.
+         * In addition, SharedMoverController applies its own forms of fake impulses and friction outside
+         * Physics simulation, which will cause issues for Dynamic bodies (Such as Friction being applied twice).
+         * Kinematic bodies have even less Physics options and as such aren't suitable for a player, especially
+         * when we move to Box2D v3 where there will be more support for players updating outside of simulation.
+         * Lastly, static bodies can't move so they shouldn't be updated. If a static body makes it here we're
+         * doing unnecessary calculations.
+         * Only a Kinematic Controller should be making it to this point.
+         */
+        DebugTools.Assert(physicsComponent.BodyType == BodyType.KinematicController,
+            $"Input mover: {ToPrettyString(uid)} in HandleMobMovement is not the correct BodyType, BodyType found: {physicsComponent.BodyType}, expected: KinematicController.");
+
         // If the body is in air but isn't weightless then it can't move
         var weightless = _gravity.IsWeightless(uid);
         var inAirHelpless = false;
@@ -344,8 +362,7 @@ public abstract partial class SharedMoverController : VirtualController
             if (!weightless && MobMoverQuery.TryGetComponent(uid, out var mobMover) &&
                 TryGetSound(weightless, uid, mover, mobMover, xform, out var sound, tileDef: tileDef))
             {
-                var soundModifier = mover.Sprinting ? InputMoverComponent.SprintingSoundModifier
-                    : InputMoverComponent.WalkingSoundModifier;
+                var soundModifier = mover.Sprinting ? InputMoverComponent.SprintingSoundModifier : InputMoverComponent.WalkingSoundModifier;
 
                 var audioParams = sound.Params
                     .WithVolume(sound.Params.Volume + soundModifier)
@@ -642,4 +659,16 @@ public abstract partial class SharedMoverController : VirtualController
         else
             args.Modifier *= ent.Comp.BaseFriction;
     }
+
+    private void OnPhysicsBodyChanged(Entity<InputMoverComponent> entity, ref PhysicsBodyTypeChangedEvent args)
+    {
+        _blocker.UpdateCanMove(entity);
+    }
+
+    private void OnCanMove(Entity<InputMoverComponent> entity, ref UpdateCanMoveEvent args)
+    {
+        // If we don't have a physics component, or have a static body type then we can't move.
+        if (!PhysicsQuery.TryComp(entity, out var body) || body.BodyType == BodyType.Static)
+            args.Cancel();
+    }
 }
index e5fdfe7336ca97935668c0f70049b5174be8f753..088c0f3ba195ca99aa3a9c5b3e54d96860f6f6ad 100644 (file)
@@ -37,7 +37,6 @@
   - type: CombatMode
   - type: Physics
     ignorePaused: true
-    bodyType: Kinematic
   - type: Access
     groups:
     - AllAccess
index 9e681dca871ca33721d92f2f68af47961a3b37ea..f5897fd2c9d8164876ec731985033b6d94f0e804 100644 (file)
@@ -5,9 +5,9 @@
   description: A sentient machine that can produce Xenoborgs. Without this the Xenoborgs are doomed.
   components:
   - type: InputMover # needs this to pilot the mothership
-  - type: MovementSpeedModifier
-    baseWalkSpeed : 0 # shouldn't move
-    baseSprintSpeed : 0 # shouldn't move
+  - type: BlockMovement # They should never be moving!
+    blockInteraction: false
+    blockUse: false
   - type: Appearance
   - type: WiresVisuals
   - type: Damageable
index f2b81f796c7a531e63011f7ab169b5fb20a64c27..e9bda23d15ca2802caba57ce869249db84ca302c 100644 (file)
@@ -84,7 +84,6 @@
     - Syndicate
     globalReceive: true
   - type: Physics
-    bodyType: Dynamic
     bodyStatus: InAir
   - type: CanMoveInAir
   # singulose components
index 658f14a6d40d445e1cd943ae57ee58cc064568ea..2da87d0d34eb6dbe1885a9087e91c12b2da8d0a4 100644 (file)
@@ -80,7 +80,6 @@
     - Syndicate
     globalReceive: true
   - type: Physics
-    bodyType: Dynamic
     bodyStatus: InAir
   - type: CanMoveInAir
   - type: EventHorizon
index 15f67245f1b31e969bd3a1d0c1e91ae2f70253fc..5fe9a6a68e664f08d0d3fb052a7077d8a48169be 100644 (file)
@@ -80,6 +80,8 @@
     damage:
       types:
         Blunt: 190
+  - type: Physics
+    bodyType: KinematicController
   - type: InputMover
   - type: MovementSpeedModifier
     baseWeightlessAcceleration: 5
index 83a04a809b33169a20c245818eb510cc63c7a977..31daa0f4e08d672354a1f38eb0c46355fb282df5 100644 (file)
@@ -20,7 +20,7 @@
       map: [ "enum.ArtifactsVisualLayers.ActivationEffect" ]
       visible: false
   - type: Physics
-    bodyType: Dynamic
+    bodyType: KinematicController
   - type: CollisionWake
     enabled: false
   - type: InteractionOutline
index 8edbbd71f4ad999cc3357db9e9e232a38ce71a34..7d85e375b21440df4fa393d53b02219e017b2d42 100644 (file)
@@ -19,6 +19,8 @@
     - state: artifact-activation
       map: [ "enum.ArtifactsVisualLayers.ActivationEffect" ]
       visible: false
+  - type: Physics
+    bodyType: KinematicController
   - type: RandomArtifactSprite
     maxSprite: 36
   - type: RandomSprite
index c634e86912b1558e1aae9f2b10c784b16e209768..265e93d720d3a3cbae02fd79d5cbe15bf5889245 100644 (file)
@@ -29,7 +29,7 @@
   - type: Damageable
   - type: Actions
   - type: Physics
-    bodyType: Dynamic
+    bodyType: KinematicController
   - type: MovementSpeedModifier
     baseWalkSpeed: 0.25
     baseSprintSpeed: 0.5