]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add a component that inserts the held item when no interaction happens on the stored...
authorShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
Sun, 11 Aug 2024 02:29:44 +0000 (19:29 -0700)
committerGitHub <noreply@github.com>
Sun, 11 Aug 2024 02:29:44 +0000 (12:29 +1000)
* Insert when held item has no interaction with stored item

* Decouple inserting on failure

* Add component that stores the used entity when no interaction happened

* Add prediction

Content.Shared/Interaction/SharedInteractionSystem.cs
Content.Shared/Storage/Components/StoreAfterFailedInteractComponent.cs [new file with mode: 0644]
Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs
Content.Shared/Storage/EntitySystems/StoreAfterFailedInteractSystem.cs [new file with mode: 0644]
Content.Shared/Storage/Events/StorageInsertFailedEvent.cs [new file with mode: 0644]

index 972fa389e4060edb7cd9f079c7c8a8efced4aa9e..e8cc831e4957c42f5ea1e15305227fd20e0da501 100644 (file)
@@ -918,11 +918,21 @@ namespace Content.Shared.Interaction
         }
 
         /// <summary>
-        /// Uses a item/object on an entity
+        /// Uses an item/object on an entity
         /// Finds components with the InteractUsing interface and calls their function
         /// NOTE: Does not have an InRangeUnobstructed check
         /// </summary>
-        public void InteractUsing(
+        /// <param name="user">User doing the interaction.</param>
+        /// <param name="used">Item being used on the <paramref name="target"/>.</param>
+        /// <param name="target">Entity getting interacted with by the <paramref name="user"/> using the
+        ///     <paramref name="used"/> entity.</param>
+        /// <param name="clickLocation">The location that the <paramref name="user"/> clicked.</param>
+        /// <param name="checkCanInteract">Whether to check that the <paramref name="user"/> can interact with the
+        ///     <paramref name="target"/>.</param>
+        /// <param name="checkCanUse">Whether to check that the <paramref name="user"/> can use the
+        ///     <paramref name="used"/> entity.</param>
+        /// <returns>True if the interaction was handled. Otherwise, false.</returns>
+        public bool InteractUsing(
             EntityUid user,
             EntityUid used,
             EntityUid target,
@@ -931,10 +941,10 @@ namespace Content.Shared.Interaction
             bool checkCanUse = true)
         {
             if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, target))
-                return;
+                return false;
 
             if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user, used))
-                return;
+                return false;
 
             _adminLogger.Add(
                 LogType.InteractUsing,
@@ -942,7 +952,7 @@ namespace Content.Shared.Interaction
                 $"{ToPrettyString(user):user} interacted with {ToPrettyString(target):target} using {ToPrettyString(used):used}");
 
             if (RangedInteractDoBefore(user, used, target, clickLocation, true))
-                return;
+                return true;
 
             // all interactions should only happen when in range / unobstructed, so no range check is needed
             var interactUsingEvent = new InteractUsingEvent(user, used, target, clickLocation);
@@ -951,15 +961,24 @@ namespace Content.Shared.Interaction
             DoContactInteraction(user, target, interactUsingEvent);
             // Contact interactions are currently only used for forensics, so we don't raise used -> target
             if (interactUsingEvent.Handled)
-                return;
+                return true;
 
-            InteractDoAfter(user, used, target, clickLocation, canReach: true);
+            if (InteractDoAfter(user, used, target, clickLocation, canReach: true))
+                return true;
+            return false;
         }
 
         /// <summary>
         ///     Used when clicking on an entity resulted in no other interaction. Used for low-priority interactions.
         /// </summary>
-        public void InteractDoAfter(EntityUid user, EntityUid used, EntityUid? target, EntityCoordinates clickLocation, bool canReach)
+        /// <param name="user"><inheritdoc cref="InteractUsing"/></param>
+        /// <param name="used"><inheritdoc cref="InteractUsing"/></param>
+        /// <param name="target"><inheritdoc cref="InteractUsing"/></param>
+        /// <param name="clickLocation"><inheritdoc cref="InteractUsing"/></param>
+        /// <param name="canReach">Whether the <paramref name="user"/> is in range of the <paramref name="target"/>.
+        ///     </param>
+        /// <returns>True if the interaction was handled. Otherwise, false.</returns>
+        public bool InteractDoAfter(EntityUid user, EntityUid used, EntityUid? target, EntityCoordinates clickLocation, bool canReach)
         {
             if (target is { Valid: false })
                 target = null;
@@ -974,10 +993,10 @@ namespace Content.Shared.Interaction
             }
 
             if (afterInteractEvent.Handled)
-                return;
+                return true;
 
             if (target == null)
-                return;
+                return false;
 
             var afterInteractUsingEvent = new AfterInteractUsingEvent(user, used, target, clickLocation, canReach);
             RaiseLocalEvent(target.Value, afterInteractUsingEvent);
@@ -988,6 +1007,10 @@ namespace Content.Shared.Interaction
                 DoContactInteraction(user, target, afterInteractUsingEvent);
                 // Contact interactions are currently only used for forensics, so we don't raise used -> target
             }
+
+            if (afterInteractUsingEvent.Handled)
+                return true;
+            return false;
         }
 
         #region ActivateItemInWorld
diff --git a/Content.Shared/Storage/Components/StoreAfterFailedInteractComponent.cs b/Content.Shared/Storage/Components/StoreAfterFailedInteractComponent.cs
new file mode 100644 (file)
index 0000000..578da52
--- /dev/null
@@ -0,0 +1,8 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Storage.Components;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class StoreAfterFailedInteractComponent : Component
+{
+}
index 8ee08f7e48cde1a17469ea82295c5fdb52385976..2689d7750d503f061b78ecdd6bb4352ab83ae37c 100644 (file)
@@ -22,6 +22,7 @@ using Content.Shared.Popups;
 using Content.Shared.Stacks;
 using Content.Shared.Storage.Components;
 using Content.Shared.Timing;
+using Content.Shared.Storage.Events;
 using Content.Shared.Verbs;
 using Content.Shared.Whitelist;
 using Robust.Shared.Audio;
@@ -366,7 +367,7 @@ public abstract class SharedStorageSystem : EntitySystem
         if (HasComp<PlaceableSurfaceComponent>(uid))
             return;
 
-        PlayerInsertHeldEntity(uid, args.User, storageComp);
+        PlayerInsertHeldEntity((uid, storageComp), args.User);
         // Always handle it, even if insertion fails.
         // We don't want to trigger any AfterInteract logic here.
         // Example issue would be placing wires if item doesn't fit in backpack.
@@ -606,7 +607,15 @@ public abstract class SharedStorageSystem : EntitySystem
             $"{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, player.Comp.ActiveHandEntity.Value, item, Transform(item).Coordinates, checkCanInteract: false);
+        if (_interactionSystem.InteractUsing(player,
+                player.Comp.ActiveHandEntity.Value,
+                item,
+                Transform(item).Coordinates,
+                checkCanInteract: false))
+            return;
+
+        var failedEv = new StorageInsertFailedEvent((storage, storage.Comp), (player, player.Comp));
+        RaiseLocalEvent(storage, ref failedEv);
     }
 
     private void OnSetItemLocation(StorageSetItemLocationEvent msg, EntitySessionEventArgs args)
@@ -988,35 +997,36 @@ public abstract class SharedStorageSystem : EntitySystem
     /// <summary>
     ///     Inserts an entity into storage from the player's active hand
     /// </summary>
-    /// <param name="uid"></param>
-    /// <param name="player">The player to insert an entity from</param>
-    /// <param name="storageComp"></param>
-    /// <returns>true if inserted, false otherwise</returns>
-    public bool PlayerInsertHeldEntity(EntityUid uid, EntityUid player, StorageComponent? storageComp = null)
+    /// <param name="ent">The storage entity and component to insert into.</param>
+    /// <param name="player">The player and hands component to insert the held entity from.</param>
+    /// <returns>True if inserted, otherwise false.</returns>
+    public bool PlayerInsertHeldEntity(Entity<StorageComponent?> ent, Entity<HandsComponent?> player)
     {
-        if (!Resolve(uid, ref storageComp) || !TryComp(player, out HandsComponent? hands) || hands.ActiveHandEntity == null)
+        if (!Resolve(ent.Owner, ref ent.Comp)
+            || !Resolve(player.Owner, ref player.Comp)
+            || player.Comp.ActiveHandEntity == null)
             return false;
 
-        var toInsert = hands.ActiveHandEntity;
+        var toInsert = player.Comp.ActiveHandEntity;
 
-        if (!CanInsert(uid, toInsert.Value, out var reason, storageComp))
+        if (!CanInsert(ent, toInsert.Value, out var reason, ent.Comp))
         {
-            _popupSystem.PopupClient(Loc.GetString(reason ?? "comp-storage-cant-insert"), uid, player);
+            _popupSystem.PopupClient(Loc.GetString(reason ?? "comp-storage-cant-insert"), ent, player);
             return false;
         }
 
-        if (!_sharedHandsSystem.CanDrop(player, toInsert.Value, hands))
+        if (!_sharedHandsSystem.CanDrop(player, toInsert.Value, player.Comp))
         {
-            _popupSystem.PopupClient(Loc.GetString("comp-storage-cant-drop", ("entity", toInsert.Value)), uid, player);
+            _popupSystem.PopupClient(Loc.GetString("comp-storage-cant-drop", ("entity", toInsert.Value)), ent, player);
             return false;
         }
 
-        return PlayerInsertEntityInWorld((uid, storageComp), player, toInsert.Value);
+        return PlayerInsertEntityInWorld((ent, ent.Comp), player, toInsert.Value);
     }
 
     /// <summary>
     ///     Inserts an Entity (<paramref name="toInsert"/>) in the world into storage, informing <paramref name="player"/> if it fails.
-    ///     <paramref name="toInsert"/> is *NOT* held, see <see cref="PlayerInsertHeldEntity(EntityUid,EntityUid,StorageComponent)"/>.
+    ///     <paramref name="toInsert"/> is *NOT* held, see <see cref="PlayerInsertHeldEntity(Entity{StorageComponent?},Entity{HandsComponent?})"/>.
     /// </summary>
     /// <param name="uid"></param>
     /// <param name="player">The player to insert an entity with</param>
diff --git a/Content.Shared/Storage/EntitySystems/StoreAfterFailedInteractSystem.cs b/Content.Shared/Storage/EntitySystems/StoreAfterFailedInteractSystem.cs
new file mode 100644 (file)
index 0000000..77f7280
--- /dev/null
@@ -0,0 +1,21 @@
+using Content.Shared.Storage.Components;
+using Content.Shared.Storage.Events;
+
+namespace Content.Shared.Storage.EntitySystems;
+
+public sealed class StoreAfterFailedInteractSystem : EntitySystem
+{
+    [Dependency] private readonly SharedStorageSystem _storage = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<StoreAfterFailedInteractComponent, StorageInsertFailedEvent>(OnStorageInsertFailed);
+    }
+
+    private void OnStorageInsertFailed(Entity<StoreAfterFailedInteractComponent> ent, ref StorageInsertFailedEvent args)
+    {
+        _storage.PlayerInsertHeldEntity(args.Storage, args.Player);
+    }
+}
diff --git a/Content.Shared/Storage/Events/StorageInsertFailedEvent.cs b/Content.Shared/Storage/Events/StorageInsertFailedEvent.cs
new file mode 100644 (file)
index 0000000..50f759e
--- /dev/null
@@ -0,0 +1,6 @@
+using Content.Shared.Hands.Components;
+
+namespace Content.Shared.Storage.Events;
+
+[ByRefEvent]
+public record struct StorageInsertFailedEvent(Entity<StorageComponent?> Storage, Entity<HandsComponent?> Player);