diff --git a/Content.Shared.Database/LogType.cs b/Content.Shared.Database/LogType.cs
index eb2b8e1f6f..85cac5899d 100644
--- a/Content.Shared.Database/LogType.cs
+++ b/Content.Shared.Database/LogType.cs
@@ -110,4 +110,9 @@ public enum LogType
/// A player did an item-use interaction of an item they were holding onto another object.
///
InteractUsing = 92,
+
+ ///
+ /// Storage & entity-storage related interactions
+ ///
+ Storage = 93,
}
diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs
index cac3b86ad6..868d26c3ae 100644
--- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs
+++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs
@@ -2,7 +2,9 @@ using System.Collections.Frozen;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Shared.ActionBlocker;
+using Content.Shared.Administration.Logs;
using Content.Shared.Containers.ItemSlots;
+using Content.Shared.Database;
using Content.Shared.Destructible;
using Content.Shared.DoAfter;
using Content.Shared.Hands.Components;
@@ -57,6 +59,7 @@ public abstract class SharedStorageSystem : EntitySystem
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
[Dependency] protected readonly UseDelaySystem UseDelay = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
+ [Dependency] private readonly ISharedAdminLogManager _adminLog = default!;
private EntityQuery _itemQuery;
private EntityQuery _stackQuery;
@@ -577,151 +580,79 @@ public abstract class SharedStorageSystem : EntitySystem
///
private void OnInteractWithItem(StorageInteractWithItemEvent msg, EntitySessionEventArgs args)
{
- if (args.SenderSession.AttachedEntity is not { } player)
- return;
-
- var uid = GetEntity(msg.StorageUid);
- var entity = GetEntity(msg.InteractedItemUid);
-
- if (!TryComp(uid, out var storageComp))
- return;
-
- if (!_ui.IsUiOpen(uid, StorageComponent.StorageUiKey.Key, player))
- return;
-
- if (!Exists(entity))
- {
- Log.Error($"Player {args.SenderSession} interacted with non-existent item {msg.InteractedItemUid} stored in {ToPrettyString(uid)}");
- return;
- }
-
- if (!ActionBlocker.CanInteract(player, entity) || !storageComp.Container.Contains(entity))
- return;
-
- // Does the player have hands?
- if (!TryComp(player, out HandsComponent? hands) || hands.Count == 0)
+ if (!ValidateInput(args, msg.StorageUid, msg.InteractedItemUid, out var player, out var storage, out var item))
return;
// If the user's active hand is empty, try pick up the item.
- if (hands.ActiveHandEntity == null)
+ if (player.Comp.ActiveHandEntity == null)
{
- if (_sharedHandsSystem.TryPickupAnyHand(player, entity, handsComp: hands)
- && storageComp.StorageRemoveSound != null)
- Audio.PlayPredicted(storageComp.StorageRemoveSound, uid, player, _audioParams);
+ _adminLog.Add(
+ LogType.Storage,
+ LogImpact.Low,
+ $"{ToPrettyString(player):player} is attempting to take {ToPrettyString(item):item} out of {ToPrettyString(storage):storage}");
+
+ if (_sharedHandsSystem.TryPickupAnyHand(player, item, handsComp: player.Comp)
+ && storage.Comp.StorageRemoveSound != null)
{
- return;
+ Audio.PlayPredicted(storage.Comp.StorageRemoveSound, storage, player, _audioParams);
}
+
+ return;
}
+ _adminLog.Add(
+ LogType.Storage,
+ LogImpact.Low,
+ $"{ToPrettyString(player):player} is interacting with {ToPrettyString(item):item} while it is stored in {ToPrettyString(storage):storage} using {ToPrettyString(player.Comp.ActiveHandEntity):used}");
+
// Else, interact using the held item
- _interactionSystem.InteractUsing(player, hands.ActiveHandEntity.Value, entity, Transform(entity).Coordinates, checkCanInteract: false);
+ _interactionSystem.InteractUsing(player, player.Comp.ActiveHandEntity.Value, item, Transform(item).Coordinates, checkCanInteract: false);
}
private void OnSetItemLocation(StorageSetItemLocationEvent msg, EntitySessionEventArgs args)
{
- if (args.SenderSession.AttachedEntity is not { } player)
+ if (!ValidateInput(args, msg.StorageEnt, msg.ItemEnt, out var player, out var storage, out var item))
return;
- var storageEnt = GetEntity(msg.StorageEnt);
- var itemEnt = GetEntity(msg.ItemEnt);
+ _adminLog.Add(
+ LogType.Storage,
+ LogImpact.Low,
+ $"{ToPrettyString(player):player} is updating the location of {ToPrettyString(item):item} within {ToPrettyString(storage):storage}");
- if (!TryComp(storageEnt, out var storageComp))
- return;
-
- if (!_ui.IsUiOpen(storageEnt, StorageComponent.StorageUiKey.Key, player))
- return;
-
- if (!Exists(itemEnt))
- {
- Log.Error($"Player {args.SenderSession} set location of non-existent item {msg.ItemEnt} stored in {ToPrettyString(storageEnt)}");
- return;
- }
-
- if (!ActionBlocker.CanInteract(player, itemEnt))
- return;
-
- TrySetItemStorageLocation((itemEnt, null), (storageEnt, storageComp), msg.Location);
+ TrySetItemStorageLocation(item!, storage!, msg.Location);
}
private void OnRemoveItem(StorageRemoveItemEvent msg, EntitySessionEventArgs args)
{
- if (args.SenderSession.AttachedEntity is not { } player)
+ if (!ValidateInput(args, msg.StorageEnt, msg.ItemEnt, out var player, out var storage, out var item))
return;
- var storageEnt = GetEntity(msg.StorageEnt);
- var itemEnt = GetEntity(msg.ItemEnt);
-
- if (!TryComp(storageEnt, out var storageComp))
- return;
-
- if (!_ui.IsUiOpen(storageEnt, StorageComponent.StorageUiKey.Key, player))
- return;
-
- if (!Exists(itemEnt))
- {
- Log.Error($"Player {args.SenderSession} set location of non-existent item {msg.ItemEnt} stored in {ToPrettyString(storageEnt)}");
- return;
- }
-
- if (!ActionBlocker.CanInteract(player, itemEnt))
- return;
-
- TransformSystem.DropNextTo(itemEnt, player);
- Audio.PlayPredicted(storageComp.StorageRemoveSound, storageEnt, player, _audioParams);
+ _adminLog.Add(
+ LogType.Storage,
+ LogImpact.Low,
+ $"{ToPrettyString(player):player} is removing {ToPrettyString(item):item} from {ToPrettyString(storage):storage}");
+ TransformSystem.DropNextTo(item.Owner, player.Owner);
+ Audio.PlayPredicted(storage.Comp.StorageRemoveSound, storage, player, _audioParams);
}
private void OnInsertItemIntoLocation(StorageInsertItemIntoLocationEvent msg, EntitySessionEventArgs args)
{
- if (args.SenderSession.AttachedEntity is not { } player)
+ if (!ValidateInput(args, msg.StorageEnt, msg.ItemEnt, out var player, out var storage, out var item, held: true))
return;
- var storageEnt = GetEntity(msg.StorageEnt);
- var itemEnt = GetEntity(msg.ItemEnt);
-
- if (!TryComp(storageEnt, out var storageComp))
- return;
-
- if (!_ui.IsUiOpen(storageEnt, StorageComponent.StorageUiKey.Key, player))
- return;
-
- if (!Exists(itemEnt))
- {
- Log.Error($"Player {args.SenderSession} set location of non-existent item {msg.ItemEnt} stored in {ToPrettyString(storageEnt)}");
- return;
- }
-
- if (!ActionBlocker.CanInteract(player, itemEnt) || !_sharedHandsSystem.IsHolding(player, itemEnt, out _))
- return;
-
- InsertAt((storageEnt, storageComp), (itemEnt, null), msg.Location, out _, player, stackAutomatically: false);
+ _adminLog.Add(
+ LogType.Storage,
+ LogImpact.Low,
+ $"{ToPrettyString(player):player} is inserting {ToPrettyString(item):item} into {ToPrettyString(storage):storage}");
+ InsertAt(storage!, item!, msg.Location, out _, player, stackAutomatically: false);
}
- // TODO: if/when someone cleans up this shitcode please make all these
- // handlers use a shared helper for checking that the ui is open etc, thanks
private void OnSaveItemLocation(StorageSaveItemLocationEvent msg, EntitySessionEventArgs args)
{
- if (args.SenderSession.AttachedEntity is not {} player)
+ if (!ValidateInput(args, msg.Storage, msg.Item, out var player, out var storage, out var item, held: true))
return;
- var storage = GetEntity(msg.Storage);
- var item = GetEntity(msg.Item);
-
- if (!HasComp(storage))
- return;
-
- if (!_ui.IsUiOpen(storage, StorageComponent.StorageUiKey.Key, player))
- return;
-
- if (!Exists(item))
- {
- Log.Error($"Player {args.SenderSession} saved location of non-existent item {msg.Item} stored in {ToPrettyString(storage)}");
- return;
- }
-
- if (!ActionBlocker.CanInteract(player, item))
- return;
-
- SaveItemLocation(storage, item);
+ SaveItemLocation(storage!, item.Owner);
}
private void OnBoundUIOpen(EntityUid uid, StorageComponent storageComp, BoundUIOpenedEvent args)
@@ -1500,6 +1431,79 @@ public abstract class SharedStorageSystem : EntitySystem
public abstract void PlayPickupAnimation(EntityUid uid, EntityCoordinates initialCoordinates,
EntityCoordinates finalCoordinates, Angle initialRotation, EntityUid? user = null);
+ private bool ValidateInput(
+ EntitySessionEventArgs args,
+ NetEntity netStorage,
+ out Entity player,
+ out Entity storage)
+ {
+ player = default;
+ storage = default;
+
+ if (args.SenderSession.AttachedEntity is not { } playerUid)
+ return false;
+
+ if (!TryComp(playerUid, out HandsComponent? hands) || hands.Count == 0)
+ return false;
+
+ if (!TryGetEntity(netStorage, out var storageUid))
+ return false;
+
+ if (!TryComp(storageUid, out StorageComponent? storageComp))
+ return false;
+
+ // TODO STORAGE use BUI events
+ // This would automatically validate that the UI is open & that the user can interact.
+ // However, we still need to manually validate that items being used are in the users hands or in the storage.
+ if (!_ui.IsUiOpen(storageUid.Value, StorageComponent.StorageUiKey.Key, playerUid))
+ return false;
+
+ if (!ActionBlocker.CanInteract(playerUid, storageUid))
+ return false;
+
+ player = new(playerUid, hands);
+ storage = new(storageUid.Value, storageComp);
+ return true;
+ }
+
+ private bool ValidateInput(EntitySessionEventArgs args,
+ NetEntity netStorage,
+ NetEntity netItem,
+ out Entity player,
+ out Entity storage,
+ out Entity item,
+ bool held = false)
+ {
+ item = default!;
+ if (!ValidateInput(args, netStorage, out player, out storage))
+ return false;
+
+ if (!TryGetEntity(netItem, out var itemUid))
+ return false;
+
+ if (held)
+ {
+ if (!_sharedHandsSystem.IsHolding(player, itemUid, out _))
+ return false;
+ }
+ else
+ {
+ if (!storage.Comp.Container.Contains(itemUid.Value))
+ return false;
+
+ DebugTools.Assert(storage.Comp.StoredItems.ContainsKey(itemUid.Value));
+ }
+
+ if (!TryComp(itemUid, out ItemComponent? itemComp))
+ return false;
+
+ if (!ActionBlocker.CanInteract(player, itemUid))
+ return false;
+
+ item = new(itemUid.Value, itemComp);
+ return true;
+ }
+
[Serializable, NetSerializable]
protected sealed class StorageComponentState : ComponentState
{