]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Fix flatpacker exploit ignoring board costs (#42445)
authorNemanja <98561806+EmoGarbage404@users.noreply.github.com>
Fri, 16 Jan 2026 00:22:24 +0000 (19:22 -0500)
committerGitHub <noreply@github.com>
Fri, 16 Jan 2026 00:22:24 +0000 (00:22 +0000)
Fix flatpacks ignoring costs and board requirements

Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs
Content.Server/Construction/FlatpackSystem.cs
Content.Shared/Construction/MachinePartSystem.cs
Content.Shared/Construction/SharedFlatpackSystem.cs
Resources/Locale/en-US/construction/components/flatpack.ftl

index 8ee8df48fd305afeb6928e23566fb61c2e581bbf..7db15596bdbad6d1dd3d8caa0271548fd5713542 100644 (file)
@@ -1,13 +1,11 @@
 using System.Linq;
 using Content.Client.Materials;
-using Content.Client.Materials.UI;
 using Content.Client.Message;
 using Content.Client.UserInterface.Controls;
 using Content.Shared.Construction.Components;
 using Content.Shared.Containers.ItemSlots;
 using Content.Shared.Materials;
 using Robust.Client.AutoGenerated;
-using Robust.Client.GameObjects;
 using Robust.Client.UserInterface.XAML;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Timing;
@@ -61,57 +59,48 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow
             !_itemSlots.TryGetSlot(_owner, flatpacker.SlotId, out var itemSlot))
             return;
 
+        var flatpackerEnt = (_owner, flatpacker);
+
         if (flatpacker.Packing)
         {
             PackButton.Disabled = true;
         }
         else if (_currentBoard != null)
         {
-            Dictionary<string, int> cost;
-            if (_entityManager.TryGetComponent<MachineBoardComponent>(_currentBoard, out var machineBoardComp))
-                cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker), (_currentBoard.Value, machineBoardComp));
-            else
-                cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker), null);
-
-            PackButton.Disabled = !_materialStorage.CanChangeMaterialAmount(_owner, cost);
+            PackButton.Disabled = !_flatpack.TryGetFlatpackCreationCost(flatpackerEnt, _currentBoard.Value, out var curCost)
+                || !_materialStorage.CanChangeMaterialAmount(_owner, curCost);
         }
 
         if (_currentBoard == itemSlot.Item)
             return;
 
         _currentBoard = itemSlot.Item;
-        CostHeaderLabel.Visible = _currentBoard != null;
+        CostHeaderLabel.Visible = false;
         InsertLabel.Visible = _currentBoard == null;
 
-        if (_currentBoard is not null)
+        if (_currentBoard is null)
+        {
+            MachineSprite.SetPrototype(NoBoardEffectId);
+            CostLabel.SetMessage(Loc.GetString("flatpacker-ui-no-board-label"));
+            MachineNameLabel.SetMessage(string.Empty);
+            PackButton.Disabled = true;
+            return;
+        }
+
+        if (_flatpack.TryGetFlatpackResultPrototype(_currentBoard.Value, out var prototype) &&
+            _flatpack.TryGetFlatpackCreationCost(flatpackerEnt, _currentBoard.Value, out var cost))
         {
-            string? prototype = null;
-            Dictionary<string, int>? cost = null;
-
-            if (_entityManager.TryGetComponent<MachineBoardComponent>(_currentBoard, out var newMachineBoardComp))
-            {
-                prototype = newMachineBoardComp.Prototype;
-                cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker), (_currentBoard.Value, newMachineBoardComp));
-            }
-            else if (_entityManager.TryGetComponent<ComputerBoardComponent>(_currentBoard, out var computerBoard))
-            {
-                prototype = computerBoard.Prototype;
-                cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker), null);
-            }
-
-            if (prototype is not null && cost is not null)
-            {
-                var proto = _prototypeManager.Index<EntityPrototype>(prototype);
-                MachineSprite.SetPrototype(prototype);
-                MachineNameLabel.SetMessage(proto.Name);
-                CostLabel.SetMarkup(GetCostString(cost));
-            }
+            var proto = _prototypeManager.Index<EntityPrototype>(prototype);
+            MachineSprite.SetPrototype(prototype);
+            MachineNameLabel.SetMessage(proto.Name);
+            CostLabel.SetMarkup(GetCostString(cost));
+            CostHeaderLabel.Visible = true;
         }
         else
         {
             MachineSprite.SetPrototype(NoBoardEffectId);
-            CostLabel.SetMessage(Loc.GetString("flatpacker-ui-no-board-label"));
-            MachineNameLabel.SetMessage(" ");
+            CostLabel.SetMarkup(Loc.GetString("flatpacker-ui-board-invalid-label"));
+            MachineNameLabel.SetMessage(string.Empty);
             PackButton.Disabled = true;
         }
     }
index 11303e7f2eeef9b65b0720aa280de665619ae606..baa123a92840c1785ea445c4545f094110c1b22c 100644 (file)
@@ -1,11 +1,9 @@
 using Content.Server.Audio;
-using Content.Server.Power.Components;
 using Content.Server.Power.EntitySystems;
 using Content.Shared.Construction;
 using Content.Shared.Construction.Components;
 using Content.Shared.Containers.ItemSlots;
 using Content.Shared.Power;
-using Robust.Shared.Prototypes;
 using Robust.Shared.Timing;
 
 namespace Content.Server.Construction;
@@ -35,16 +33,8 @@ public sealed class FlatpackSystem : SharedFlatpackSystem
         if (!_itemSlots.TryGetSlot(uid, comp.SlotId, out var itemSlot) || itemSlot.Item is not { } board)
             return;
 
-        Dictionary<string, int> cost;
-        if (TryComp<MachineBoardComponent>(board, out var machine))
-            cost = GetFlatpackCreationCost(ent, (board, machine));
-        else if (TryComp<ComputerBoardComponent>(board, out var computer) && computer.Prototype != null)
-            cost = GetFlatpackCreationCost(ent, null);
-        else
-        {
-            Log.Error($"Encountered invalid flatpack board while packing: {ToPrettyString(board)}");
+        if (!TryGetFlatpackCreationCost(ent, board, out var cost))
             return;
-        }
 
         if (!MaterialStorage.CanChangeMaterialAmount(uid, cost))
             return;
@@ -80,29 +70,15 @@ public sealed class FlatpackSystem : SharedFlatpackSystem
         if (!_itemSlots.TryGetSlot(uid, comp.SlotId, out var itemSlot) || itemSlot.Item is not { } board)
             return;
 
-        Dictionary<string, int> cost;
-        EntProtoId proto;
-        if (TryComp<MachineBoardComponent>(board, out var machine))
-        {
-            cost = GetFlatpackCreationCost(ent, (board, machine));
-            proto = machine.Prototype;
-        }
-        else if (TryComp<ComputerBoardComponent>(board, out var computer) && computer.Prototype != null)
-        {
-            cost = GetFlatpackCreationCost(ent, null);
-            proto = computer.Prototype;
-        }
-        else
-        {
-            Log.Error($"Encountered invalid flatpack board while packing: {ToPrettyString(board)}");
+        if (!TryGetFlatpackCreationCost(ent, board, out var cost) ||
+            !TryGetFlatpackResultPrototype(board, out var proto))
             return;
-        }
 
         if (!MaterialStorage.TryChangeMaterialAmount((ent, null), cost))
             return;
 
         var flatpack = Spawn(comp.BaseFlatpackPrototype, Transform(ent).Coordinates);
-        SetupFlatpack(flatpack, proto, board);
+        SetupFlatpack(flatpack, proto.Value, board);
         Del(board);
     }
 
index 7ac9fde94c763171086162976b562ecf2dc126ca..4783c2a332a38d4bf65a57da824fe1d9bb2f0751 100644 (file)
@@ -58,11 +58,11 @@ namespace Content.Shared.Construction
             }
         }
 
-        public Dictionary<string, int> GetMachineBoardMaterialCost(Entity<MachineBoardComponent> entity, int coefficient = 1)
+        public bool TryGetMachineBoardMaterialCost(Entity<MachineBoardComponent> entity, out Dictionary<string, int> materials, int coefficient = 1)
         {
             var (_, comp) = entity;
 
-            var materials = new Dictionary<string, int>();
+            materials = new Dictionary<string, int>();
 
             foreach (var (stackId, amount) in comp.StackRequirements)
             {
@@ -89,9 +89,14 @@ namespace Content.Shared.Construction
                         materials[mat] += matAmount * amount * coefficient;
                     }
                 }
+                else
+                {
+                    // The item has no material cost, so we cannot get the full cost.
+                    return false;
+                }
             }
 
-            var genericPartInfo = comp.ComponentRequirements.Values.Concat(comp.ComponentRequirements.Values);
+            var genericPartInfo = comp.ComponentRequirements.Values.Concat(comp.TagRequirements.Values);
             foreach (var info in genericPartInfo)
             {
                 var amount = info.Amount;
@@ -118,9 +123,15 @@ namespace Content.Shared.Construction
                         materials[mat] += matAmount * amount * coefficient;
                     }
                 }
+                else
+                {
+                    // The item has no material cost, so we cannot get the full cost.
+                    return false;
+                }
             }
 
-            return materials;
+            // We were able to construct all elements of the recipe.
+            return true;
         }
     }
 }
index a83948b167411817cff971c541f7a2c2e2adf560..f6a56d9ae4430033db42cc00e8fb63c620ccaf5f 100644 (file)
@@ -1,3 +1,4 @@
+using System.Diagnostics.CodeAnalysis;
 using Content.Shared.Construction.Components;
 using Content.Shared.Administration.Logs;
 using Content.Shared.Containers.ItemSlots;
@@ -125,14 +126,34 @@ public abstract class SharedFlatpackSystem : EntitySystem
         Appearance.SetData(ent, FlatpackVisuals.Machine, MetaData(board).EntityPrototype?.ID ?? string.Empty);
     }
 
+    /// <summary>
+    /// Returns the prototype from a board that the flatpacker will create.
+    /// </summary>
+    public bool TryGetFlatpackResultPrototype(EntityUid board, [NotNullWhen(true)] out EntProtoId? prototype)
+    {
+        prototype = null;
+
+        if (TryComp<MachineBoardComponent>(board, out var machine))
+            prototype = machine.Prototype;
+        else if (TryComp<ComputerBoardComponent>(board, out var computer))
+            prototype = computer.Prototype;
+        return prototype is not null;
+    }
+
+    /// <summary>
+    /// Tries to get the cost to produce an item, fails if unable to produce it.
+    /// </summary>
+    /// <param name="entity">The flatpacking machine</param>
     /// <param name="machineBoard">The machine board to pack. If null, this implies we are packing a computer board</param>
-    public Dictionary<string, int> GetFlatpackCreationCost(Entity<FlatpackCreatorComponent> entity, Entity<MachineBoardComponent>? machineBoard)
+    /// <param name="cost">Cost to produce</param>
+    public bool TryGetFlatpackCreationCost(Entity<FlatpackCreatorComponent> entity, EntityUid machineBoard, out Dictionary<string, int> cost)
     {
-        Dictionary<string, int> cost = new();
+        cost = new();
         Dictionary<ProtoId<MaterialPrototype>, int> baseCost;
-        if (machineBoard is not null)
+        if (TryComp<MachineBoardComponent>(machineBoard, out var machineBoardComp))
         {
-            cost = MachinePart.GetMachineBoardMaterialCost(machineBoard.Value, -1);
+            if (!MachinePart.TryGetMachineBoardMaterialCost((machineBoard, machineBoardComp), out cost, -1))
+                return false;
             baseCost = entity.Comp.BaseMachineCost;
         }
         else
@@ -144,6 +165,6 @@ public abstract class SharedFlatpackSystem : EntitySystem
             cost[mat] -= amount;
         }
 
-        return cost;
+        return true;
     }
 }
index 0957d92f3e0790080a7a204e0081f7b3aff02ff6..a47cea782c8fd15200dfe268c0cf6c305d44c6a5 100644 (file)
@@ -8,5 +8,7 @@ flatpacker-ui-title = Flatpacker 1001
 flatpacker-ui-materials-label = Materials
 flatpacker-ui-cost-label = Packing Cost
 flatpacker-ui-no-board-label = No board present!
+flatpacker-ui-board-invalid-label = [color=red]Invalid board!
+    Unable to print![/color]
 flatpacker-ui-insert-board = Insert a board to begin.
 flatpacker-ui-pack-button = Pack