diff --git a/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs
index 1d39a7996c..2e6b8114ba 100644
--- a/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Content.Server.Chemistry.Components.SolutionManager;
+using Content.Server.Fluids.Components;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reaction;
@@ -213,17 +214,46 @@ namespace Content.Server.Chemistry.EntitySystems
///
/// Adds a solution to the container, if it can fully fit.
///
- ///
- /// The container to which we try to add.
- /// The solution to try to add.
+ /// entity holding targetSolution
+ /// entity holding targetSolution
+ /// solution being added
/// If the solution could be added.
- public bool TryAddSolution(EntityUid targetUid, Solution? targetSolution, Solution solution)
+ public bool TryAddSolution(EntityUid targetUid, Solution? targetSolution, Solution addedSolution)
{
- if (targetSolution == null || !targetSolution.CanAddSolution(solution) || solution.TotalVolume == 0)
+ if (targetSolution == null
+ || !targetSolution.CanAddSolution(addedSolution) || targetSolution.TotalVolume == 0)
return false;
- targetSolution.AddSolution(solution);
+ addedSolution.AddSolution(targetSolution);
+ UpdateChemicals(targetUid, addedSolution, true);
+ return true;
+ }
+
+ ///
+ /// Adds a solution to the container, overflowing the rest.
+ /// Unlike TryAddSolution it will ignore size limits.
+ ///
+ /// entity holding targetSolution
+ /// The container to which we try to add.
+ /// solution being added
+ /// After addition this much will be left in targetSolution
+ /// Solution that exceeded overflowThreshold
+ ///
+ public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution,
+ Solution addedSolution,
+ FixedPoint2 overflowThreshold,
+ [NotNullWhen(true)] out Solution? overflowingSolution)
+ {
+ if (addedSolution.TotalVolume == 0)
+ {
+ overflowingSolution = null;
+ return false;
+ }
+
+ targetSolution.AddSolution(addedSolution);
UpdateChemicals(targetUid, targetSolution, true);
+ overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero,
+ targetSolution.CurrentVolume - overflowThreshold));
return true;
}
@@ -295,19 +325,6 @@ namespace Content.Server.Chemistry.EntitySystems
return removedReagent;
}
- public void TryRemoveAllReagents(EntityUid uid, Solution solution, List removeReagents)
- {
- if (removeReagents.Count == 0)
- return;
-
- foreach (var reagent in removeReagents)
- {
- solution.RemoveReagent(reagent.ReagentId, reagent.Quantity);
- }
-
- UpdateChemicals(uid, solution);
- }
-
public FixedPoint2 GetReagentQuantity(EntityUid owner, string reagentId)
{
var reagentQuantity = FixedPoint2.New(0);
diff --git a/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs b/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs
index f0a1bdc3a5..95daf37beb 100644
--- a/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs
+++ b/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs
@@ -1,5 +1,4 @@
-using Content.Server.Fluids.Components;
-using Content.Server.Fluids.EntitySystems;
+using Content.Server.Fluids.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
@@ -20,8 +19,8 @@ namespace Content.Server.Chemistry.TileReactions
var spillSystem = EntitySystem.Get();
if (reactVolume < 5 || !spillSystem.TryGetPuddle(tile, out _)) return FixedPoint2.Zero;
- return spillSystem.SpillAt(tile,new Solution(reagent.ID, reactVolume), "PuddleSmear", true, false, true) != null
- ? reactVolume
+ return spillSystem.SpillAt(tile,new Solution(reagent.ID, reactVolume), "PuddleSmear", true, false, true) != null
+ ? reactVolume
: FixedPoint2.Zero;
}
}
diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs
index dbb9a8fca6..b21e0f6654 100644
--- a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs
+++ b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs
@@ -37,7 +37,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
else if (Solution != null &&
solutionContainerSystem.TryGetSolution(owner, Solution, out var behaviorSolution))
{
- spillableSystem.SpillAt(behaviorSolution, coordinates, "PuddleSmear", false);
+ spillableSystem.SpillAt(behaviorSolution, coordinates, "PuddleSmear");
}
}
}
diff --git a/Content.Server/Fluids/Components/FluidSpreaderComponent.cs b/Content.Server/Fluids/Components/FluidSpreaderComponent.cs
new file mode 100644
index 0000000000..27ee2c4a5e
--- /dev/null
+++ b/Content.Server/Fluids/Components/FluidSpreaderComponent.cs
@@ -0,0 +1,14 @@
+using Content.Server.Fluids.EntitySystems;
+using Content.Shared.Chemistry.Components;
+
+namespace Content.Server.Fluids.Components;
+
+[RegisterComponent]
+[Friend(typeof(FluidSpreaderSystem))]
+public sealed class FluidSpreaderComponent : Component
+{
+ [ViewVariables]
+ public Solution OverflownSolution = default!;
+
+ public bool Enabled { get; set; }
+}
diff --git a/Content.Server/Fluids/Components/PuddleComponent.cs b/Content.Server/Fluids/Components/PuddleComponent.cs
index eec596d154..b7bdab7568 100644
--- a/Content.Server/Fluids/Components/PuddleComponent.cs
+++ b/Content.Server/Fluids/Components/PuddleComponent.cs
@@ -48,11 +48,6 @@ namespace Content.Server.Fluids.Components
[DataField("spillSound")]
public SoundSpecifier SpillSound = new SoundPathSpecifier("/Audio/Effects/Fluids/splat.ogg");
- ///
- /// Whether or not this puddle is currently overflowing onto its neighbors
- ///
- public bool Overflown;
-
[ViewVariables(VVAccess.ReadOnly)]
public FixedPoint2 CurrentVolume => EntitySystem.Get().CurrentVolume(Owner);
diff --git a/Content.Server/Fluids/EntitySystems/FluidSpreaderSystem.cs b/Content.Server/Fluids/EntitySystems/FluidSpreaderSystem.cs
new file mode 100644
index 0000000000..c4907bc5d6
--- /dev/null
+++ b/Content.Server/Fluids/EntitySystems/FluidSpreaderSystem.cs
@@ -0,0 +1,208 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using Content.Server.Chemistry.EntitySystems;
+using Content.Server.Fluids.Components;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Directions;
+using Content.Shared.FixedPoint;
+using Content.Shared.Physics;
+using JetBrains.Annotations;
+using Robust.Shared.Map;
+using Robust.Shared.Physics;
+using Robust.Shared.Utility;
+
+namespace Content.Server.Fluids.EntitySystems;
+
+[UsedImplicitly]
+public sealed class FluidSpreaderSystem : EntitySystem
+{
+ [Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly PuddleSystem _puddleSystem = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
+
+
+ private float _accumulatedTimeFrame;
+ private HashSet _fluidSpread = new();
+
+ public override void Initialize()
+ {
+ SubscribeLocalEvent((uid, component, _) =>
+ FluidSpreaderAdd(uid, component));
+ }
+
+ public void AddOverflowingPuddle(PuddleComponent puddleComponent, Solution? solution = null)
+ {
+ var puddleSolution = solution;
+ if (puddleSolution == null && !_solutionContainerSystem.TryGetSolution(puddleComponent.Owner,
+ puddleComponent.SolutionName,
+ out puddleSolution)) return;
+
+ if (puddleSolution.CurrentVolume <= puddleComponent.OverflowVolume)
+ return;
+
+ var spreaderComponent = EntityManager.EnsureComponent(puddleComponent.Owner);
+ spreaderComponent.OverflownSolution = puddleSolution;
+ spreaderComponent.Enabled = true;
+ FluidSpreaderAdd(spreaderComponent.Owner, spreaderComponent);
+ }
+
+ private void FluidSpreaderAdd(EntityUid uid, FluidSpreaderComponent component)
+ {
+ if (component.Enabled)
+ _fluidSpread.Add(uid);
+ }
+
+ public override void Update(float frameTime)
+ {
+ _accumulatedTimeFrame += frameTime;
+
+ if (!(_accumulatedTimeFrame >= 1.0f))
+ return;
+
+ _accumulatedTimeFrame -= 1.0f;
+
+ base.Update(frameTime);
+
+ var remQueue = new RemQueue();
+ foreach (var uid in _fluidSpread)
+ {
+ MetaDataComponent? meta = null;
+
+ if (Paused(uid, meta))
+ continue;
+
+ // If not paused
+ // it's either Deleted or will be via SpreadFluid
+ remQueue.Add(uid);
+
+ if (Deleted(uid, meta))
+ continue;
+
+ SpreadFluid(uid);
+ }
+
+ foreach (var removeUid in remQueue)
+ {
+ _fluidSpread.Remove(removeUid);
+ }
+ }
+
+ private void SpreadFluid(EntityUid suid)
+ {
+ PuddleComponent? puddleComponent = null;
+ MetaDataComponent? metadataOriginal = null;
+ TransformComponent? transformOrig = null;
+ FluidSpreaderComponent? spreader = null;
+
+ if (!Resolve(suid, ref puddleComponent, ref metadataOriginal, ref transformOrig, ref spreader, false))
+ return;
+
+ var prototypeName = metadataOriginal.EntityPrototype!.ID;
+
+ var puddles = new List { puddleComponent };
+ var visitedTiles = new HashSet();
+
+ if (!_mapManager.TryGetGrid(transformOrig.GridID, out var mapGrid))
+ return;
+
+ while (puddles.Count > 0
+ && spreader.OverflownSolution.CurrentVolume > FixedPoint2.Zero)
+ {
+ var nextToExpand = new List<(Vector2i, EntityUid?)>();
+
+ var divided = spreader.OverflownSolution.CurrentVolume / puddles.Count;
+
+ foreach (var puddle in puddles)
+ {
+ if (puddle.CurrentVolume >= puddle.OverflowVolume) continue;
+
+ // -puddle.OverflowLeft is guaranteed to be >= 0
+ // iff puddle.CurrentVolume >= puddle.OverflowVolume
+ var split = FixedPoint2.Min(divided, -puddle.OverflowLeft);
+ _puddleSystem.TryAddSolution(
+ puddle.Owner,
+ spreader.OverflownSolution.SplitSolution(split),
+ false, false, puddle);
+ }
+
+ // if solution is spent do not explore
+ if (spreader.OverflownSolution.CurrentVolume <= FixedPoint2.Zero)
+ continue;
+
+ // find edges
+ foreach (var puddle in puddles)
+ {
+ TransformComponent? transform = null;
+
+ if (!Resolve(puddle.Owner, ref transform, false))
+ continue;
+
+ // prepare next set of puddles to be expanded
+ var puddlePos = transform.Coordinates.ToVector2i(EntityManager, _mapManager);
+ foreach (var direction in SharedDirectionExtensions.RandomDirections().ToArray())
+ {
+ var newPos = puddlePos.Offset(direction);
+ if (visitedTiles.Contains(newPos))
+ continue;
+
+ visitedTiles.Add(newPos);
+
+ if (CanExpand(newPos, mapGrid, out var uid))
+ nextToExpand.Add((newPos, uid));
+ }
+ }
+
+ puddles = new List();
+
+ // prepare edges for next iteration
+ foreach (var (pos, uid) in nextToExpand)
+ {
+ if (spreader.OverflownSolution.CurrentVolume <= FixedPoint2.Zero)
+ continue;
+
+ var puddleUid = uid!.Value;
+ var coordinate = mapGrid.GridTileToWorld(pos);
+ if (uid == EntityUid.Invalid)
+ {
+ puddleUid = EntityManager.SpawnEntity(prototypeName, coordinate);
+ }
+
+ puddles.Add(EntityManager.GetComponent(puddleUid));
+ }
+ }
+ }
+
+ private bool CanExpand(Vector2i newPos, IMapGrid mapGrid,
+ [NotNullWhen(true)] out EntityUid? uid)
+ {
+ if (!mapGrid.TryGetTileRef(newPos, out var tileRef)
+ || tileRef.Tile.IsEmpty)
+ {
+ uid = null;
+ return false;
+ }
+
+ foreach (var entity in mapGrid.GetAnchoredEntities(newPos))
+ {
+ IPhysBody? physics = null;
+ PuddleComponent? existingPuddle = null;
+
+ // This is an invalid location
+ if (Resolve(entity, ref physics, false)
+ && (physics.CollisionLayer & (int) CollisionGroup.Impassable) != 0)
+ {
+ uid = null;
+ return false;
+ }
+
+ if (!Resolve(entity, ref existingPuddle, false))
+ continue;
+
+ uid = entity;
+ return true;
+ }
+
+ uid = EntityUid.Invalid;
+ return true;
+ }
+}
diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs
index 44b8014494..c39a30fdf2 100644
--- a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs
+++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs
@@ -1,28 +1,12 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
using Content.Server.Chemistry.EntitySystems;
-using Content.Server.Construction.Components;
using Content.Server.Fluids.Components;
using Content.Shared.Chemistry.Components;
-using Content.Shared.Database;
-using Content.Shared.Directions;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Fluids;
-using Content.Shared.Maps;
-using Content.Shared.Physics;
using Content.Shared.Slippery;
-using Content.Shared.Verbs;
using JetBrains.Annotations;
using Robust.Shared.Audio;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Localization;
-using Robust.Shared.Map;
-using Robust.Shared.Maths;
-using Robust.Shared.Physics;
using Robust.Shared.Player;
namespace Content.Server.Fluids.EntitySystems
@@ -30,8 +14,8 @@ namespace Content.Server.Fluids.EntitySystems
[UsedImplicitly]
public sealed class PuddleSystem : EntitySystem
{
- [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
+ [Dependency] private readonly FluidSpreaderSystem _fluidSpreaderSystem = default!;
public override void Initialize()
{
@@ -45,7 +29,7 @@ namespace Content.Server.Fluids.EntitySystems
private void OnInit(EntityUid uid, PuddleComponent component, ComponentInit args)
{
- var solution = _solutionContainerSystem.EnsureSolution(uid, component.SolutionName);
+ var solution = _solutionContainerSystem.EnsureSolution(uid, component.SolutionName);
solution.MaxVolume = FixedPoint2.New(1000);
}
@@ -111,21 +95,6 @@ namespace Content.Server.Fluids.EntitySystems
QueueDel(uid);
}
- ///
- /// Whether adding this solution to this puddle would overflow.
- ///
- /// Uid of owning entity
- /// Puddle to which we are adding solution
- /// Solution we intend to add
- ///
- public bool WouldOverflow(EntityUid uid, Solution solution, PuddleComponent? puddle = null)
- {
- if (!Resolve(uid, ref puddle))
- return false;
-
- return puddle.CurrentVolume + solution.TotalVolume > puddle.OverflowVolume;
- }
-
public bool EmptyHolder(EntityUid uid, PuddleComponent? puddleComponent = null)
{
if (!Resolve(uid, ref puddleComponent))
@@ -147,24 +116,40 @@ namespace Content.Server.Fluids.EntitySystems
: FixedPoint2.Zero;
}
- public bool TryAddSolution(EntityUid uid, Solution solution,
+ ///
+ ///
+ ///
+ /// Puddle to which we add
+ /// Solution that is added to puddleComponent
+ /// Play sound on overflow
+ /// Overflow on encountered values
+ /// Optional resolved PuddleComponent
+ ///
+ public bool TryAddSolution(EntityUid puddleUid,
+ Solution addedSolution,
bool sound = true,
bool checkForOverflow = true,
PuddleComponent? puddleComponent = null)
{
- if (!Resolve(uid, ref puddleComponent))
+ if (!Resolve(puddleUid, ref puddleComponent))
return false;
- if (solution.TotalVolume == 0 ||
+ if (addedSolution.TotalVolume == 0 ||
!_solutionContainerSystem.TryGetSolution(puddleComponent.Owner, puddleComponent.SolutionName,
out var puddleSolution))
{
return false;
}
-
var result = _solutionContainerSystem
- .TryAddSolution(puddleComponent.Owner, puddleSolution, solution);
+ .TryMixAndOverflow(puddleComponent.Owner, puddleSolution, addedSolution, puddleComponent.OverflowVolume,
+ out var overflowSolution);
+
+ if (checkForOverflow && overflowSolution != null)
+ {
+ _fluidSpreaderSystem.AddOverflowingPuddle(puddleComponent, overflowSolution);
+ }
+
if (!result)
{
return false;
@@ -172,11 +157,6 @@ namespace Content.Server.Fluids.EntitySystems
RaiseLocalEvent(puddleComponent.Owner, new SolutionChangedEvent());
- if (checkForOverflow)
- {
- CheckOverflow(puddleComponent);
- }
-
if (!sound)
{
return true;
@@ -188,139 +168,18 @@ namespace Content.Server.Fluids.EntitySystems
}
///
- /// Will overflow this entity to neighboring entities if required
+ /// Whether adding this solution to this puddle would overflow.
///
- private void CheckOverflow(PuddleComponent puddleComponent)
+ /// Uid of owning entity
+ /// Puddle to which we are adding solution
+ /// Solution we intend to add
+ ///
+ public bool WouldOverflow(EntityUid uid, Solution solution, PuddleComponent? puddle = null)
{
- if (puddleComponent.CurrentVolume <= puddleComponent.OverflowVolume
- || puddleComponent.Overflown)
- return;
-
- var nextPuddles = new List() { puddleComponent };
- var overflownPuddles = new List();
-
- while (puddleComponent.OverflowLeft > FixedPoint2.Zero && nextPuddles.Count > 0)
- {
- foreach (var next in nextPuddles.ToArray())
- {
- nextPuddles.Remove(next);
-
- next.Overflown = true;
- overflownPuddles.Add(next);
-
- var adjacentPuddles = GetAllAdjacentOverflow(next).ToArray();
- if (puddleComponent.OverflowLeft <= FixedPoint2.Epsilon * adjacentPuddles.Length)
- {
- break;
- }
-
- if (adjacentPuddles.Length == 0)
- {
- continue;
- }
-
- var numberOfAdjacent = FixedPoint2.New(adjacentPuddles.Length);
- var overflowSplit = puddleComponent.OverflowLeft / numberOfAdjacent;
- foreach (var adjacent in adjacentPuddles)
- {
- var adjacentPuddle = adjacent();
- var quantity = FixedPoint2.Min(overflowSplit, adjacentPuddle.OverflowVolume);
- var puddleSolution = _solutionContainerSystem.EnsureSolution(puddleComponent.Owner,
- puddleComponent.SolutionName);
- var spillAmount = _solutionContainerSystem.SplitSolution(puddleComponent.Owner,
- puddleSolution, quantity);
-
- TryAddSolution(adjacentPuddle.Owner, spillAmount, false, false);
- nextPuddles.Add(adjacentPuddle);
- }
- }
- }
-
- foreach (var puddle in overflownPuddles)
- {
- puddle.Overflown = false;
- }
- }
-
- ///
- /// Finds or creates adjacent puddles in random directions from this one
- ///
- /// Enumerable of the puddles found or to be created
- private IEnumerable> GetAllAdjacentOverflow(PuddleComponent puddleComponent)
- {
- foreach (var direction in SharedDirectionExtensions.RandomDirections())
- {
- if (TryGetAdjacentOverflow(puddleComponent, direction, out var puddle))
- {
- yield return puddle;
- }
- }
- }
-
- ///
- /// Tries to get an adjacent coordinate to overflow to, unless it is blocked by a wall on the
- /// same tile or the tile is empty
- ///
- ///
- /// The direction to get the puddle from, respective to this one
- /// The puddle that was found or is to be created, or null if there
- /// is a wall in the way
- /// true if a puddle was found or created, false otherwise
- private bool TryGetAdjacentOverflow(PuddleComponent puddleComponent, Direction direction,
- [NotNullWhen(true)] out Func? puddle)
- {
- puddle = default;
-
- // We're most likely in space, do nothing.
- if (!EntityManager.GetComponent(puddleComponent.Owner).GridID.IsValid())
+ if (!Resolve(uid, ref puddle))
return false;
- var mapGrid = _mapManager.GetGrid(EntityManager.GetComponent(puddleComponent.Owner).GridID);
- var coords = EntityManager.GetComponent(puddleComponent.Owner).Coordinates;
-
- if (!coords.Offset(direction).TryGetTileRef(out var tile))
- {
- return false;
- }
-
- // If space return early, let that spill go out into the void
- if (tile.Value.Tile.IsEmpty)
- {
- return false;
- }
-
- if (!EntityManager.GetComponent(puddleComponent.Owner).Anchored)
- return false;
-
- foreach (var entity in mapGrid.GetInDir(coords, direction))
- {
- if (EntityManager.TryGetComponent(entity, out IPhysBody? physics) &&
- (physics.CollisionLayer & (int)CollisionGroup.Impassable) != 0)
- {
- puddle = default;
- return false;
- }
-
- if (EntityManager.TryGetComponent(entity, out PuddleComponent? existingPuddle))
- {
- if (existingPuddle.Overflown)
- {
- return false;
- }
-
- puddle = () => existingPuddle;
- }
- }
-
- puddle ??= () =>
- {
- var id = EntityManager.SpawnEntity(
- EntityManager.GetComponent(puddleComponent.Owner).EntityPrototype?.ID,
- mapGrid.DirectionToGrid(coords, direction));
- return EntityManager.GetComponent(id);
- };
-
- return true;
+ return puddle.CurrentVolume + solution.TotalVolume > puddle.OverflowVolume;
}
}
}
diff --git a/Content.Server/Fluids/EntitySystems/SpillableSystem.cs b/Content.Server/Fluids/EntitySystems/SpillableSystem.cs
index b3a8ab6469..047c6ba518 100644
--- a/Content.Server/Fluids/EntitySystems/SpillableSystem.cs
+++ b/Content.Server/Fluids/EntitySystems/SpillableSystem.cs
@@ -3,7 +3,6 @@ using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Clothing.Components;
-using Content.Server.Coordinates.Helpers;
using Content.Server.Fluids.Components;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
@@ -13,17 +12,13 @@ using Content.Shared.Inventory.Events;
using Content.Shared.Throwing;
using Content.Shared.Verbs;
using JetBrains.Annotations;
-using Robust.Server.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.Server.Fluids.EntitySystems;
[UsedImplicitly]
-public class SpillableSystem : EntitySystem
+public sealed class SpillableSystem : EntitySystem
{
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly PuddleSystem _puddleSystem = default!;
@@ -61,7 +56,6 @@ public class SpillableSystem : EntitySystem
// spill all solution on the player
var drainedSolution = _solutionContainerSystem.Drain(uid, solution, solution.DrainAvailable);
SpillAt(args.Equipee, drainedSolution, "PuddleSmear");
-
}
///
@@ -174,10 +168,13 @@ public class SpillableSystem : EntitySystem
if (!noTileReact)
{
// First, do all tile reactions
- foreach (var (reagentId, quantity) in solution.Contents)
+ for (var i = 0; i < solution.Contents.Count; i++)
{
+ var (reagentId, quantity) = solution.Contents[i];
var proto = _prototypeManager.Index(reagentId);
- proto.ReactionTile(tileRef, quantity);
+ var removed = proto.ReactionTile(tileRef, quantity);
+ if (removed <= FixedPoint2.Zero) continue;
+ solution.RemoveReagent(reagentId, removed);
}
}
@@ -188,40 +185,34 @@ public class SpillableSystem : EntitySystem
// Get normalized co-ordinate for spill location and spill it in the centre
// TODO: Does SnapGrid or something else already do this?
var spillGridCoords = mapGrid.GridTileToWorld(tileRef.GridIndices);
-
- var spillEntities = _entityLookup.GetEntitiesIntersecting(mapGrid.ParentMapId, spillGridCoords.Position).ToArray();
- foreach (var spillEntity in spillEntities)
- {
- if (_solutionContainerSystem.TryGetRefillableSolution(spillEntity, out var solutionContainerComponent))
- {
- _solutionContainerSystem.Refill(spillEntity, solutionContainerComponent,
- solution.SplitSolution(FixedPoint2.Min(
- solutionContainerComponent.AvailableVolume,
- solutionContainerComponent.MaxSpillRefill))
- );
- }
- }
+ var startEntity = EntityUid.Invalid;
+ PuddleComponent? puddleComponent = null;
if (combine)
{
+ var spillEntities = _entityLookup.GetEntitiesIntersecting(tileRef).ToArray();
+
foreach (var spillEntity in spillEntities)
{
- if (!EntityManager.TryGetComponent(spillEntity, out PuddleComponent? puddleComponent)) continue;
+ if (!EntityManager.TryGetComponent(spillEntity, out puddleComponent)) continue;
if (!overflow && _puddleSystem.WouldOverflow(puddleComponent.Owner, solution, puddleComponent))
return null;
- if (!_puddleSystem.TryAddSolution(puddleComponent.Owner, solution, sound)) continue;
+ if (!_puddleSystem.TryAddSolution(puddleComponent.Owner, solution, sound, overflow)) continue;
- return puddleComponent;
+ startEntity = puddleComponent.Owner;
+ break;
}
}
- var puddleEnt = EntityManager.SpawnEntity(prototype, spillGridCoords);
- var newPuddleComponent = EntityManager.GetComponent(puddleEnt);
+ if (startEntity != EntityUid.Invalid)
+ return puddleComponent;
- _puddleSystem.TryAddSolution(newPuddleComponent.Owner, solution, sound);
+ startEntity = EntityManager.SpawnEntity(prototype, spillGridCoords);
+ puddleComponent = EntityManager.EnsureComponent(startEntity);
+ _puddleSystem.TryAddSolution(startEntity, solution, sound, overflow);
- return newPuddleComponent;
+ return puddleComponent;
}
}