Fixes dropping item in container (#29900)

* Items droped in containers will end up in containers

* Adds integration test for dropping entity while inside container

* comment

* comment

* trim the diff

---------

Co-authored-by: plykiya <plykiya@protonmail.com>
This commit is contained in:
Plykiya
2024-07-12 02:24:08 -07:00
committed by GitHub
parent 160364e100
commit a8cae6f3e6
2 changed files with 88 additions and 3 deletions

View File

@@ -1,8 +1,10 @@
using System.Linq; using System.Linq;
using Content.Server.Storage.EntitySystems;
using Content.Shared.Hands.Components; using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems; using Content.Shared.Hands.EntitySystems;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Map; using Robust.Shared.Map;
@@ -11,6 +13,19 @@ namespace Content.IntegrationTests.Tests.Hands;
[TestFixture] [TestFixture]
public sealed class HandTests public sealed class HandTests
{ {
[TestPrototypes]
private const string Prototypes = @"
- type: entity
id: TestPickUpThenDropInContainerTestBox
name: box
components:
- type: EntityStorage
- type: ContainerContainer
containers:
entity_storage: !type:Container
";
[Test] [Test]
public async Task TestPickupDrop() public async Task TestPickupDrop()
{ {
@@ -57,4 +72,69 @@ public sealed class HandTests
await server.WaitPost(() => mapMan.DeleteMap(data.MapId)); await server.WaitPost(() => mapMan.DeleteMap(data.MapId));
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
} }
[Test]
public async Task TestPickUpThenDropInContainer()
{
await using var pair = await PoolManager.GetServerClient(new PoolSettings
{
Connected = true,
DummyTicker = false
});
var server = pair.Server;
var map = await pair.CreateTestMap();
await pair.RunTicksSync(5);
var entMan = server.ResolveDependency<IEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var mapMan = server.ResolveDependency<IMapManager>();
var sys = entMan.System<SharedHandsSystem>();
var tSys = entMan.System<TransformSystem>();
var containerSystem = server.System<SharedContainerSystem>();
EntityUid item = default;
EntityUid box = default;
EntityUid player = default;
HandsComponent hands = default!;
// spawn the elusive box and crowbar at the coordinates
await server.WaitPost(() => box = server.EntMan.SpawnEntity("TestPickUpThenDropInContainerTestBox", map.GridCoords));
await server.WaitPost(() => item = server.EntMan.SpawnEntity("Crowbar", map.GridCoords));
// place the player at the exact same coordinates and have them grab the crowbar
await server.WaitPost(() =>
{
player = playerMan.Sessions.First().AttachedEntity!.Value;
tSys.PlaceNextTo(player, item);
hands = entMan.GetComponent<HandsComponent>(player);
sys.TryPickup(player, item, hands.ActiveHand!);
});
await pair.RunTicksSync(5);
Assert.That(hands.ActiveHandEntity, Is.EqualTo(item));
// Open then close the box to place the player, who is holding the crowbar, inside of it
var storage = server.System<EntityStorageSystem>();
await server.WaitPost(() =>
{
storage.OpenStorage(box);
storage.CloseStorage(box);
});
await pair.RunTicksSync(5);
Assert.That(containerSystem.IsEntityInContainer(player), Is.True);
// Dropping the item while the player is inside the box should cause the item
// to also be inside the same container the player is in now,
// with the item not being in the player's hands
await server.WaitPost(() =>
{
sys.TryDrop(player, item, null!);
});
await pair.RunTicksSync(5);
var xform = entMan.GetComponent<TransformComponent>(player);
var itemXform = entMan.GetComponent<TransformComponent>(item);
Assert.That(hands.ActiveHandEntity, Is.Not.EqualTo(item));
Assert.That(containerSystem.IsInSameOrNoContainer((player, xform), (item, itemXform)));
await server.WaitPost(() => mapMan.DeleteMap(map.MapId));
await pair.CleanReturnAsync();
}
} }

View File

@@ -110,7 +110,10 @@ public abstract partial class SharedHandsSystem
return false; return false;
var entity = hand.HeldEntity!.Value; var entity = hand.HeldEntity!.Value;
DoDrop(uid, hand, doDropInteraction: doDropInteraction, handsComp);
// if item is a fake item (like with pulling), just delete it rather than bothering with trying to drop it into the world
if (TryComp(entity, out VirtualItemComponent? @virtual))
_virtualSystem.DeleteVirtualItem((entity, @virtual), uid);
if (TerminatingOrDeleted(entity)) if (TerminatingOrDeleted(entity))
return true; return true;
@@ -122,16 +125,18 @@ public abstract partial class SharedHandsSystem
var userXform = Transform(uid); var userXform = Transform(uid);
var isInContainer = ContainerSystem.IsEntityOrParentInContainer(uid, xform: userXform); var isInContainer = ContainerSystem.IsEntityOrParentInContainer(uid, xform: userXform);
// drop the item inside the container if the user is in a container
if (targetDropLocation == null || isInContainer) if (targetDropLocation == null || isInContainer)
{ {
// If user is in a container, drop item into that container. Otherwise, attach to grid or map.
TransformSystem.DropNextTo((entity, itemXform), (uid, userXform)); TransformSystem.DropNextTo((entity, itemXform), (uid, userXform));
return true; return true;
} }
// otherwise, remove the item from their hands and place it at the calculated interaction range position
DoDrop(uid, hand, doDropInteraction: doDropInteraction, handsComp);
var (itemPos, itemRot) = TransformSystem.GetWorldPositionRotation(entity); var (itemPos, itemRot) = TransformSystem.GetWorldPositionRotation(entity);
var origin = new MapCoordinates(itemPos, itemXform.MapID); var origin = new MapCoordinates(itemPos, itemXform.MapID);
var target = targetDropLocation.Value.ToMap(EntityManager, TransformSystem); var target = TransformSystem.ToMapCoordinates(targetDropLocation.Value);
TransformSystem.SetWorldPositionRotation(entity, GetFinalDropCoordinates(uid, origin, target), itemRot); TransformSystem.SetWorldPositionRotation(entity, GetFinalDropCoordinates(uid, origin, target), itemRot);
return true; return true;
} }