From 49dd17dcab3f6a6e327f6b3cc1f0ccd1afef66bf Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:47:53 +0200 Subject: [PATCH] Fix reagents with ReagentData being duplicated (#30983) Initial commit --- .../Chemistry/Components/Solution.cs | 69 ++++++++++++++----- .../Reaction/ChemicalReactionSystem.cs | 2 +- 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/Content.Shared/Chemistry/Components/Solution.cs b/Content.Shared/Chemistry/Components/Solution.cs index 725a685a8b..35ab28f34a 100644 --- a/Content.Shared/Chemistry/Components/Solution.cs +++ b/Content.Shared/Chemistry/Components/Solution.cs @@ -480,41 +480,72 @@ namespace Content.Shared.Chemistry.Components /// /// The reagent to be removed. /// How much reagent was actually removed. Zero if the reagent is not present on the solution. - public FixedPoint2 RemoveReagent(ReagentQuantity toRemove, bool preserveOrder = false) + public FixedPoint2 RemoveReagent(ReagentQuantity toRemove, bool preserveOrder = false, bool ignoreReagentData = false) { if (toRemove.Quantity <= FixedPoint2.Zero) return FixedPoint2.Zero; + List reagentIndices = new List(); + int totalRemoveVolume = 0; + for (var i = 0; i < Contents.Count; i++) { - var (reagent, curQuantity) = Contents[i]; + var (reagent, quantity) = Contents[i]; - if(reagent.Prototype != toRemove.Reagent.Prototype) - continue; + if (ignoreReagentData) + { + if (reagent.Prototype != toRemove.Reagent.Prototype) + continue; + } + else + { + if (reagent != toRemove.Reagent) + continue; + } + //We prepend instead of add to handle the Contents list back-to-front later down. + //It makes RemoveSwap safe to use. + totalRemoveVolume += quantity.Value; + reagentIndices.Insert(0, i); + } + + if (totalRemoveVolume <= 0) + { + // Reagent is not on the solution... + return FixedPoint2.Zero; + } + + FixedPoint2 removedQuantity = 0; + for (var i = 0; i < reagentIndices.Count; i++) + { + var (reagent, curQuantity) = Contents[reagentIndices[i]]; + + // This is set up such that integer rounding will tend to take more reagents. + var split = ((long)toRemove.Quantity.Value) * curQuantity.Value / totalRemoveVolume; + + var splitQuantity = FixedPoint2.FromCents((int)split); - var newQuantity = curQuantity - toRemove.Quantity; + var newQuantity = curQuantity - splitQuantity; _heatCapacityDirty = true; if (newQuantity <= 0) { if (!preserveOrder) - Contents.RemoveSwap(i); + Contents.RemoveSwap(reagentIndices[i]); else - Contents.RemoveAt(i); + Contents.RemoveAt(reagentIndices[i]); Volume -= curQuantity; - ValidateSolution(); - return curQuantity; + removedQuantity += curQuantity; + continue; } - Contents[i] = new ReagentQuantity(reagent, newQuantity); - Volume -= toRemove.Quantity; - ValidateSolution(); - return toRemove.Quantity; + Contents[reagentIndices[i]] = new ReagentQuantity(reagent, newQuantity); + Volume -= splitQuantity; + removedQuantity += splitQuantity; } + ValidateSolution(); - // Reagent is not on the solution... - return FixedPoint2.Zero; + return removedQuantity; } /// @@ -523,9 +554,9 @@ namespace Content.Shared.Chemistry.Components /// The prototype of the reagent to be removed. /// The amount of reagent to remove. /// How much reagent was actually removed. Zero if the reagent is not present on the solution. - public FixedPoint2 RemoveReagent(string prototype, FixedPoint2 quantity, List? data = null) + public FixedPoint2 RemoveReagent(string prototype, FixedPoint2 quantity, List? data = null, bool ignoreReagentData = false) { - return RemoveReagent(new ReagentQuantity(prototype, quantity, data)); + return RemoveReagent(new ReagentQuantity(prototype, quantity, data), ignoreReagentData: ignoreReagentData); } /// @@ -534,9 +565,9 @@ namespace Content.Shared.Chemistry.Components /// The reagent to be removed. /// The amount of reagent to remove. /// How much reagent was actually removed. Zero if the reagent is not present on the solution. - public FixedPoint2 RemoveReagent(ReagentId reagentId, FixedPoint2 quantity, bool preserveOrder = false) + public FixedPoint2 RemoveReagent(ReagentId reagentId, FixedPoint2 quantity, bool preserveOrder = false, bool ignoreReagentData = false) { - return RemoveReagent(new ReagentQuantity(reagentId, quantity), preserveOrder); + return RemoveReagent(new ReagentQuantity(reagentId, quantity), preserveOrder, ignoreReagentData); } public void RemoveAllSolution() diff --git a/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs index f9dfa9b273..534b6ba9f6 100644 --- a/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs +++ b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs @@ -172,7 +172,7 @@ namespace Content.Shared.Chemistry.Reaction if (!reactant.Value.Catalyst) { var amountToRemove = unitReactions * reactant.Value.Amount; - solution.RemoveReagent(reactant.Key, amountToRemove); + solution.RemoveReagent(reactant.Key, amountToRemove, ignoreReagentData: true); } } -- 2.52.0