diff --git a/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs
index e27063b1b5..04aa6546a9 100644
--- a/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs
@@ -61,35 +61,11 @@ public sealed class SolutionSpikableSystem : EntitySystem
return;
}
- if (_solutionSystem.TryMixAndOverflow(target,
- targetSolution,
- sourceSolution,
- targetSolution.MaxVolume,
- out var overflow))
- {
- if (overflow.Volume > 0)
- {
- RaiseLocalEvent(target, new SolutionSpikeOverflowEvent(overflow));
- }
+ if (!_solutionSystem.ForceAddSolution(target, targetSolution, sourceSolution))
+ return;
- _popupSystem.PopupEntity(Loc.GetString(spikableSource.Popup, ("spiked-entity", target), ("spike-entity", source)), user, user);
-
- sourceSolution.RemoveAllSolution();
-
- _triggerSystem.Trigger(source, user);
- }
- }
-}
-
-public sealed class SolutionSpikeOverflowEvent : HandledEntityEventArgs
-{
- ///
- /// The solution that's been overflowed from the spike.
- ///
- public Solution Overflow { get; }
-
- public SolutionSpikeOverflowEvent(Solution overflow)
- {
- Overflow = overflow;
+ _popupSystem.PopupEntity(Loc.GetString(spikableSource.Popup, ("spiked-entity", target), ("spike-entity", source)), user, user);
+ sourceSolution.RemoveAllSolution();
+ _triggerSystem.Trigger(source, user);
}
}
diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs
index 39485d60f7..a6d6a5b204 100644
--- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs
+++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs
@@ -34,7 +34,7 @@ public sealed partial class PuddleSystem
SubscribeLocalEvent(SplashOnMeleeHit, after: new[] { typeof(OpenableSystem) });
SubscribeLocalEvent>(AddSpillVerb);
SubscribeLocalEvent(OnGotEquipped);
- SubscribeLocalEvent(OnSpikeOverflow);
+ SubscribeLocalEvent(OnOverflow);
SubscribeLocalEvent(OnDoAfter);
}
@@ -46,13 +46,12 @@ public sealed partial class PuddleSystem
args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon"));
}
- private void OnSpikeOverflow(EntityUid uid, SpillableComponent component, SolutionSpikeOverflowEvent args)
+ private void OnOverflow(EntityUid uid, SpillableComponent component, ref SolutionOverflowEvent args)
{
- if (!args.Handled)
- {
- TrySpillAt(Transform(uid).Coordinates, args.Overflow, out _);
- }
+ if (args.Handled)
+ return;
+ TrySpillAt(Transform(uid).Coordinates, args.Overflow, out _);
args.Handled = true;
}
diff --git a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs b/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs
index d4c599557b..a5c35b5e6c 100644
--- a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs
+++ b/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs
@@ -30,6 +30,24 @@ public sealed class SolutionChangedEvent : EntityEventArgs
}
}
+///
+/// An event raised when more reagents are added to a (managed) solution than it can hold.
+///
+[ByRefEvent]
+public record struct SolutionOverflowEvent(EntityUid SolutionEnt, Solution SolutionHolder, Solution Overflow)
+{
+ /// The entity which contains the solution that has overflowed.
+ public readonly EntityUid SolutionEnt = SolutionEnt;
+ /// The solution that has overflowed.
+ public readonly Solution SolutionHolder = SolutionHolder;
+ /// The reagents that have overflowed the solution.
+ public readonly Solution Overflow = Overflow;
+ /// The volume by which the solution has overflowed.
+ public readonly FixedPoint2 OverflowVol = Overflow.Volume;
+ /// Whether some subscriber has taken care of the effects of the overflow.
+ public bool Handled = false;
+}
+
///
/// Part of Chemistry system deal with SolutionContainers
///
@@ -265,6 +283,14 @@ public sealed partial class SolutionContainerSystem : EntitySystem
_chemistrySystem.FullyReactSolution(solutionHolder, uid, solutionHolder.MaxVolume, mixerComponent);
}
+ var overflowVol = solutionHolder.Volume - solutionHolder.MaxVolume;
+ if (overflowVol > FixedPoint2.Zero)
+ {
+ var overflow = solutionHolder.SplitSolution(overflowVol);
+ var overflowEv = new SolutionOverflowEvent(uid, solutionHolder, overflow);
+ RaiseLocalEvent(uid, ref overflowEv);
+ }
+
UpdateAppearance(uid, solutionHolder);
RaiseLocalEvent(uid, new SolutionChangedEvent(solutionHolder, solutionHolder.Name));
}
@@ -417,24 +443,6 @@ public sealed partial class SolutionContainerSystem : EntitySystem
return RemoveReagent(targetUid, container, new ReagentQuantity(reagentId, quantity));
}
- ///
- /// Adds a solution to the container, if it can fully fit.
- ///
- /// entity holding targetSolution
- /// entity holding targetSolution
- /// solution being added
- /// If the solution could be added.
- public bool TryAddSolution(EntityUid targetUid, Solution? targetSolution, Solution addedSolution)
- {
- if (targetSolution == null
- || !targetSolution.CanAddSolution(addedSolution) || addedSolution.Volume == 0)
- return false;
-
- targetSolution.AddSolution(addedSolution, _prototypeManager);
- UpdateChemicals(targetUid, targetSolution, true);
- return true;
- }
-
///
/// Moves some quantity of a solution from one solution to another.
///
@@ -497,32 +505,86 @@ public sealed partial class SolutionContainerSystem : EntitySystem
}
///
- /// Adds a solution to the container, overflowing the rest.
- /// It will
- /// Unlike it will ignore size limits.
+ /// Adds a solution to the container, if it can fully fit.
///
/// entity holding targetSolution
- /// The container to which we try to add.
- /// solution being added
- /// After addition this much will be left in targetSolution. Should be less
- /// than targetSolution.TotalVolume
+ /// entity holding targetSolution
+ /// solution being added
+ /// If the solution could be added.
+ public bool TryAddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd)
+ {
+ if (toAdd.Volume == FixedPoint2.Zero)
+ return true;
+ if (toAdd.Volume > targetSolution.AvailableVolume)
+ return false;
+
+ ForceAddSolution(targetUid, targetSolution, toAdd);
+ return true;
+ }
+
+ ///
+ /// Adds as much of a solution to a container as can fit.
+ ///
+ /// The entity containing
+ /// The solution being added to.
+ /// The solution being added to
+ /// The quantity of the solution actually added.
+ public FixedPoint2 AddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd)
+ {
+ if (toAdd.Volume == FixedPoint2.Zero)
+ return FixedPoint2.Zero;
+
+ var quantity = FixedPoint2.Max(FixedPoint2.Zero, FixedPoint2.Min(toAdd.Volume, targetSolution.AvailableVolume));
+ if (quantity < toAdd.Volume)
+ TryTransferSolution(targetUid, targetSolution, toAdd, quantity);
+ else
+ ForceAddSolution(targetUid, targetSolution, toAdd);
+
+ return quantity;
+ }
+
+ ///
+ /// Adds a solution to a container and updates the container.
+ ///
+ /// The entity containing
+ /// The solution being added to.
+ /// The solution being added to
+ /// Whether any reagents were added to the solution.
+ public bool ForceAddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd)
+ {
+ if (toAdd.Volume == FixedPoint2.Zero)
+ return false;
+
+ targetSolution.AddSolution(toAdd, _prototypeManager);
+ UpdateChemicals(targetUid, targetSolution, needsReactionsProcessing: true);
+ return true;
+ }
+
+ ///
+ /// Adds a solution to the container, removing the overflow.
+ /// Unlike it will ignore size limits.
+ ///
+ /// The entity containing
+ /// The solution being added to.
+ /// The solution being added to
+ /// The combined volume above which the overflow will be returned.
+ /// If the combined volume is below this an empty solution is returned.
/// Solution that exceeded overflowThreshold
- ///
+ /// Whether any reagents were added to .
public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution,
- Solution addedSolution,
+ Solution toAdd,
FixedPoint2 overflowThreshold,
[NotNullWhen(true)] out Solution? overflowingSolution)
{
- if (addedSolution.Volume == 0 || overflowThreshold > targetSolution.MaxVolume)
+ if (toAdd.Volume == 0 || overflowThreshold > targetSolution.MaxVolume)
{
overflowingSolution = null;
return false;
}
- targetSolution.AddSolution(addedSolution, _prototypeManager);
+ targetSolution.AddSolution(toAdd, _prototypeManager);
+ overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero, targetSolution.Volume - overflowThreshold));
UpdateChemicals(targetUid, targetSolution, true);
- overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero,
- targetSolution.Volume - overflowThreshold));
return true;
}
@@ -778,4 +840,8 @@ public sealed partial class SolutionContainerSystem : EntitySystem
}
#endregion Thermal Energy and Temperature
+
+ #region Event Handlers
+
+ #endregion Event Handlers
}
diff --git a/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs
index 4ec50bc61a..ed53b78466 100644
--- a/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs
+++ b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs
@@ -262,12 +262,6 @@ namespace Content.Shared.Chemistry.Reaction
if (products.Count == 0)
return true;
- // remove excess product
- // TODO spill excess?
- var excessVolume = solution.Volume - maxVolume;
- if (excessVolume > 0)
- solution.RemoveSolution(excessVolume);
-
// Add any reactions associated with the new products. This may re-add reactions that were already iterated
// over previously. The new product may mean the reactions are applicable again and need to be processed.
foreach (var product in products)
@@ -279,16 +273,10 @@ namespace Content.Shared.Chemistry.Reaction
return true;
}
- ///
- /// Continually react a solution until no more reactions occur.
- ///
- public void FullyReactSolution(Solution solution, EntityUid owner) => FullyReactSolution(solution, owner, FixedPoint2.MaxValue, null);
-
///
/// Continually react a solution until no more reactions occur, with a volume constraint.
- /// If a reaction's products would exceed the max volume, some product is deleted.
///
- public void FullyReactSolution(Solution solution, EntityUid owner, FixedPoint2 maxVolume, ReactionMixerComponent? mixerComponent)
+ public void FullyReactSolution(Solution solution, EntityUid owner, FixedPoint2 maxVolume, ReactionMixerComponent? mixerComponent = null)
{
// construct the initial set of reactions to check.
SortedSet reactions = new();
diff --git a/Resources/Prototypes/Recipes/Reactions/cleaning.yml b/Resources/Prototypes/Recipes/Reactions/cleaning.yml
index 8ae72853be..1c68aeb2e3 100644
--- a/Resources/Prototypes/Recipes/Reactions/cleaning.yml
+++ b/Resources/Prototypes/Recipes/Reactions/cleaning.yml
@@ -31,4 +31,4 @@
Oxygen:
amount: 1
products:
- SpaceLube: 3
+ SpaceLube: 5