From: Milon Date: Mon, 22 Dec 2025 07:59:30 +0000 (+0100) Subject: fix solution contents duplication on spill behavior (#33231) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=f59ef4b986bba91c5755c9dc6fcdf9a82581e2fe;p=space-station-14.git fix solution contents duplication on spill behavior (#33231) * 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> --- diff --git a/Content.Client/Fluids/PuddleSystem.cs b/Content.Client/Fluids/PuddleSystem.cs index 1ab1ded3e8..ab96d24d85 100644 --- a/Content.Client/Fluids/PuddleSystem.cs +++ b/Content.Client/Fluids/PuddleSystem.cs @@ -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. /// - public override bool TrySplashSpillAt(EntityUid uid, EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true, EntityUid? user = null) + public override bool TrySplashSpillAt(Entity 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; diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs index ff050ce2cd..ad34f05edd 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs @@ -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; - /// - /// 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. - /// - /// Entity on which behavior is executed - /// system calling the behavior - /// - public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null) - { - var solutionContainerSystem = system.EntityManager.System(); - var spillableSystem = system.EntityManager.System(); +[UsedImplicitly] +[DataDefinition] +public sealed partial class SpillBehavior : IThresholdBehavior +{ + /// + /// Optional fallback solution name if SpillableComponent is not present. + /// + [DataField] + public string? Solution; - var coordinates = system.EntityManager.GetComponent(owner).Coordinates; + /// + /// 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. + /// + /// Entity whose solution will be spilled + /// System calling this behavior + /// Optional entity that caused this behavior to trigger + public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null) + { + var puddleSystem = system.EntityManager.System(); + var solutionContainer = system.EntityManager.System(); + var coordinates = system.EntityManager.GetComponent(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); } } diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs index 01526d4ee5..e632d6efb3 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs @@ -29,23 +29,14 @@ public sealed partial class PuddleSystem private void SpillOnLand(Entity 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 entity, ref SpillDoAfterEvent args) diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs index 2f966354ec..c756a8e696 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs @@ -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 /// - public override bool TrySplashSpillAt(EntityUid uid, + public override bool TrySplashSpillAt(Entity 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(); @@ -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); } /// diff --git a/Content.Shared/Fluids/SharedPuddleSystem.cs b/Content.Shared/Fluids/SharedPuddleSystem.cs index e81d1c9d11..8f87734717 100644 --- a/Content.Shared/Fluids/SharedPuddleSystem.cs +++ b/Content.Shared/Fluids/SharedPuddleSystem.cs @@ -354,6 +354,15 @@ public abstract partial class SharedPuddleSystem : EntitySystem } #region Spill + + /// + public abstract bool TrySplashSpillAt(Entity 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 /// /// On the client, this will always set to and return false. /// - 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); diff --git a/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs b/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs index 82d90f4c92..9a0e3e79fa 100644 --- a/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs @@ -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);