Spill into containers lying around (#3345)

* Spill into containers lying around

* Make spillability definable in yaml

* Address reviews
This commit is contained in:
Clyybber
2021-02-21 02:14:41 +01:00
committed by GitHub
parent c3b4753cc1
commit c5ab6f191b
3 changed files with 40 additions and 80 deletions

View File

@@ -1,7 +1,9 @@
#nullable enable #nullable enable
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Utility; using Content.Server.Utility;
using Content.Shared.Chemistry; using Content.Shared.Chemistry;
using Content.Shared.GameObjects.Components.Chemistry;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
@@ -23,8 +25,7 @@ namespace Content.Server.GameObjects.Components.Fluids
/// <returns>The puddle if one was created, null otherwise.</returns> /// <returns>The puddle if one was created, null otherwise.</returns>
public static PuddleComponent? SpillAt(this Solution solution, IEntity entity, string prototype, bool sound = true) public static PuddleComponent? SpillAt(this Solution solution, IEntity entity, string prototype, bool sound = true)
{ {
var coordinates = entity.Transform.Coordinates; return solution.SpillAt(entity.Transform.Coordinates, prototype, sound);
return solution.SpillAt(coordinates, prototype, sound);
} }
/// <summary> /// <summary>
@@ -52,61 +53,16 @@ namespace Content.Server.GameObjects.Components.Fluids
/// <param name="prototype">The prototype to use.</param> /// <param name="prototype">The prototype to use.</param>
/// <param name="sound">Whether or not to play the spill sound.</param> /// <param name="sound">Whether or not to play the spill sound.</param>
/// <returns>The puddle if one was created, null otherwise.</returns> /// <returns>The puddle if one was created, null otherwise.</returns>
public static PuddleComponent? SpillAt(this Solution solution, EntityCoordinates coordinates, string prototype, bool sound = true) public static PuddleComponent? SpillAt(this Solution solution, EntityCoordinates coordinates, string prototype, bool overflow = true, bool sound = true)
{ {
if (solution.TotalVolume == 0) if (solution.TotalVolume == 0) return null;
{
return null;
}
var mapManager = IoCManager.Resolve<IMapManager>(); var mapManager = IoCManager.Resolve<IMapManager>();
var entityManager = IoCManager.Resolve<IEntityManager>(); var entityManager = IoCManager.Resolve<IEntityManager>();
var serverEntityManager = IoCManager.Resolve<IServerEntityManager>();
if (!mapManager.TryGetGrid(coordinates.GetGridId(entityManager), out var mapGrid)) if (!mapManager.TryGetGrid(coordinates.GetGridId(entityManager), out var mapGrid)) return null; // Let's not spill to space.
return null; // Let's not spill to space.
// If space return early, let that spill go out into the void return SpillAt(mapGrid.GetTileRef(coordinates), solution, prototype, overflow, sound);
var tileRef = mapGrid.GetTileRef(coordinates);
if (tileRef.Tile.IsEmpty)
{
return null;
}
// 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.GridTileToLocal(tileRef.GridIndices);
var spilt = false;
foreach (var spillEntity in entityManager.GetEntitiesAt(mapGrid.ParentMapId, spillGridCoords.Position))
{
if (!spillEntity.TryGetComponent(out PuddleComponent? puddleComponent))
{
continue;
}
if (!puddleComponent.TryAddSolution(solution, sound))
{
continue;
}
spilt = true;
break;
}
// Did we add to an existing puddle
if (spilt)
{
return null;
}
var puddle = serverEntityManager.SpawnEntity(prototype, spillGridCoords);
var newPuddleComponent = puddle.GetComponent<PuddleComponent>();
newPuddleComponent.TryAddSolution(solution, sound);
return newPuddleComponent;
} }
/// <summary> /// <summary>
@@ -141,44 +97,44 @@ namespace Content.Server.GameObjects.Components.Fluids
public static PuddleComponent? SpillAt(this TileRef tileRef, Solution solution, string prototype, bool overflow = true, bool sound = true) public static PuddleComponent? SpillAt(this TileRef tileRef, Solution solution, string prototype, bool overflow = true, bool sound = true)
{ {
if (solution.TotalVolume <= 0) if (solution.TotalVolume <= 0) return null;
{
return null;
}
var mapManager = IoCManager.Resolve<IMapManager>(); var mapManager = IoCManager.Resolve<IMapManager>();
var entityManager = IoCManager.Resolve<IEntityManager>(); var entityManager = IoCManager.Resolve<IEntityManager>();
var serverEntityManager = IoCManager.Resolve<IServerEntityManager>(); var serverEntityManager = IoCManager.Resolve<IServerEntityManager>();
var gridId = tileRef.GridIndex;
// If space return early, let that spill go out into the void // If space return early, let that spill go out into the void
if (tileRef.Tile.IsEmpty) if (tileRef.Tile.IsEmpty) return null;
{
return null;
}
PuddleComponent? puddle = null; var gridId = tileRef.GridIndex;
if (!mapManager.TryGetGrid(gridId, out var mapGrid)) return null; // Let's not spill to invalid grids.
// Get normalized co-ordinate for spill location and spill it in the centre // Get normalized co-ordinate for spill location and spill it in the centre
// TODO: Does SnapGrid or something else already do this? // TODO: Does SnapGrid or something else already do this?
if (!mapManager.TryGetGrid(gridId, out var spillTileMapGrid)) var spillGridCoords = mapGrid.GridTileToLocal(tileRef.GridIndices);
return null; // Let's not spill to invalid grids.
var spillGridCoords = spillTileMapGrid.GridTileToLocal(tileRef.GridIndices);
PuddleComponent? puddle = null;
var spilt = false; var spilt = false;
foreach (var spillEntity in entityManager.GetEntitiesAt(spillTileMapGrid.ParentMapId, spillGridCoords.Position)) var spillEntities = entityManager.GetEntitiesIntersecting(mapGrid.ParentMapId, spillGridCoords.Position).ToArray();
foreach (var spillEntity in spillEntities)
{ {
if (!spillEntity.TryGetComponent(out PuddleComponent? puddleComponent)) if (spillEntity.TryGetComponent(out ISolutionInteractionsComponent? solutionContainerComponent) &&
continue; solutionContainerComponent.CanRefill)
{
solutionContainerComponent.Refill(
solution.SplitSolution(ReagentUnit.Min(solutionContainerComponent.RefillSpaceAvailable, solutionContainerComponent.MaxSpillRefill))
);
}
}
if (!overflow && puddleComponent.WouldOverflow(solution)) foreach (var spillEntity in spillEntities)
return null; {
if (!spillEntity.TryGetComponent(out PuddleComponent? puddleComponent)) continue;
if (!puddleComponent.TryAddSolution(solution, sound)) if (!overflow && puddleComponent.WouldOverflow(solution)) return null;
continue;
if (!puddleComponent.TryAddSolution(solution, sound)) continue;
puddle = puddleComponent; puddle = puddleComponent;
spilt = true; spilt = true;
@@ -186,17 +142,14 @@ namespace Content.Server.GameObjects.Components.Fluids
} }
// Did we add to an existing puddle // Did we add to an existing puddle
if (spilt) if (spilt) return puddle;
{
return puddle;
}
var puddleEnt = serverEntityManager.SpawnEntity(prototype, spillGridCoords); var puddleEnt = serverEntityManager.SpawnEntity(prototype, spillGridCoords);
puddle = puddleEnt.GetComponent<PuddleComponent>(); var newPuddleComponent = puddleEnt.GetComponent<PuddleComponent>();
puddle.TryAddSolution(solution, sound); newPuddleComponent.TryAddSolution(solution, sound);
return puddle; return newPuddleComponent;
} }
} }
} }

View File

@@ -64,6 +64,11 @@ namespace Content.Shared.GameObjects.Components.Chemistry
bool CanRefill => false; bool CanRefill => false;
ReagentUnit RefillSpaceAvailable => ReagentUnit.Zero; ReagentUnit RefillSpaceAvailable => ReagentUnit.Zero;
/// <summary>
/// The amount that will transfer if something is spilled on the container.
/// </summary>
ReagentUnit MaxSpillRefill => ReagentUnit.Zero;
void Refill(Solution solution) void Refill(Solution solution)
{ {

View File

@@ -73,6 +73,7 @@ namespace Content.Shared.GameObjects.Components.Chemistry
serializer.DataField(this, x => x.MaxVolume, "maxVol", ReagentUnit.New(0)); serializer.DataField(this, x => x.MaxVolume, "maxVol", ReagentUnit.New(0));
serializer.DataField(this, x => x.Solution, "contents", new Solution()); serializer.DataField(this, x => x.Solution, "contents", new Solution());
serializer.DataField(this, x => x.Capabilities, "caps", SolutionContainerCaps.None); serializer.DataField(this, x => x.Capabilities, "caps", SolutionContainerCaps.None);
serializer.DataField(this, x => x.MaxSpillRefill, "maxSpillRefill", MaxVolume / ReagentUnit.New(4));
} }
public void RemoveAllSolution() public void RemoveAllSolution()
@@ -214,6 +215,7 @@ namespace Content.Shared.GameObjects.Components.Chemistry
ReagentUnit ISolutionInteractionsComponent.InjectSpaceAvailable => EmptyVolume; ReagentUnit ISolutionInteractionsComponent.InjectSpaceAvailable => EmptyVolume;
ReagentUnit ISolutionInteractionsComponent.DrawAvailable => CurrentVolume; ReagentUnit ISolutionInteractionsComponent.DrawAvailable => CurrentVolume;
ReagentUnit ISolutionInteractionsComponent.DrainAvailable => CurrentVolume; ReagentUnit ISolutionInteractionsComponent.DrainAvailable => CurrentVolume;
public ReagentUnit MaxSpillRefill { get; set; }
void ISolutionInteractionsComponent.Refill(Solution solution) void ISolutionInteractionsComponent.Refill(Solution solution)
{ {