diff --git a/Content.IntegrationTests/Tests/PDA/PDAExtensionsTests.cs b/Content.IntegrationTests/Tests/PDA/PDAExtensionsTests.cs new file mode 100644 index 0000000000..36cba26fe7 --- /dev/null +++ b/Content.IntegrationTests/Tests/PDA/PDAExtensionsTests.cs @@ -0,0 +1,125 @@ +using System.Linq; +using System.Threading.Tasks; +using Content.Server.GameObjects.Components.Access; +using Content.Server.GameObjects.Components.GUI; +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects.Components.PDA; +using Content.Server.Interfaces.GameObjects.Components.Items; +using NUnit.Framework; +using Robust.Server.Player; +using Robust.Shared.GameObjects; + +namespace Content.IntegrationTests.Tests.PDA +{ + public class PDAExtensionsTests : ContentIntegrationTest + { + private const string IdCardDummy = "DummyIdCard"; + private const string PdaDummy = "DummyPda"; + + private static readonly string Prototypes = $@" +- type: entity + id: {IdCardDummy} + name: {IdCardDummy} + components: + - type: IdCard + - type: Item + +- type: entity + id: {PdaDummy} + name: {PdaDummy} + components: + - type: PDA + idCard: {IdCardDummy} + - type: Item"; + + [Test] + public async Task PlayerGetIdComponent() + { + var clientOptions = new ClientIntegrationOptions + { + ExtraPrototypes = Prototypes + }; + + var serverOptions = new ServerIntegrationOptions + { + ExtraPrototypes = Prototypes + }; + + var (client, server) = await StartConnectedServerClientPair(clientOptions, serverOptions); + + await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync()); + + var sPlayerManager = server.ResolveDependency(); + var sEntityManager = server.ResolveDependency(); + + await server.WaitAssertion(() => + { + var player = sPlayerManager.GetAllPlayers().Single().AttachedEntity; + + Assert.NotNull(player); + + // The player spawns with an ID on by default + Assert.NotNull(player.GetHeldId()); + Assert.True(player.TryGetHeldId(out var id)); + Assert.NotNull(id); + + // Put PDA in hand + var dummyPda = sEntityManager.SpawnEntity(PdaDummy, player.Transform.MapPosition); + var pdaItemComponent = dummyPda.GetComponent(); + player.GetComponent().PutInHand(pdaItemComponent); + + var pdaComponent = dummyPda.GetComponent(); + var pdaIdCard = sEntityManager.SpawnEntity(IdCardDummy, player.Transform.MapPosition).GetComponent(); + pdaComponent.InsertIdCard(pdaIdCard); + var pdaContainedId = pdaComponent.ContainedID; + + // The PDA in the hand should be found first + Assert.NotNull(player.GetHeldId()); + Assert.True(player.TryGetHeldId(out id)); + Assert.NotNull(id); + Assert.That(id, Is.EqualTo(pdaContainedId)); + + // Put ID card in hand + var idDummy = sEntityManager.SpawnEntity(IdCardDummy, player.Transform.MapPosition); + var idItemComponent = idDummy.GetComponent(); + player.GetComponent().PutInHand(idItemComponent); + + var idCardComponent = idDummy.GetComponent(); + + // The ID in the hand should be found first + Assert.NotNull(player.GetHeldId()); + Assert.True(player.TryGetHeldId(out id)); + Assert.NotNull(id); + Assert.That(id, Is.EqualTo(idCardComponent)); + + // Remove all IDs and PDAs + var inventory = player.GetComponent(); + + foreach (var slot in inventory.Slots) + { + var item = inventory.GetSlotItem(slot); + + if (item == null) + { + continue; + } + + if (item.Owner.HasComponent()) + { + inventory.ForceUnequip(slot); + } + } + + var hands = player.GetComponent(); + + hands.Drop(dummyPda, false); + hands.Drop(idDummy, false); + + // No ID + Assert.Null(player.GetHeldId()); + Assert.False(player.TryGetHeldId(out id)); + Assert.Null(id); + }); + } + } +} diff --git a/Content.Server/GameObjects/Components/PDA/PDAExtensions.cs b/Content.Server/GameObjects/Components/PDA/PDAExtensions.cs new file mode 100644 index 0000000000..07c90a002d --- /dev/null +++ b/Content.Server/GameObjects/Components/PDA/PDAExtensions.cs @@ -0,0 +1,80 @@ +#nullable enable +using System.Diagnostics.CodeAnalysis; +using Content.Server.GameObjects.Components.Access; +using Content.Server.GameObjects.Components.GUI; +using Content.Server.Interfaces.GameObjects.Components.Items; +using Robust.Shared.GameObjects; + +namespace Content.Server.GameObjects.Components.PDA +{ + public static class PdaExtensions + { + /// + /// Gets the id that a player is holding in their hands or inventory. + /// Order: Hands > ID slot > PDA in ID slot + /// + /// The player to check in. + /// The id card component. + public static IdCardComponent? GetHeldId(this IEntity player) + { + IdCardComponent? firstIdInPda = null; + + if (player.TryGetComponent(out IHandsComponent? hands)) + { + foreach (var item in hands.GetAllHeldItems()) + { + if (firstIdInPda == null && + item.Owner.TryGetComponent(out PDAComponent? pda) && + pda.ContainedID != null) + { + firstIdInPda = pda.ContainedID; + } + + if (item.Owner.TryGetComponent(out IdCardComponent? card)) + { + return card; + } + } + } + + if (firstIdInPda != null) + { + return firstIdInPda; + } + + IdCardComponent? firstIdInInventory = null; + + if (player.TryGetComponent(out InventoryComponent? inventory)) + { + foreach (var item in inventory.GetAllHeldItems()) + { + if (firstIdInInventory == null && + item.TryGetComponent(out PDAComponent? pda) && + pda.ContainedID != null) + { + firstIdInInventory = pda.ContainedID; + } + + if (item.TryGetComponent(out IdCardComponent? card)) + { + return card; + } + } + } + + return firstIdInInventory; + } + + /// + /// Gets the id that a player is holding in their hands or inventory. + /// Order: Hands > ID slot > PDA in ID slot + /// + /// The player to check in. + /// The id card component. + /// true if found, false otherwise. + public static bool TryGetHeldId(this IEntity player, [NotNullWhen(true)] out IdCardComponent? id) + { + return (id = player.GetHeldId()) != null; + } + } +} diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index e8f3bd0cee..52cf5087ea 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -130,6 +130,7 @@ True True True + True True True True