Cache CanMove (#7480)

This commit is contained in:
Leon Friedrich
2022-04-10 16:48:11 +12:00
committed by GitHub
parent 4135d9813b
commit 87eede8785
26 changed files with 218 additions and 109 deletions

View File

@@ -1,15 +1,14 @@
using Content.Shared.Body.Events;
using Content.Shared.Body.Events;
using Content.Shared.DragDrop;
using Content.Shared.Emoting;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Movement;
using Content.Shared.Movement.Components;
using Content.Shared.Speech;
using Content.Shared.Throwing;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
namespace Content.Shared.ActionBlocker
{
@@ -19,11 +18,34 @@ namespace Content.Shared.ActionBlocker
[UsedImplicitly]
public sealed class ActionBlockerSystem : EntitySystem
{
public bool CanMove(EntityUid uid)
public override void Initialize()
{
var ev = new MovementAttemptEvent(uid);
base.Initialize();
SubscribeLocalEvent<IMoverComponent, ComponentStartup>(OnMoverStartup);
}
private void OnMoverStartup(EntityUid uid, IMoverComponent component, ComponentStartup args)
{
UpdateCanMove(uid, component);
}
public bool CanMove(EntityUid uid, IMoverComponent? component = null)
{
return Resolve(uid, ref component, false) && component.CanMove;
}
public bool UpdateCanMove(EntityUid uid, IMoverComponent? component = null)
{
if (!Resolve(uid, ref component, false))
return false;
var ev = new UpdateCanMoveEvent(uid);
RaiseLocalEvent(uid, ev);
if (component.CanMove == ev.Cancelled && component is Component comp)
Dirty(comp);
component.CanMove = !ev.Cancelled;
return !ev.Cancelled;
}

View File

@@ -1,3 +1,4 @@
using Content.Shared.ActionBlocker;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
using Content.Shared.Movement;
@@ -7,6 +8,8 @@ namespace Content.Shared.Administration;
public sealed class AdminFrozenSystem : EntitySystem
{
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
public override void Initialize()
{
base.Initialize();
@@ -14,7 +17,22 @@ public sealed class AdminFrozenSystem : EntitySystem
SubscribeLocalEvent<AdminFrozenComponent, UseAttemptEvent>((_, _, args) => args.Cancel());
SubscribeLocalEvent<AdminFrozenComponent, PickupAttemptEvent>((_, _, args) => args.Cancel());
SubscribeLocalEvent<AdminFrozenComponent, ThrowAttemptEvent>((_, _, args) => args.Cancel());
SubscribeLocalEvent<AdminFrozenComponent, MovementAttemptEvent>((_, _, args) => args.Cancel());
SubscribeLocalEvent<AdminFrozenComponent, InteractionAttemptEvent>((_, _, args) => args.Cancel());
SubscribeLocalEvent<AdminFrozenComponent, ComponentStartup>(UpdateCanMove);
SubscribeLocalEvent<AdminFrozenComponent, ComponentShutdown>(UpdateCanMove);
SubscribeLocalEvent<AdminFrozenComponent, UpdateCanMoveEvent>(OnUpdateCanMove);
}
private void OnUpdateCanMove(EntityUid uid, AdminFrozenComponent component, UpdateCanMoveEvent args)
{
if (component.LifeStage > ComponentLifeStage.Running)
return;
args.Cancel();
}
private void UpdateCanMove(EntityUid uid, AdminFrozenComponent component, EntityEventArgs args)
{
_blocker.UpdateCanMove(uid);
}
}

View File

@@ -17,7 +17,7 @@ namespace Content.Shared.Buckle
SubscribeLocalEvent<SharedBuckleComponent, DownAttemptEvent>(HandleDown);
SubscribeLocalEvent<SharedBuckleComponent, StandAttemptEvent>(HandleStand);
SubscribeLocalEvent<SharedBuckleComponent, ThrowPushbackAttemptEvent>(HandleThrowPushback);
SubscribeLocalEvent<SharedBuckleComponent, MovementAttemptEvent>(HandleMove);
SubscribeLocalEvent<SharedBuckleComponent, UpdateCanMoveEvent>(HandleMove);
SubscribeLocalEvent<SharedBuckleComponent, ChangeDirectionAttemptEvent>(OnBuckleChangeDirectionAttempt);
}
@@ -27,8 +27,11 @@ namespace Content.Shared.Buckle
args.Cancel();
}
private void HandleMove(EntityUid uid, SharedBuckleComponent component, MovementAttemptEvent args)
private void HandleMove(EntityUid uid, SharedBuckleComponent component, UpdateCanMoveEvent args)
{
if (component.LifeStage > ComponentLifeStage.Running)
return;
if (component.Buckled)
args.Cancel();
}

View File

@@ -8,11 +8,14 @@ namespace Content.Shared.Climbing
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SharedClimbingComponent, MovementAttemptEvent>(HandleMoveAttempt);
SubscribeLocalEvent<SharedClimbingComponent, UpdateCanMoveEvent>(HandleMoveAttempt);
}
private void HandleMoveAttempt(EntityUid uid, SharedClimbingComponent component, MovementAttemptEvent args)
private void HandleMoveAttempt(EntityUid uid, SharedClimbingComponent component, UpdateCanMoveEvent args)
{
if (component.LifeStage > ComponentLifeStage.Running)
return;
if (component.OwnerIsTransitioning)
args.Cancel();
}

View File

@@ -1,12 +1,8 @@
using System;
using Content.Shared.ActionBlocker;
using Content.Shared.Physics;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Physics;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Climbing
{
@@ -14,6 +10,7 @@ namespace Content.Shared.Climbing
public abstract class SharedClimbingComponent : Component
{
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
protected bool IsOnClimbableThisFrame
{
@@ -47,6 +44,8 @@ namespace Content.Shared.Climbing
{
physicsComponent.BodyType = BodyType.KinematicController;
}
_sysMan.GetEntitySystem<ActionBlockerSystem>().UpdateCanMove(Owner);
}
}

View File

@@ -1,9 +1,11 @@
using Content.Shared.ActionBlocker;
using Content.Shared.Cuffs.Components;
using Content.Shared.DragDrop;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Movement;
using Content.Shared.Physics.Pull;
using Content.Shared.Pulling.Components;
using Robust.Shared.GameObjects;
@@ -11,20 +13,29 @@ namespace Content.Shared.Cuffs
{
public abstract class SharedCuffableSystem : EntitySystem
{
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SharedCuffableComponent, StopPullingEvent>(HandleStopPull);
SubscribeLocalEvent<SharedCuffableComponent, MovementAttemptEvent>(HandleMoveAttempt);
SubscribeLocalEvent<SharedCuffableComponent, UpdateCanMoveEvent>(HandleMoveAttempt);
SubscribeLocalEvent<SharedCuffableComponent, UseAttemptEvent>(OnUseAttempt);
SubscribeLocalEvent<SharedCuffableComponent, InteractionAttemptEvent>(OnInteractAttempt);
SubscribeLocalEvent<SharedCuffableComponent, IsEquippingAttemptEvent>(OnEquipAttempt);
SubscribeLocalEvent<SharedCuffableComponent, IsUnequippingAttemptEvent>(OnUnequipAttempt);
SubscribeLocalEvent<SharedCuffableComponent, DropAttemptEvent>(OnDropAttempt);
SubscribeLocalEvent<SharedCuffableComponent, PickupAttemptEvent>(OnPickupAttempt);
SubscribeLocalEvent<SharedCuffableComponent, PullMessage>(OnPull);
}
private void HandleMoveAttempt(EntityUid uid, SharedCuffableComponent component, MovementAttemptEvent args)
private void OnPull(EntityUid uid, SharedCuffableComponent component, PullMessage args)
{
if (!component.CanStillInteract)
_blocker.UpdateCanMove(uid);
}
private void HandleMoveAttempt(EntityUid uid, SharedCuffableComponent component, UpdateCanMoveEvent args)
{
if (component.CanStillInteract || !EntityManager.TryGetComponent(uid, out SharedPullableComponent? pullable) || !pullable.BeingPulled)
return;

View File

@@ -1,3 +1,4 @@
using Content.Shared.ActionBlocker;
using Content.Shared.Damage;
using Content.Shared.DragDrop;
using Content.Shared.Emoting;
@@ -17,6 +18,8 @@ namespace Content.Shared.MobState.EntitySystems
{
public sealed class MobStateSystem : EntitySystem
{
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
public override void Initialize()
{
base.Initialize();
@@ -33,12 +36,17 @@ namespace Content.Shared.MobState.EntitySystems
SubscribeLocalEvent<MobStateComponent, PickupAttemptEvent>(OnPickupAttempt);
SubscribeLocalEvent<MobStateComponent, StartPullAttemptEvent>(OnStartPullAttempt);
SubscribeLocalEvent<MobStateComponent, DamageChangedEvent>(UpdateState);
SubscribeLocalEvent<MobStateComponent, MovementAttemptEvent>(OnMoveAttempt);
SubscribeLocalEvent<MobStateComponent, UpdateCanMoveEvent>(OnMoveAttempt);
SubscribeLocalEvent<MobStateComponent, StandAttemptEvent>(OnStandAttempt);
SubscribeLocalEvent<MobStateChangedEvent>(OnStateChanged);
// Note that there's no check for Down attempts because if a mob's in crit or dead, they can be downed...
}
#region ActionBlocker
private void OnStateChanged(MobStateChangedEvent ev)
{
_blocker.UpdateCanMove(ev.Entity);
}
private void CheckAct(EntityUid uid, MobStateComponent component, CancellableEntityEventArgs args)
{
@@ -118,7 +126,7 @@ namespace Content.Shared.MobState.EntitySystems
component.UpdateState(args.Damageable.TotalDamage);
}
private void OnMoveAttempt(EntityUid uid, MobStateComponent component, MovementAttemptEvent args)
private void OnMoveAttempt(EntityUid uid, MobStateComponent component, UpdateCanMoveEvent args)
{
switch (component.CurrentState)
{

View File

@@ -1,4 +1,4 @@
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
namespace Content.Shared.Movement.Components
@@ -22,6 +22,12 @@ namespace Content.Shared.Movement.Components
/// </summary>
bool Sprinting { get; }
/// <summary>
/// Can the entity currently move. Avoids having to raise move-attempt events every time a player moves.
/// Note that this value will be overridden by the action blocker system, and shouldn't just be set directly.
/// </summary>
bool CanMove { get; set; }
Angle LastGridAngle { get; set; }
/// <summary>

View File

@@ -10,6 +10,7 @@ namespace Content.Shared.Movement.Components
public bool IgnorePaused => false;
public float CurrentWalkSpeed => 0f;
public float CurrentSprintSpeed => 0f;
public bool CanMove { get; set; } = true;
public Angle LastGridAngle { get => Angle.Zero; set {} }

View File

@@ -1,14 +1,10 @@
using System;
using Content.Shared.ActionBlocker;
using Content.Shared.CCVar;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Players;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Movement.Components
{
@@ -63,6 +59,9 @@ namespace Content.Shared.Movement.Components
public bool Sprinting => !HasFlag(_heldMoveButtons, MoveButtons.Walk);
[ViewVariables(VVAccess.ReadWrite)]
public bool CanMove { get; set; } = true;
/// <summary>
/// Calculated linear velocity direction of the entity.
/// </summary>
@@ -124,7 +123,7 @@ namespace Content.Shared.Movement.Components
{
base.Initialize();
Owner.EnsureComponentWarn<PhysicsComponent>();
LastGridAngle = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(Owner).Parent?.WorldRotation ?? new Angle(0);
LastGridAngle = _entityManager.GetComponent<TransformComponent>(Owner).Parent?.WorldRotation ?? new Angle(0);
}
/// <summary>
@@ -200,12 +199,13 @@ namespace Content.Shared.Movement.Components
_heldMoveButtons = state.Buttons;
_lastInputTick = GameTick.Zero;
_lastInputSubTick = 0;
CanMove = state.CanMove;
}
}
public override ComponentState GetComponentState()
{
return new MoverComponentState(_heldMoveButtons);
return new MoverComponentState(_heldMoveButtons, CanMove);
}
/// <summary>
@@ -244,10 +244,12 @@ namespace Content.Shared.Movement.Components
private sealed class MoverComponentState : ComponentState
{
public MoveButtons Buttons { get; }
public readonly bool CanMove;
public MoverComponentState(MoveButtons buttons)
public MoverComponentState(MoveButtons buttons, bool canMove)
{
Buttons = buttons;
CanMove = canMove;
}
}

View File

@@ -1,14 +0,0 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Movement
{
public sealed class MovementAttemptEvent : CancellableEntityEventArgs
{
public MovementAttemptEvent(EntityUid uid)
{
Uid = uid;
}
public EntityUid Uid { get; }
}
}

View File

@@ -1,5 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.ActionBlocker;
using Content.Shared.Audio;
using Content.Shared.CCVar;
using Content.Shared.Friction;
@@ -27,7 +26,6 @@ namespace Content.Shared.Movement
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly TagSystem _tags = default!;
@@ -114,7 +112,7 @@ namespace Content.Shared.Movement
{
DebugTools.Assert(!UsedMobMovement.ContainsKey(mover.Owner));
if (!UseMobMovement(physicsComponent))
if (!UseMobMovement(mover, physicsComponent))
{
UsedMobMovement[mover.Owner] = false;
return;
@@ -184,13 +182,13 @@ namespace Content.Shared.Movement
return UsedMobMovement.TryGetValue(uid, out var used) && used;
}
protected bool UseMobMovement(PhysicsComponent body)
protected bool UseMobMovement(IMoverComponent mover, PhysicsComponent body)
{
return body.BodyStatus == BodyStatus.OnGround &&
EntityManager.HasComponent<MobStateComponent>(body.Owner) &&
return mover.CanMove &&
body.BodyStatus == BodyStatus.OnGround &&
HasComp<MobStateComponent>(body.Owner) &&
// If we're being pulled then don't mess with our velocity.
(!EntityManager.TryGetComponent(body.Owner, out SharedPullableComponent? pullable) || !pullable.BeingPulled) &&
_blocker.CanMove((body).Owner);
(!TryComp(body.Owner, out SharedPullableComponent? pullable) || !pullable.BeingPulled);
}
/// <summary>

View File

@@ -0,0 +1,17 @@
using Content.Shared.Movement.Components;
namespace Content.Shared.Movement;
/// <summary>
/// Raised whenever <see cref="IMoverComponent.CanMove"/> needs to be updated. Cancel this event to prevent a
/// mover from moving.
/// </summary>
public sealed class UpdateCanMoveEvent : CancellableEntityEventArgs
{
public UpdateCanMoveEvent(EntityUid uid)
{
Uid = uid;
}
public EntityUid Uid { get; }
}

View File

@@ -1,9 +1,9 @@
using System;
using Content.Shared.ActionBlocker;
using Content.Shared.Actions;
using Content.Shared.DragDrop;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
using Content.Shared.Movement;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
namespace Content.Shared.PAI
@@ -19,6 +19,9 @@ namespace Content.Shared.PAI
/// </summary>
public abstract class SharedPAISystem : EntitySystem
{
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
public override void Initialize()
{
base.Initialize();
@@ -26,12 +29,32 @@ namespace Content.Shared.PAI
SubscribeLocalEvent<PAIComponent, InteractionAttemptEvent>(OnInteractAttempt);
SubscribeLocalEvent<PAIComponent, DropAttemptEvent>(OnDropAttempt);
SubscribeLocalEvent<PAIComponent, PickupAttemptEvent>(OnPickupAttempt);
SubscribeLocalEvent<PAIComponent, MovementAttemptEvent>(OnMoveAttempt);
SubscribeLocalEvent<PAIComponent, UpdateCanMoveEvent>(OnMoveAttempt);
SubscribeLocalEvent<PAIComponent, ChangeDirectionAttemptEvent>(OnChangeDirectionAttempt);
SubscribeLocalEvent<PAIComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<PAIComponent, ComponentShutdown>(OnShutdown);
}
private void OnMoveAttempt(EntityUid uid, PAIComponent component, MovementAttemptEvent args)
private void OnStartup(EntityUid uid, PAIComponent component, ComponentStartup args)
{
_blocker.UpdateCanMove(uid);
if (component.MidiAction != null)
_actionsSystem.AddAction(uid, component.MidiAction, null);
}
private void OnShutdown(EntityUid uid, PAIComponent component, ComponentShutdown args)
{
_blocker.UpdateCanMove(uid);
if (component.MidiAction != null)
_actionsSystem.RemoveAction(uid, component.MidiAction);
}
private void OnMoveAttempt(EntityUid uid, PAIComponent component, UpdateCanMoveEvent args)
{
if (component.LifeStage > ComponentLifeStage.Running)
return;
args.Cancel(); // no more scurrying around on lil robot legs.
}

View File

@@ -1,4 +1,5 @@
using System;
using Content.Shared.ActionBlocker;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
@@ -16,6 +17,9 @@ namespace Content.Shared.Shuttles.Components
[NetworkedComponent]
public sealed class PilotComponent : Component
{
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
[Dependency] private readonly IEntityManager _entMan = default!;
[ViewVariables] public SharedShuttleConsoleComponent? Console { get; set; }
/// <summary>
@@ -37,15 +41,14 @@ namespace Content.Shared.Shuttles.Components
return;
}
var entityManager = IoCManager.Resolve<IEntityManager>();
if (!entityManager.TryGetComponent(console, out SharedShuttleConsoleComponent? shuttleConsoleComponent))
if (!_entMan.TryGetComponent(console, out SharedShuttleConsoleComponent? shuttleConsoleComponent))
{
Logger.Warning($"Unable to set Helmsman console to {console}");
return;
}
Console = shuttleConsoleComponent;
_sysMan.GetEntitySystem<ActionBlockerSystem>().UpdateCanMove(Owner);
}
public override ComponentState GetComponentState()

View File

@@ -1,19 +1,36 @@
using Content.Shared.ActionBlocker;
using Content.Shared.Movement;
using Content.Shared.Shuttles.Components;
using Robust.Shared.GameObjects;
namespace Content.Shared.Shuttles
{
public abstract class SharedShuttleConsoleSystem : EntitySystem
{
[Dependency] protected readonly ActionBlockerSystem ActionBlockerSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PilotComponent, MovementAttemptEvent>(HandleMovementBlock);
SubscribeLocalEvent<PilotComponent, UpdateCanMoveEvent>(HandleMovementBlock);
SubscribeLocalEvent<PilotComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<PilotComponent, ComponentShutdown>(HandlePilotShutdown);
}
private void HandleMovementBlock(EntityUid uid, PilotComponent component, MovementAttemptEvent args)
protected virtual void HandlePilotShutdown(EntityUid uid, PilotComponent component, ComponentShutdown args)
{
ActionBlockerSystem.UpdateCanMove(uid);
}
private void OnStartup(EntityUid uid, PilotComponent component, ComponentStartup args)
{
ActionBlockerSystem.UpdateCanMove(uid);
}
private void HandleMovementBlock(EntityUid uid, PilotComponent component, UpdateCanMoveEvent args)
{
if (component.LifeStage > ComponentLifeStage.Running)
return;
if (component.Console == null) return;
args.Cancel();
}

View File

@@ -1,4 +1,5 @@
using System;
using Content.Shared.ActionBlocker;
using Content.Shared.Audio;
using Content.Shared.DragDrop;
using Content.Shared.Interaction;
@@ -25,6 +26,7 @@ namespace Content.Shared.Stunnable
[UsedImplicitly]
public abstract class SharedStunSystem : EntitySystem
{
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
[Dependency] private readonly StandingStateSystem _standingStateSystem = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffectSystem = default!;
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!;
@@ -37,6 +39,9 @@ namespace Content.Shared.Stunnable
SubscribeLocalEvent<SlowedDownComponent, ComponentInit>(OnSlowInit);
SubscribeLocalEvent<SlowedDownComponent, ComponentRemove>(OnSlowRemove);
SubscribeLocalEvent<StunnedComponent, ComponentStartup>(UpdateCanMove);
SubscribeLocalEvent<StunnedComponent, ComponentShutdown>(UpdateCanMove);
SubscribeLocalEvent<SlowedDownComponent, ComponentGetState>(OnSlowGetState);
SubscribeLocalEvent<SlowedDownComponent, ComponentHandleState>(OnSlowHandleState);
@@ -48,7 +53,7 @@ namespace Content.Shared.Stunnable
SubscribeLocalEvent<SlowedDownComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
// Attempt event subscriptions.
SubscribeLocalEvent<StunnedComponent, MovementAttemptEvent>(OnMoveAttempt);
SubscribeLocalEvent<StunnedComponent, UpdateCanMoveEvent>(OnMoveAttempt);
SubscribeLocalEvent<StunnedComponent, InteractionAttemptEvent>(OnInteractAttempt);
SubscribeLocalEvent<StunnedComponent, UseAttemptEvent>(OnUseAttempt);
SubscribeLocalEvent<StunnedComponent, ThrowAttemptEvent>(OnThrowAttempt);
@@ -58,6 +63,11 @@ namespace Content.Shared.Stunnable
SubscribeLocalEvent<StunnedComponent, IsUnequippingAttemptEvent>(OnUnequipAttempt);
}
private void UpdateCanMove(EntityUid uid, StunnedComponent component, EntityEventArgs args)
{
_blocker.UpdateCanMove(uid);
}
private void OnSlowGetState(EntityUid uid, SlowedDownComponent component, ref ComponentGetState args)
{
args.State = new SlowedDownComponentState(component.SprintSpeedModifier, component.WalkSpeedModifier);
@@ -205,8 +215,11 @@ namespace Content.Shared.Stunnable
#region Attempt Event Handling
private void OnMoveAttempt(EntityUid uid, StunnedComponent stunned, MovementAttemptEvent args)
private void OnMoveAttempt(EntityUid uid, StunnedComponent stunned, UpdateCanMoveEvent args)
{
if (stunned.LifeStage > ComponentLifeStage.Running)
return;
args.Cancel();
}