Add StorageInteractionTest (#28541)
This commit is contained in:
@@ -18,7 +18,7 @@ public sealed class DispenserTest : InteractionTest
|
||||
ToggleNeedPower();
|
||||
|
||||
// Insert beaker
|
||||
await Interact("Beaker");
|
||||
await InteractUsing("Beaker");
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
|
||||
// Open BUI
|
||||
|
||||
@@ -16,10 +16,8 @@ public sealed class ComputerConstruction : InteractionTest
|
||||
await StartConstruction(Computer);
|
||||
|
||||
// Initial interaction (ghost turns into real entity)
|
||||
await Interact(Steel, 5);
|
||||
ClientAssertPrototype(ComputerFrame, ClientTarget);
|
||||
Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()];
|
||||
ClientTarget = null;
|
||||
await InteractUsing(Steel, 5);
|
||||
ClientAssertPrototype(ComputerFrame, Target);
|
||||
|
||||
// Perform construction steps
|
||||
await Interact(
|
||||
@@ -41,7 +39,7 @@ public sealed class ComputerConstruction : InteractionTest
|
||||
await StartDeconstruction(ComputerId);
|
||||
|
||||
// Initial interaction turns id computer into generic computer
|
||||
await Interact(Screw);
|
||||
await InteractUsing(Screw);
|
||||
AssertPrototype(ComputerFrame);
|
||||
|
||||
// Perform deconstruction steps
|
||||
@@ -71,7 +69,7 @@ public sealed class ComputerConstruction : InteractionTest
|
||||
await SpawnTarget(ComputerId);
|
||||
|
||||
// Initial interaction turns id computer into generic computer
|
||||
await Interact(Screw);
|
||||
await InteractUsing(Screw);
|
||||
AssertPrototype(ComputerFrame);
|
||||
|
||||
// Perform partial deconstruction steps
|
||||
|
||||
@@ -17,17 +17,14 @@ public sealed class GrilleWindowConstruction : InteractionTest
|
||||
{
|
||||
// Construct Grille
|
||||
await StartConstruction(Grille);
|
||||
await Interact(Rod, 10);
|
||||
ClientAssertPrototype(Grille, ClientTarget);
|
||||
|
||||
Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()];
|
||||
await InteractUsing(Rod, 10);
|
||||
ClientAssertPrototype(Grille, Target);
|
||||
var grille = Target;
|
||||
|
||||
// Construct Window
|
||||
await StartConstruction(Window);
|
||||
await Interact(Glass, 10);
|
||||
ClientAssertPrototype(Window, ClientTarget);
|
||||
Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()];
|
||||
await InteractUsing(Glass, 10);
|
||||
ClientAssertPrototype(Window, Target);
|
||||
|
||||
// Deconstruct Window
|
||||
await Interact(Screw, Wrench);
|
||||
@@ -35,7 +32,7 @@ public sealed class GrilleWindowConstruction : InteractionTest
|
||||
|
||||
// Deconstruct Grille
|
||||
Target = grille;
|
||||
await Interact(Cut);
|
||||
await InteractUsing(Cut);
|
||||
AssertDeleted();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,8 @@ public sealed class MachineConstruction : InteractionTest
|
||||
public async Task ConstructProtolathe()
|
||||
{
|
||||
await StartConstruction(MachineFrame);
|
||||
await Interact(Steel, 5);
|
||||
ClientAssertPrototype(Unfinished, ClientTarget);
|
||||
Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()];
|
||||
await InteractUsing(Steel, 5);
|
||||
ClientAssertPrototype(Unfinished, Target);
|
||||
await Interact(Wrench, Cable);
|
||||
AssertPrototype(MachineFrame);
|
||||
await Interact(ProtolatheBoard, Bin1, Bin1, Manipulator1, Manipulator1, Beaker, Beaker, Screw);
|
||||
@@ -51,7 +50,7 @@ public sealed class MachineConstruction : InteractionTest
|
||||
AssertPrototype(MachineFrame);
|
||||
|
||||
// Change it into an autolathe
|
||||
await Interact("AutolatheMachineCircuitboard");
|
||||
await InteractUsing("AutolatheMachineCircuitboard");
|
||||
AssertPrototype(MachineFrame);
|
||||
await Interact(Bin1, Bin1, Bin1, Manipulator1, Glass, Screw);
|
||||
AssertPrototype("Autolathe");
|
||||
|
||||
@@ -19,21 +19,21 @@ public sealed class PanelScrewing : InteractionTest
|
||||
|
||||
// Open & close panel
|
||||
Assert.That(comp.Open, Is.False);
|
||||
await Interact(Screw);
|
||||
await InteractUsing(Screw);
|
||||
Assert.That(comp.Open, Is.True);
|
||||
await Interact(Screw);
|
||||
await InteractUsing(Screw);
|
||||
Assert.That(comp.Open, Is.False);
|
||||
|
||||
// Interrupted DoAfters
|
||||
await Interact(Screw, awaitDoAfters: false);
|
||||
await InteractUsing(Screw, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
Assert.That(comp.Open, Is.False);
|
||||
await Interact(Screw);
|
||||
await InteractUsing(Screw);
|
||||
Assert.That(comp.Open, Is.True);
|
||||
await Interact(Screw, awaitDoAfters: false);
|
||||
await InteractUsing(Screw, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
Assert.That(comp.Open, Is.True);
|
||||
await Interact(Screw);
|
||||
await InteractUsing(Screw);
|
||||
Assert.That(comp.Open, Is.False);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ public sealed class PlaceableDeconstruction : InteractionTest
|
||||
{
|
||||
await StartDeconstruction("Table");
|
||||
Assert.That(Comp<PlaceableSurfaceComponent>().IsPlaceable);
|
||||
await Interact(Wrench);
|
||||
await InteractUsing(Wrench);
|
||||
AssertPrototype("TableFrame");
|
||||
await Interact(Wrench);
|
||||
await InteractUsing(Wrench);
|
||||
AssertDeleted();
|
||||
await AssertEntityLookup((Steel, 1), (Rod, 2));
|
||||
}
|
||||
|
||||
@@ -12,11 +12,10 @@ public sealed class WallConstruction : InteractionTest
|
||||
public async Task ConstructWall()
|
||||
{
|
||||
await StartConstruction(Wall);
|
||||
await Interact(Steel, 2);
|
||||
await InteractUsing(Steel, 2);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
ClientAssertPrototype(Girder, ClientTarget);
|
||||
Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()];
|
||||
await Interact(Steel, 2);
|
||||
ClientAssertPrototype(Girder, Target);
|
||||
await InteractUsing(Steel, 2);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
AssertPrototype(WallSolid);
|
||||
}
|
||||
@@ -25,7 +24,7 @@ public sealed class WallConstruction : InteractionTest
|
||||
public async Task DeconstructWall()
|
||||
{
|
||||
await StartDeconstruction(WallSolid);
|
||||
await Interact(Weld);
|
||||
await InteractUsing(Weld);
|
||||
AssertPrototype(Girder);
|
||||
await Interact(Wrench, Screw);
|
||||
AssertDeleted();
|
||||
|
||||
@@ -11,8 +11,8 @@ public sealed class WindowConstruction : InteractionTest
|
||||
public async Task ConstructWindow()
|
||||
{
|
||||
await StartConstruction(Window);
|
||||
await Interact(Glass, 5);
|
||||
ClientAssertPrototype(Window, ClientTarget);
|
||||
await InteractUsing(Glass, 5);
|
||||
ClientAssertPrototype(Window, Target);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -28,8 +28,8 @@ public sealed class WindowConstruction : InteractionTest
|
||||
public async Task ConstructReinforcedWindow()
|
||||
{
|
||||
await StartConstruction(RWindow);
|
||||
await Interact(RGlass, 5);
|
||||
ClientAssertPrototype(RWindow, ClientTarget);
|
||||
await InteractUsing(RGlass, 5);
|
||||
ClientAssertPrototype(RWindow, Target);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed class WindowRepair : InteractionTest
|
||||
Assert.That(comp.Damage.GetTotal(), Is.GreaterThan(FixedPoint2.Zero));
|
||||
|
||||
// Repair the entity
|
||||
await Interact(Weld);
|
||||
await InteractUsing(Weld);
|
||||
Assert.That(comp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero));
|
||||
|
||||
// Validate that we can still deconstruct the entity (i.e., that welding deconstruction is not blocked).
|
||||
|
||||
@@ -16,31 +16,31 @@ public sealed class DoAfterCancellationTests : InteractionTest
|
||||
public async Task CancelWallDeconstruct()
|
||||
{
|
||||
await StartDeconstruction(WallConstruction.WallSolid);
|
||||
await Interact(Weld, awaitDoAfters: false);
|
||||
await InteractUsing(Weld, awaitDoAfters: false);
|
||||
|
||||
// Failed do-after has no effect
|
||||
await CancelDoAfters();
|
||||
AssertPrototype(WallConstruction.WallSolid);
|
||||
|
||||
// Second attempt works fine
|
||||
await Interact(Weld);
|
||||
await InteractUsing(Weld);
|
||||
AssertPrototype(WallConstruction.Girder);
|
||||
|
||||
// Repeat for wrenching interaction
|
||||
AssertAnchored();
|
||||
await Interact(Wrench, awaitDoAfters: false);
|
||||
await InteractUsing(Wrench, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
AssertAnchored();
|
||||
AssertPrototype(WallConstruction.Girder);
|
||||
await Interact(Wrench);
|
||||
await InteractUsing(Wrench);
|
||||
AssertAnchored(false);
|
||||
|
||||
// Repeat for screwdriver interaction.
|
||||
AssertExists();
|
||||
await Interact(Screw, awaitDoAfters: false);
|
||||
await InteractUsing(Screw, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
AssertExists();
|
||||
await Interact(Screw);
|
||||
await InteractUsing(Screw);
|
||||
AssertDeleted();
|
||||
}
|
||||
|
||||
@@ -48,17 +48,16 @@ public sealed class DoAfterCancellationTests : InteractionTest
|
||||
public async Task CancelWallConstruct()
|
||||
{
|
||||
await StartConstruction(WallConstruction.Wall);
|
||||
await Interact(Steel, 5, awaitDoAfters: false);
|
||||
await InteractUsing(Steel, 5, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
|
||||
await Interact(Steel, 5);
|
||||
ClientAssertPrototype(WallConstruction.Girder, ClientTarget);
|
||||
Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()];
|
||||
await Interact(Steel, 5, awaitDoAfters: false);
|
||||
await InteractUsing(Steel, 5);
|
||||
ClientAssertPrototype(WallConstruction.Girder, Target);
|
||||
await InteractUsing(Steel, 5, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
AssertPrototype(WallConstruction.Girder);
|
||||
|
||||
await Interact(Steel, 5);
|
||||
await InteractUsing(Steel, 5);
|
||||
AssertPrototype(WallConstruction.WallSolid);
|
||||
}
|
||||
|
||||
@@ -66,11 +65,11 @@ public sealed class DoAfterCancellationTests : InteractionTest
|
||||
public async Task CancelTilePry()
|
||||
{
|
||||
await SetTile(Floor);
|
||||
await Interact(Pry, awaitDoAfters: false);
|
||||
await InteractUsing(Pry, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
await AssertTile(Floor);
|
||||
|
||||
await Interact(Pry);
|
||||
await InteractUsing(Pry);
|
||||
await AssertTile(Plating);
|
||||
}
|
||||
|
||||
@@ -78,7 +77,7 @@ public sealed class DoAfterCancellationTests : InteractionTest
|
||||
public async Task CancelRepeatedTilePry()
|
||||
{
|
||||
await SetTile(Floor);
|
||||
await Interact(Pry, awaitDoAfters: false);
|
||||
await InteractUsing(Pry, awaitDoAfters: false);
|
||||
await RunTicks(1);
|
||||
Assert.That(ActiveDoAfters.Count(), Is.EqualTo(1));
|
||||
await AssertTile(Floor);
|
||||
@@ -89,7 +88,7 @@ public sealed class DoAfterCancellationTests : InteractionTest
|
||||
await AssertTile(Floor);
|
||||
|
||||
// Third do after will work fine
|
||||
await Interact(Pry);
|
||||
await InteractUsing(Pry);
|
||||
Assert.That(ActiveDoAfters.Count(), Is.EqualTo(0));
|
||||
await AssertTile(Plating);
|
||||
}
|
||||
@@ -102,7 +101,7 @@ public sealed class DoAfterCancellationTests : InteractionTest
|
||||
|
||||
Assert.That(comp.IsWelded, Is.False);
|
||||
|
||||
await Interact(Weld, awaitDoAfters: false);
|
||||
await InteractUsing(Weld, awaitDoAfters: false);
|
||||
await RunTicks(1);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -120,7 +119,7 @@ public sealed class DoAfterCancellationTests : InteractionTest
|
||||
});
|
||||
|
||||
// Third do after will work fine
|
||||
await Interact(Weld);
|
||||
await InteractUsing(Weld);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ActiveDoAfters.Count(), Is.EqualTo(0));
|
||||
@@ -128,7 +127,7 @@ public sealed class DoAfterCancellationTests : InteractionTest
|
||||
});
|
||||
|
||||
// Repeat test for un-welding
|
||||
await Interact(Weld, awaitDoAfters: false);
|
||||
await InteractUsing(Weld, awaitDoAfters: false);
|
||||
await RunTicks(1);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -141,7 +140,7 @@ public sealed class DoAfterCancellationTests : InteractionTest
|
||||
Assert.That(ActiveDoAfters.Count(), Is.EqualTo(0));
|
||||
Assert.That(comp.IsWelded, Is.True);
|
||||
});
|
||||
await Interact(Weld);
|
||||
await InteractUsing(Weld);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ActiveDoAfters.Count(), Is.EqualTo(0));
|
||||
|
||||
@@ -22,7 +22,7 @@ public sealed class RemoveEncryptionKeys : InteractionTest
|
||||
});
|
||||
|
||||
// Remove the key
|
||||
await Interact(Screw);
|
||||
await InteractUsing(Screw);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.EqualTo(0));
|
||||
@@ -34,7 +34,7 @@ public sealed class RemoveEncryptionKeys : InteractionTest
|
||||
await AssertEntityLookup(("EncryptionKeyCommon", 1));
|
||||
|
||||
// Re-insert a key.
|
||||
await Interact("EncryptionKeyCentCom");
|
||||
await InteractUsing("EncryptionKeyCentCom");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.EqualTo(1));
|
||||
@@ -59,7 +59,7 @@ public sealed class RemoveEncryptionKeys : InteractionTest
|
||||
});
|
||||
|
||||
// cannot remove keys without opening panel
|
||||
await Interact(Pry);
|
||||
await InteractUsing(Pry);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.GreaterThan(0));
|
||||
@@ -68,7 +68,7 @@ public sealed class RemoveEncryptionKeys : InteractionTest
|
||||
});
|
||||
|
||||
// Open panel
|
||||
await Interact(Screw);
|
||||
await InteractUsing(Screw);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(panel.Open, Is.True);
|
||||
@@ -79,7 +79,7 @@ public sealed class RemoveEncryptionKeys : InteractionTest
|
||||
});
|
||||
|
||||
// Now remove the keys
|
||||
await Interact(Pry);
|
||||
await InteractUsing(Pry);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.EqualTo(0));
|
||||
@@ -87,7 +87,7 @@ public sealed class RemoveEncryptionKeys : InteractionTest
|
||||
});
|
||||
|
||||
// Reinsert a key
|
||||
await Interact("EncryptionKeyCentCom");
|
||||
await InteractUsing("EncryptionKeyCentCom");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.EqualTo(1));
|
||||
@@ -97,7 +97,7 @@ public sealed class RemoveEncryptionKeys : InteractionTest
|
||||
});
|
||||
|
||||
// Remove it again
|
||||
await Interact(Pry);
|
||||
await InteractUsing(Pry);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.EqualTo(0));
|
||||
@@ -106,7 +106,7 @@ public sealed class RemoveEncryptionKeys : InteractionTest
|
||||
|
||||
// Prying again will start deconstructing the machine.
|
||||
AssertPrototype("TelecomServerFilled");
|
||||
await Interact(Pry);
|
||||
await InteractUsing(Pry);
|
||||
AssertPrototype("MachineFrame");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public abstract partial class InteractionTest
|
||||
public int Quantity;
|
||||
|
||||
/// <summary>
|
||||
/// If true, a check has been performed to see if the prototype ia an entity prototype with a stack component,
|
||||
/// If true, a check has been performed to see if the prototype is an entity prototype with a stack component,
|
||||
/// in which case the specifier was converted into a stack-specifier
|
||||
/// </summary>
|
||||
public bool Converted;
|
||||
@@ -100,7 +100,7 @@ public abstract partial class InteractionTest
|
||||
|
||||
if (!ProtoMan.TryIndex<EntityPrototype>(spec.Prototype, out var entProto))
|
||||
{
|
||||
Assert.Fail($"Unkown prototype: {spec.Prototype}");
|
||||
Assert.Fail($"Unknown prototype: {spec.Prototype}");
|
||||
return default;
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ public abstract partial class InteractionTest
|
||||
|
||||
/// <summary>
|
||||
/// Convert an entity-uid to a matching entity specifier. Useful when doing entity lookups & checking that the
|
||||
/// right quantity of entities/materials werre produced. Returns null if passed an entity with a null prototype.
|
||||
/// right quantity of entities/materials were produced. Returns null if passed an entity with a null prototype.
|
||||
/// </summary>
|
||||
protected EntitySpecifier? ToEntitySpecifier(EntityUid uid)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ using Content.Shared.Construction.Prototypes;
|
||||
using Content.Shared.Gravity;
|
||||
using Content.Shared.Item;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
@@ -44,8 +45,9 @@ public abstract partial class InteractionTest
|
||||
return;
|
||||
|
||||
var comp = CEntMan.GetComponent<ConstructionGhostComponent>(clientTarget!.Value);
|
||||
ClientTarget = clientTarget;
|
||||
ConstructionGhostId = comp.Owner.Id;
|
||||
Target = CEntMan.GetNetEntity(clientTarget.Value);
|
||||
Assert.That(Target.Value.IsClientSide());
|
||||
ConstructionGhostId = clientTarget.Value.GetHashCode();
|
||||
});
|
||||
|
||||
await RunTicks(1);
|
||||
@@ -129,21 +131,20 @@ public abstract partial class InteractionTest
|
||||
/// <summary>
|
||||
/// Place an entity prototype into the players hand. Deletes any currently held entity.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Automatically enables welders.
|
||||
/// </remarks>
|
||||
protected async Task<NetEntity> PlaceInHands(string id, int quantity = 1, bool enableWelder = true)
|
||||
/// <param name="id">The entity or stack prototype to spawn and place into the users hand</param>
|
||||
/// <param name="quantity">The number of entities to spawn. If the prototype is a stack, this sets the stack count.</param>
|
||||
/// <param name="enableToggleable">Whether or not to automatically enable any toggleable items</param>
|
||||
protected async Task<NetEntity> PlaceInHands(string id, int quantity = 1, bool enableToggleable = true)
|
||||
{
|
||||
return await PlaceInHands((id, quantity), enableWelder);
|
||||
return await PlaceInHands((id, quantity), enableToggleable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Place an entity prototype into the players hand. Deletes any currently held entity.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Automatically enables welders.
|
||||
/// </remarks>
|
||||
protected async Task<NetEntity> PlaceInHands(EntitySpecifier entity, bool enableWelder = true)
|
||||
/// <param name="entity">The entity type & quantity to spawn and place into the users hand</param>
|
||||
/// <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)
|
||||
{
|
||||
@@ -165,7 +166,7 @@ public abstract partial class InteractionTest
|
||||
Assert.That(HandSys.TryPickup(playerEnt, item, Hands.ActiveHand, false, false, Hands));
|
||||
|
||||
// turn on welders
|
||||
if (enableWelder && SEntMan.TryGetComponent(item, out itemToggle) && !itemToggle.Activated)
|
||||
if (enableToggleable && SEntMan.TryGetComponent(item, out itemToggle) && !itemToggle.Activated)
|
||||
{
|
||||
Assert.That(ItemToggleSys.TryActivate(item, playerEnt, itemToggle: itemToggle));
|
||||
}
|
||||
@@ -173,7 +174,7 @@ public abstract partial class InteractionTest
|
||||
|
||||
await RunTicks(1);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.EqualTo(item));
|
||||
if (enableWelder && itemToggle != null)
|
||||
if (enableToggleable && itemToggle != null)
|
||||
Assert.That(itemToggle.Activated);
|
||||
|
||||
return SEntMan.GetNetEntity(item);
|
||||
@@ -254,21 +255,20 @@ public abstract partial class InteractionTest
|
||||
/// <summary>
|
||||
/// Place an entity prototype into the players hand and interact with the given entity (or target position)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Empty strings imply empty hands.
|
||||
/// </remarks>
|
||||
protected async Task Interact(string id, int quantity = 1, bool shouldSucceed = true, bool awaitDoAfters = true)
|
||||
/// <param name="id">The entity or stack prototype to spawn and place into the users hand</param>
|
||||
/// <param name="quantity">The number of entities to spawn. If the prototype is a stack, this sets the stack count.</param>
|
||||
/// <param name="awaitDoAfters">Whether or not to wait for any do-afters to complete</param>
|
||||
protected async Task InteractUsing(string id, int quantity = 1, bool awaitDoAfters = true)
|
||||
{
|
||||
await Interact((id, quantity), shouldSucceed, awaitDoAfters);
|
||||
await InteractUsing((id, quantity), awaitDoAfters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Place an entity prototype into the players hand and interact with the given entity (or target position)
|
||||
/// Place an entity prototype into the players hand and interact with the given entity (or target position).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Empty strings imply empty hands.
|
||||
/// </remarks>
|
||||
protected async Task Interact(EntitySpecifier entity, bool shouldSucceed = true, bool awaitDoAfters = true)
|
||||
/// <param name="entity">The entity type & quantity to spawn and place into the users hand</param>
|
||||
/// <param name="awaitDoAfters">Whether or not to wait for any do-afters to complete</param>
|
||||
protected async Task InteractUsing(EntitySpecifier entity, bool awaitDoAfters = true)
|
||||
{
|
||||
// For every interaction, we will also examine the entity, just in case this breaks something, somehow.
|
||||
// (e.g., servers attempt to assemble construction examine hints).
|
||||
@@ -278,38 +278,80 @@ public abstract partial class InteractionTest
|
||||
}
|
||||
|
||||
await PlaceInHands(entity);
|
||||
await Interact(shouldSucceed, awaitDoAfters);
|
||||
await Interact(awaitDoAfters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interact with an entity using the currently held entity.
|
||||
/// </summary>
|
||||
protected async Task Interact(bool shouldSucceed = true, bool awaitDoAfters = true)
|
||||
/// <param name="awaitDoAfters">Whether or not to wait for any do-afters to complete</param>
|
||||
protected async Task Interact(bool awaitDoAfters = true)
|
||||
{
|
||||
var clientTarget = ClientTarget;
|
||||
|
||||
if ((clientTarget?.IsValid() != true || CEntMan.Deleted(clientTarget)) && (Target == null || Target.Value.IsValid()))
|
||||
if (Target == null || !Target.Value.IsClientSide())
|
||||
{
|
||||
await Server.WaitPost(() => InteractSys.UserInteraction(SEntMan.GetEntity(Player), SEntMan.GetCoordinates(TargetCoords), SEntMan.GetEntity(Target)));
|
||||
await RunTicks(1);
|
||||
await Interact(Target, TargetCoords, awaitDoAfters);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The entity is client-side, so attempt to start construction
|
||||
var clientEnt = ClientTarget ?? CEntMan.GetEntity(Target);
|
||||
|
||||
await Client.WaitPost(() => CConSys.TryStartConstruction(clientEnt!.Value));
|
||||
await RunTicks(5);
|
||||
}
|
||||
// The target is a client-side entity, so we will just attempt to start construction under the assumption that
|
||||
// it is a construction ghost.
|
||||
|
||||
await Client.WaitPost(() => CConSys.TryStartConstruction(CTarget!.Value));
|
||||
await RunTicks(5);
|
||||
|
||||
if (awaitDoAfters)
|
||||
await AwaitDoAfters(shouldSucceed);
|
||||
await AwaitDoAfters();
|
||||
|
||||
await CheckTargetChange(shouldSucceed && awaitDoAfters);
|
||||
await CheckTargetChange();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Interact(EntityUid?,EntityCoordinates,bool)"/>
|
||||
protected async Task Interact(NetEntity? target, NetCoordinates coordinates, bool awaitDoAfters = true)
|
||||
{
|
||||
Assert.That(SEntMan.TryGetEntity(target, out var sTarget) || target == null);
|
||||
var coords = SEntMan.GetCoordinates(coordinates);
|
||||
Assert.That(coords.IsValid(SEntMan));
|
||||
await Interact(sTarget, coords, awaitDoAfters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Variant of <see cref="InteractUsing"/> that performs several interactions using different entities.
|
||||
/// Interact with an entity using the currently held entity.
|
||||
/// </summary>
|
||||
protected async Task Interact(EntityUid? target, EntityCoordinates coordinates, bool awaitDoAfters = true)
|
||||
{
|
||||
Assert.That(SEntMan.TryGetEntity(Player, out var player));
|
||||
|
||||
await Server.WaitPost(() => InteractSys.UserInteraction(player!.Value, coordinates, target));
|
||||
await RunTicks(1);
|
||||
|
||||
if (awaitDoAfters)
|
||||
await AwaitDoAfters();
|
||||
|
||||
await CheckTargetChange();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activate an entity.
|
||||
/// </summary>
|
||||
protected async Task Activate(NetEntity? target = null, bool awaitDoAfters = true)
|
||||
{
|
||||
target ??= Target;
|
||||
Assert.That(target, Is.Not.Null);
|
||||
Assert.That(SEntMan.TryGetEntity(target!.Value, out var sTarget));
|
||||
Assert.That(SEntMan.TryGetEntity(Player, out var player));
|
||||
|
||||
await Server.WaitPost(() => InteractSys.InteractionActivate(player!.Value, sTarget!.Value));
|
||||
await RunTicks(1);
|
||||
|
||||
if (awaitDoAfters)
|
||||
await AwaitDoAfters();
|
||||
|
||||
await CheckTargetChange();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Variant of <see cref="InteractUsing(string,int,bool)"/> that performs several interactions using different entities.
|
||||
/// Useful for quickly finishing multiple construction steps.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Empty strings imply empty hands.
|
||||
@@ -318,7 +360,7 @@ public abstract partial class InteractionTest
|
||||
{
|
||||
foreach (var spec in specifiers)
|
||||
{
|
||||
await Interact(spec);
|
||||
await InteractUsing(spec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +380,7 @@ public abstract partial class InteractionTest
|
||||
/// <summary>
|
||||
/// Wait for any currently active DoAfters to finish.
|
||||
/// </summary>
|
||||
protected async Task AwaitDoAfters(bool shouldSucceed = true, int maxExpected = 1)
|
||||
protected async Task AwaitDoAfters(int maxExpected = 1)
|
||||
{
|
||||
if (!ActiveDoAfters.Any())
|
||||
return;
|
||||
@@ -353,13 +395,12 @@ public abstract partial class InteractionTest
|
||||
await RunTicks(10);
|
||||
}
|
||||
|
||||
if (!shouldSucceed)
|
||||
return;
|
||||
|
||||
foreach (var doAfter in doAfters)
|
||||
{
|
||||
Assert.That(!doAfter.Cancelled);
|
||||
}
|
||||
|
||||
await RunTicks(5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -398,39 +439,28 @@ public abstract partial class InteractionTest
|
||||
/// Check if the test's target entity has changed. E.g., construction interactions will swap out entities while
|
||||
/// a structure is being built.
|
||||
/// </summary>
|
||||
protected async Task CheckTargetChange(bool shouldSucceed)
|
||||
protected async Task CheckTargetChange()
|
||||
{
|
||||
if (Target == null)
|
||||
return;
|
||||
|
||||
var target = Target.Value;
|
||||
var originalTarget = Target.Value;
|
||||
await RunTicks(5);
|
||||
|
||||
if (ClientTarget != null && CEntMan.IsClientSide(ClientTarget.Value))
|
||||
if (Target.Value.IsClientSide() && CTestSystem.Ghosts.TryGetValue(ConstructionGhostId, out var newWeh))
|
||||
{
|
||||
Assert.That(CEntMan.Deleted(ClientTarget.Value), Is.EqualTo(shouldSucceed),
|
||||
$"Construction ghost was {(shouldSucceed ? "not deleted" : "deleted")}.");
|
||||
|
||||
if (shouldSucceed)
|
||||
{
|
||||
Assert.That(CTestSystem.Ghosts.TryGetValue(ConstructionGhostId, out var newWeh),
|
||||
$"Failed to get construction entity from ghost Id");
|
||||
|
||||
await Client.WaitPost(() => CLogger.Debug($"Construction ghost {ConstructionGhostId} became entity {newWeh}"));
|
||||
Target = newWeh;
|
||||
}
|
||||
CLogger.Debug($"Construction ghost {ConstructionGhostId} became entity {newWeh}");
|
||||
Target = newWeh;
|
||||
}
|
||||
|
||||
if (STestSystem.EntChanges.TryGetValue(Target.Value, out var newServerWeh))
|
||||
{
|
||||
await Server.WaitPost(
|
||||
() => SLogger.Debug($"Construction entity {Target.Value} changed to {newServerWeh}"));
|
||||
|
||||
SLogger.Debug($"Construction entity {Target.Value} changed to {newServerWeh}");
|
||||
Target = newServerWeh;
|
||||
}
|
||||
|
||||
if (Target != target)
|
||||
await CheckTargetChange(shouldSucceed);
|
||||
if (Target != originalTarget)
|
||||
await CheckTargetChange();
|
||||
}
|
||||
|
||||
#region Asserts
|
||||
@@ -444,16 +474,10 @@ public abstract partial class InteractionTest
|
||||
return;
|
||||
}
|
||||
|
||||
var meta = SEntMan.GetComponent<MetaDataComponent>(SEntMan.GetEntity(target.Value));
|
||||
var meta = CEntMan.GetComponent<MetaDataComponent>(CEntMan.GetEntity(target.Value));
|
||||
Assert.That(meta.EntityPrototype?.ID, Is.EqualTo(prototype));
|
||||
}
|
||||
|
||||
protected void ClientAssertPrototype(string? prototype, EntityUid? target)
|
||||
{
|
||||
var netEnt = CTestSystem.Ghosts[target.GetHashCode()];
|
||||
AssertPrototype(prototype, netEnt);
|
||||
}
|
||||
|
||||
protected void AssertPrototype(string? prototype, NetEntity? target = null)
|
||||
{
|
||||
target ??= Target;
|
||||
@@ -699,6 +723,8 @@ public abstract partial class InteractionTest
|
||||
protected IEnumerable<Shared.DoAfter.DoAfter> ActiveDoAfters
|
||||
=> DoAfters.DoAfters.Values.Where(x => !x.Cancelled && !x.Completed);
|
||||
|
||||
#region Component
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method to get components on the target. Returns SERVER-SIDE components.
|
||||
/// </summary>
|
||||
@@ -708,9 +734,23 @@ public abstract partial class InteractionTest
|
||||
if (target == null)
|
||||
Assert.Fail("No target specified");
|
||||
|
||||
return SEntMan.GetComponent<T>(SEntMan.GetEntity(target!.Value));
|
||||
return SEntMan.GetComponent<T>(ToServer(target!.Value));
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Comp{T}"/>
|
||||
protected bool TryComp<T>(NetEntity? target, [NotNullWhen(true)] out T? comp) where T : IComponent
|
||||
{
|
||||
return SEntMan.TryGetComponent(ToServer(target), out comp);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Comp{T}"/>
|
||||
protected bool TryComp<T>([NotNullWhen(true)] out T? comp) where T : IComponent
|
||||
{
|
||||
return SEntMan.TryGetComponent(STarget, out comp);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Set the tile at the target position to some prototype.
|
||||
/// </summary>
|
||||
@@ -833,23 +873,70 @@ public abstract partial class InteractionTest
|
||||
return true;
|
||||
}
|
||||
|
||||
protected bool IsUiOpen(Enum key)
|
||||
{
|
||||
if (!TryComp(Player, out UserInterfaceUserComponent? user))
|
||||
return false;
|
||||
|
||||
foreach (var keys in user.OpenInterfaces.Values)
|
||||
{
|
||||
if (keys.Contains(key))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI
|
||||
|
||||
/// <summary>
|
||||
/// Presses and releases a button on some client-side window. Will fail if the button cannot be found.
|
||||
/// Attempts to find, and then presses and releases a control on some client-side window.
|
||||
/// Will fail if the control cannot be found.
|
||||
/// </summary>
|
||||
protected async Task ClickControl<TWindow>(string name) where TWindow : BaseWindow
|
||||
protected async Task ClickControl<TWindow, TControl>(string name, BoundKeyFunction? function = null)
|
||||
where TWindow : BaseWindow
|
||||
where TControl : Control
|
||||
{
|
||||
await ClickControl(GetControl<TWindow, Control>(name));
|
||||
var window = GetWindow<TWindow>();
|
||||
var control = GetControlFromField<TControl>(name, window);
|
||||
await ClickControl(control, function);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates a click and release at the center of some UI Constrol.
|
||||
/// Attempts to find, and then presses and releases a control on some client-side widget.
|
||||
/// Will fail if the control cannot be found.
|
||||
/// </summary>
|
||||
protected async Task ClickControl(Control control)
|
||||
protected async Task ClickWidgetControl<TWidget, TControl>(string name, BoundKeyFunction? function = null)
|
||||
where TWidget : UIWidget, new()
|
||||
where TControl : Control
|
||||
{
|
||||
var widget = GetWidget<TWidget>();
|
||||
var control = GetControlFromField<TControl>(name, widget);
|
||||
await ClickControl(control, function);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ClickControl{TWindow,TControl}"/>
|
||||
protected async Task ClickControl<TWindow>(string name, BoundKeyFunction? function = null)
|
||||
where TWindow : BaseWindow
|
||||
{
|
||||
await ClickControl<TWindow, Control>(name, function);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ClickWidgetControl{TWidget,TControl}"/>
|
||||
protected async Task ClickWidgetControl<TWidget>(string name, BoundKeyFunction? function = null)
|
||||
where TWidget : UIWidget, new()
|
||||
{
|
||||
await ClickWidgetControl<TWidget, Control>(name, function);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates a click and release at the center of some UI control.
|
||||
/// </summary>
|
||||
protected async Task ClickControl(Control control, BoundKeyFunction? function = null)
|
||||
{
|
||||
function ??= EngineKeyFunctions.UIClick;
|
||||
var screenCoords = new ScreenCoordinates(
|
||||
control.GlobalPixelPosition + control.PixelSize / 2,
|
||||
control.Window?.Id ?? default);
|
||||
@@ -858,7 +945,7 @@ public abstract partial class InteractionTest
|
||||
var relativePixelPos = screenCoords.Position - control.GlobalPixelPosition;
|
||||
|
||||
var args = new GUIBoundKeyEventArgs(
|
||||
EngineKeyFunctions.UIClick,
|
||||
function.Value,
|
||||
BoundKeyState.Down,
|
||||
screenCoords,
|
||||
default,
|
||||
@@ -869,7 +956,7 @@ public abstract partial class InteractionTest
|
||||
await RunTicks(1);
|
||||
|
||||
args = new GUIBoundKeyEventArgs(
|
||||
EngineKeyFunctions.UIClick,
|
||||
function.Value,
|
||||
BoundKeyState.Up,
|
||||
screenCoords,
|
||||
default,
|
||||
@@ -881,31 +968,26 @@ public abstract partial class InteractionTest
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to find a control on some client-side window. Will fail if the control cannot be found.
|
||||
/// Attempt to retrieve a control by looking for a field on some other control.
|
||||
/// </summary>
|
||||
protected TControl GetControl<TWindow, TControl>(string name)
|
||||
where TWindow : BaseWindow
|
||||
/// <remarks>
|
||||
/// Will fail if the control cannot be found.
|
||||
/// </remarks>
|
||||
protected TControl GetControlFromField<TControl>(string name, Control parent)
|
||||
where TControl : Control
|
||||
{
|
||||
var control = GetControl<TWindow>(name);
|
||||
Assert.That(control.GetType().IsAssignableTo(typeof(TControl)));
|
||||
return (TControl) control;
|
||||
}
|
||||
|
||||
protected Control GetControl<TWindow>(string name) where TWindow : BaseWindow
|
||||
{
|
||||
const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
var field = typeof(TWindow).GetField(name, flags);
|
||||
var prop = typeof(TWindow).GetProperty(name, flags);
|
||||
var parentType = parent.GetType();
|
||||
var field = parentType.GetField(name, flags);
|
||||
var prop = parentType.GetProperty(name, flags);
|
||||
|
||||
if (field == null && prop == null)
|
||||
{
|
||||
Assert.Fail($"Window {typeof(TWindow).Name} does not have a field or property named {name}");
|
||||
Assert.Fail($"Window {parentType.Name} does not have a field or property named {name}");
|
||||
return default!;
|
||||
}
|
||||
|
||||
var window = GetWindow<TWindow>();
|
||||
var fieldOrProp = field?.GetValue(window) ?? prop?.GetValue(window);
|
||||
var fieldOrProp = field?.GetValue(parent) ?? prop?.GetValue(parent);
|
||||
|
||||
if (fieldOrProp is not Control control)
|
||||
{
|
||||
@@ -913,7 +995,59 @@ public abstract partial class InteractionTest
|
||||
return default!;
|
||||
}
|
||||
|
||||
return control;
|
||||
Assert.That(control.GetType().IsAssignableTo(typeof(TControl)));
|
||||
return (TControl) control;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to retrieve a control that matches some predicate by iterating through a control's children.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Will fail if the control cannot be found.
|
||||
/// </remarks>
|
||||
protected TControl GetControlFromChildren<TControl>(Func<TControl, bool> predicate, Control parent, bool recursive = true)
|
||||
where TControl : Control
|
||||
{
|
||||
if (TryGetControlFromChildren(predicate, parent, out var control, recursive))
|
||||
return control;
|
||||
|
||||
Assert.Fail($"Failed to find a {nameof(TControl)} that satisfies the predicate in {parent.Name}");
|
||||
return default!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to retrieve a control of a given type by iterating through a control's children.
|
||||
/// </summary>
|
||||
protected TControl GetControlFromChildren<TControl>(Control parent, bool recursive = false)
|
||||
where TControl : Control
|
||||
{
|
||||
return GetControlFromChildren<TControl>(static _ => true, parent, recursive);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to retrieve a control that matches some predicate by iterating through a control's children.
|
||||
/// </summary>
|
||||
protected bool TryGetControlFromChildren<TControl>(
|
||||
Func<TControl, bool> predicate,
|
||||
Control parent,
|
||||
[NotNullWhen(true)] out TControl? control,
|
||||
bool recursive = true)
|
||||
where TControl : Control
|
||||
{
|
||||
foreach (var ctrl in parent.Children)
|
||||
{
|
||||
if (ctrl is TControl cast && predicate(cast))
|
||||
{
|
||||
control = cast;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (recursive && TryGetControlFromChildren(predicate, ctrl, out control))
|
||||
return true;
|
||||
}
|
||||
|
||||
control = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -944,7 +1078,6 @@ public abstract partial class InteractionTest
|
||||
return window != null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to find a currently open client-side window.
|
||||
/// </summary>
|
||||
@@ -962,6 +1095,34 @@ public abstract partial class InteractionTest
|
||||
return window != null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to find client-side UI widget.
|
||||
/// </summary>
|
||||
protected UIWidget GetWidget<TWidget>()
|
||||
where TWidget : UIWidget, new()
|
||||
{
|
||||
if (TryFindWidget(out TWidget? widget))
|
||||
return widget;
|
||||
|
||||
Assert.Fail($"Could not find a {typeof(TWidget).Name} widget");
|
||||
return default!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to find client-side UI widget.
|
||||
/// </summary>
|
||||
private bool TryFindWidget<TWidget>([NotNullWhen(true)] out TWidget? uiWidget)
|
||||
where TWidget : UIWidget, new()
|
||||
{
|
||||
uiWidget = null;
|
||||
var screen = UiMan.ActiveScreen;
|
||||
if (screen == null)
|
||||
return false;
|
||||
|
||||
return screen.TryGetWidget(out uiWidget);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Power
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#nullable enable
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
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;
|
||||
@@ -24,6 +26,7 @@ using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.UnitTesting;
|
||||
using Content.Shared.Item.ItemToggle;
|
||||
using Robust.Client.State;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Interaction;
|
||||
|
||||
@@ -64,15 +67,12 @@ public abstract partial class InteractionTest
|
||||
/// The player entity that performs all these interactions. Defaults to an admin-observer with 1 hand.
|
||||
/// </summary>
|
||||
protected NetEntity Player;
|
||||
|
||||
protected EntityUid SPlayer => ToServer(Player);
|
||||
protected EntityUid CPlayer => ToClient(Player);
|
||||
protected EntityUid SPlayer;
|
||||
protected EntityUid CPlayer;
|
||||
|
||||
protected ICommonSession ClientSession = default!;
|
||||
protected ICommonSession ServerSession = default!;
|
||||
|
||||
public EntityUid? ClientTarget;
|
||||
|
||||
/// <summary>
|
||||
/// The current target entity. This is the default entity for various helper functions.
|
||||
/// </summary>
|
||||
@@ -108,6 +108,7 @@ public abstract partial class InteractionTest
|
||||
protected InteractionTestSystem STestSystem = default!;
|
||||
protected SharedTransformSystem Transform = default!;
|
||||
protected ISawmill SLogger = default!;
|
||||
protected SharedUserInterfaceSystem SUiSys = default!;
|
||||
|
||||
// CLIENT dependencies
|
||||
protected IEntityManager CEntMan = default!;
|
||||
@@ -119,6 +120,7 @@ public abstract partial class InteractionTest
|
||||
protected ExamineSystem ExamineSys = default!;
|
||||
protected InteractionTestSystem CTestSystem = default!;
|
||||
protected ISawmill CLogger = default!;
|
||||
protected SharedUserInterfaceSystem CUiSys = default!;
|
||||
|
||||
// player components
|
||||
protected HandsComponent Hands = default!;
|
||||
@@ -168,6 +170,7 @@ public abstract partial class InteractionTest
|
||||
STestSystem = SEntMan.System<InteractionTestSystem>();
|
||||
Stack = SEntMan.System<StackSystem>();
|
||||
SLogger = Server.ResolveDependency<ILogManager>().RootSawmill;
|
||||
SUiSys = Client.System<SharedUserInterfaceSystem>();
|
||||
|
||||
// client dependencies
|
||||
CEntMan = Client.ResolveDependency<IEntityManager>();
|
||||
@@ -179,6 +182,7 @@ public abstract partial class InteractionTest
|
||||
CConSys = CEntMan.System<ConstructionSystem>();
|
||||
ExamineSys = CEntMan.System<ExamineSystem>();
|
||||
CLogger = Client.ResolveDependency<ILogManager>().RootSawmill;
|
||||
CUiSys = Client.System<SharedUserInterfaceSystem>();
|
||||
|
||||
// Setup map.
|
||||
await Pair.CreateTestMap();
|
||||
@@ -204,15 +208,16 @@ public abstract partial class InteractionTest
|
||||
|
||||
old = cPlayerMan.LocalEntity;
|
||||
Player = SEntMan.GetNetEntity(SEntMan.SpawnEntity(PlayerPrototype, SEntMan.GetCoordinates(PlayerCoords)));
|
||||
var serverPlayerEnt = SEntMan.GetEntity(Player);
|
||||
Server.PlayerMan.SetAttachedEntity(ServerSession, serverPlayerEnt);
|
||||
Hands = SEntMan.GetComponent<HandsComponent>(serverPlayerEnt);
|
||||
DoAfters = SEntMan.GetComponent<DoAfterComponent>(serverPlayerEnt);
|
||||
SPlayer = SEntMan.GetEntity(Player);
|
||||
Server.PlayerMan.SetAttachedEntity(ServerSession, SPlayer);
|
||||
Hands = SEntMan.GetComponent<HandsComponent>(SPlayer);
|
||||
DoAfters = SEntMan.GetComponent<DoAfterComponent>(SPlayer);
|
||||
});
|
||||
|
||||
// Check player got attached.
|
||||
await RunTicks(5);
|
||||
Assert.That(CEntMan.GetNetEntity(cPlayerMan.LocalEntity), Is.EqualTo(Player));
|
||||
CPlayer = ToClient(Player);
|
||||
Assert.That(cPlayerMan.LocalEntity, Is.EqualTo(CPlayer));
|
||||
|
||||
// Delete old player entity.
|
||||
await Server.WaitPost(() =>
|
||||
@@ -235,6 +240,10 @@ public abstract partial class InteractionTest
|
||||
}
|
||||
});
|
||||
|
||||
// Change UI state to in-game.
|
||||
var state = Client.ResolveDependency<IStateManager>();
|
||||
await Client.WaitPost(() => state.RequestStateChange<GameplayState>());
|
||||
|
||||
// Final player asserts/checks.
|
||||
await Pair.ReallyBeIdle(5);
|
||||
Assert.Multiple(() =>
|
||||
|
||||
@@ -22,32 +22,32 @@ public sealed class ModularGrenadeTests : InteractionTest
|
||||
Target = SEntMan.GetNetEntity(await FindEntity("ModularGrenade"));
|
||||
|
||||
await Drop();
|
||||
await Interact(Cable);
|
||||
await InteractUsing(Cable);
|
||||
|
||||
// Insert & remove trigger
|
||||
AssertComp<OnUseTimerTriggerComponent>(false);
|
||||
await Interact(Trigger);
|
||||
await InteractUsing(Trigger);
|
||||
AssertComp<OnUseTimerTriggerComponent>();
|
||||
await FindEntity(Trigger, LookupFlags.Uncontained, shouldSucceed: false);
|
||||
await Interact(Pry);
|
||||
await InteractUsing(Pry);
|
||||
AssertComp<OnUseTimerTriggerComponent>(false);
|
||||
|
||||
// Trigger was dropped to floor, not deleted.
|
||||
await FindEntity(Trigger, LookupFlags.Uncontained);
|
||||
|
||||
// Re-insert
|
||||
await Interact(Trigger);
|
||||
await InteractUsing(Trigger);
|
||||
AssertComp<OnUseTimerTriggerComponent>();
|
||||
|
||||
// Insert & remove payload.
|
||||
await Interact(Payload);
|
||||
await InteractUsing(Payload);
|
||||
await FindEntity(Payload, LookupFlags.Uncontained, shouldSucceed: false);
|
||||
await Interact(Pry);
|
||||
await InteractUsing(Pry);
|
||||
var ent = await FindEntity(Payload, LookupFlags.Uncontained);
|
||||
await Delete(ent);
|
||||
|
||||
// successfully insert a second time
|
||||
await Interact(Payload);
|
||||
await InteractUsing(Payload);
|
||||
ent = await FindEntity(Payload);
|
||||
var sys = SEntMan.System<SharedContainerSystem>();
|
||||
Assert.That(sys.IsEntityInContainer(ent));
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
using Content.Client.UserInterface.Systems.Hotbar.Widgets;
|
||||
using Content.Client.UserInterface.Systems.Storage.Controls;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.PDA;
|
||||
using Content.Shared.Storage;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Storage;
|
||||
|
||||
public sealed class StorageInteractionTest : InteractionTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Check that players can interact with items in storage if the storage UI is open
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task UiInteractTest()
|
||||
{
|
||||
var sys = Server.System<SharedContainerSystem>();
|
||||
|
||||
await SpawnTarget("ClothingBackpack");
|
||||
var backpack = ToServer(Target);
|
||||
|
||||
// Initially no BUI is open.
|
||||
Assert.That(IsUiOpen(StorageComponent.StorageUiKey.Key), Is.False);
|
||||
Assert.That(IsUiOpen(PdaUiKey.Key), Is.False);
|
||||
|
||||
// Activating the backpack opens the UI
|
||||
await Activate();
|
||||
Assert.That(IsUiOpen(StorageComponent.StorageUiKey.Key), Is.True);
|
||||
Assert.That(IsUiOpen(PdaUiKey.Key), Is.False);
|
||||
|
||||
// Pick up a PDA
|
||||
var pda = await PlaceInHands("PassengerPDA");
|
||||
var sPda = ToServer(pda);
|
||||
Assert.That(sys.IsEntityInContainer(sPda), Is.True);
|
||||
Assert.That(sys.TryGetContainingContainer((sPda, null), out var container));
|
||||
Assert.That(container!.Owner, Is.EqualTo(SPlayer));
|
||||
|
||||
// Insert the PDA into the backpack
|
||||
await Interact();
|
||||
Assert.That(sys.TryGetContainingContainer((sPda, null), out container));
|
||||
Assert.That(container!.Owner, Is.EqualTo(backpack));
|
||||
|
||||
// Use "e" / ActivateInWorld to open the PDA UI while it is still in the backpack.
|
||||
var ctrl = GetStorageControl(pda);
|
||||
await ClickControl(ctrl, ContentKeyFunctions.ActivateItemInWorld);
|
||||
await RunTicks(10);
|
||||
Assert.That(IsUiOpen(StorageComponent.StorageUiKey.Key), Is.True);
|
||||
Assert.That(IsUiOpen(PdaUiKey.Key), Is.True);
|
||||
|
||||
// Click on the pda to pick it up and remove it from the backpack.
|
||||
await ClickControl(ctrl, ContentKeyFunctions.MoveStoredItem);
|
||||
await RunTicks(10);
|
||||
Assert.That(sys.TryGetContainingContainer((sPda, null), out container));
|
||||
Assert.That(container!.Owner, Is.EqualTo(SPlayer));
|
||||
|
||||
// UIs should still be open
|
||||
Assert.That(IsUiOpen(StorageComponent.StorageUiKey.Key), Is.True);
|
||||
Assert.That(IsUiOpen(PdaUiKey.Key), Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the control that corresponds to the given entity in the currently open storage UI.
|
||||
/// </summary>
|
||||
private ItemGridPiece GetStorageControl(NetEntity target)
|
||||
{
|
||||
var uid = ToClient(target);
|
||||
var hotbar = GetWidget<HotbarGui>();
|
||||
var storageContainer = GetControlFromField<Control>(nameof(HotbarGui.StorageContainer), hotbar);
|
||||
return GetControlFromChildren<ItemGridPiece>(c => c.Entity == uid, storageContainer);
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,10 @@ public sealed class TileConstructionTests : InteractionTest
|
||||
await AssertTile(Plating, PlayerCoords);
|
||||
AssertGridCount(1);
|
||||
await SetTile(null);
|
||||
await Interact(Rod);
|
||||
await InteractUsing(Rod);
|
||||
await AssertTile(Lattice);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
await Interact(Cut);
|
||||
await InteractUsing(Cut);
|
||||
await AssertTile(null);
|
||||
await AssertEntityLookup((Rod, 1));
|
||||
AssertGridCount(1);
|
||||
@@ -43,14 +43,14 @@ public sealed class TileConstructionTests : InteractionTest
|
||||
// Place Lattice
|
||||
var oldPos = TargetCoords;
|
||||
TargetCoords = SEntMan.GetNetCoordinates(new EntityCoordinates(MapData.MapUid, 1, 0));
|
||||
await Interact(Rod);
|
||||
await InteractUsing(Rod);
|
||||
TargetCoords = oldPos;
|
||||
await AssertTile(Lattice);
|
||||
AssertGridCount(1);
|
||||
|
||||
// Cut lattice
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
await Interact(Cut);
|
||||
await InteractUsing(Cut);
|
||||
await AssertTile(null);
|
||||
AssertGridCount(0);
|
||||
|
||||
@@ -76,25 +76,25 @@ public sealed class TileConstructionTests : InteractionTest
|
||||
// Space -> Lattice
|
||||
var oldPos = TargetCoords;
|
||||
TargetCoords = SEntMan.GetNetCoordinates(new EntityCoordinates(MapData.MapUid, 1, 0));
|
||||
await Interact(Rod);
|
||||
await InteractUsing(Rod);
|
||||
TargetCoords = oldPos;
|
||||
await AssertTile(Lattice);
|
||||
AssertGridCount(1);
|
||||
|
||||
// Lattice -> Plating
|
||||
await Interact(Steel);
|
||||
await InteractUsing(Steel);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
await AssertTile(Plating);
|
||||
AssertGridCount(1);
|
||||
|
||||
// Plating -> Tile
|
||||
await Interact(FloorItem);
|
||||
await InteractUsing(FloorItem);
|
||||
Assert.That(Hands.ActiveHandEntity, Is.Null);
|
||||
await AssertTile(Floor);
|
||||
AssertGridCount(1);
|
||||
|
||||
// Tile -> Plating
|
||||
await Interact(Pry);
|
||||
await InteractUsing(Pry);
|
||||
await AssertTile(Plating);
|
||||
AssertGridCount(1);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ public sealed class WeldableTests : InteractionTest
|
||||
|
||||
Assert.That(comp.IsWelded, Is.False);
|
||||
|
||||
await Interact(Weld);
|
||||
await InteractUsing(Weld);
|
||||
Assert.That(comp.IsWelded, Is.True);
|
||||
AssertPrototype(Locker); // Prototype did not change.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user