]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
fix solution contents duplication on spill behavior (#33231)
authorMilon <milonpl.git@proton.me>
Mon, 22 Dec 2025 07:59:30 +0000 (08:59 +0100)
committerGitHub <noreply@github.com>
Mon, 22 Dec 2025 07:59:30 +0000 (07:59 +0000)
* I’M SCREAMING INTO THE VOID AND IT’S NOT LISTENING

* review

* explodes pancakes with mind

* graaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

* Meteors RAAAAAAAAAAH

* I'm so tired of solutions

* whhop

* revert

---------

Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
Content.Client/Fluids/PuddleSystem.cs
Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs
Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs
Content.Server/Fluids/EntitySystems/PuddleSystem.cs
Content.Shared/Fluids/SharedPuddleSystem.cs
Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs

index 1ab1ded3e8e303229826fe1d6248f7059f9d27f6..ab96d24d85a4d9f28f1bfe857509547dc2da09ac 100644 (file)
@@ -73,7 +73,19 @@ public sealed class PuddleSystem : SharedPuddleSystem
     // Maybe someday we'll have clientside prediction for entity spawning, but not today.
     // Until then, these methods do nothing on the client.
     /// <inheritdoc/>
-    public override bool TrySplashSpillAt(EntityUid uid, EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true, EntityUid? user = null)
+    public override bool TrySplashSpillAt(Entity<SpillableComponent?> entity, EntityCoordinates coordinates, out EntityUid puddleUid, out Solution solution, bool sound = true, EntityUid? user = null)
+    {
+        puddleUid = EntityUid.Invalid;
+        solution = new Solution();
+        return false;
+    }
+
+    public override bool TrySplashSpillAt(EntityUid entity,
+        EntityCoordinates coordinates,
+        Solution spilled,
+        out EntityUid puddleUid,
+        bool sound = true,
+        EntityUid? user = null)
     {
         puddleUid = EntityUid.Invalid;
         return false;
index ff050ce2cda1a63d0707f16f5e230ca822dc184d..ad34f05edd0fb7df4ec9a006fc1a609e9a7f89f3 100644 (file)
@@ -1,42 +1,38 @@
-using Content.Shared.Chemistry.EntitySystems;
 using Content.Server.Fluids.EntitySystems;
-using Content.Shared.Fluids.Components;
+using Content.Shared.Chemistry.EntitySystems;
 using JetBrains.Annotations;
 
-namespace Content.Server.Destructible.Thresholds.Behaviors
-{
-    [UsedImplicitly]
-    [DataDefinition]
-    public sealed partial class SpillBehavior : IThresholdBehavior
-    {
-        [DataField]
-        public string? Solution;
+namespace Content.Server.Destructible.Thresholds.Behaviors;
 
-        /// <summary>
-        /// If there is a SpillableComponent on EntityUidowner use it to create a puddle/smear.
-        /// Or whatever solution is specified in the behavior itself.
-        /// If none are available do nothing.
-        /// </summary>
-        /// <param name="owner">Entity on which behavior is executed</param>
-        /// <param name="system">system calling the behavior</param>
-        /// <param name="cause"></param>
-        public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
-        {
-            var solutionContainerSystem = system.EntityManager.System<SharedSolutionContainerSystem>();
-            var spillableSystem = system.EntityManager.System<PuddleSystem>();
+[UsedImplicitly]
+[DataDefinition]
+public sealed partial class SpillBehavior : IThresholdBehavior
+{
+    /// <summary>
+    /// Optional fallback solution name if SpillableComponent is not present.
+    /// </summary>
+    [DataField]
+    public string? Solution;
 
-            var coordinates = system.EntityManager.GetComponent<TransformComponent>(owner).Coordinates;
+    /// <summary>
+    /// When triggered, spills the entity's solution onto the ground.
+    /// Will first try to use the solution from a SpillableComponent if present,
+    /// otherwise falls back to the solution specified in the behavior's data fields.
+    /// The solution is properly drained/split before spilling to prevent double-spilling with other behaviors.
+    /// </summary>
+    /// <param name="owner">Entity whose solution will be spilled</param>
+    /// <param name="system">System calling this behavior</param>
+    /// <param name="cause">Optional entity that caused this behavior to trigger</param>
+    public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
+    {
+        var puddleSystem = system.EntityManager.System<PuddleSystem>();
+        var solutionContainer = system.EntityManager.System<SharedSolutionContainerSystem>();
+        var coordinates = system.EntityManager.GetComponent<TransformComponent>(owner).Coordinates;
 
-            if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) &&
-                solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, out _, out var compSolution))
-            {
-                spillableSystem.TrySplashSpillAt(owner, coordinates, compSolution, out _, false, user: cause);
-            }
-            else if (Solution != null &&
-                     solutionContainerSystem.TryGetSolution(owner, Solution, out _, out var behaviorSolution))
-            {
-                spillableSystem.TrySplashSpillAt(owner, coordinates, behaviorSolution, out _, user: cause);
-            }
-        }
+        // Spill the solution that was drained/split
+        if (solutionContainer.TryGetSolution(owner, Solution, out _, out var solution))
+            puddleSystem.TrySplashSpillAt(owner, coordinates, solution, out _, false, cause);
+        else
+            puddleSystem.TrySplashSpillAt(owner, coordinates, out _, out _, false, cause);
     }
 }
index 01526d4ee5a6c435f23c24687b56d5c876881f3f..e632d6efb3291111c2cc1f28435284af194181ad 100644 (file)
@@ -29,23 +29,14 @@ public sealed partial class PuddleSystem
 
     private void SpillOnLand(Entity<SpillableComponent> entity, ref LandEvent args)
     {
-        if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution))
+        if (!entity.Comp.SpillWhenThrown || Openable.IsClosed(entity.Owner))
             return;
 
-        if (Openable.IsClosed(entity.Owner))
-            return;
-
-        if (!entity.Comp.SpillWhenThrown)
-            return;
-
-        if (args.User != null)
+        if (TrySplashSpillAt(entity.Owner, Transform(entity).Coordinates, out _, out var solution) && args.User != null)
         {
             AdminLogger.Add(LogType.Landed,
                 $"{ToPrettyString(entity.Owner):entity} spilled a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution} on landing");
         }
-
-        var drainedSolution = _solutionContainerSystem.Drain(entity.Owner, soln.Value, solution.Volume);
-        TrySplashSpillAt(entity.Owner, Transform(entity).Coordinates, drainedSolution, out _);
     }
 
     private void OnDoAfter(Entity<SpillableComponent> entity, ref SpillDoAfterEvent args)
index 2f966354eca38ffb744354763fd9de3349f39776..c756a8e6963679ff148ff193c52ffd1dd0c12b24 100644 (file)
@@ -369,16 +369,37 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
 
     // TODO: This can be predicted once https://github.com/space-wizards/RobustToolbox/pull/5849 is merged
     /// <inheritdoc/>
-    public override bool TrySplashSpillAt(EntityUid uid,
+    public override bool TrySplashSpillAt(Entity<SpillableComponent?> entity,
         EntityCoordinates coordinates,
-        Solution solution,
         out EntityUid puddleUid,
+        out Solution spilled,
         bool sound = true,
         EntityUid? user = null)
     {
         puddleUid = EntityUid.Invalid;
+        spilled = new Solution();
 
-        if (solution.Volume == 0)
+        if (!Resolve(entity, ref entity.Comp))
+            return false;
+
+        if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var solution))
+            return false;
+
+        spilled = solution.Value.Comp.Solution;
+
+        return TrySplashSpillAt(entity, coordinates, spilled, out puddleUid, sound, user);
+    }
+
+    public override bool TrySplashSpillAt(EntityUid entity,
+        EntityCoordinates coordinates,
+        Solution spilled,
+        out EntityUid puddleUid,
+        bool sound = true,
+        EntityUid? user = null)
+    {
+        puddleUid = EntityUid.Invalid;
+
+        if (spilled.Volume == 0)
             return false;
 
         var targets = new List<EntityUid>();
@@ -392,26 +413,28 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
             var owner = ent.Owner;
 
             // between 5 and 30%
-            var splitAmount = solution.Volume * _random.NextFloat(0.05f, 0.30f);
-            var splitSolution = solution.SplitSolution(splitAmount);
+            var splitAmount = spilled.Volume * _random.NextFloat(0.05f, 0.30f);
+            var splitSolution = spilled.SplitSolution(splitAmount);
 
             if (user != null)
             {
                 AdminLogger.Add(LogType.Landed,
-                    $"{ToPrettyString(user.Value):user} threw {ToPrettyString(uid):entity} which splashed a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution} onto {ToPrettyString(owner):target}");
+                    $"{ToPrettyString(user.Value):user} threw {ToPrettyString(entity):entity} which splashed a solution {SharedSolutionContainerSystem.ToPrettyString(spilled):solution} onto {ToPrettyString(owner):target}");
             }
 
             targets.Add(owner);
             Reactive.DoEntityReaction(owner, splitSolution, ReactionMethod.Touch);
-            Popups.PopupEntity(
-                Loc.GetString("spill-land-spilled-on-other", ("spillable", uid),
-                    ("target", Identity.Entity(owner, EntityManager))), owner, PopupType.SmallCaution);
+            Popups.PopupEntity(Loc.GetString("spill-land-spilled-on-other",
+                    ("spillable", entity),
+                    ("target", Identity.Entity(owner, EntityManager))),
+                owner,
+                PopupType.SmallCaution);
         }
 
-        _color.RaiseEffect(solution.GetColor(_prototypeManager), targets,
-            Filter.Pvs(uid, entityManager: EntityManager));
+        _color.RaiseEffect(spilled.GetColor(_prototypeManager), targets,
+            Filter.Pvs(entity, entityManager: EntityManager));
 
-        return TrySpillAt(coordinates, solution, out puddleUid, sound);
+        return TrySpillAt(coordinates, spilled, out puddleUid, sound);
     }
 
     /// <inheritdoc/>
index e81d1c9d114cf72c2b3831225abdcfeface8510e..8f87734717d051df17ad85b829be38063808834f 100644 (file)
@@ -354,6 +354,15 @@ public abstract partial class SharedPuddleSystem : EntitySystem
     }
 
     #region Spill
+
+    /// <inheritdoc cref="TrySplashSpillAt(EntityUid,EntityCoordinates,Solution,out EntityUid,bool,EntityUid?)"/>
+    public abstract bool TrySplashSpillAt(Entity<SpillableComponent?> entity,
+        EntityCoordinates coordinates,
+        out EntityUid puddleUid,
+        out Solution spilled,
+        bool sound = true,
+        EntityUid? user = null);
+
     // These methods are in Shared to make it easier to interact with PuddleSystem in Shared code.
     // Note that they always fail when run on the client, not creating a puddle and returning false.
     // Adding proper prediction to this system would require spawning temporary puddle entities on the
@@ -367,9 +376,9 @@ public abstract partial class SharedPuddleSystem : EntitySystem
     /// <remarks>
     /// On the client, this will always set <paramref name="puddleUid"/> to <see cref="EntityUid.Invalid"/> and return false.
     /// </remarks>
-    public abstract bool TrySplashSpillAt(EntityUid uid,
+    public abstract bool TrySplashSpillAt(EntityUid entity,
         EntityCoordinates coordinates,
-        Solution solution,
+        Solution spilled,
         out EntityUid puddleUid,
         bool sound = true,
         EntityUid? user = null);
index 82d90f4c928c8324d23e69b6762170c86aa1a1ee..9a0e3e79fa60124a8d05d2c291ba29b7aecd09f7 100644 (file)
@@ -179,8 +179,8 @@ public sealed partial class PressurizedSolutionSystem : EntitySystem
         var solution = _solutionContainer.SplitSolution(soln.Value, interactions.Volume);
 
         // Spray the solution onto the ground and anyone nearby
-        if (TryComp(entity, out TransformComponent? transform))
-            _puddle.TrySplashSpillAt(entity, transform.Coordinates, solution, out _, sound: false);
+        var coordinates = Transform(entity).Coordinates;
+        _puddle.TrySplashSpillAt(entity.Owner, coordinates, out _, out _, sound: false);
 
         var drinkName = Identity.Entity(entity, EntityManager);