- type: Hands
- type: ComplexInteraction
- type: InputMover
+ - type: Physics
+ bodyType: KinematicController
- type: Body
prototype: Human
- type: StandingState
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);
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;
using Robust.Shared.Physics.Controllers;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Systems;
+using Robust.Shared.Utility;
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;
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)
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:
[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;
}
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);
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.
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();
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;
SubscribeLocalEvent<MovementSpeedModifierComponent, TileFrictionEvent>(OnTileFriction);
SubscribeLocalEvent<InputMoverComponent, ComponentStartup>(OnMoverStartup);
+ SubscribeLocalEvent<InputMoverComponent, PhysicsBodyTypeChangedEvent>(OnPhysicsBodyChanged);
+ SubscribeLocalEvent<InputMoverComponent, UpdateCanMoveEvent>(OnCanMove);
InitializeInput();
InitializeRelay();
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;
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)
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();
+ }
}
- type: CombatMode
- type: Physics
ignorePaused: true
- bodyType: Kinematic
- type: Access
groups:
- AllAccess
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
- Syndicate
globalReceive: true
- type: Physics
- bodyType: Dynamic
bodyStatus: InAir
- type: CanMoveInAir
# singulose components
- Syndicate
globalReceive: true
- type: Physics
- bodyType: Dynamic
bodyStatus: InAir
- type: CanMoveInAir
- type: EventHorizon
damage:
types:
Blunt: 190
+ - type: Physics
+ bodyType: KinematicController
- type: InputMover
- type: MovementSpeedModifier
baseWeightlessAcceleration: 5
map: [ "enum.ArtifactsVisualLayers.ActivationEffect" ]
visible: false
- type: Physics
- bodyType: Dynamic
+ bodyType: KinematicController
- type: CollisionWake
enabled: false
- type: InteractionOutline
- state: artifact-activation
map: [ "enum.ArtifactsVisualLayers.ActivationEffect" ]
visible: false
+ - type: Physics
+ bodyType: KinematicController
- type: RandomArtifactSprite
maxSprite: 36
- type: RandomSprite
- type: Damageable
- type: Actions
- type: Physics
- bodyType: Dynamic
+ bodyType: KinematicController
- type: MovementSpeedModifier
baseWalkSpeed: 0.25
baseSprintSpeed: 0.5