Merge remote-tracking branch 'upstream/master' into ed-21-06-2024-upstream-sync

# Conflicts:
#	Resources/Prototypes/Maps/europa.yml
#	Resources/Prototypes/Maps/train.yml
This commit is contained in:
Ed
2024-06-21 18:30:31 +03:00
443 changed files with 8337 additions and 2540 deletions

View File

@@ -0,0 +1,56 @@
using Content.IntegrationTests.Tests.Interaction;
using Content.Shared.Buckle;
using Content.Shared.Buckle.Components;
using Content.Shared.Input;
using Content.Shared.Movement.Pulling.Components;
namespace Content.IntegrationTests.Tests.Buckle;
public sealed class BuckleDragTest : InteractionTest
{
// Check that dragging a buckled player unbuckles them.
[Test]
public async Task BucklePullTest()
{
var urist = await SpawnTarget("MobHuman");
var sUrist = ToServer(urist);
await SpawnTarget("Chair");
var buckle = Comp<BuckleComponent>(urist);
var strap = Comp<StrapComponent>(Target);
var puller = Comp<PullerComponent>(Player);
var pullable = Comp<PullableComponent>(urist);
#pragma warning disable RA0002
buckle.Delay = TimeSpan.Zero;
#pragma warning restore RA0002
// Initially not buckled to the chair and not pulling anything
Assert.That(buckle.Buckled, Is.False);
Assert.That(buckle.BuckledTo, Is.Null);
Assert.That(strap.BuckledEntities, Is.Empty);
Assert.That(puller.Pulling, Is.Null);
Assert.That(pullable.Puller, Is.Null);
Assert.That(pullable.BeingPulled, Is.False);
// Strap the human to the chair
Assert.That(Server.System<SharedBuckleSystem>().TryBuckle(sUrist, SPlayer, STarget.Value));
await RunTicks(5);
Assert.That(buckle.Buckled, Is.True);
Assert.That(buckle.BuckledTo, Is.EqualTo(STarget));
Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[]{sUrist}));
Assert.That(puller.Pulling, Is.Null);
Assert.That(pullable.Puller, Is.Null);
Assert.That(pullable.BeingPulled, Is.False);
// Start pulling, and thus unbuckle them
await PressKey(ContentKeyFunctions.TryPullObject, cursorEntity:urist);
await RunTicks(5);
Assert.That(buckle.Buckled, Is.False);
Assert.That(buckle.BuckledTo, Is.Null);
Assert.That(strap.BuckledEntities, Is.Empty);
Assert.That(puller.Pulling, Is.EqualTo(sUrist));
Assert.That(pullable.Puller, Is.EqualTo(SPlayer));
Assert.That(pullable.BeingPulled, Is.True);
}
}

View File

@@ -91,7 +91,6 @@ namespace Content.IntegrationTests.Tests.Buckle
{
Assert.That(strap, Is.Not.Null);
Assert.That(strap.BuckledEntities, Is.Empty);
Assert.That(strap.OccupiedSize, Is.Zero);
});
// Side effects of buckling
@@ -111,8 +110,6 @@ namespace Content.IntegrationTests.Tests.Buckle
// Side effects of buckling for the strap
Assert.That(strap.BuckledEntities, Does.Contain(human));
Assert.That(strap.OccupiedSize, Is.EqualTo(buckle.Size));
Assert.That(strap.OccupiedSize, Is.Positive);
});
#pragma warning disable NUnit2045 // Interdependent asserts.
@@ -122,7 +119,7 @@ namespace Content.IntegrationTests.Tests.Buckle
// Trying to unbuckle too quickly fails
Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False);
Assert.That(buckle.Buckled);
Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False);
Assert.That(buckleSystem.TryUnbuckle(human, human), Is.False);
Assert.That(buckle.Buckled);
#pragma warning restore NUnit2045
});
@@ -149,7 +146,6 @@ namespace Content.IntegrationTests.Tests.Buckle
// Unbuckle, strap
Assert.That(strap.BuckledEntities, Is.Empty);
Assert.That(strap.OccupiedSize, Is.Zero);
});
#pragma warning disable NUnit2045 // Interdependent asserts.
@@ -160,9 +156,9 @@ namespace Content.IntegrationTests.Tests.Buckle
// On cooldown
Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False);
Assert.That(buckle.Buckled);
Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False);
Assert.That(buckleSystem.TryUnbuckle(human, human), Is.False);
Assert.That(buckle.Buckled);
Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False);
Assert.That(buckleSystem.TryUnbuckle(human, human), Is.False);
Assert.That(buckle.Buckled);
#pragma warning restore NUnit2045
});
@@ -189,7 +185,6 @@ namespace Content.IntegrationTests.Tests.Buckle
#pragma warning disable NUnit2045 // Interdependent asserts.
Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle), Is.False);
Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False);
Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False);
#pragma warning restore NUnit2045
// Move near the chair
@@ -202,12 +197,10 @@ namespace Content.IntegrationTests.Tests.Buckle
Assert.That(buckle.Buckled);
Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False);
Assert.That(buckle.Buckled);
Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False);
Assert.That(buckle.Buckled);
#pragma warning restore NUnit2045
// Force unbuckle
Assert.That(buckleSystem.TryUnbuckle(human, human, true, buckleComp: buckle));
buckleSystem.Unbuckle(human, human);
Assert.Multiple(() =>
{
Assert.That(buckle.Buckled, Is.False);
@@ -311,7 +304,7 @@ namespace Content.IntegrationTests.Tests.Buckle
// Break our guy's kneecaps
foreach (var leg in legs)
{
xformSystem.DetachParentToNull(leg.Id, entityManager.GetComponent<TransformComponent>(leg.Id));
entityManager.DeleteEntity(leg.Id);
}
});
@@ -328,7 +321,8 @@ namespace Content.IntegrationTests.Tests.Buckle
Assert.That(hand.HeldEntity, Is.Null);
}
buckleSystem.TryUnbuckle(human, human, true, buckleComp: buckle);
buckleSystem.Unbuckle(human, human);
Assert.That(buckle.Buckled, Is.False);
});
await pair.CleanReturnAsync();

View File

@@ -1,5 +1,6 @@
#nullable enable
using Content.IntegrationTests.Tests.Interaction;
using Content.IntegrationTests.Tests.Movement;
using Robust.Shared.Maths;
using ClimbingComponent = Content.Shared.Climbing.Components.ClimbingComponent;
using ClimbSystem = Content.Shared.Climbing.Systems.ClimbSystem;

View File

@@ -59,11 +59,6 @@ public sealed class CraftingTests : InteractionTest
await AssertEntityLookup((Rod, 2), (Cable, 7), (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>
@@ -93,28 +88,22 @@ public sealed class CraftingTests : InteractionTest
await RunTicks(1);
// DoAfter is in progress. Entity not spawned, stacks have been split and someingredients are in a container.
Assert.Multiple(async () =>
{
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, Has.Count.EqualTo(8));
Assert.That(wireStack, Has.Count.EqualTo(7));
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, Has.Count.EqualTo(8));
Assert.That(wireStack, Has.Count.EqualTo(7));
await FindEntity(Spear, shouldSucceed: false);
});
await FindEntity(Spear, shouldSucceed: false);
// Cancel the DoAfter. Should drop ingredients to the floor.
await CancelDoAfters();
Assert.Multiple(async () =>
{
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));
});
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
#pragma warning disable CS4014 // Legacy construction code uses DoAfterAwait. See above.
@@ -123,24 +112,17 @@ public sealed class CraftingTests : InteractionTest
await RunTicks(1);
// DoAfter is in progress. Entity not spawned, ingredients are in a container.
Assert.Multiple(async () =>
{
Assert.That(ActiveDoAfters.Count(), Is.EqualTo(1));
Assert.That(sys.IsEntityInContainer(shard), Is.True);
await FindEntity(Spear, shouldSucceed: false);
});
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.
Assert.Multiple(async () =>
{
await FindEntity(Spear);
Assert.That(sys.IsEntityInContainer(rods), Is.False);
Assert.That(sys.IsEntityInContainer(wires), Is.False);
Assert.That(SEntMan.Deleted(shard));
});
await FindEntity(Spear);
Assert.That(sys.IsEntityInContainer(rods), Is.False);
Assert.That(sys.IsEntityInContainer(wires), Is.False);
Assert.That(SEntMan.Deleted(shard));
}
#endif
}

View File

@@ -84,8 +84,9 @@ public abstract partial class InteractionTest
/// <summary>
/// Spawn an entity entity and set it as the target.
/// </summary>
[MemberNotNull(nameof(Target))]
protected async Task SpawnTarget(string prototype)
[MemberNotNull(nameof(Target), nameof(STarget), nameof(CTarget))]
#pragma warning disable CS8774 // Member must have a non-null value when exiting.
protected async Task<NetEntity> SpawnTarget(string prototype)
{
Target = NetEntity.Invalid;
await Server.WaitPost(() =>
@@ -95,7 +96,9 @@ public abstract partial class InteractionTest
await RunTicks(5);
AssertPrototype(prototype);
return Target!.Value;
}
#pragma warning restore CS8774 // Member must have a non-null value when exiting.
/// <summary>
/// Spawn an entity in preparation for deconstruction
@@ -1170,14 +1173,17 @@ public abstract partial class InteractionTest
#region Inputs
/// <summary>
/// Make the client press and then release a key. This assumes the key is currently released.
/// This will default to using the <see cref="Target"/> entity and <see cref="TargetCoords"/> coordinates.
/// </summary>
protected async Task PressKey(
BoundKeyFunction key,
int ticks = 1,
NetCoordinates? coordinates = null,
NetEntity cursorEntity = default)
NetEntity? cursorEntity = null)
{
await SetKey(key, BoundKeyState.Down, coordinates, cursorEntity);
await RunTicks(ticks);
@@ -1186,15 +1192,17 @@ public abstract partial class InteractionTest
}
/// <summary>
/// Make the client press or release a key
/// Make the client press or release a key.
/// This will default to using the <see cref="Target"/> entity and <see cref="TargetCoords"/> coordinates.
/// </summary>
protected async Task SetKey(
BoundKeyFunction key,
BoundKeyState state,
NetCoordinates? coordinates = null,
NetEntity cursorEntity = default)
NetEntity? cursorEntity = null)
{
var coords = coordinates ?? TargetCoords;
var target = cursorEntity ?? Target ?? default;
ScreenCoordinates screen = default;
var funcId = InputManager.NetworkBindMap.KeyFunctionID(key);
@@ -1203,7 +1211,7 @@ public abstract partial class InteractionTest
State = state,
Coordinates = CEntMan.GetCoordinates(coords),
ScreenCoordinates = screen,
Uid = CEntMan.GetEntity(cursorEntity),
Uid = CEntMan.GetEntity(target),
};
await Client.WaitPost(() => InputSystem.HandleInputCommand(ClientSession, key, message));

View File

@@ -84,6 +84,7 @@ public abstract partial class InteractionTest
protected NetEntity? Target;
protected EntityUid? STarget => ToServer(Target);
protected EntityUid? CTarget => ToClient(Target);
/// <summary>
@@ -128,7 +129,6 @@ public abstract partial class InteractionTest
public float TickPeriod => (float) STiming.TickPeriod.TotalSeconds;
// Simple mob that has one hand and can perform misc interactions.
[TestPrototypes]
private const string TestPrototypes = @"
@@ -142,6 +142,8 @@ public abstract partial class InteractionTest
- type: ComplexInteraction
- type: MindContainer
- type: Stripping
- type: Puller
- type: Physics
- type: Tag
tags:
- CanPilot
@@ -207,8 +209,8 @@ public abstract partial class InteractionTest
SEntMan.System<SharedMindSystem>().WipeMind(ServerSession.ContentData()?.Mind);
old = cPlayerMan.LocalEntity;
Player = SEntMan.GetNetEntity(SEntMan.SpawnEntity(PlayerPrototype, SEntMan.GetCoordinates(PlayerCoords)));
SPlayer = SEntMan.GetEntity(Player);
SPlayer = SEntMan.SpawnEntity(PlayerPrototype, SEntMan.GetCoordinates(PlayerCoords));
Player = SEntMan.GetNetEntity(SPlayer);
Server.PlayerMan.SetAttachedEntity(ServerSession, SPlayer);
Hands = SEntMan.GetComponent<HandsComponent>(SPlayer);
DoAfters = SEntMan.GetComponent<DoAfterComponent>(SPlayer);

View File

@@ -0,0 +1,63 @@
using Content.Shared.Alert;
using Content.Shared.Buckle.Components;
using Robust.Shared.Maths;
namespace Content.IntegrationTests.Tests.Movement;
public sealed class BuckleMovementTest : MovementTest
{
// Check that interacting with a chair straps you to it and prevents movement.
[Test]
public async Task ChairTest()
{
await SpawnTarget("Chair");
var cAlert = Client.System<AlertsSystem>();
var sAlert = Server.System<AlertsSystem>();
var buckle = Comp<BuckleComponent>(Player);
var strap = Comp<StrapComponent>(Target);
#pragma warning disable RA0002
buckle.Delay = TimeSpan.Zero;
#pragma warning restore RA0002
// Initially not buckled to the chair, and standing off to the side
Assert.That(Delta(), Is.InRange(0.9f, 1.1f));
Assert.That(buckle.Buckled, Is.False);
Assert.That(buckle.BuckledTo, Is.Null);
Assert.That(strap.BuckledEntities, Is.Empty);
Assert.That(cAlert.IsShowingAlert(CPlayer, strap.BuckledAlertType), Is.False);
Assert.That(sAlert.IsShowingAlert(SPlayer, strap.BuckledAlertType), Is.False);
// Interact results in being buckled to the chair
await Interact();
Assert.That(Delta(), Is.InRange(-0.01f, 0.01f));
Assert.That(buckle.Buckled, Is.True);
Assert.That(buckle.BuckledTo, Is.EqualTo(STarget));
Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[]{SPlayer}));
Assert.That(cAlert.IsShowingAlert(CPlayer, strap.BuckledAlertType), Is.True);
Assert.That(sAlert.IsShowingAlert(SPlayer, strap.BuckledAlertType), Is.True);
// Attempting to walk away does nothing
await Move(DirectionFlag.East, 1);
Assert.That(Delta(), Is.InRange(-0.01f, 0.01f));
Assert.That(buckle.Buckled, Is.True);
Assert.That(buckle.BuckledTo, Is.EqualTo(STarget));
Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[]{SPlayer}));
Assert.That(cAlert.IsShowingAlert(CPlayer, strap.BuckledAlertType), Is.True);
Assert.That(sAlert.IsShowingAlert(SPlayer, strap.BuckledAlertType), Is.True);
// Interacting again will unbuckle the player
await Interact();
Assert.That(Delta(), Is.InRange(-0.5f, 0.5f));
Assert.That(buckle.Buckled, Is.False);
Assert.That(buckle.BuckledTo, Is.Null);
Assert.That(strap.BuckledEntities, Is.Empty);
Assert.That(cAlert.IsShowingAlert(CPlayer, strap.BuckledAlertType), Is.False);
Assert.That(sAlert.IsShowingAlert(SPlayer, strap.BuckledAlertType), Is.False);
// And now they can move away
await Move(DirectionFlag.SouthEast, 1);
Assert.That(Delta(), Is.LessThan(-1));
}
}

View File

@@ -1,8 +1,9 @@
#nullable enable
using System.Numerics;
using Content.IntegrationTests.Tests.Interaction;
using Robust.Shared.GameObjects;
namespace Content.IntegrationTests.Tests.Interaction;
namespace Content.IntegrationTests.Tests.Movement;
/// <summary>
/// This is a variation of <see cref="InteractionTest"/> that sets up the player with a normal human entity and a simple

View File

@@ -0,0 +1,73 @@
#nullable enable
using Content.Shared.Alert;
using Content.Shared.Input;
using Content.Shared.Movement.Pulling.Components;
using Robust.Shared.Maths;
namespace Content.IntegrationTests.Tests.Movement;
public sealed class PullingTest : MovementTest
{
protected override int Tiles => 4;
[Test]
public async Task PullTest()
{
var cAlert = Client.System<AlertsSystem>();
var sAlert = Server.System<AlertsSystem>();
await SpawnTarget("MobHuman");
var puller = Comp<PullerComponent>(Player);
var pullable = Comp<PullableComponent>(Target);
// Player is initially to the left of the target and not pulling anything
Assert.That(Delta(), Is.InRange(0.9f, 1.1f));
Assert.That(puller.Pulling, Is.Null);
Assert.That(pullable.Puller, Is.Null);
Assert.That(pullable.BeingPulled, Is.False);
Assert.That(cAlert.IsShowingAlert(CPlayer, puller.PullingAlert), Is.False);
Assert.That(sAlert.IsShowingAlert(SPlayer, puller.PullingAlert), Is.False);
// Start pulling
await PressKey(ContentKeyFunctions.TryPullObject);
await RunTicks(5);
Assert.That(puller.Pulling, Is.EqualTo(STarget));
Assert.That(pullable.Puller, Is.EqualTo(SPlayer));
Assert.That(pullable.BeingPulled, Is.True);
Assert.That(cAlert.IsShowingAlert(CPlayer, puller.PullingAlert), Is.True);
Assert.That(sAlert.IsShowingAlert(SPlayer, puller.PullingAlert), Is.True);
// Move to the left and check that the target moves with the player and is still being pulled.
await Move(DirectionFlag.West, 1);
Assert.That(Delta(), Is.InRange(0.9f, 1.3f));
Assert.That(puller.Pulling, Is.EqualTo(STarget));
Assert.That(pullable.Puller, Is.EqualTo(SPlayer));
Assert.That(pullable.BeingPulled, Is.True);
Assert.That(cAlert.IsShowingAlert(CPlayer, puller.PullingAlert), Is.True);
Assert.That(sAlert.IsShowingAlert(SPlayer, puller.PullingAlert), Is.True);
// Move in the other direction
await Move(DirectionFlag.East, 2);
Assert.That(Delta(), Is.InRange(-1.3f, -0.9f));
Assert.That(puller.Pulling, Is.EqualTo(STarget));
Assert.That(pullable.Puller, Is.EqualTo(SPlayer));
Assert.That(pullable.BeingPulled, Is.True);
Assert.That(cAlert.IsShowingAlert(CPlayer, puller.PullingAlert), Is.True);
Assert.That(sAlert.IsShowingAlert(SPlayer, puller.PullingAlert), Is.True);
// Stop pulling
await PressKey(ContentKeyFunctions.ReleasePulledObject);
await RunTicks(5);
Assert.That(Delta(), Is.InRange(-1.3f, -0.9f));
Assert.That(puller.Pulling, Is.Null);
Assert.That(pullable.Puller, Is.Null);
Assert.That(pullable.BeingPulled, Is.False);
Assert.That(cAlert.IsShowingAlert(CPlayer, puller.PullingAlert), Is.False);
Assert.That(sAlert.IsShowingAlert(SPlayer, puller.PullingAlert), Is.False);
// Move back to the left and ensure the target is no longer following us.
await Move(DirectionFlag.West, 2);
Assert.That(Delta(), Is.GreaterThan(2f));
}
}

View File

@@ -8,7 +8,7 @@ using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.Maths;
namespace Content.IntegrationTests.Tests.Slipping;
namespace Content.IntegrationTests.Tests.Movement;
public sealed class SlippingTest : MovementTest
{
@@ -36,18 +36,14 @@ public sealed class SlippingTest : MovementTest
Assert.That(modifier, Is.EqualTo(1), "Player is not moving at full speed.");
// Player is to the left of the banana peel and has not slipped.
#pragma warning disable NUnit2045
Assert.That(Delta(), Is.GreaterThan(0.5f));
Assert.That(sys.Slipped, Does.Not.Contain(SEntMan.GetEntity(Player)));
#pragma warning restore NUnit2045
// Walking over the banana slowly does not trigger a slip.
await SetKey(EngineKeyFunctions.Walk, BoundKeyState.Down);
await Move(DirectionFlag.East, 1f);
#pragma warning disable NUnit2045
Assert.That(Delta(), Is.LessThan(0.5f));
Assert.That(sys.Slipped, Does.Not.Contain(SEntMan.GetEntity(Player)));
#pragma warning restore NUnit2045
AssertComp<KnockedDownComponent>(false, Player);
// Moving at normal speeds does trigger a slip.

View File

@@ -1,15 +1,52 @@
using System.Collections.Generic;
using Content.Server.Station.Systems;
using Content.Shared.Inventory;
using Content.Shared.Preferences;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles.Jobs;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests.Preferences;
[TestFixture]
[Ignore("HumanoidAppearance crashes upon loading default profiles.")]
public sealed class LoadoutTests
{
[TestPrototypes]
private const string Prototypes = @"
- type: playTimeTracker
id: PlayTimeLoadoutTester
- type: loadout
id: TestJumpsuit
equipment: TestJumpsuit
- type: startingGear
id: TestJumpsuit
equipment:
jumpsuit: ClothingUniformJumpsuitColorGrey
- type: loadoutGroup
id: LoadoutTesterJumpsuit
name: generic-unknown
loadouts:
- TestJumpsuit
- type: roleLoadout
id: JobLoadoutTester
groups:
- LoadoutTesterJumpsuit
- type: job
id: LoadoutTester
playTimeTracker: PlayTimeLoadoutTester
";
private readonly Dictionary<string, EntProtoId> _expectedEquipment = new()
{
["jumpsuit"] = "ClothingUniformJumpsuitColorGrey"
};
/// <summary>
/// Checks that an empty loadout still spawns with default gear and not naked.
/// </summary>
@@ -26,18 +63,38 @@ public sealed class LoadoutTests
// Check that an empty role loadout spawns gear
var stationSystem = entManager.System<StationSpawningSystem>();
var inventorySystem = entManager.System<InventorySystem>();
var testMap = await pair.CreateTestMap();
// That's right I can't even spawn a dummy profile without station spawning / humanoidappearance code crashing.
var profile = new HumanoidCharacterProfile();
profile.SetLoadout(new RoleLoadout("TestRoleLoadout"));
stationSystem.SpawnPlayerMob(testMap.GridCoords, job: new JobComponent()
await server.WaitAssertion(() =>
{
// Sue me, there's so much involved in setting up jobs
Prototype = "CargoTechnician"
}, profile, station: null);
var profile = new HumanoidCharacterProfile();
profile.SetLoadout(new RoleLoadout("LoadoutTester"));
var tester = stationSystem.SpawnPlayerMob(testMap.GridCoords, job: new JobComponent()
{
Prototype = "LoadoutTester"
}, profile, station: null);
var slotQuery = inventorySystem.GetSlotEnumerator(tester);
var checkedCount = 0;
while (slotQuery.NextItem(out var item, out var slot))
{
// Make sure the slot is valid
Assert.That(_expectedEquipment.TryGetValue(slot.Name, out var expectedItem), $"Spawned item in unexpected slot: {slot.Name}");
// Make sure that the item is the right one
var meta = entManager.GetComponent<MetaDataComponent>(item);
Assert.That(meta.EntityPrototype.ID, Is.EqualTo(expectedItem.Id), $"Spawned wrong item in slot {slot.Name}!");
checkedCount++;
}
// Make sure the number of items is the same
Assert.That(checkedCount, Is.EqualTo(_expectedEquipment.Count), "Number of items does not match expected!");
entManager.DeleteEntity(tester);
});
await pair.CleanReturnAsync();
}