Add interaction tests (#15251)
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Construction.Interaction;
|
||||
|
||||
public sealed class ComputerConstruction : InteractionTest
|
||||
{
|
||||
private const string Computer = "Computer";
|
||||
private const string ComputerId = "ComputerId";
|
||||
private const string ComputerFrame = "ComputerFrame";
|
||||
private const string IdBoard = "IDComputerCircuitboard";
|
||||
|
||||
[Test]
|
||||
public async Task ConstructComputer()
|
||||
{
|
||||
// Place ghost
|
||||
await StartConstruction(Computer);
|
||||
|
||||
// Initial interaction (ghost turns into real entity)
|
||||
await Interact(Steel, 5);
|
||||
AssertPrototype(ComputerFrame);
|
||||
|
||||
// Perform construction steps
|
||||
await Interact(
|
||||
Wrench,
|
||||
IdBoard,
|
||||
Screw,
|
||||
(Cable, 5),
|
||||
(Glass, 2),
|
||||
Screw);
|
||||
|
||||
// Construction finished, target entity was replaced with a new one:
|
||||
AssertPrototype(ComputerId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DeconstructComputer()
|
||||
{
|
||||
// Spawn initial entity
|
||||
await StartDeconstruction(ComputerId);
|
||||
|
||||
// Initial interaction turns id computer into generic computer
|
||||
await Interact(Screw);
|
||||
AssertPrototype(ComputerFrame);
|
||||
|
||||
// Perform deconstruction steps
|
||||
await Interact(
|
||||
Pry,
|
||||
Cut,
|
||||
Screw,
|
||||
Pry,
|
||||
Wrench,
|
||||
Weld);
|
||||
|
||||
// construction finished, entity no longer exists.
|
||||
AssertDeleted();
|
||||
|
||||
// Check expected entities were dropped.
|
||||
await AssertEntityLookup(
|
||||
IdBoard,
|
||||
(Cable, 5),
|
||||
(Steel, 5),
|
||||
(Glass, 2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChangeComputer()
|
||||
{
|
||||
// Spawn initial entity
|
||||
await SpawnTarget(ComputerId);
|
||||
|
||||
// Initial interaction turns id computer into generic computer
|
||||
await Interact(Screw);
|
||||
AssertPrototype(ComputerFrame);
|
||||
|
||||
// Perform partial deconstruction steps
|
||||
await Interact(
|
||||
Pry,
|
||||
Cut,
|
||||
Screw,
|
||||
Pry);
|
||||
|
||||
// Entity should still exist
|
||||
AssertPrototype(ComputerFrame);
|
||||
|
||||
// Begin re-constructing with a new circuit board
|
||||
await Interact(
|
||||
"CargoRequestComputerCircuitboard",
|
||||
Screw,
|
||||
(Cable, 5),
|
||||
(Glass, 2),
|
||||
Screw);
|
||||
|
||||
// Construction finished, target entity was replaced with a new one:
|
||||
AssertPrototype("ComputerCargoOrders");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using Content.Shared.Stacks;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Construction.Interaction;
|
||||
|
||||
public sealed class CraftingTests : InteractionTest
|
||||
{
|
||||
public const string ShardGlass = "ShardGlass";
|
||||
public const string Spear = "Spear";
|
||||
|
||||
/// <summary>
|
||||
/// Craft a simple instant recipe
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task CraftRods()
|
||||
{
|
||||
await PlaceInHands(Steel);
|
||||
await CraftItem(Rod);
|
||||
await FindEntity((Rod, 2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Craft a simple recipe with a DoAfter
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task CraftGrenade()
|
||||
{
|
||||
await PlaceInHands(Steel, 5);
|
||||
await CraftItem("ModularGrenadeRecipe");
|
||||
await FindEntity("ModularGrenade");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Craft a complex recipe (more than one ingredient).
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task CraftSpear()
|
||||
{
|
||||
// Spawn a full tack of rods in the user's hands.
|
||||
await PlaceInHands(Rod, 10);
|
||||
await SpawnEntity((Cable, 10), PlayerCoords);
|
||||
|
||||
// Attempt (and fail) to craft without glass.
|
||||
await CraftItem(Spear, shouldSucceed: false);
|
||||
await FindEntity(Spear, shouldSucceed: false);
|
||||
|
||||
// Spawn three shards of glass and finish crafting (only one is needed).
|
||||
await SpawnTarget(ShardGlass);
|
||||
await SpawnTarget(ShardGlass);
|
||||
await SpawnTarget(ShardGlass);
|
||||
await CraftItem(Spear);
|
||||
await FindEntity(Spear);
|
||||
|
||||
// Player's hands should be full of the remaining rods, except those dropped during the failed crafting attempt.
|
||||
// Spear and left over stacks should be on the floor.
|
||||
await AssertEntityLookup((Rod, 2), (Cable, 8), (ShardGlass, 2), (Spear, 1));
|
||||
}
|
||||
|
||||
// The following is wrapped in an if DEBUG. This is because of cursed state handling bugs. Tests don't (de)serialize
|
||||
// net messages and just copy objects by reference. This means that the server will directly modify cached server
|
||||
// states on the client's end. Crude fix at the moment is to used modified state handling while in debug mode
|
||||
// Otherwise, this test cannot work.
|
||||
#if DEBUG
|
||||
/// <summary>
|
||||
/// Cancel crafting a complex recipe.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task CancelCraft()
|
||||
{
|
||||
var rods = await SpawnEntity((Rod, 10), TargetCoords);
|
||||
var wires = await SpawnEntity((Cable, 10), TargetCoords);
|
||||
var shard = await SpawnEntity(ShardGlass, TargetCoords);
|
||||
|
||||
var rodStack = SEntMan.GetComponent<StackComponent>(rods);
|
||||
var wireStack = SEntMan.GetComponent<StackComponent>(wires);
|
||||
|
||||
await RunTicks(5);
|
||||
var sys = SEntMan.System<SharedContainerSystem>();
|
||||
Assert.That(sys.IsEntityInContainer(rods), Is.False);
|
||||
Assert.That(sys.IsEntityInContainer(wires), Is.False);
|
||||
Assert.That(sys.IsEntityInContainer(shard), Is.False);
|
||||
|
||||
await Server.WaitPost(() => SConstruction.TryStartItemConstruction(Spear, Player));
|
||||
await RunTicks(1);
|
||||
|
||||
// DoAfter is in progress. Entity not spawned, stacks have been split and someingredients are in a container.
|
||||
Assert.That(ActiveDoAfters.Count(), Is.EqualTo(1));
|
||||
Assert.That(sys.IsEntityInContainer(shard), Is.True);
|
||||
Assert.That(sys.IsEntityInContainer(rods), Is.False);
|
||||
Assert.That(sys.IsEntityInContainer(wires), Is.False);
|
||||
Assert.That(rodStack.Count, Is.EqualTo(8));
|
||||
Assert.That(wireStack.Count, Is.EqualTo(8));
|
||||
await FindEntity(Spear, shouldSucceed: false);
|
||||
|
||||
// Cancel the DoAfter. Should drop ingredients to the floor.
|
||||
await CancelDoAfters();
|
||||
Assert.That(sys.IsEntityInContainer(rods), Is.False);
|
||||
Assert.That(sys.IsEntityInContainer(wires), Is.False);
|
||||
Assert.That(sys.IsEntityInContainer(shard), Is.False);
|
||||
await FindEntity(Spear, shouldSucceed: false);
|
||||
await AssertEntityLookup((Rod, 10), (Cable, 10), (ShardGlass, 1));
|
||||
|
||||
// Re-attempt the do-after
|
||||
await Server.WaitPost(() => SConstruction.TryStartItemConstruction(Spear, Player));
|
||||
await RunTicks(1);
|
||||
|
||||
// DoAfter is in progress. Entity not spawned, ingredients are in a container.
|
||||
Assert.That(ActiveDoAfters.Count(), Is.EqualTo(1));
|
||||
Assert.That(sys.IsEntityInContainer(shard), Is.True);
|
||||
await FindEntity(Spear, shouldSucceed: false);
|
||||
|
||||
// Finish the DoAfter
|
||||
await AwaitDoAfters();
|
||||
|
||||
// Spear has been crafted. Rods and wires are no longer contained. Glass has been consumed.
|
||||
await FindEntity(Spear);
|
||||
Assert.That(sys.IsEntityInContainer(rods), Is.False);
|
||||
Assert.That(sys.IsEntityInContainer(wires), Is.False);
|
||||
Assert.That(SEntMan.Deleted(shard));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using Content.Shared.Construction.Prototypes;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Construction.Interaction;
|
||||
|
||||
/// <summary>
|
||||
/// Check that we can build grilles on top of windows, but not the other way around.
|
||||
/// </summary>
|
||||
public sealed class GrilleWindowConstruction : InteractionTest
|
||||
{
|
||||
private const string Grille = "Grille";
|
||||
private const string Window = "Window";
|
||||
|
||||
[Test]
|
||||
public async Task WindowOnGrille()
|
||||
{
|
||||
// Construct Grille
|
||||
await StartConstruction(Grille);
|
||||
await Interact(Rod, 10);
|
||||
AssertPrototype(Grille);
|
||||
|
||||
var grille = Target;
|
||||
|
||||
// Construct Window
|
||||
await StartConstruction(Window);
|
||||
await Interact(Glass, 10);
|
||||
AssertPrototype(Window);
|
||||
|
||||
// Deconstruct Window
|
||||
await Interact(Screw, Wrench);
|
||||
AssertDeleted();
|
||||
|
||||
// Deconstruct Grille
|
||||
Target = grille;
|
||||
await Interact(Cut);
|
||||
AssertDeleted();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(Grille, Grille)]
|
||||
[TestCase(Window, Grille)]
|
||||
[TestCase(Window, Window)]
|
||||
public async Task ConstructionBlocker(string first, string second)
|
||||
{
|
||||
// Spawn blocking entity
|
||||
await SpawnTarget(first);
|
||||
|
||||
// Further construction attempts fail - blocked by first entity interaction.
|
||||
await Client.WaitPost(() =>
|
||||
{
|
||||
var proto = ProtoMan.Index<ConstructionPrototype>(second);
|
||||
Assert.That(CConSys.TrySpawnGhost(proto, TargetCoords, Direction.South, out _), Is.False);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Construction.Interaction;
|
||||
|
||||
public sealed class MachineConstruction : InteractionTest
|
||||
{
|
||||
private const string MachineFrame = "MachineFrame";
|
||||
private const string Unfinished = "UnfinishedMachineFrame";
|
||||
private const string ProtolatheBoard = "ProtolatheMachineCircuitboard";
|
||||
private const string Protolathe = "Protolathe";
|
||||
private const string Beaker = "Beaker";
|
||||
|
||||
[Test]
|
||||
public async Task ConstructProtolathe()
|
||||
{
|
||||
await StartConstruction(MachineFrame);
|
||||
await Interact(Steel, 5);
|
||||
AssertPrototype(Unfinished);
|
||||
await Interact(Wrench, Cable);
|
||||
AssertPrototype(MachineFrame);
|
||||
await Interact(ProtolatheBoard, Bin1, Bin1, Manipulator1, Manipulator1, Beaker, Beaker, Screw);
|
||||
AssertPrototype(Protolathe);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DeconstructProtolathe()
|
||||
{
|
||||
await StartDeconstruction(Protolathe);
|
||||
await Interact(Screw, Pry);
|
||||
AssertPrototype(MachineFrame);
|
||||
await Interact(Pry, Cut);
|
||||
AssertPrototype(Unfinished);
|
||||
await Interact(Wrench, Screw);
|
||||
AssertDeleted();
|
||||
await AssertEntityLookup(
|
||||
(Steel, 5),
|
||||
(Cable, 1),
|
||||
(Beaker, 2),
|
||||
(Manipulator1, 2),
|
||||
(Bin1, 2),
|
||||
(ProtolatheBoard, 1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChangeMachine()
|
||||
{
|
||||
// Partially deconstruct a protolathe.
|
||||
await SpawnTarget(Protolathe);
|
||||
await Interact(Screw, Pry, Pry);
|
||||
AssertPrototype(MachineFrame);
|
||||
|
||||
// Change it into an autolathe
|
||||
await Interact("AutolatheMachineCircuitboard");
|
||||
AssertPrototype(MachineFrame);
|
||||
await Interact(Bin1, Bin1, Bin1, Manipulator1, Glass, Screw);
|
||||
AssertPrototype("Autolathe");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task UpgradeLathe()
|
||||
{
|
||||
// Partially deconstruct a protolathe.
|
||||
await SpawnTarget(Protolathe);
|
||||
|
||||
// Initially has all quality-1 parts.
|
||||
foreach (var part in SConstruction.GetAllParts(Target!.Value))
|
||||
{
|
||||
Assert.That(part.Rating, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
// Partially deconstruct lathe
|
||||
await Interact(Screw, Pry, Pry);
|
||||
AssertPrototype(MachineFrame);
|
||||
|
||||
// Reconstruct with better parts.
|
||||
await Interact(ProtolatheBoard, Bin4, Bin4, Manipulator4, Manipulator4, Beaker, Beaker);
|
||||
await Interact(Screw);
|
||||
AssertPrototype(Protolathe);
|
||||
|
||||
// Query now returns higher quality parts.
|
||||
foreach (var part in SConstruction.GetAllParts(Target!.Value))
|
||||
{
|
||||
Assert.That(part.Rating, Is.EqualTo(4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared.Wires;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Construction.Interaction;
|
||||
|
||||
public sealed class PanelScrewing : InteractionTest
|
||||
{
|
||||
[Test]
|
||||
public async Task ApcPanel()
|
||||
{
|
||||
await SpawnTarget("APCBasic");
|
||||
var comp = Comp<ApcComponent>();
|
||||
|
||||
// Open & close panel
|
||||
Assert.That(comp.IsApcOpen, Is.False);
|
||||
|
||||
await Interact(Screw);
|
||||
Assert.That(comp.IsApcOpen, Is.True);
|
||||
await Interact(Screw);
|
||||
Assert.That(comp.IsApcOpen, Is.False);
|
||||
|
||||
// Interrupted DoAfters
|
||||
await Interact(Screw, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
Assert.That(comp.IsApcOpen, Is.False);
|
||||
await Interact(Screw);
|
||||
Assert.That(comp.IsApcOpen, Is.True);
|
||||
await Interact(Screw, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
Assert.That(comp.IsApcOpen, Is.True);
|
||||
await Interact(Screw);
|
||||
Assert.That(comp.IsApcOpen, Is.False);
|
||||
}
|
||||
|
||||
// Test wires panel on both airlocks & tcomms servers. These both use the same component, but comms may have
|
||||
// conflicting interactions due to encryption key removal interactions.
|
||||
[Test]
|
||||
[TestCase("Airlock")]
|
||||
[TestCase("TelecomServerFilled")]
|
||||
public async Task WiresPanelScrewing(string prototype)
|
||||
{
|
||||
await SpawnTarget(prototype);
|
||||
var comp = Comp<WiresPanelComponent>();
|
||||
|
||||
// Open & close panel
|
||||
Assert.That(comp.Open, Is.False);
|
||||
await Interact(Screw);
|
||||
Assert.That(comp.Open, Is.True);
|
||||
await Interact(Screw);
|
||||
Assert.That(comp.Open, Is.False);
|
||||
|
||||
// Interrupted DoAfters
|
||||
await Interact(Screw, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
Assert.That(comp.Open, Is.False);
|
||||
await Interact(Screw);
|
||||
Assert.That(comp.Open, Is.True);
|
||||
await Interact(Screw, awaitDoAfters: false);
|
||||
await CancelDoAfters();
|
||||
Assert.That(comp.Open, Is.True);
|
||||
await Interact(Screw);
|
||||
Assert.That(comp.Open, Is.False);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using Content.Shared.Placeable;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Construction.Interaction;
|
||||
|
||||
public sealed class PlaceableDeconstruction : InteractionTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks that you can deconstruct placeable surfaces (i.e., placing a wrench on a table does not take priority).
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task DeconstructTable()
|
||||
{
|
||||
await StartDeconstruction("Table");
|
||||
Assert.That(Comp<PlaceableSurfaceComponent>().IsPlaceable);
|
||||
await Interact(Wrench);
|
||||
AssertPrototype("TableFrame");
|
||||
await Interact(Wrench);
|
||||
AssertDeleted();
|
||||
await AssertEntityLookup((Steel, 1), (Rod, 2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Construction.Interaction;
|
||||
|
||||
public sealed class WallConstruction : InteractionTest
|
||||
{
|
||||
public const string Girder = "Girder";
|
||||
public const string WallSolid = "WallSolid";
|
||||
public const string Wall = "Wall";
|
||||
|
||||
[Test]
|
||||
public async Task ConstructWall()
|
||||
{
|
||||
await StartConstruction(Wall);
|
||||
await Interact(Steel, 2);
|
||||
Assert.IsNull(Hands.ActiveHandEntity);
|
||||
AssertPrototype(Girder);
|
||||
await Interact(Steel, 2);
|
||||
Assert.IsNull(Hands.ActiveHandEntity);
|
||||
AssertPrototype(WallSolid);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DeconstructWall()
|
||||
{
|
||||
await StartDeconstruction(WallSolid);
|
||||
await Interact(Weld);
|
||||
AssertPrototype(Girder);
|
||||
await Interact(Wrench, Screw);
|
||||
AssertDeleted();
|
||||
await AssertEntityLookup((Steel, 4));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Construction.Interaction;
|
||||
|
||||
public sealed class WindowConstruction : InteractionTest
|
||||
{
|
||||
private const string Window = "Window";
|
||||
private const string RWindow = "ReinforcedWindow";
|
||||
|
||||
[Test]
|
||||
public async Task ConstructWindow()
|
||||
{
|
||||
await StartConstruction(Window);
|
||||
await Interact(Glass, 5);
|
||||
AssertPrototype(Window);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DeconstructWindow()
|
||||
{
|
||||
await StartDeconstruction(Window);
|
||||
await Interact(Screw, Wrench);
|
||||
AssertDeleted();
|
||||
await AssertEntityLookup((Glass, 2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ConstructReinforcedWindow()
|
||||
{
|
||||
await StartConstruction(RWindow);
|
||||
await Interact(RGlass, 5);
|
||||
AssertPrototype(RWindow);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DeonstructReinforcedWindow()
|
||||
{
|
||||
await StartDeconstruction(RWindow);
|
||||
await Interact(
|
||||
Weld,
|
||||
Screw,
|
||||
Pry,
|
||||
Weld,
|
||||
Screw,
|
||||
Wrench);
|
||||
AssertDeleted();
|
||||
await AssertEntityLookup((RGlass, 2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Construction.Interaction;
|
||||
|
||||
public sealed class WindowRepair : InteractionTest
|
||||
{
|
||||
[Test]
|
||||
public async Task RepairReinforcedWindow()
|
||||
{
|
||||
await SpawnTarget("ReinforcedWindow");
|
||||
|
||||
// Damage the entity.
|
||||
var sys = SEntMan.System<DamageableSystem>();
|
||||
var comp = Comp<DamageableComponent>();
|
||||
var damageType = Server.ResolveDependency<IPrototypeManager>().Index<DamageTypePrototype>("Blunt");
|
||||
var damage = new DamageSpecifier(damageType, FixedPoint2.New(10));
|
||||
Assert.That(comp.Damage.Total, Is.EqualTo(FixedPoint2.Zero));
|
||||
await Server.WaitPost(() => sys.TryChangeDamage(Target, damage, ignoreResistances: true));
|
||||
await RunTicks(5);
|
||||
Assert.That(comp.Damage.Total, Is.GreaterThan(FixedPoint2.Zero));
|
||||
|
||||
// Repair the entity
|
||||
await Interact(Weld);
|
||||
Assert.That(comp.Damage.Total, Is.EqualTo(FixedPoint2.Zero));
|
||||
|
||||
// Validate that we can still deconstruct the entity (i.e., that welding deconstruction is not blocked).
|
||||
await Interact(
|
||||
Weld,
|
||||
Screw,
|
||||
Pry,
|
||||
Weld,
|
||||
Screw,
|
||||
Wrench);
|
||||
AssertDeleted();
|
||||
await AssertEntityLookup((RGlass, 2));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user