fix: Block EntityStorage from inserting into mechs (#37942)
This additionally moves the hard-coded check for HandsComp that previously did this, and moves it into an event which now both HandsSystem and MechSystem subscribe to.
This commit is contained in:
@@ -3,6 +3,7 @@ using Content.Shared.Database;
|
|||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Inventory.VirtualItem;
|
using Content.Shared.Inventory.VirtualItem;
|
||||||
|
using Content.Shared.Storage.Components;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
@@ -20,6 +21,7 @@ public abstract partial class SharedHandsSystem
|
|||||||
private void InitializeDrop()
|
private void InitializeDrop()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<HandsComponent, EntRemovedFromContainerMessage>(HandleEntityRemoved);
|
SubscribeLocalEvent<HandsComponent, EntRemovedFromContainerMessage>(HandleEntityRemoved);
|
||||||
|
SubscribeLocalEvent<HandsComponent, EntityStorageIntoContainerAttemptEvent>(OnEntityStorageDump);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void HandleEntityRemoved(EntityUid uid, HandsComponent hands, EntRemovedFromContainerMessage args)
|
protected virtual void HandleEntityRemoved(EntityUid uid, HandsComponent hands, EntRemovedFromContainerMessage args)
|
||||||
@@ -39,6 +41,14 @@ public abstract partial class SharedHandsSystem
|
|||||||
_virtualSystem.DeleteVirtualItem((args.Entity, @virtual), uid);
|
_virtualSystem.DeleteVirtualItem((args.Entity, @virtual), uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnEntityStorageDump(Entity<HandsComponent> ent, ref EntityStorageIntoContainerAttemptEvent args)
|
||||||
|
{
|
||||||
|
// If you're physically carrying an EntityStroage which tries to dump its contents out,
|
||||||
|
// we want those contents to fall to the floor.
|
||||||
|
args.Cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
private bool ShouldIgnoreRestrictions(EntityUid user)
|
private bool ShouldIgnoreRestrictions(EntityUid user)
|
||||||
{
|
{
|
||||||
//Checks if the Entity is something that shouldn't care about drop distance or walls ie Aghost
|
//Checks if the Entity is something that shouldn't care about drop distance or walls ie Aghost
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using Content.Shared.Mech.Equipment.Components;
|
|||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Movement.Components;
|
||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Storage.Components;
|
||||||
using Content.Shared.Weapons.Melee;
|
using Content.Shared.Weapons.Melee;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
@@ -48,6 +49,7 @@ public abstract partial class SharedMechSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<MechComponent, UserActivateInWorldEvent>(RelayInteractionEvent);
|
SubscribeLocalEvent<MechComponent, UserActivateInWorldEvent>(RelayInteractionEvent);
|
||||||
SubscribeLocalEvent<MechComponent, ComponentStartup>(OnStartup);
|
SubscribeLocalEvent<MechComponent, ComponentStartup>(OnStartup);
|
||||||
SubscribeLocalEvent<MechComponent, DestructionEventArgs>(OnDestruction);
|
SubscribeLocalEvent<MechComponent, DestructionEventArgs>(OnDestruction);
|
||||||
|
SubscribeLocalEvent<MechComponent, EntityStorageIntoContainerAttemptEvent>(OnEntityStorageDump);
|
||||||
SubscribeLocalEvent<MechComponent, GetAdditionalAccessEvent>(OnGetAdditionalAccess);
|
SubscribeLocalEvent<MechComponent, GetAdditionalAccessEvent>(OnGetAdditionalAccess);
|
||||||
SubscribeLocalEvent<MechComponent, DragDropTargetEvent>(OnDragDrop);
|
SubscribeLocalEvent<MechComponent, DragDropTargetEvent>(OnDragDrop);
|
||||||
SubscribeLocalEvent<MechComponent, CanDropTargetEvent>(OnCanDragDrop);
|
SubscribeLocalEvent<MechComponent, CanDropTargetEvent>(OnCanDragDrop);
|
||||||
@@ -104,6 +106,12 @@ public abstract partial class SharedMechSystem : EntitySystem
|
|||||||
BreakMech(uid, component);
|
BreakMech(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnEntityStorageDump(Entity<MechComponent> entity, ref EntityStorageIntoContainerAttemptEvent args)
|
||||||
|
{
|
||||||
|
// There's no reason we should dump into /any/ of the mech's containers.
|
||||||
|
args.Cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnGetAdditionalAccess(EntityUid uid, MechComponent component, ref GetAdditionalAccessEvent args)
|
private void OnGetAdditionalAccess(EntityUid uid, MechComponent component, ref GetAdditionalAccessEvent args)
|
||||||
{
|
{
|
||||||
var pilot = component.PilotSlot.ContainedEntity;
|
var pilot = component.PilotSlot.ContainedEntity;
|
||||||
@@ -147,7 +155,7 @@ public abstract partial class SharedMechSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Destroys the mech, removing the user and ejecting all installed equipment.
|
/// Destroys the mech, removing the user and ejecting anything contained.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="uid"></param>
|
/// <param name="uid"></param>
|
||||||
/// <param name="component"></param>
|
/// <param name="component"></param>
|
||||||
@@ -237,14 +245,19 @@ public abstract partial class SharedMechSystem : EntitySystem
|
|||||||
/// <param name="toRemove"></param>
|
/// <param name="toRemove"></param>
|
||||||
/// <param name="component"></param>
|
/// <param name="component"></param>
|
||||||
/// <param name="equipmentComponent"></param>
|
/// <param name="equipmentComponent"></param>
|
||||||
/// <param name="forced">Whether or not the removal can be cancelled</param>
|
/// <param name="forced">
|
||||||
|
/// Whether or not the removal can be cancelled, and if non-mech equipment should be ejected.
|
||||||
|
/// </param>
|
||||||
public void RemoveEquipment(EntityUid uid, EntityUid toRemove, MechComponent? component = null,
|
public void RemoveEquipment(EntityUid uid, EntityUid toRemove, MechComponent? component = null,
|
||||||
MechEquipmentComponent? equipmentComponent = null, bool forced = false)
|
MechEquipmentComponent? equipmentComponent = null, bool forced = false)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref component))
|
if (!Resolve(uid, ref component))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!Resolve(toRemove, ref equipmentComponent))
|
// When forced, we also want to handle the possibility that the "equipment" isn't actually equipment.
|
||||||
|
// This /shouldn't/ be possible thanks to OnEntityStorageDump, but there's been quite a few regressions
|
||||||
|
// with entities being hardlock stuck inside mechs.
|
||||||
|
if (!Resolve(toRemove, ref equipmentComponent) && !forced)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!forced)
|
if (!forced)
|
||||||
@@ -261,7 +274,9 @@ public abstract partial class SharedMechSystem : EntitySystem
|
|||||||
if (component.CurrentSelectedEquipment == toRemove)
|
if (component.CurrentSelectedEquipment == toRemove)
|
||||||
CycleEquipment(uid, component);
|
CycleEquipment(uid, component);
|
||||||
|
|
||||||
equipmentComponent.EquipmentOwner = null;
|
if (forced && equipmentComponent != null)
|
||||||
|
equipmentComponent.EquipmentOwner = null;
|
||||||
|
|
||||||
_container.Remove(toRemove, component.EquipmentContainer);
|
_container.Remove(toRemove, component.EquipmentContainer);
|
||||||
UpdateUserInterface(uid, component);
|
UpdateUserInterface(uid, component);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,6 +166,13 @@ public record struct InsertIntoEntityStorageAttemptEvent(EntityUid ItemToInsert,
|
|||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public record struct EntityStorageInsertedIntoAttemptEvent(EntityUid ItemToInsert, bool Cancelled = false);
|
public record struct EntityStorageInsertedIntoAttemptEvent(EntityUid ItemToInsert, bool Cancelled = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on the Container's owner whenever an entity storage tries to dump its
|
||||||
|
/// contents while within a container.
|
||||||
|
/// </summary>
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct EntityStorageIntoContainerAttemptEvent(BaseContainer Container, bool Cancelled = false);
|
||||||
|
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public record struct StorageOpenAttemptEvent(EntityUid User, bool Silent, bool Cancelled = false);
|
public record struct StorageOpenAttemptEvent(EntityUid User, bool Silent, bool Cancelled = false);
|
||||||
|
|
||||||
|
|||||||
@@ -305,10 +305,13 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
|||||||
|
|
||||||
_container.Remove(toRemove, component.Contents);
|
_container.Remove(toRemove, component.Contents);
|
||||||
|
|
||||||
if (_container.IsEntityInContainer(container))
|
if (_container.IsEntityInContainer(container)
|
||||||
|
&& _container.TryGetOuterContainer(container, Transform(container), out var outerContainer))
|
||||||
{
|
{
|
||||||
if (_container.TryGetOuterContainer(container, Transform(container), out var outerContainer) &&
|
|
||||||
!HasComp<HandsComponent>(outerContainer.Owner))
|
var attemptEvent = new EntityStorageIntoContainerAttemptEvent(outerContainer);
|
||||||
|
RaiseLocalEvent(outerContainer.Owner, ref attemptEvent);
|
||||||
|
if (!attemptEvent.Cancelled)
|
||||||
{
|
{
|
||||||
_container.Insert(toRemove, outerContainer);
|
_container.Insert(toRemove, outerContainer);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user