Deprecate IActionBlocker in favour of cancellable events (#4193)

* Deprecate IActionBlocker in favour of cancellable events

* Bring back old speech/emoting component restrictions

* Rename action blocker listener methods

* Use Entity System public methods instead of extension methods

Co-authored-by: Vera Aguilera Puerto <gradientvera@outlook.com>
This commit is contained in:
DrSmugleaf
2021-06-19 10:03:24 +02:00
committed by GitHub
parent e1e54e9cb1
commit 9b8185db23
98 changed files with 673 additions and 365 deletions

View File

@@ -1,78 +0,0 @@
#nullable enable
using Robust.Shared.GameObjects;
namespace Content.Shared.ActionBlocker
{
public static class ActionBlockerExtensions
{
public static bool CanMove(this IEntity entity)
{
return ActionBlockerSystem.CanMove(entity);
}
public static bool CanInteract(this IEntity entity)
{
return ActionBlockerSystem.CanInteract(entity);
}
public static bool CanUse(this IEntity entity)
{
return ActionBlockerSystem.CanUse(entity);
}
public static bool CanThrow(this IEntity entity)
{
return ActionBlockerSystem.CanThrow(entity);
}
public static bool CanSpeak(this IEntity entity)
{
return ActionBlockerSystem.CanSpeak(entity);
}
public static bool CanDrop(this IEntity entity)
{
return ActionBlockerSystem.CanDrop(entity);
}
public static bool CanPickup(this IEntity entity)
{
return ActionBlockerSystem.CanPickup(entity);
}
public static bool CanEmote(this IEntity entity)
{
return ActionBlockerSystem.CanEmote(entity);
}
public static bool CanAttack(this IEntity entity)
{
return ActionBlockerSystem.CanAttack(entity);
}
public static bool CanEquip(this IEntity entity)
{
return ActionBlockerSystem.CanEquip(entity);
}
public static bool CanUnequip(this IEntity entity)
{
return ActionBlockerSystem.CanUnequip(entity);
}
public static bool CanChangeDirection(this IEntity entity)
{
return ActionBlockerSystem.CanChangeDirection(entity);
}
public static bool CanShiver(this IEntity entity)
{
return ActionBlockerSystem.CanShiver(entity);
}
public static bool CanSweat(this IEntity entity)
{
return ActionBlockerSystem.CanSweat(entity);
}
}
}

View File

@@ -1,8 +1,14 @@
#nullable enable
using System.Diagnostics.CodeAnalysis;
using Content.Shared.DragDrop;
using Content.Shared.EffectBlocker;
using Content.Shared.Emoting;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Metabolism.Events;
using Content.Shared.Movement;
using Content.Shared.Speech;
using Content.Shared.Throwing;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
@@ -15,184 +21,254 @@ namespace Content.Shared.ActionBlocker
[UsedImplicitly]
public class ActionBlockerSystem : EntitySystem
{
public static bool CanMove(IEntity entity)
public bool CanMove(IEntity entity)
{
var canMove = true;
var ev = new MovementAttemptEvent(entity);
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
{
canMove &= blocker.CanMove(); // Sets var to false if false
if (!blocker.CanMove())
{
ev.Cancel();
break;
}
}
return canMove;
return !ev.Cancelled;
}
public static bool CanInteract([NotNullWhen(true)] IEntity? entity)
public bool CanInteract(IEntity entity)
{
if (entity == null)
var ev = new InteractionAttemptEvent(entity);
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
return false;
if (!blocker.CanInteract())
{
ev.Cancel();
break;
}
}
var canInteract = true;
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
{
canInteract &= blocker.CanInteract();
}
return canInteract;
return !ev.Cancelled;
}
public static bool CanUse([NotNullWhen(true)] IEntity? entity)
public bool CanUse(IEntity entity)
{
if (entity == null)
var ev = new UseAttemptEvent(entity);
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
return false;
if (!blocker.CanUse())
{
ev.Cancel();
break;
}
}
var canUse = true;
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
{
canUse &= blocker.CanUse();
}
return canUse;
return !ev.Cancelled;
}
public static bool CanThrow(IEntity entity)
public bool CanThrow(IEntity entity)
{
var canThrow = true;
var ev = new ThrowAttemptEvent(entity);
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canThrow &= blocker.CanThrow();
if (!blocker.CanThrow())
{
ev.Cancel();
break;
}
}
return canThrow;
return !ev.Cancelled;
}
public static bool CanSpeak(IEntity entity)
public bool CanSpeak(IEntity entity)
{
if (!entity.HasComponent<SharedSpeechComponent>())
return false;
var ev = new SpeakAttemptEvent(entity);
var canSpeak = true;
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canSpeak &= blocker.CanSpeak();
if (!blocker.CanSpeak())
{
ev.Cancel();
break;
}
}
return canSpeak;
return !ev.Cancelled;
}
public static bool CanDrop(IEntity entity)
public bool CanDrop(IEntity entity)
{
var canDrop = true;
var ev = new DropAttemptEvent(entity);
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canDrop &= blocker.CanDrop();
if (!blocker.CanDrop())
{
ev.Cancel();
break;
}
}
return canDrop;
return !ev.Cancelled;
}
public static bool CanPickup(IEntity entity)
public bool CanPickup(IEntity entity)
{
var canPickup = true;
var ev = new PickupAttemptEvent(entity);
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canPickup &= blocker.CanPickup();
if (!blocker.CanPickup())
{
ev.Cancel();
break;
}
}
return canPickup;
return !ev.Cancelled;
}
public static bool CanEmote(IEntity entity)
public bool CanEmote(IEntity entity)
{
if (!entity.HasComponent<SharedEmotingComponent>())
return false;
var ev = new EmoteAttemptEvent(entity);
var canEmote = true;
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canEmote &= blocker.CanEmote();
if (!blocker.CanEmote())
{
ev.Cancel();
break;
}
}
return canEmote;
return !ev.Cancelled;
}
public static bool CanAttack(IEntity entity)
public bool CanAttack(IEntity entity)
{
var canAttack = true;
var ev = new AttackAttemptEvent(entity);
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canAttack &= blocker.CanAttack();
if (!blocker.CanAttack())
{
ev.Cancel();
break;
}
}
return canAttack;
return !ev.Cancelled;
}
public static bool CanEquip(IEntity entity)
public bool CanEquip(IEntity entity)
{
var canEquip = true;
var ev = new EquipAttemptEvent(entity);
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canEquip &= blocker.CanEquip();
if (!blocker.CanEquip())
{
ev.Cancel();
break;
}
}
return canEquip;
return !ev.Cancelled;
}
public static bool CanUnequip(IEntity entity)
public bool CanUnequip(IEntity entity)
{
var canUnequip = true;
var ev = new UnequipAttemptEvent(entity);
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canUnequip &= blocker.CanUnequip();
if (!blocker.CanUnequip())
{
ev.Cancel();
break;
}
}
return canUnequip;
return !ev.Cancelled;
}
public static bool CanChangeDirection(IEntity entity)
public bool CanChangeDirection(IEntity entity)
{
var canChangeDirection = true;
var ev = new ChangeDirectionAttemptEvent(entity);
foreach (var blocker in entity.GetAllComponents<IActionBlocker>())
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canChangeDirection &= blocker.CanChangeDirection();
if (!blocker.CanChangeDirection())
{
ev.Cancel();
break;
}
}
return canChangeDirection;
return !ev.Cancelled;
}
public static bool CanShiver(IEntity entity)
public bool CanShiver(IEntity entity)
{
var canShiver = true;
foreach (var component in entity.GetAllComponents<IActionBlocker>())
var ev = new ShiverAttemptEvent(entity);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canShiver &= component.CanShiver();
if (!blocker.CanShiver())
{
ev.Cancel();
break;
}
}
return canShiver;
return !ev.Cancelled;
}
public static bool CanSweat(IEntity entity)
public bool CanSweat(IEntity entity)
{
var canSweat = true;
foreach (var component in entity.GetAllComponents<IActionBlocker>())
var ev = new SweatAttemptEvent(entity);
RaiseLocalEvent(entity.Uid, ev);
foreach (var blocker in ev.Entity.GetAllComponents<IActionBlocker>())
{
canSweat &= component.CanSweat();
if (!blocker.CanSweat())
{
ev.Cancel();
break;
}
}
return canSweat;
return !ev.Cancelled;
}
}
}

View File

@@ -1,4 +1,5 @@
#nullable enable
using System;
using Content.Shared.EffectBlocker;
namespace Content.Shared.ActionBlocker
@@ -7,34 +8,49 @@ namespace Content.Shared.ActionBlocker
/// This interface gives components the ability to block certain actions from
/// being done by the owning entity. For effects see <see cref="IEffectBlocker"/>
/// </summary>
[Obsolete("Use events instead")]
public interface IActionBlocker
{
[Obsolete("Use MoveAttemptEvent instead")]
bool CanMove() => true;
[Obsolete("Use InteractAttemptEvent instead")]
bool CanInteract() => true;
[Obsolete("Use UseAttemptEvent instead")]
bool CanUse() => true;
[Obsolete("Use ThrowAttemptEvent instead")]
bool CanThrow() => true;
[Obsolete("Use SpeakAttemptEvent instead")]
bool CanSpeak() => true;
[Obsolete("Use DropAttemptEvent instead")]
bool CanDrop() => true;
[Obsolete("Use PickupAttemptEvent instead")]
bool CanPickup() => true;
[Obsolete("Use EmoteAttemptEvent instead")]
bool CanEmote() => true;
[Obsolete("Use AttackAttemptEvent instead")]
bool CanAttack() => true;
[Obsolete("Use EquipAttemptEvent instead")]
bool CanEquip() => true;
[Obsolete("Use UnequipAttemptEvent instead")]
bool CanUnequip() => true;
[Obsolete("Use ChangeDirectionAttemptEvent instead")]
bool CanChangeDirection() => true;
[Obsolete("Use ShiverAttemptEvent instead")]
bool CanShiver() => true;
[Obsolete("Use SweatAttemptEvent instead")]
bool CanSweat() => true;
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.DragDrop
{
public class DropAttemptEvent : CancellableEntityEventArgs
{
public DropAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Emoting
{
public class EmoteAttemptEvent : CancellableEntityEventArgs
{
public EmoteAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -0,0 +1,22 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Emoting
{
public class EmoteSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<EmoteAttemptEvent>(OnEmoteAttempt);
}
private void OnEmoteAttempt(EmoteAttemptEvent ev)
{
if (!ev.Entity.HasComponent<SharedEmotingComponent>())
{
ev.Cancel();
}
}
}
}

View File

@@ -1,20 +1,19 @@
using System;
using Content.Shared.CCVar;
using Content.Shared.Movement;
using Content.Shared.Movement.Components;
using JetBrains.Annotations;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Broadphase;
using Robust.Shared.Physics.Controllers;
using Robust.Shared.Physics.Dynamics;
#nullable enable
namespace Content.Shared.Physics.Controllers
namespace Content.Shared.Friction
{
public sealed class SharedTileFrictionController : VirtualController
{

View File

@@ -8,7 +8,7 @@ using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Movement.Components
namespace Content.Shared.Friction
{
[RegisterComponent]
public class SharedTileFrictionModifier : Component

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Interaction.Events
{
public class AttackAttemptEvent : CancellableEntityEventArgs
{
public AttackAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Interaction.Events
{
public class ChangeDirectionAttemptEvent : CancellableEntityEventArgs
{
public ChangeDirectionAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Interaction.Events
{
public class InteractionAttemptEvent : CancellableEntityEventArgs
{
public InteractionAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Interaction.Events
{
public class UseAttemptEvent : CancellableEntityEventArgs
{
public UseAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Inventory.Events
{
public class EquipAttemptEvent : CancellableEntityEventArgs
{
public EquipAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Inventory.Events
{
public class UnequipAttemptEvent : CancellableEntityEventArgs
{
public UnequipAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Item
{
public class PickupAttemptEvent : CancellableEntityEventArgs
{
public PickupAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -112,7 +112,7 @@ namespace Content.Shared.Item
/// </summary>
public bool CanPickup(IEntity user)
{
if (!ActionBlockerSystem.CanPickup(user))
if (!EntitySystem.Get<ActionBlockerSystem>().CanPickup(user))
return false;
if (user.Transform.MapID != Owner.Transform.MapID)

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Metabolism.Events
{
public class ShiverAttemptEvent : CancellableEntityEventArgs
{
public ShiverAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Metabolism.Events
{
public class SweatAttemptEvent : CancellableEntityEventArgs
{
public SweatAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -6,7 +6,7 @@ using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision;
using Robust.Shared.Physics.Dynamics;
namespace Content.Shared.Movement
namespace Content.Shared.Movement.EntitySystems
{
public sealed class SharedMobMoverSystem : EntitySystem
{

View File

@@ -9,7 +9,7 @@ using Robust.Shared.Input.Binding;
using Robust.Shared.Maths;
using Robust.Shared.Players;
namespace Content.Shared.Movement
namespace Content.Shared.Movement.EntitySystems
{
/// <summary>
/// Handles converting inputs into movement.

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Movement
{
public class MovementAttemptEvent : CancellableEntityEventArgs
{
public MovementAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -11,7 +11,7 @@ using Robust.Shared.Physics;
using Robust.Shared.Physics.Broadphase;
using Robust.Shared.Physics.Controllers;
namespace Content.Shared.Physics.Controllers
namespace Content.Shared.Movement
{
/// <summary>
/// Handles player and NPC mob movement.
@@ -105,7 +105,7 @@ namespace Content.Shared.Physics.Controllers
{
return (body.BodyStatus == BodyStatus.OnGround) &
body.Owner.HasComponent<IMobStateComponent>() &&
ActionBlockerSystem.CanMove(body.Owner) &&
EntitySystem.Get<ActionBlockerSystem>().CanMove(body.Owner) &&
(!body.Owner.IsWeightless(body, mapManager: mapManager) ||
body.Owner.TryGetComponent(out SharedPlayerMobMoverComponent? mover) &&
IsAroundCollider(broadPhaseSystem, body.Owner.Transform, mover, body));

View File

@@ -2,6 +2,7 @@
using System;
using Content.Shared.ActionBlocker;
using Content.Shared.Alert;
using Content.Shared.Movement;
using Content.Shared.Movement.Components;
using Content.Shared.NetIDs;
using Content.Shared.Physics.Pull;
@@ -365,7 +366,7 @@ namespace Content.Shared.Pulling.Components
void IRelayMoveInput.MoveInputPressed(ICommonSession session)
{
var entity = session.AttachedEntity;
if (entity == null || !ActionBlockerSystem.CanMove(entity)) return;
if (entity == null || !EntitySystem.Get<ActionBlockerSystem>().CanMove(entity)) return;
TryStopPull();
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Speech
{
public class SpeakAttemptEvent : CancellableEntityEventArgs
{
public SpeakAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}

View File

@@ -0,0 +1,22 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Speech
{
public class SpeechSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SpeakAttemptEvent>(OnSpeakAttempt);
}
private void OnSpeakAttempt(SpeakAttemptEvent ev)
{
if (!ev.Entity.HasComponent<SharedSpeechComponent>())
{
ev.Cancel();
}
}
}
}

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using Content.Shared.ActionBlocker;
using Content.Shared.DragDrop;
using Content.Shared.Interaction.Events;
using Content.Shared.NetIDs;
using Content.Shared.Placeable;
using Robust.Shared.GameObjects;
@@ -34,7 +35,7 @@ namespace Content.Shared.Storage
bool IDraggable.Drop(DragDropEvent eventArgs)
{
if (!ActionBlockerSystem.CanInteract(eventArgs.User))
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(eventArgs.User))
{
return false;
}

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using Content.Shared.ActionBlocker;
using Content.Shared.DragDrop;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction.Events;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using static Content.Shared.Inventory.EquipmentSlotDefines;
@@ -18,7 +19,7 @@ namespace Content.Shared.Strip.Components
{
return by != Owner
&& by.HasComponent<ISharedHandsComponent>()
&& ActionBlockerSystem.CanInteract(by);
&& EntitySystem.Get<ActionBlockerSystem>().CanInteract(by);
}
bool IDraggable.CanDrop(CanDropEvent args)

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.Throwing
{
public class ThrowAttemptEvent : CancellableEntityEventArgs
{
public ThrowAttemptEvent(IEntity entity)
{
Entity = entity;
}
public IEntity Entity { get; }
}
}