better fluid spreading (#14529)

This commit is contained in:
Slava0135
2023-03-24 17:09:52 +03:00
committed by GitHub
parent 473a02120d
commit 81159b0ff5
2 changed files with 46 additions and 39 deletions

View File

@@ -3,13 +3,13 @@ using System.Linq;
using Content.Server.Fluids.Components; using Content.Server.Fluids.Components;
using Content.Shared; using Content.Shared;
using Content.Shared.Directions; using Content.Shared.Directions;
using Content.Shared.Maps;
using Content.Shared.Physics; using Content.Shared.Physics;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
using Robust.Shared.Physics; using Robust.Shared.Physics;
using Robust.Shared.Utility; using Robust.Shared.Physics.Systems;
using Robust.Shared.Physics.Components;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Server.Fluids.EntitySystems; namespace Content.Server.Fluids.EntitySystems;
@@ -23,6 +23,8 @@ public sealed class FluidSpreaderSystem : EntitySystem
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly PuddleSystem _puddleSystem = default!; [Dependency] private readonly PuddleSystem _puddleSystem = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
/// <summary> /// <summary>
/// Adds an overflow component to the map data component tracking overflowing puddles /// Adds an overflow component to the map data component tracking overflowing puddles
@@ -72,20 +74,19 @@ public sealed class FluidSpreaderSystem : EntitySystem
puddles.Clear(); puddles.Clear();
var pos = transform.Coordinates; var pos = transform.Coordinates;
var totalVolume = _puddleSystem.CurrentVolume(puddle.Owner, puddle); var totalVolume = _puddleSystem.CurrentVolume(puddleUid, puddle);
exploreDirections.Shuffle(); exploreDirections.Shuffle();
foreach (var direction in exploreDirections) foreach (var direction in exploreDirections)
{ {
var newPos = pos.Offset(direction); var newPos = pos.Offset(direction);
if (CheckTile(puddle.Owner, puddle, newPos, mapGrid, if (CheckTile(puddleUid, puddle, newPos, mapGrid, puddleQuery, out var uid, out var component))
out var puddleComponent))
{ {
puddles.Add(puddleComponent); puddles.Add(component);
totalVolume += _puddleSystem.CurrentVolume(puddleComponent.Owner, puddleComponent); totalVolume += _puddleSystem.CurrentVolume(uid.Value, component);
} }
} }
_puddleSystem.EqualizePuddles(puddle.Owner, puddles, totalVolume, newIteration, puddle); _puddleSystem.EqualizePuddles(puddleUid, puddles, totalVolume, newIteration, puddle);
} }
fluidMapData.Puddles.Clear(); fluidMapData.Puddles.Clear();
@@ -100,49 +101,57 @@ public sealed class FluidSpreaderSystem : EntitySystem
/// </summary> /// </summary>
/// <param name="srcUid">Entity Uid of original puddle</param> /// <param name="srcUid">Entity Uid of original puddle</param>
/// <param name="srcPuddle">PuddleComponent attached to srcUid</param> /// <param name="srcPuddle">PuddleComponent attached to srcUid</param>
/// <param name="pos">at which to check tile</param> /// <param name="dstPos">at which to check tile</param>
/// <param name="mapGrid">helper param needed to extract entities</param> /// <param name="mapGrid">helper param needed to extract entities</param>
/// <param name="puddle">either found or newly created PuddleComponent.</param> /// <param name="newPuddleUid">either found or newly created PuddleComponent.</param>
/// <returns>true if tile is empty or occupied by a non-overflowing puddle (or a puddle close to being overflowing)</returns> /// <returns>true if tile is empty or occupied by a non-overflowing puddle (or a puddle close to being overflowing)</returns>
private bool CheckTile(EntityUid srcUid, PuddleComponent srcPuddle, EntityCoordinates pos, MapGridComponent mapGrid, private bool CheckTile(EntityUid srcUid, PuddleComponent srcPuddle, EntityCoordinates dstPos,
[NotNullWhen(true)] out PuddleComponent? puddle) MapGridComponent mapGrid, EntityQuery<PuddleComponent> puddleQuery,
[NotNullWhen(true)] out EntityUid? newPuddleUid, [NotNullWhen(true)] out PuddleComponent? newPuddleComp)
{ {
if (!mapGrid.TryGetTileRef(pos, out var tileRef) if (!mapGrid.TryGetTileRef(dstPos, out var tileRef)
|| tileRef.Tile.IsEmpty) || tileRef.Tile.IsEmpty)
{ {
puddle = null; newPuddleUid = null;
newPuddleComp = null;
return false;
}
// check if puddle can spread there at all
var dstMap = dstPos.ToMap(EntityManager, _transform);
var dst = dstMap.Position;
var src = Transform(srcUid).MapPosition.Position;
var dir = src - dst;
var ray = new CollisionRay(dst, dir.Normalized, (int) (CollisionGroup.Impassable | CollisionGroup.HighImpassable));
var mapId = dstMap.MapId;
var results = _physics.IntersectRay(mapId, ray, dir.Length, returnOnFirstHit: true);
if (results.Any())
{
newPuddleUid = null;
newPuddleComp = null;
return false; return false;
} }
var puddleCurrentVolume = _puddleSystem.CurrentVolume(srcUid, srcPuddle); var puddleCurrentVolume = _puddleSystem.CurrentVolume(srcUid, srcPuddle);
foreach (var entity in dstPos.GetEntitiesInTile())
foreach (var entity in mapGrid.GetAnchoredEntities(pos))
{ {
// If this is valid puddle check if we spread to it. if (puddleQuery.TryGetComponent(entity, out var existingPuddle))
if (TryComp(entity, out PuddleComponent? existingPuddle))
{ {
// If current puddle has more volume than current we skip that field if (_puddleSystem.CurrentVolume(entity, existingPuddle) >= puddleCurrentVolume)
if (_puddleSystem.CurrentVolume(existingPuddle.Owner, existingPuddle) >= puddleCurrentVolume)
{ {
puddle = null; newPuddleUid = null;
newPuddleComp = null;
return false; return false;
} }
newPuddleUid = entity;
puddle = existingPuddle; newPuddleComp = existingPuddle;
return true; return true;
} }
// if not puddle is this tile blocked by an object like wall or door
if (TryComp(entity, out PhysicsComponent? physComponent)
&& physComponent.CanCollide
&& (physComponent.CollisionLayer & (int) CollisionGroup.MobMask) != 0)
{
puddle = null;
return false;
}
} }
puddle = _puddleSystem.SpawnPuddle(srcUid, pos, srcPuddle); _puddleSystem.SpawnPuddle(srcUid, dstPos, srcPuddle, out var uid, out var comp);
newPuddleUid = uid;
newPuddleComp = comp;
return true; return true;
} }
} }

View File

@@ -266,17 +266,15 @@ namespace Content.Server.Fluids.EntitySystems
return CurrentVolume(uid, puddle) > puddle.OverflowVolume; return CurrentVolume(uid, puddle) > puddle.OverflowVolume;
} }
public PuddleComponent SpawnPuddle(EntityUid srcUid, EntityCoordinates pos, PuddleComponent? srcPuddleComponent = null) public void SpawnPuddle(EntityUid srcUid, EntityCoordinates pos, PuddleComponent srcPuddleComponent, out EntityUid uid, out PuddleComponent component)
{ {
MetaDataComponent? metadata = null; MetaDataComponent? metadata = null;
Resolve(srcUid, ref srcPuddleComponent, ref metadata); Resolve(srcUid, ref metadata);
var prototype = metadata?.EntityPrototype?.ID ?? "PuddleSmear"; // TODO Spawn a entity based on another entity var prototype = metadata?.EntityPrototype?.ID ?? "PuddleSmear"; // TODO Spawn a entity based on another entity
var destUid = EntityManager.SpawnEntity(prototype, pos); uid = EntityManager.SpawnEntity(prototype, pos);
var destPuddle = EntityManager.EnsureComponent<PuddleComponent>(destUid); component = EntityManager.EnsureComponent<PuddleComponent>(uid);
return destPuddle;
} }
} }
} }