]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Stack and storage enhancements (#16405)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Mon, 15 May 2023 02:24:45 +0000 (12:24 +1000)
committerGitHub <noreply@github.com>
Mon, 15 May 2023 02:24:45 +0000 (22:24 -0400)
Content.Client/Storage/UI/StorageWindow.cs
Content.Server/Stack/StackSystem.cs
Content.Server/Storage/EntitySystems/StorageSystem.cs
Content.Shared/Stacks/SharedStackSystem.cs
Resources/Prototypes/Entities/Objects/Materials/ore.yml
Resources/Prototypes/Entities/Objects/Tools/cable_coils.yml

index eca118d76257d99fd264ecd2470e557204ba61bd..55ac04679fb76c2cc013a4b86d21dd832e9c8252 100644 (file)
@@ -5,7 +5,9 @@ using Robust.Client.UserInterface.CustomControls;
 using Content.Client.Items.Components;
 using Content.Client.Stylesheets;
 using Content.Client.UserInterface.Controls;
+using Content.Shared.IdentityManagement;
 using Content.Shared.Item;
+using Content.Shared.Stacks;
 using Robust.Client.UserInterface;
 using static Robust.Client.UserInterface.Controls.BoxContainer;
 using static Content.Shared.Storage.SharedStorageComponent;
@@ -28,7 +30,7 @@ namespace Content.Client.Storage.UI
         public StorageWindow(IEntityManager entityManager)
         {
             _entityManager = entityManager;
-            SetSize = (200, 320);
+            SetSize = (240, 320);
             Title = Loc.GetString("comp-storage-window-title");
             RectClipContent = true;
 
@@ -112,6 +114,9 @@ namespace Content.Client.Storage.UI
 
             _entityManager.TryGetComponent(entity, out SpriteComponent? sprite);
             _entityManager.TryGetComponent(entity, out ItemComponent? item);
+            _entityManager.TryGetComponent(entity, out StackComponent? stack);
+            var count = stack?.Count ?? 1;
+            var size = item?.Size;
 
             button.AddChild(new BoxContainer
             {
@@ -131,12 +136,13 @@ namespace Content.Client.Storage.UI
                         {
                             HorizontalExpand = true,
                             ClipText = true,
-                            Text = _entityManager.GetComponent<MetaDataComponent>(entity).EntityName
+                            Text = _entityManager.GetComponent<MetaDataComponent>(Identity.Entity(entity, _entityManager)).EntityName +
+                                   (count > 1 ? $" x {count}" : string.Empty),
                         },
                         new Label
                         {
                             Align = Label.AlignMode.Right,
-                            Text = item?.Size.ToString() ?? Loc.GetString("comp-storage-no-item-size"),
+                            Text = size.ToString() ?? Loc.GetString("comp-storage-no-item-size"),
                         }
                     }
             });
index 4e2d09950095cd30d768c029f765840aea476883..f7dd3a8583a1ea59cea661e9ff8132f033a4273e 100644 (file)
@@ -1,7 +1,10 @@
+using Content.Server.Storage.Components;
+using Content.Server.Storage.EntitySystems;
 using Content.Shared.Popups;
 using Content.Shared.Stacks;
 using Content.Shared.Verbs;
 using JetBrains.Annotations;
+using Robust.Server.Containers;
 using Robust.Shared.Map;
 using Robust.Shared.Prototypes;
 
@@ -14,6 +17,8 @@ namespace Content.Server.Stack
     [UsedImplicitly]
     public sealed class StackSystem : SharedStackSystem
     {
+        [Dependency] private readonly ContainerSystem _container = default!;
+        [Dependency] private readonly StorageSystem _storage = default!;
         [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
 
         public static readonly int[] DefaultSplitAmounts = { 1, 5, 10, 20, 30, 50 };
@@ -160,6 +165,12 @@ namespace Content.Server.Stack
             if (Split(uid, amount, userTransform.Coordinates, stack) is not {} split)
                 return;
 
+            if (_container.TryGetContainingContainer(uid, out var container) &&
+                TryComp<ServerStorageComponent>(container.Owner, out var storage))
+            {
+                _storage.UpdateStorageUI(container.Owner, storage);
+            }
+
             HandsSystem.PickupOrDrop(userUid, split);
 
             PopupSystem.PopupCursor(Loc.GetString("comp-stack-split"), userUid);
index fc05ba91219ca4fbcfe2ef0c55400c580153806d..829101dccfc31630df4ca6eca1e01b5c6c7acbac 100644 (file)
@@ -3,6 +3,7 @@ using Content.Server.Administration.Managers;
 using Content.Server.Ghost.Components;
 using Content.Server.Interaction;
 using Content.Server.Popups;
+using Content.Server.Stack;
 using Content.Server.Storage.Components;
 using Content.Shared.ActionBlocker;
 using Content.Shared.Administration;
@@ -37,10 +38,8 @@ using static Content.Shared.Storage.SharedStorageComponent;
 
 namespace Content.Server.Storage.EntitySystems
 {
-    [UsedImplicitly]
     public sealed partial class StorageSystem : EntitySystem
     {
-        [Dependency] private readonly IGameTiming _gameTiming = default!;
         [Dependency] private readonly IRobustRandom _random = default!;
         [Dependency] private readonly IAdminManager _admin = default!;
         [Dependency] private readonly ContainerSystem _containerSystem = default!;
@@ -57,6 +56,7 @@ namespace Content.Server.Storage.EntitySystems
         [Dependency] private readonly SharedCombatModeSystem _combatMode = default!;
         [Dependency] private readonly SharedTransformSystem _transform = default!;
         [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+        [Dependency] private readonly StackSystem _stack = default!;
         [Dependency] private readonly UseDelaySystem _useDelay = default!;
 
         /// <inheritdoc />
@@ -423,7 +423,7 @@ namespace Content.Server.Storage.EntitySystems
                 _appearance.SetData(uid, StackVisuals.Hide, !storageComp.IsOpen);
         }
 
-        private void RecalculateStorageUsed(ServerStorageComponent storageComp)
+        public void RecalculateStorageUsed(ServerStorageComponent storageComp)
         {
             storageComp.StorageUsed = 0;
             storageComp.SizeCache.Clear();
@@ -438,11 +438,20 @@ namespace Content.Server.Storage.EntitySystems
                 if (!itemQuery.TryGetComponent(entity, out var itemComp))
                     continue;
 
-                storageComp.StorageUsed += itemComp.Size;
-                storageComp.SizeCache.Add(entity, itemComp.Size);
+                var size = itemComp.Size;
+                storageComp.StorageUsed += size;
+                storageComp.SizeCache.Add(entity, size);
             }
         }
 
+        public int GetAvailableSpace(EntityUid uid, ServerStorageComponent? component = null)
+        {
+            if (!Resolve(uid, ref component))
+                return 0;
+
+            return component.StorageCapacityMax - component.StorageUsed;
+        }
+
         /// <summary>
         ///     Move entities from one storage to another.
         /// </summary>
@@ -508,7 +517,7 @@ namespace Content.Server.Storage.EntitySystems
                 return false;
             }
 
-            if (TryComp(insertEnt, out ItemComponent? itemComp) &&
+            if (!HasComp<StackComponent>(insertEnt) && TryComp(insertEnt, out ItemComponent? itemComp) &&
                 itemComp.Size > storageComp.StorageCapacityMax - storageComp.StorageUsed)
             {
                 reason = "comp-storage-insufficient-capacity";
@@ -525,9 +534,63 @@ namespace Content.Server.Storage.EntitySystems
         /// <returns>true if the entity was inserted, false otherwise</returns>
         public bool Insert(EntityUid uid, EntityUid insertEnt, ServerStorageComponent? storageComp = null, bool playSound = true)
         {
-            if (!Resolve(uid, ref storageComp) || !CanInsert(uid, insertEnt, out _, storageComp) || storageComp.Storage?.Insert(insertEnt) == false)
+            if (!Resolve(uid, ref storageComp) || !CanInsert(uid, insertEnt, out _, storageComp) || storageComp.Storage == null)
                 return false;
 
+            /*
+             * 1. If the inserted thing is stackable then try to stack it to existing stacks
+             * 2. If anything remains insert whatever is possible.
+             * 3. If insertion is not possible then leave the stack as is.
+             * At either rate still play the insertion sound
+             *
+             * For now we just treat items as always being the same size regardless of stack count.
+             */
+
+            // If it's stackable then prefer to stack it
+            var stackQuery = GetEntityQuery<StackComponent>();
+
+            if (stackQuery.TryGetComponent(insertEnt, out var insertStack))
+            {
+                var toInsertCount = insertStack.Count;
+
+                foreach (var ent in storageComp.Storage.ContainedEntities)
+                {
+                    if (!stackQuery.TryGetComponent(ent, out var containedStack) || !insertStack.StackTypeId.Equals(containedStack.StackTypeId))
+                        continue;
+
+                    if (!_stack.TryAdd(insertEnt, ent, insertStack, containedStack))
+                        continue;
+
+                    var remaining = insertStack.Count;
+                    toInsertCount -= toInsertCount - remaining;
+
+                    if (remaining > 0)
+                        continue;
+
+                    break;
+                }
+
+                // Still stackable remaining
+                if (insertStack.Count > 0)
+                {
+                    // Try to insert it as a new stack.
+                    if (TryComp(insertEnt, out ItemComponent? itemComp) &&
+                        itemComp.Size > storageComp.StorageCapacityMax - storageComp.StorageUsed ||
+                        !storageComp.Storage.Insert(insertEnt))
+                    {
+                        // If we also didn't do any stack fills above then just end
+                        // otherwise play sound and update UI anyway.
+                        if (toInsertCount == insertStack.Count)
+                            return false;
+                    }
+                }
+            }
+            // Non-stackable but no insertion for reasons.
+            else if (!storageComp.Storage.Insert(insertEnt))
+            {
+                return false;
+            }
+
             if (playSound && storageComp.StorageInsertSound is not null)
                 _audio.PlayPvs(storageComp.StorageInsertSound, uid);
 
@@ -643,7 +706,7 @@ namespace Content.Server.Storage.EntitySystems
             }
         }
 
-        private void UpdateStorageUI(EntityUid uid, ServerStorageComponent storageComp)
+        public void UpdateStorageUI(EntityUid uid, ServerStorageComponent storageComp)
         {
             if (storageComp.Storage == null)
                 return;
index b34498677c9a2521ff9ba0a2a1804a44e6a69530..0882777c4a8778950f49bf9a073fd81efea0a49c 100644 (file)
@@ -105,7 +105,7 @@ namespace Content.Shared.Stacks
             if (!Resolve(recipient, ref recipientStack, false) || !Resolve(donor, ref donorStack, false))
                 return false;
 
-            if (recipientStack.StackTypeId == null || !recipientStack.StackTypeId.Equals(donorStack.StackTypeId))
+            if (string.IsNullOrEmpty(recipientStack.StackTypeId) || !recipientStack.StackTypeId.Equals(donorStack.StackTypeId))
                 return false;
 
             transfered = Math.Min(donorStack.Count, GetAvailableSpace(recipientStack));
@@ -270,7 +270,7 @@ namespace Content.Shared.Stacks
             if (component.MaxCountOverride != null)
                 return component.MaxCountOverride.Value;
 
-            if (component.StackTypeId == null)
+            if (string.IsNullOrEmpty(component.StackTypeId))
                 return 1;
 
             var stackProto = _prototype.Index<StackPrototype>(component.StackTypeId);
@@ -289,6 +289,38 @@ namespace Content.Shared.Stacks
             return GetMaxCount(component) - component.Count;
         }
 
+        /// <summary>
+        /// Tries to add one stack to another. May have some leftover count in the inserted entity.
+        /// </summary>
+        public bool TryAdd(EntityUid insertEnt, EntityUid targetEnt, StackComponent? insertStack = null, StackComponent? targetStack = null)
+        {
+            if (!Resolve(insertEnt, ref insertStack) || !Resolve(targetEnt, ref targetStack))
+                return false;
+
+            var count = insertStack.Count;
+            return TryAdd(insertEnt, targetEnt, count, insertStack, targetStack);
+        }
+
+        /// <summary>
+        /// Tries to add one stack to another. May have some leftover count in the inserted entity.
+        /// </summary>
+        public bool TryAdd(EntityUid insertEnt, EntityUid targetEnt, int count, StackComponent? insertStack = null, StackComponent? targetStack = null)
+        {
+            if (!Resolve(insertEnt, ref insertStack) || !Resolve(targetEnt, ref targetStack))
+                return false;
+
+            var available = GetAvailableSpace(targetStack);
+
+            if (available <= 0)
+                return false;
+
+            var change = Math.Min(available, count);
+
+            SetCount(targetEnt, targetStack.Count + change, targetStack);
+            SetCount(insertEnt, insertStack.Count - change, insertStack);
+            return true;
+        }
+
         private void OnStackStarted(EntityUid uid, StackComponent component, ComponentStartup args)
         {
             if (!TryComp(uid, out AppearanceComponent? appearance))
index 3690cf7963db1dc2476a3c0fe895be4fbcabed8f..136405704e79200077f307a32697a5d1606d524c 100644 (file)
@@ -9,6 +9,7 @@
     sprite: Objects/Materials/ore.rsi
   - type: Item
     sprite: Objects/Materials/ore.rsi
+    size: 30
   - type: ItemStatus
   - type: Tag
     tags:
index 43339e244231be2612b807cb8dafc8d8a07bd15d..4c0dd0133051678e008db1e9fe794342c68d5666 100644 (file)
@@ -17,9 +17,9 @@
     stackType: Cable
   - type: Sprite
     sprite: Objects/Tools/cable-coils.rsi
-    netsync: false
   - type: Item
     sprite: Objects/Tools/cable-coils.rsi
+    size: 10
   - type: CablePlacer
   - type: Clickable
   - type: StaticPrice
@@ -39,7 +39,6 @@
   - type: Sprite
     state: coilhv-30
   - type: Item
-    size: 10
     heldPrefix: coilhv
   - type: CablePlacer
     cablePrototypeID: CableHV
@@ -59,8 +58,6 @@
   components:
   - type: Sprite
     state: coilhv-10
-  - type: Item
-    size: 3
   - type: Stack
     count: 1
 
@@ -76,7 +73,6 @@
   - type: Sprite
     state: coilmv-30
   - type: Item
-    size: 10
     heldPrefix: coilmv
   - type: CablePlacer
     cablePrototypeID: CableMV
@@ -96,8 +92,6 @@
   components:
   - type: Sprite
     state: coilmv-10
-  - type: Item
-    size: 3
   - type: Stack
     count: 1
 
   - type: Sprite
     state: coillv-30
   - type: Item
-    size: 10
     heldPrefix: coillv
   - type: CablePlacer
     cablePrototypeID: CableApcExtension
   components:
   - type: Sprite
     state: coillv-10
-  - type: Item
-    size: 3
   - type: Stack
     count: 1