AnchorableComponent light cleanup. (#4009)

* Remove awful commands

* Unanchoring is a word.

* Fix disposal tests....

* Slight anchorable cleanup
This commit is contained in:
Vera Aguilera Puerto
2021-05-16 22:33:21 +02:00
committed by GitHub
parent efbe129d61
commit dc03f1f545
7 changed files with 73 additions and 288 deletions

View File

@@ -8,6 +8,7 @@ using NUnit.Framework;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Physics;
namespace Content.IntegrationTests.Tests.Disposal namespace Content.IntegrationTests.Tests.Disposal
{ {
@@ -63,6 +64,8 @@ namespace Content.IntegrationTests.Tests.Disposal
name: HumanDummy name: HumanDummy
id: HumanDummy id: HumanDummy
components: components:
- type: Body
- type: MobState
- type: Damageable - type: Damageable
damagePrototype: biologicalDamageContainer damagePrototype: biologicalDamageContainer
@@ -70,6 +73,7 @@ namespace Content.IntegrationTests.Tests.Disposal
name: WrenchDummy name: WrenchDummy
id: WrenchDummy id: WrenchDummy
components: components:
- type: Item
- type: Tool - type: Tool
qualities: qualities:
- Anchoring - Anchoring
@@ -120,16 +124,13 @@ namespace Content.IntegrationTests.Tests.Disposal
Assert.True(disposalTrunk.HasComponent<DisposalEntryComponent>()); Assert.True(disposalTrunk.HasComponent<DisposalEntryComponent>());
// Can't insert, unanchored and unpowered // Can't insert, unanchored and unpowered
var disposalUnitAnchorable = disposalUnit.GetComponent<AnchorableComponent>(); var physics = disposalUnit.GetComponent<IPhysBody>();
await disposalUnitAnchorable.TryUnAnchor(human, null, true); physics.BodyType = BodyType.Dynamic;
Assert.False(unit.Anchored); Assert.False(unit.Anchored);
UnitInsertContains(unit, false, human, wrench, disposalUnit, disposalTrunk); UnitInsertContains(unit, false, human, wrench, disposalUnit, disposalTrunk);
// Anchor the disposal unit // Anchor the disposal unit
await disposalUnitAnchorable.TryAnchor(human, null, true); physics.BodyType = BodyType.Static;
Assert.True(disposalUnit.TryGetComponent(out AnchorableComponent? anchorableUnit));
Assert.True(await anchorableUnit!.TryAnchor(human, wrench));
Assert.True(unit.Anchored);
// No power // No power
Assert.False(unit.Powered); Assert.False(unit.Powered);

View File

@@ -1,58 +0,0 @@
#nullable enable
using System.Linq;
using Content.Server.Administration;
using Content.Server.GameObjects.Components;
using Content.Shared.Administration;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.Commands.Interactable
{
[AdminCommand(AdminFlags.Debug)]
class AnchorCommand : IConsoleCommand
{
public string Command => "anchor";
public string Description => "Anchors all entities in a radius around the user";
public string Help => $"Usage: {Command} <radius>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var player = shell.Player as IPlayerSession;
if (player?.AttachedEntity == null)
{
return;
}
if (args.Length != 1)
{
shell.WriteLine(Help);
return;
}
if (!int.TryParse(args[0], out var radius))
{
shell.WriteLine($"{args[0]} isn't a valid integer.");
return;
}
if (radius < 0)
{
shell.WriteLine("Radius must be positive.");
return;
}
var entities = IoCManager.Resolve<IEntityLookup>().GetEntitiesInRange(player.AttachedEntity, radius).ToList();
foreach (var entity in entities)
{
if (entity.TryGetComponent(out AnchorableComponent? anchorable))
{
_ = anchorable.TryAnchor(player.AttachedEntity, force: true);
}
}
}
}
}

View File

@@ -1,58 +0,0 @@
#nullable enable
using System.Linq;
using Content.Server.Administration;
using Content.Server.GameObjects.Components;
using Content.Shared.Administration;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.Commands.Interactable
{
[AdminCommand(AdminFlags.Debug)]
class UnAnchorCommand : IConsoleCommand
{
public string Command => "unanchor";
public string Description => "Unanchors all anchorable entities in a radius around the user";
public string Help => $"Usage: {Command} <radius>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var player = shell.Player as IPlayerSession;
if (player?.AttachedEntity == null)
{
return;
}
if (args.Length != 1)
{
shell.WriteLine(Help);
return;
}
if (!int.TryParse(args[0], out var radius))
{
shell.WriteLine($"{args[0]} isn't a valid integer.");
return;
}
if (radius < 0)
{
shell.WriteLine("Radius must be positive.");
return;
}
var entities = IoCManager.Resolve<IEntityLookup>().GetEntitiesInRange(player.AttachedEntity, radius).ToList();
foreach (var entity in entities)
{
if (entity.TryGetComponent(out AnchorableComponent? anchorable))
{
_ = anchorable.TryUnAnchor(player.AttachedEntity, force: true);
}
}
}
}
}

View File

@@ -1,60 +0,0 @@
#nullable enable
using Content.Server.Administration;
using Content.Server.GameObjects.Components;
using Content.Shared.Administration;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Physics;
namespace Content.Server.Commands
{
[AdminCommand(AdminFlags.Debug)]
public class SetAnchorCommand : IConsoleCommand
{
public string Command => "setanchor";
public string Description => "Sets the anchoring state of an entity.";
public string Help => "setanchor <entity id> <value (optional)>";
public async void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length == 0 || args.Length > 2)
{
shell.WriteLine("Invalid number of argument!");
return;
}
if (!int.TryParse(args[0], out var id))
{
shell.WriteLine("Invalid argument specified!");
return;
}
var entId = new EntityUid(id);
var entityManager = IoCManager.Resolve<IEntityManager>();
if (!entityManager.TryGetEntity(entId, out var entity) || entity.Deleted || !entity.TryGetComponent(out AnchorableComponent? anchorable))
{
shell.WriteLine("Invalid entity specified!");
return;
}
if (args.Length == 2)
{
if (!bool.TryParse(args[1], out var value))
{
shell.WriteLine("Invalid argument specified!");
return;
}
if (value)
await anchorable.TryAnchor(default, force: true);
else
await anchorable.TryUnAnchor(default, force: true);
return;
}
await anchorable.TryToggleAnchor(default, force: true);
}
}
}

View File

@@ -1,6 +1,5 @@
#nullable enable #nullable enable
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Interactable;
using Content.Server.GameObjects.Components.Pulling; using Content.Server.GameObjects.Components.Pulling;
@@ -14,6 +13,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components namespace Content.Server.GameObjects.Components
{ {
// TODO: Move this component's logic to an EntitySystem.
[RegisterComponent] [RegisterComponent]
public class AnchorableComponent : Component, IInteractUsing public class AnchorableComponent : Component, IInteractUsing
{ {
@@ -32,49 +32,40 @@ namespace Content.Server.GameObjects.Components
[DataField("snap")] [DataField("snap")]
public bool Snap { get; private set; } = true; public bool Snap { get; private set; } = true;
public override void Initialize()
{
base.Initialize();
Owner.EnsureComponent<PhysicsComponent>(out _physicsComponent);
}
/// <summary> /// <summary>
/// Checks if a tool can change the anchored status. /// Checks if a tool can change the anchored status.
/// </summary> /// </summary>
/// <param name="user">The user doing the action</param> /// <param name="user">The user doing the action</param>
/// <param name="utilizing">The tool being used, can be null if forcing it</param> /// <param name="utilizing">The tool being used</param>
/// <param name="force">Whether or not to check if the tool is valid</param> /// <param name="anchoring">True if we're anchoring, and false if we're unanchoring.</param>
/// <returns>true if it is valid, false otherwise</returns> /// <returns>true if it is valid, false otherwise</returns>
private async Task<bool> Valid(IEntity? user, IEntity? utilizing, [NotNullWhen(true)] bool force = false) private async Task<bool> Valid(IEntity user, IEntity utilizing, bool anchoring)
{ {
if (!Owner.HasComponent<IPhysBody>()) if (!Owner.HasComponent<IPhysBody>())
{ {
return false; return false;
} }
if (user != null && !force) BaseAnchoredAttemptEvent attempt =
{ anchoring ? new AnchorAttemptEvent(user, utilizing) : new UnanchorAttemptEvent(user, utilizing);
if (utilizing == null ||
!utilizing.TryGetComponent(out ToolComponent? tool) ||
!(await tool.UseTool(user, Owner, 0.5f, Tool)))
{
return false;
}
}
return true; Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, attempt, false);
if (attempt.Cancelled)
return false;
return utilizing.TryGetComponent(out ToolComponent? tool) && await tool.UseTool(user, Owner, 0.5f, Tool);
} }
/// <summary> /// <summary>
/// Tries to anchor the owner of this component. /// Tries to anchor the owner of this component.
/// </summary> /// </summary>
/// <param name="user">The entity doing the anchoring</param> /// <param name="user">The entity doing the anchoring</param>
/// <param name="utilizing">The tool being used, if any</param> /// <param name="utilizing">The tool being used</param>
/// <param name="force">Whether or not to ignore valid tool checks</param>
/// <returns>true if anchored, false otherwise</returns> /// <returns>true if anchored, false otherwise</returns>
public async Task<bool> TryAnchor(IEntity? user, IEntity? utilizing = null, bool force = false) public async Task<bool> TryAnchor(IEntity user, IEntity utilizing)
{ {
if (!(await Valid(user, utilizing, force))) if (!(await Valid(user, utilizing, true)))
{ {
return false; return false;
} }
@@ -82,13 +73,6 @@ namespace Content.Server.GameObjects.Components
if (_physicsComponent == null) if (_physicsComponent == null)
return false; return false;
var attempt = new AnchorAttemptMessage();
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, attempt, false);
if (attempt.Cancelled)
return false;
// Snap rotation to cardinal (multiple of 90) // Snap rotation to cardinal (multiple of 90)
var rot = Owner.Transform.LocalRotation; var rot = Owner.Transform.LocalRotation;
Owner.Transform.LocalRotation = Math.Round(rot / (Math.PI / 2)) * (Math.PI / 2); Owner.Transform.LocalRotation = Math.Round(rot / (Math.PI / 2)) * (Math.PI / 2);
@@ -106,7 +90,7 @@ namespace Content.Server.GameObjects.Components
_physicsComponent.BodyType = BodyType.Static; _physicsComponent.BodyType = BodyType.Static;
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new AnchoredMessage(), false); Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new AnchoredEvent(user, utilizing), false);
return true; return true;
} }
@@ -118,9 +102,9 @@ namespace Content.Server.GameObjects.Components
/// <param name="utilizing">The tool being used, if any</param> /// <param name="utilizing">The tool being used, if any</param>
/// <param name="force">Whether or not to ignore valid tool checks</param> /// <param name="force">Whether or not to ignore valid tool checks</param>
/// <returns>true if unanchored, false otherwise</returns> /// <returns>true if unanchored, false otherwise</returns>
public async Task<bool> TryUnAnchor(IEntity? user, IEntity? utilizing = null, bool force = false) public async Task<bool> TryUnAnchor(IEntity user, IEntity utilizing)
{ {
if (!(await Valid(user, utilizing, force))) if (!(await Valid(user, utilizing, false)))
{ {
return false; return false;
} }
@@ -128,16 +112,9 @@ namespace Content.Server.GameObjects.Components
if (_physicsComponent == null) if (_physicsComponent == null)
return false; return false;
var attempt = new UnanchorAttemptMessage();
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, attempt, false);
if (attempt.Cancelled)
return false;
_physicsComponent.BodyType = BodyType.Dynamic; _physicsComponent.BodyType = BodyType.Dynamic;
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new UnanchoredMessage(), false); Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new UnanchoredEvent(user, utilizing), false);
return true; return true;
} }
@@ -146,17 +123,16 @@ namespace Content.Server.GameObjects.Components
/// Tries to toggle the anchored status of this component's owner. /// Tries to toggle the anchored status of this component's owner.
/// </summary> /// </summary>
/// <param name="user">The entity doing the unanchoring</param> /// <param name="user">The entity doing the unanchoring</param>
/// <param name="utilizing">The tool being used, if any</param> /// <param name="utilizing">The tool being used</param>
/// <param name="force">Whether or not to ignore valid tool checks</param>
/// <returns>true if toggled, false otherwise</returns> /// <returns>true if toggled, false otherwise</returns>
public async Task<bool> TryToggleAnchor(IEntity? user, IEntity? utilizing = null, bool force = false) public async Task<bool> TryToggleAnchor(IEntity user, IEntity utilizing)
{ {
if (_physicsComponent == null) if (_physicsComponent == null)
return false; return false;
return _physicsComponent.BodyType == BodyType.Static ? return _physicsComponent.BodyType == BodyType.Static ?
await TryUnAnchor(user, utilizing, force) : await TryUnAnchor(user, utilizing) :
await TryAnchor(user, utilizing, force); await TryAnchor(user, utilizing);
} }
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
@@ -165,9 +141,47 @@ namespace Content.Server.GameObjects.Components
} }
} }
public class AnchorAttemptMessage : CancellableEntityEventArgs { } public abstract class BaseAnchoredAttemptEvent : CancellableEntityEventArgs
public class UnanchorAttemptMessage : CancellableEntityEventArgs { } {
public IEntity User { get; }
public IEntity Tool { get; }
public class AnchoredMessage : EntityEventArgs {} protected BaseAnchoredAttemptEvent(IEntity user, IEntity tool)
public class UnanchoredMessage : EntityEventArgs {} {
User = user;
Tool = tool;
}
}
public class AnchorAttemptEvent : BaseAnchoredAttemptEvent
{
public AnchorAttemptEvent(IEntity user, IEntity tool) : base(user, tool) { }
}
public class UnanchorAttemptEvent : BaseAnchoredAttemptEvent
{
public UnanchorAttemptEvent(IEntity user, IEntity tool) : base(user, tool) { }
}
public abstract class BaseAnchoredEvent : EntityEventArgs
{
public IEntity User { get; }
public IEntity Tool { get; }
protected BaseAnchoredEvent(IEntity user, IEntity tool)
{
User = user;
Tool = tool;
}
}
public class AnchoredEvent : BaseAnchoredEvent
{
public AnchoredEvent(IEntity user, IEntity tool) : base(user, tool) { }
}
public class UnanchoredEvent : BaseAnchoredEvent
{
public UnanchoredEvent(IEntity user, IEntity tool) : base(user, tool) { }
}
} }

View File

@@ -1,55 +0,0 @@
#nullable enable
using Content.Shared.GameObjects.Verbs;
using Robust.Server.Console;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Physics;
namespace Content.Server.GlobalVerbs
{
[GlobalVerb]
public class SetAnchorVerb : GlobalVerb
{
public override bool RequireInteractionRange => false;
public override bool BlockedByContainers => false;
public override void GetData(IEntity user, IEntity target, VerbData data)
{
data.CategoryData = VerbCategories.Debug;
data.Visibility = VerbVisibility.Invisible;
data.IconTexture = "/Textures/Interface/VerbIcons/anchor.svg.192dpi.png";
var groupController = IoCManager.Resolve<IConGroupController>();
if (user.TryGetComponent<ActorComponent>(out var player))
{
if (!target.TryGetComponent(out PhysicsComponent? physics))
{
return;
}
if (groupController.CanCommand(player.PlayerSession, "setanchor"))
{
data.Text = physics.BodyType == BodyType.Static ? "Unanchor" : "Anchor";
data.Visibility = VerbVisibility.Visible;
}
}
}
public override void Activate(IEntity user, IEntity target)
{
if (user.TryGetComponent<ActorComponent>(out var player))
{
var groupController = IoCManager.Resolve<IConGroupController>();
if (!groupController.CanCommand(player.PlayerSession, "setanchor"))
return;
if (target.TryGetComponent(out PhysicsComponent? physics))
{
physics.BodyType = physics.BodyType == BodyType.Static ? BodyType.Dynamic : BodyType.Static;
}
}
}
}
}

View File

@@ -169,6 +169,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Trasen/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Trasen/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unanchor/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=unanchor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unanchored/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Unanchored/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unanchoring/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Uncancel/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Uncancel/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Uncancels/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Uncancels/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Uncuff/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Uncuff/@EntryIndexedValue">True</s:Boolean>