HandsSystem Refactor (#38438)
* checkpoint * pt 2 * pt... i forgot * pt 4 * patch * More test fixes * optimization!!! * the REAL hand system * fix RetractableItemActionSystem.cs oversight * the review * test * remove test usage of body prototype * Update Content.IntegrationTests/Tests/Interaction/InteractionTest.cs Co-authored-by: Tayrtahn <tayrtahn@gmail.com> * hellcode * hellcode 2 * Minor cleanup * test * Chasing the last of the bugs * changes --------- Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
This commit is contained in:
@@ -25,7 +25,7 @@ public sealed class RetractableItemActionTest : InteractionTest
|
||||
await Server.WaitAssertion(() =>
|
||||
{
|
||||
// Make sure the player's hand starts empty
|
||||
var heldItem = Hands.ActiveHandEntity;
|
||||
var heldItem = handsSystem.GetActiveItem((playerUid, Hands));
|
||||
Assert.That(heldItem, Is.Null, $"Player is holding an item ({SEntMan.ToPrettyString(heldItem)}) at start of test.");
|
||||
|
||||
// Inspect the action prototype to find the item it spawns
|
||||
@@ -43,14 +43,14 @@ public sealed class RetractableItemActionTest : InteractionTest
|
||||
var actionEnt = actionsSystem.GetAction(actionUid);
|
||||
|
||||
// Make sure the player's hand is still empty
|
||||
heldItem = Hands.ActiveHandEntity;
|
||||
heldItem = handsSystem.GetActiveItem((playerUid, Hands));
|
||||
Assert.That(heldItem, Is.Null, $"Player is holding an item ({SEntMan.ToPrettyString(heldItem)}) after adding action.");
|
||||
|
||||
// Activate the arm blade
|
||||
actionsSystem.PerformAction(ToServer(Player), actionEnt!.Value);
|
||||
|
||||
// Make sure the player is now holding the expected item
|
||||
heldItem = Hands.ActiveHandEntity;
|
||||
heldItem = handsSystem.GetActiveItem((playerUid, Hands));
|
||||
Assert.That(heldItem, Is.Not.Null, $"Expected player to be holding {spawnedProtoId} but was holding nothing.");
|
||||
AssertPrototype(spawnedProtoId, SEntMan.GetNetEntity(heldItem));
|
||||
|
||||
@@ -58,7 +58,7 @@ public sealed class RetractableItemActionTest : InteractionTest
|
||||
actionsSystem.PerformAction(ToServer(Player), actionEnt.Value);
|
||||
|
||||
// Make sure the player's hand is empty again
|
||||
heldItem = Hands.ActiveHandEntity;
|
||||
heldItem = handsSystem.GetActiveItem((playerUid, Hands));
|
||||
Assert.That(heldItem, Is.Null, $"Player is still holding an item ({SEntMan.ToPrettyString(heldItem)}) after second use.");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -293,9 +293,9 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
Assert.That(buckle.Buckled);
|
||||
|
||||
// With items in all hands
|
||||
foreach (var hand in hands.Hands.Values)
|
||||
foreach (var hand in hands.Hands.Keys)
|
||||
{
|
||||
Assert.That(hand.HeldEntity, Is.Not.Null);
|
||||
Assert.That(handsSys.GetHeldItem((human, hands), hand), Is.Not.Null);
|
||||
}
|
||||
|
||||
var bodySystem = entityManager.System<BodySystem>();
|
||||
@@ -316,9 +316,9 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
Assert.That(buckle.Buckled);
|
||||
|
||||
// Now with no item in any hand
|
||||
foreach (var hand in hands.Hands.Values)
|
||||
foreach (var hand in hands.Hands.Keys)
|
||||
{
|
||||
Assert.That(hand.HeldEntity, Is.Null);
|
||||
Assert.That(handsSys.GetHeldItem((human, hands), hand), Is.Null);
|
||||
}
|
||||
|
||||
buckleSystem.Unbuckle(human, human);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Client.Chemistry.UI;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Server.Chemistry.Components;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Chemistry;
|
||||
@@ -19,7 +18,7 @@ public sealed class DispenserTest : InteractionTest
|
||||
|
||||
// Insert beaker
|
||||
await InteractUsing("Beaker");
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Null);
|
||||
|
||||
// Open BUI
|
||||
await Interact();
|
||||
@@ -29,18 +28,18 @@ public sealed class DispenserTest : InteractionTest
|
||||
await SendBui(ReagentDispenserUiKey.Key, ev);
|
||||
|
||||
// Beaker is back in the player's hands
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Not.Null);
|
||||
AssertPrototype("Beaker", SEntMan.GetNetEntity(Hands.ActiveHandEntity));
|
||||
Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Not.Null);
|
||||
AssertPrototype("Beaker", SEntMan.GetNetEntity(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands))));
|
||||
|
||||
// Re-insert the beaker
|
||||
await Interact();
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Null);
|
||||
|
||||
// Re-eject using the button directly instead of sending a BUI event. This test is really just a test of the
|
||||
// bui/window helper methods.
|
||||
await ClickControl<ReagentDispenserWindow>(nameof(ReagentDispenserWindow.EjectButton));
|
||||
await RunTicks(5);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Not.Null);
|
||||
AssertPrototype("Beaker", SEntMan.GetNetEntity(Hands.ActiveHandEntity));
|
||||
Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Not.Null);
|
||||
AssertPrototype("Beaker", SEntMan.GetNetEntity(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ public sealed class SuicideCommandTests
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var item = entManager.SpawnEntity("SharpTestObject", transformSystem.GetMapCoordinates(player));
|
||||
Assert.That(handsSystem.TryPickup(player, item, handsComponent.ActiveHand!));
|
||||
Assert.That(handsSystem.TryPickup(player, item, handsComponent.ActiveHandId!));
|
||||
entManager.TryGetComponent<ExecutionComponent>(item, out var executionComponent);
|
||||
Assert.That(executionComponent, Is.Not.EqualTo(null));
|
||||
});
|
||||
@@ -342,7 +342,7 @@ public sealed class SuicideCommandTests
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var item = entManager.SpawnEntity("MixedDamageTestObject", transformSystem.GetMapCoordinates(player));
|
||||
Assert.That(handsSystem.TryPickup(player, item, handsComponent.ActiveHand!));
|
||||
Assert.That(handsSystem.TryPickup(player, item, handsComponent.ActiveHandId!));
|
||||
entManager.TryGetComponent<ExecutionComponent>(item, out var executionComponent);
|
||||
Assert.That(executionComponent, Is.Not.EqualTo(null));
|
||||
});
|
||||
|
||||
@@ -13,10 +13,10 @@ public sealed class WallConstruction : InteractionTest
|
||||
{
|
||||
await StartConstruction(Wall);
|
||||
await InteractUsing(Steel, 2);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Null);
|
||||
ClientAssertPrototype(Girder, Target);
|
||||
await InteractUsing(Steel, 2);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Null);
|
||||
AssertPrototype(WallSolid);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,20 +53,20 @@ public sealed class HandTests
|
||||
var xform = entMan.GetComponent<TransformComponent>(player);
|
||||
item = entMan.SpawnEntity("Crowbar", tSys.GetMapCoordinates(player, xform: xform));
|
||||
hands = entMan.GetComponent<HandsComponent>(player);
|
||||
sys.TryPickup(player, item, hands.ActiveHand!);
|
||||
sys.TryPickup(player, item, hands.ActiveHandId!);
|
||||
});
|
||||
|
||||
// run ticks here is important, as errors may happen within the container system's frame update methods.
|
||||
await pair.RunTicksSync(5);
|
||||
Assert.That(hands.ActiveHandEntity, Is.EqualTo(item));
|
||||
Assert.That(sys.GetActiveItem((player, hands)), Is.EqualTo(item));
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
sys.TryDrop(player, item, null!);
|
||||
sys.TryDrop(player, item);
|
||||
});
|
||||
|
||||
await pair.RunTicksSync(5);
|
||||
Assert.That(hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(sys.GetActiveItem((player, hands)), Is.Null);
|
||||
|
||||
await server.WaitPost(() => mapSystem.DeleteMap(data.MapId));
|
||||
await pair.CleanReturnAsync();
|
||||
@@ -105,10 +105,10 @@ public sealed class HandTests
|
||||
player = playerMan.Sessions.First().AttachedEntity!.Value;
|
||||
tSys.PlaceNextTo(player, item);
|
||||
hands = entMan.GetComponent<HandsComponent>(player);
|
||||
sys.TryPickup(player, item, hands.ActiveHand!);
|
||||
sys.TryPickup(player, item, hands.ActiveHandId!);
|
||||
});
|
||||
await pair.RunTicksSync(5);
|
||||
Assert.That(hands.ActiveHandEntity, Is.EqualTo(item));
|
||||
Assert.That(sys.GetActiveItem((player, hands)), Is.EqualTo(item));
|
||||
|
||||
// Open then close the box to place the player, who is holding the crowbar, inside of it
|
||||
var storage = server.System<EntityStorageSystem>();
|
||||
@@ -125,12 +125,12 @@ public sealed class HandTests
|
||||
// with the item not being in the player's hands
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
sys.TryDrop(player, item, null!);
|
||||
sys.TryDrop(player, item);
|
||||
});
|
||||
await pair.RunTicksSync(5);
|
||||
var xform = entMan.GetComponent<TransformComponent>(player);
|
||||
var itemXform = entMan.GetComponent<TransformComponent>(item);
|
||||
Assert.That(hands.ActiveHandEntity, Is.Not.EqualTo(item));
|
||||
Assert.That(sys.GetActiveItem((player, hands)), Is.Not.EqualTo(item));
|
||||
Assert.That(containerSystem.IsInSameOrNoContainer((player, xform), (item, itemXform)));
|
||||
|
||||
await server.WaitPost(() => mapSystem.DeleteMap(map.MapId));
|
||||
|
||||
@@ -120,18 +120,18 @@ public abstract partial class InteractionTest
|
||||
/// </summary>
|
||||
protected async Task DeleteHeldEntity()
|
||||
{
|
||||
if (Hands.ActiveHandEntity is { } held)
|
||||
if (HandSys.GetActiveItem((ToServer(Player), Hands)) is { } held)
|
||||
{
|
||||
await Server.WaitPost(() =>
|
||||
{
|
||||
Assert.That(HandSys.TryDrop(SEntMan.GetEntity(Player), null, false, true, Hands));
|
||||
Assert.That(HandSys.TryDrop((SEntMan.GetEntity(Player), Hands), null, false, true));
|
||||
SEntMan.DeleteEntity(held);
|
||||
SLogger.Debug($"Deleting held entity");
|
||||
});
|
||||
}
|
||||
|
||||
await RunTicks(1);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(HandSys.GetActiveItem((ToServer(Player), Hands)), Is.Null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -152,7 +152,7 @@ public abstract partial class InteractionTest
|
||||
/// <param name="enableToggleable">Whether or not to automatically enable any toggleable items</param>
|
||||
protected async Task<NetEntity> PlaceInHands(EntitySpecifier entity, bool enableToggleable = true)
|
||||
{
|
||||
if (Hands.ActiveHand == null)
|
||||
if (Hands.ActiveHandId == null)
|
||||
{
|
||||
Assert.Fail("No active hand");
|
||||
return default;
|
||||
@@ -169,7 +169,7 @@ public abstract partial class InteractionTest
|
||||
{
|
||||
var playerEnt = SEntMan.GetEntity(Player);
|
||||
|
||||
Assert.That(HandSys.TryPickup(playerEnt, item, Hands.ActiveHand, false, false, Hands));
|
||||
Assert.That(HandSys.TryPickup(playerEnt, item, Hands.ActiveHandId, false, false, false, Hands));
|
||||
|
||||
// turn on welders
|
||||
if (enableToggleable && SEntMan.TryGetComponent(item, out itemToggle) && !itemToggle.Activated)
|
||||
@@ -179,7 +179,7 @@ public abstract partial class InteractionTest
|
||||
});
|
||||
|
||||
await RunTicks(1);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.EqualTo(item));
|
||||
Assert.That(HandSys.GetActiveItem((ToServer(Player), Hands)), Is.EqualTo(item));
|
||||
if (enableToggleable && itemToggle != null)
|
||||
Assert.That(itemToggle.Activated);
|
||||
|
||||
@@ -193,7 +193,7 @@ public abstract partial class InteractionTest
|
||||
{
|
||||
entity ??= Target;
|
||||
|
||||
if (Hands.ActiveHand == null)
|
||||
if (Hands.ActiveHandId == null)
|
||||
{
|
||||
Assert.Fail("No active hand");
|
||||
return;
|
||||
@@ -212,11 +212,11 @@ public abstract partial class InteractionTest
|
||||
|
||||
await Server.WaitPost(() =>
|
||||
{
|
||||
Assert.That(HandSys.TryPickup(SEntMan.GetEntity(Player), uid.Value, Hands.ActiveHand, false, false, Hands, item));
|
||||
Assert.That(HandSys.TryPickup(ToServer(Player), uid.Value, Hands.ActiveHandId, false, false, false, Hands, item));
|
||||
});
|
||||
|
||||
await RunTicks(1);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.EqualTo(uid));
|
||||
Assert.That(HandSys.GetActiveItem((ToServer(Player), Hands)), Is.EqualTo(uid));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -224,7 +224,7 @@ public abstract partial class InteractionTest
|
||||
/// </summary>
|
||||
protected async Task Drop()
|
||||
{
|
||||
if (Hands.ActiveHandEntity == null)
|
||||
if (HandSys.GetActiveItem((ToServer(Player), Hands)) == null)
|
||||
{
|
||||
Assert.Fail("Not holding any entity to drop");
|
||||
return;
|
||||
@@ -232,11 +232,11 @@ public abstract partial class InteractionTest
|
||||
|
||||
await Server.WaitPost(() =>
|
||||
{
|
||||
Assert.That(HandSys.TryDrop(SEntMan.GetEntity(Player), handsComp: Hands));
|
||||
Assert.That(HandSys.TryDrop((ToServer(Player), Hands)));
|
||||
});
|
||||
|
||||
await RunTicks(1);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(HandSys.GetActiveItem((ToServer(Player), Hands)), Is.Null);
|
||||
}
|
||||
|
||||
#region Interact
|
||||
@@ -246,7 +246,7 @@ public abstract partial class InteractionTest
|
||||
/// </summary>
|
||||
protected async Task UseInHand()
|
||||
{
|
||||
if (Hands.ActiveHandEntity is not { } target)
|
||||
if (HandSys.GetActiveItem((ToServer(Player), Hands)) is not { } target)
|
||||
{
|
||||
Assert.Fail("Not holding any entity");
|
||||
return;
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#nullable enable
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client.Construction;
|
||||
using Content.Client.Examine;
|
||||
using Content.Client.Gameplay;
|
||||
using Content.IntegrationTests.Pair;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Stack;
|
||||
using Content.Server.Tools;
|
||||
using Content.Shared.Body.Part;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Interaction;
|
||||
@@ -135,10 +132,13 @@ public abstract partial class InteractionTest
|
||||
- type: entity
|
||||
id: InteractionTestMob
|
||||
components:
|
||||
- type: Body
|
||||
prototype: Aghost
|
||||
- type: DoAfter
|
||||
- type: Hands
|
||||
hands:
|
||||
hand_right: # only one hand, so that they do not accidentally pick up deconstruction products
|
||||
location: Right
|
||||
sortedHands:
|
||||
- hand_right
|
||||
- type: ComplexInteraction
|
||||
- type: MindContainer
|
||||
- type: Stripping
|
||||
@@ -230,20 +230,6 @@ public abstract partial class InteractionTest
|
||||
SEntMan.DeleteEntity(old.Value);
|
||||
});
|
||||
|
||||
// Ensure that the player only has one hand, so that they do not accidentally pick up deconstruction products
|
||||
await Server.WaitPost(() =>
|
||||
{
|
||||
// I lost an hour of my life trying to track down how the hell interaction tests were breaking
|
||||
// so greatz to this. Just make your own body prototype!
|
||||
var bodySystem = SEntMan.System<BodySystem>();
|
||||
var hands = bodySystem.GetBodyChildrenOfType(SEntMan.GetEntity(Player), BodyPartType.Hand).ToArray();
|
||||
|
||||
for (var i = 1; i < hands.Length; i++)
|
||||
{
|
||||
SEntMan.DeleteEntity(hands[i].Id);
|
||||
}
|
||||
});
|
||||
|
||||
// Change UI state to in-game.
|
||||
var state = Client.ResolveDependency<IStateManager>();
|
||||
await Client.WaitPost(() => state.RequestStateChange<GameplayState>());
|
||||
|
||||
@@ -17,7 +17,7 @@ public sealed class TileConstructionTests : InteractionTest
|
||||
await SetTile(null);
|
||||
await InteractUsing(Rod);
|
||||
await AssertTile(Lattice);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Null);
|
||||
await InteractUsing(Cut);
|
||||
await AssertTile(null);
|
||||
await AssertEntityLookup((Rod, 1));
|
||||
@@ -49,7 +49,7 @@ public sealed class TileConstructionTests : InteractionTest
|
||||
AssertGridCount(1);
|
||||
|
||||
// Cut lattice
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Null);
|
||||
await InteractUsing(Cut);
|
||||
await AssertTile(null);
|
||||
AssertGridCount(0);
|
||||
@@ -83,13 +83,13 @@ public sealed class TileConstructionTests : InteractionTest
|
||||
|
||||
// Lattice -> Plating
|
||||
await InteractUsing(FloorItem);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Null);
|
||||
await AssertTile(Plating);
|
||||
AssertGridCount(1);
|
||||
|
||||
// Plating -> Tile
|
||||
await InteractUsing(FloorItem);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Null);
|
||||
await AssertTile(Floor);
|
||||
AssertGridCount(1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user