Merge branch 'master' into 2020-08-19-firelocks

# Conflicts:
#	Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs
#	Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs
#	SpaceStation14.sln.DotSettings
This commit is contained in:
Víctor Aguilera Puerto
2020-08-28 14:35:45 +02:00
494 changed files with 11527 additions and 3829 deletions

View File

@@ -1,9 +1,11 @@
#nullable enable
using System;
using Content.Server.GameObjects.Components.Atmos;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Atmos;
using Robust.Server.Interfaces.Console;
using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
@@ -58,7 +60,9 @@ namespace Content.Server.Atmos
public string Help => "listgases";
public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
{
foreach (var gasPrototype in Atmospherics.Gases)
var atmosSystem = EntitySystem.Get<AtmosphereSystem>();
foreach (var gasPrototype in atmosSystem.Gases)
{
shell.SendText(player, $"{gasPrototype.Name} ID: {gasPrototype.ID}");
}

View File

@@ -0,0 +1,16 @@
using Robust.Shared.GameObjects;
namespace Content.Server.Atmos
{
public class FireActEvent : EntitySystemMessage
{
public float Temperature { get; }
public float Volume { get; }
public FireActEvent(float temperature, float volume)
{
Temperature = temperature;
Volume = volume;
}
}
}

View File

@@ -4,8 +4,10 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Content.Server.Atmos.Reactions;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
@@ -20,12 +22,17 @@ namespace Content.Server.Atmos
[Serializable]
public class GasMixture : IExposeData, IEquatable<GasMixture>, ICloneable
{
private readonly AtmosphereSystem _atmosphereSystem;
[ViewVariables]
private float[] _moles = new float[Atmospherics.TotalNumberOfGases];
[ViewVariables]
private float[] _molesArchived = new float[Atmospherics.TotalNumberOfGases];
[ViewVariables]
private float _temperature = Atmospherics.TCMB;
public IReadOnlyList<float> Gases => _moles;
[ViewVariables]
@@ -51,7 +58,7 @@ namespace Content.Server.Atmos
for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
{
capacity += Atmospherics.GetGas(i).SpecificHeat * _moles[i];
capacity += _atmosphereSystem.GetGas(i).SpecificHeat * _moles[i];
}
return MathF.Max(capacity, Atmospherics.MinimumHeatCapacity);
@@ -68,7 +75,7 @@ namespace Content.Server.Atmos
for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
{
capacity += Atmospherics.GetGas(i).SpecificHeat * _molesArchived[i];
capacity += _atmosphereSystem.GetGas(i).SpecificHeat * _molesArchived[i];
}
return MathF.Max(capacity, Atmospherics.MinimumHeatCapacity);
@@ -122,15 +129,21 @@ namespace Content.Server.Atmos
[ViewVariables]
public float Volume { get; set; }
public GasMixture()
public GasMixture() : this(null)
{
}
public GasMixture(float volume)
public GasMixture(AtmosphereSystem? atmosphereSystem)
{
_atmosphereSystem = atmosphereSystem ?? EntitySystem.Get<AtmosphereSystem>();
}
public GasMixture(float volume, AtmosphereSystem? atmosphereSystem = null)
{
if (volume < 0)
volume = 0;
Volume = volume;
_atmosphereSystem = atmosphereSystem ?? EntitySystem.Get<AtmosphereSystem>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -215,12 +228,12 @@ namespace Content.Server.Atmos
public GasMixture RemoveRatio(float ratio)
{
if(ratio <= 0)
return new GasMixture(Volume);
return new GasMixture(Volume, _atmosphereSystem);
if (ratio > 1)
ratio = 1;
var removed = new GasMixture {Volume = Volume, Temperature = Temperature};
var removed = new GasMixture(_atmosphereSystem) {Volume = Volume, Temperature = Temperature};
for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
{
@@ -243,7 +256,7 @@ namespace Content.Server.Atmos
public void CopyFromMutable(GasMixture sample)
{
if (Immutable) return;
sample._moles.AsSpan().CopyTo(_moles.AsSpan());
sample._moles.CopyTo(_moles, 0);
Temperature = sample.Temperature;
}
@@ -274,7 +287,7 @@ namespace Content.Server.Atmos
if (!(MathF.Abs(delta) >= Atmospherics.GasMinMoles)) continue;
if (absTemperatureDelta > Atmospherics.MinimumTemperatureDeltaToConsider)
{
var gasHeatCapacity = delta * Atmospherics.GetGas(i).SpecificHeat;
var gasHeatCapacity = delta * _atmosphereSystem.GetGas(i).SpecificHeat;
if (delta > 0)
{
heatCapacityToSharer += gasHeatCapacity;
@@ -476,8 +489,7 @@ namespace Content.Server.Atmos
var temperature = Temperature;
var energy = ThermalEnergy;
// TODO ATMOS Take reaction priority into account!
foreach (var prototype in IoCManager.Resolve<IPrototypeManager>().EnumeratePrototypes<GasReactionPrototype>())
foreach (var prototype in _atmosphereSystem.GasReactions)
{
if (energy < prototype.MinimumEnergyRequirement ||
temperature < prototype.MinimumTemperatureRequirement)
@@ -499,7 +511,7 @@ namespace Content.Server.Atmos
if (!doReaction)
continue;
reaction = prototype.React(this, holder);
reaction = prototype.React(this, holder, _atmosphereSystem.EventBus);
if(reaction.HasFlag(ReactionResult.StopReactions))
break;
}
@@ -579,7 +591,7 @@ namespace Content.Server.Atmos
public object Clone()
{
var newMixture = new GasMixture()
var newMixture = new GasMixture(_atmosphereSystem)
{
_moles = (float[])_moles.Clone(),
_molesArchived = (float[])_molesArchived.Clone(),

View File

@@ -2,7 +2,6 @@
using Content.Server.Interfaces;
using Content.Shared.Chemistry;
using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.Components.Pointing;
using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.EntitySystems;
@@ -20,10 +19,8 @@ namespace Content.Server.Atmos
[RegisterComponent]
public class GasSprayerComponent : Component, IAfterInteract
{
#pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerEntityManager _serverEntityManager = default!;
#pragma warning restore 649
//TODO: create a function that can create a gas based on a solution mix
public override string Name => "GasSprayer";

View File

@@ -1,6 +1,7 @@
#nullable enable
using System;
using Content.Server.GameObjects.Components.Atmos;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.Interfaces.Random;
@@ -24,7 +25,7 @@ namespace Content.Server.Atmos
private const float ProbabilityBasePercent = 10f;
private const float ThrowForce = 100f;
public void ExperiencePressureDifference(int cycle, float pressureDifference, Direction direction,
public void ExperiencePressureDifference(int cycle, float pressureDifference, AtmosDirection direction,
float pressureResistanceProbDelta, GridCoordinates throwTarget)
{
if (ControlledComponent == null)
@@ -54,14 +55,14 @@ namespace Content.Server.Atmos
if (throwTarget != GridCoordinates.InvalidGrid)
{
var moveForce = maxForce * MathHelper.Clamp(moveProb, 0, 100) / 150f;
var pos = ((throwTarget.Position - transform.GridPosition.Position).Normalized + direction.ToVec()).Normalized;
var pos = ((throwTarget.Position - transform.GridPosition.Position).Normalized + direction.ToDirection().ToVec()).Normalized;
LinearVelocity = pos * moveForce;
}
else
{
var moveForce = MathF.Min(maxForce * MathHelper.Clamp(moveProb, 0, 100) / 2500f, 20f);
LinearVelocity = direction.ToVec() * moveForce;
LinearVelocity = direction.ToDirection().ToVec() * moveForce;
}
pressureComponent.LastHighPressureMovementAirCycle = cycle;

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Atmos.Piping;
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
@@ -12,11 +14,6 @@ namespace Content.Server.Atmos
/// </summary>
int UpdateCounter { get; }
/// <summary>
/// How many tiles have high pressure delta.
/// </summary>
int HighPressureDeltaCount { get; }
/// <summary>
/// Control variable for equalization.
/// </summary>
@@ -120,14 +117,14 @@ namespace Content.Server.Atmos
/// </summary>
/// <param name="indices"></param>
/// <returns></returns>
TileAtmosphere GetTile(MapIndices indices);
TileAtmosphere GetTile(MapIndices indices, bool createSpace = true);
/// <summary>
/// Returns a tile.
/// </summary>
/// <param name="coordinates"></param>
/// <returns></returns>
TileAtmosphere GetTile(GridCoordinates coordinates);
TileAtmosphere GetTile(GridCoordinates coordinates, bool createSpace = true);
/// <summary>
/// Returns if the tile in question is air-blocked.
@@ -158,5 +155,13 @@ namespace Content.Server.Atmos
Dictionary<Direction, TileAtmosphere> GetAdjacentTiles(MapIndices indices, bool includeAirBlocked = false);
void Update(float frameTime);
void AddPipeNet(IPipeNet pipeNet);
void RemovePipeNet(IPipeNet pipeNet);
void AddPipeNetDevice(PipeNetDeviceComponent pipeNetDevice);
void RemovePipeNetDevice(PipeNetDeviceComponent pipeNetDevice);
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using Content.Server.Interfaces;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using YamlDotNet.RepresentationModel;
@@ -64,13 +65,13 @@ namespace Content.Server.Atmos.Reactions
serializer.DataField(ref _effects, "effects", new List<IGasReactionEffect>());
}
public ReactionResult React(GasMixture mixture, IGasMixtureHolder holder)
public ReactionResult React(GasMixture mixture, IGasMixtureHolder holder, IEventBus eventBus)
{
var result = ReactionResult.NoReaction;
foreach (var effect in _effects)
{
result |= effect.React(mixture, holder);
result |= effect.React(mixture, holder, eventBus);
}
return result;

View File

@@ -1,8 +1,12 @@
#nullable enable
using System;
using Content.Server.Interfaces;
using Content.Server.Interfaces.GameObjects.Components.Interaction;
using Content.Shared.Atmos;
using Content.Shared.Maps;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Serialization;
namespace Content.Server.Atmos.Reactions
@@ -10,7 +14,7 @@ namespace Content.Server.Atmos.Reactions
[UsedImplicitly]
public class PhoronFireReaction : IGasReactionEffect
{
public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder)
public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, IEventBus eventBus)
{
var energyReleased = 0f;
var oldHeatCapacity = mixture.HeatCapacity;
@@ -71,9 +75,7 @@ namespace Content.Server.Atmos.Reactions
{
location.HotspotExpose(temperature, mixture.Volume);
// TODO ATMOS Expose temperature all items on cell
location.TemperatureExpose(mixture, temperature, mixture.Volume);
eventBus.QueueEvent(EventSource.Local, new TemperatureExposeEvent(location.GridIndices, location.GridIndex, mixture, temperature, mixture.Volume));
}
}

View File

@@ -1,7 +1,10 @@
#nullable enable
using Content.Server.Interfaces;
using Content.Server.Interfaces.GameObjects.Components.Interaction;
using Content.Shared.Atmos;
using Content.Shared.Maps;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
namespace Content.Server.Atmos.Reactions
@@ -13,7 +16,7 @@ namespace Content.Server.Atmos.Reactions
{
}
public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder)
public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, IEventBus eventBus)
{
var energyReleased = 0f;
var oldHeatCapacity = mixture.HeatCapacity;
@@ -66,9 +69,7 @@ namespace Content.Server.Atmos.Reactions
{
location.HotspotExpose(temperature, mixture.Volume);
// TODO ATMOS Expose temperature all items on cell
location.TemperatureExpose(mixture, temperature, mixture.Volume);
eventBus.QueueEvent(EventSource.Local, new TemperatureExposeEvent(location.GridIndices, location.GridIndex, mixture, temperature, mixture.Volume));
}
}

View File

@@ -0,0 +1,23 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
namespace Content.Server.Atmos
{
public class TemperatureExposeEvent : EntitySystemMessage
{
public MapIndices Indices { get; }
public GridId Grid { get; }
public GasMixture Air { get; }
public float Temperature { get; }
public float Volume { get; }
public TemperatureExposeEvent(MapIndices indices, GridId gridId, GasMixture air, float temperature, float volume)
{
Indices = indices;
Grid = gridId;
Air = air;
Temperature = temperature;
Volume = volume;
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using Content.Shared.Atmos;
using Robust.Shared.Maths;
using Robust.Shared.ViewVariables;
@@ -30,15 +31,15 @@ namespace Content.Server.Atmos
[ViewVariables]
public float TransferDirectionSouth;
public float this[Direction direction]
public float this[AtmosDirection direction]
{
get =>
direction switch
{
Direction.East => TransferDirectionEast,
Direction.West => TransferDirectionWest,
Direction.North => TransferDirectionNorth,
Direction.South => TransferDirectionSouth,
AtmosDirection.East => TransferDirectionEast,
AtmosDirection.West => TransferDirectionWest,
AtmosDirection.North => TransferDirectionNorth,
AtmosDirection.South => TransferDirectionSouth,
_ => throw new ArgumentOutOfRangeException(nameof(direction))
};
@@ -46,16 +47,16 @@ namespace Content.Server.Atmos
{
switch (direction)
{
case Direction.East:
case AtmosDirection.East:
TransferDirectionEast = value;
break;
case Direction.West:
case AtmosDirection.West:
TransferDirectionWest = value;
break;
case Direction.North:
case AtmosDirection.North:
TransferDirectionNorth = value;
break;
case Direction.South:
case AtmosDirection.South:
TransferDirectionSouth = value;
break;
default:
@@ -64,10 +65,16 @@ namespace Content.Server.Atmos
}
}
public float this[int index]
{
get => this[(AtmosDirection) (1 << index)];
set => this[(AtmosDirection) (1 << index)] = value;
}
[ViewVariables]
public float CurrentTransferAmount;
public Direction CurrentTransferDirection;
public AtmosDirection CurrentTransferDirection;
[ViewVariables]
public bool FastDone;

View File

@@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Content.Server.Atmos.Reactions;
using Content.Server.GameObjects.Components.Atmos;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.GameObjects.EntitySystems.Atmos;
using Content.Server.Interfaces;
using Content.Shared.Atmos;
@@ -12,13 +11,13 @@ using Content.Shared.Audio;
using Content.Shared.Maps;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Random;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Random;
@@ -28,18 +27,15 @@ namespace Content.Server.Atmos
{
public class TileAtmosphere : IGasMixtureHolder
{
[Robust.Shared.IoC.Dependency] private IRobustRandom _robustRandom = default!;
[Robust.Shared.IoC.Dependency] private IEntityManager _entityManager = default!;
[Robust.Shared.IoC.Dependency] private IMapManager _mapManager = default!;
[Robust.Shared.IoC.Dependency] private readonly IRobustRandom _robustRandom = default!;
[Robust.Shared.IoC.Dependency] private readonly IEntityManager _entityManager = default!;
[Robust.Shared.IoC.Dependency] private readonly IMapManager _mapManager = default!;
private static readonly TileAtmosphereComparer _comparer = new TileAtmosphereComparer();
private static readonly TileAtmosphereComparer Comparer = new TileAtmosphereComparer();
[ViewVariables]
private int _archivedCycle = 0;
[ViewVariables]
private int _currentCycle = 0;
[ViewVariables] private int _archivedCycle;
[ViewVariables] private int _currentCycle;
[ViewVariables]
private static GasTileOverlaySystem _gasTileOverlaySystem;
@@ -51,13 +47,13 @@ namespace Content.Server.Atmos
private float _temperatureArchived = Atmospherics.T20C;
// I know this being static is evil, but I seriously can't come up with a better solution to sound spam.
private static int _soundCooldown = 0;
private static int _soundCooldown;
[ViewVariables]
public TileAtmosphere PressureSpecificTarget { get; set; } = null;
public TileAtmosphere PressureSpecificTarget { get; set; }
[ViewVariables]
public float PressureDifference { get; set; } = 0;
public float PressureDifference { get; set; }
[ViewVariables(VVAccess.ReadWrite)]
public float HeatCapacity { get; set; } = 1f;
@@ -66,13 +62,19 @@ namespace Content.Server.Atmos
public float ThermalConductivity => Tile?.Tile.GetContentTileDefinition().ThermalConductivity ?? 0.05f;
[ViewVariables]
public bool Excited { get; set; } = false;
public bool Excited { get; set; }
[ViewVariables]
private GridAtmosphereComponent _gridAtmosphereComponent;
private readonly GridAtmosphereComponent _gridAtmosphereComponent;
/// <summary>
/// Adjacent tiles in the same order as <see cref="AtmosDirection"/>. (NSEW)
/// </summary>
[ViewVariables]
private readonly TileAtmosphere[] _adjacentTiles = new TileAtmosphere[Atmospherics.Directions];
[ViewVariables]
private readonly Dictionary<Direction, TileAtmosphere> _adjacentTiles = new Dictionary<Direction, TileAtmosphere>();
private AtmosDirection _adjacentBits = AtmosDirection.Invalid;
[ViewVariables]
private TileAtmosInfo _tileAtmosInfo;
@@ -80,7 +82,7 @@ namespace Content.Server.Atmos
[ViewVariables]
public Hotspot Hotspot;
private Direction _pressureDirection;
private AtmosDirection _pressureDirection;
[ViewVariables]
public GridId GridIndex { get; }
@@ -100,14 +102,16 @@ namespace Content.Server.Atmos
[ViewVariables]
public bool BlocksAir => _gridAtmosphereComponent.IsAirBlocked(GridIndices);
public TileAtmosphere(GridAtmosphereComponent atmosphereComponent, GridId gridIndex, MapIndices gridIndices, GasMixture mixture = null)
public TileAtmosphere(GridAtmosphereComponent atmosphereComponent, GridId gridIndex, MapIndices gridIndices, GasMixture mixture = null, bool immutable = false)
{
IoCManager.InjectDependencies(this);
_gridAtmosphereComponent = atmosphereComponent;
GridIndex = gridIndex;
GridIndices = gridIndices;
Air = mixture;
ResetTileAtmosInfo();
if(immutable)
Air?.MarkImmutable();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -163,7 +167,7 @@ namespace Content.Server.Atmos
}
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void HighPressureMovements()
{
// TODO ATMOS finish this
@@ -175,7 +179,6 @@ namespace Content.Server.Atmos
GridIndices.ToGridCoordinates(_mapManager, GridIndex), AudioHelpers.WithVariation(0.125f).WithVolume(MathHelper.Clamp(PressureDifference / 10, 10, 100)));
}
foreach (var entity in _entityManager.GetEntitiesIntersecting(_mapManager.GetGrid(GridIndex).ParentMapId, Box2.UnitCentered.Translated(GridIndices)))
{
if (!entity.TryGetComponent(out ICollidableComponent physics)
@@ -195,7 +198,7 @@ namespace Content.Server.Atmos
if (PressureDifference > 100)
{
// Do space wind graphics here!
// TODO ATMOS Do space wind graphics here!
}
_soundCooldown++;
@@ -220,20 +223,22 @@ namespace Content.Server.Atmos
}
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EqualizePressureInZone(int cycleNum)
{
if (Air == null || (_tileAtmosInfo.LastCycle >= cycleNum)) return; // Already done.
ResetTileAtmosInfo();
_tileAtmosInfo = new TileAtmosInfo();
var startingMoles = Air.TotalMoles;
var runAtmos = false;
// We need to figure if this is necessary
foreach (var (direction, other) in _adjacentTiles)
for (var i = 0; i < Atmospherics.Directions; i++)
{
var direction = (AtmosDirection) (1 << i);
if (!_adjacentBits.HasFlag(direction)) continue;
var other = _adjacentTiles[i];
if (other?.Air == null) continue;
var comparisonMoles = other.Air.TotalMoles;
if (!(MathF.Abs(comparisonMoles - startingMoles) > Atmospherics.MinimumMolesDeltaToMove)) continue;
@@ -265,13 +270,15 @@ namespace Content.Server.Atmos
totalMoles += tileMoles;
}
foreach (var (_, adj) in exploring._adjacentTiles)
for (var j = 0; j < Atmospherics.Directions; j++)
{
var direction = (AtmosDirection) (1 << j);
if (!exploring._adjacentBits.HasFlag(direction)) continue;
var adj = exploring._adjacentTiles[j];
if (adj?.Air == null) continue;
if(adj._tileAtmosInfo.LastQueueCycle == queueCycle) continue;
adj.ResetTileAtmosInfo();
adj._tileAtmosInfo = new TileAtmosInfo {LastQueueCycle = queueCycle};
adj._tileAtmosInfo.LastQueueCycle = queueCycle;
if(tileCount < Atmospherics.ZumosHardTileLimit)
tiles[tileCount++] = adj;
if (adj.Air.Immutable)
@@ -326,47 +333,42 @@ namespace Content.Server.Atmos
if (giverTilesLength > logN && takerTilesLength > logN)
{
// Even if it fails, it will speed up the next part.
Array.Sort(tiles, 0, tileCount, _comparer);
Array.Sort(tiles, 0, tileCount, Comparer);
for (var i = 0; i < tileCount; i++)
{
var tile = tiles[i];
tile._tileAtmosInfo.FastDone = true;
if (!(tile._tileAtmosInfo.MoleDelta > 0)) continue;
var eligibleDirections = ArrayPool<Direction>.Shared.Rent(4);
var eligibleDirections = AtmosDirection.Invalid;
var eligibleDirectionCount = 0;
foreach (var direction in Cardinal)
for (var j = 0; j < Atmospherics.Directions; j++)
{
if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) continue;
var direction = (AtmosDirection) (1 << j);
if (!tile._adjacentBits.HasFlag(direction)) continue;
var tile2 = tile._adjacentTiles[j];
// skip anything that isn't part of our current processing block.
if (tile2._tileAtmosInfo.FastDone || tile2._tileAtmosInfo.LastQueueCycle != queueCycle)
continue;
eligibleDirections[eligibleDirectionCount++] = direction;
eligibleDirections |= direction;
eligibleDirectionCount++;
}
if (eligibleDirectionCount <= 0)
continue; // Oof we've painted ourselves into a corner. Bad luck. Next part will handle this.
var molesToMove = tile._tileAtmosInfo.MoleDelta / eligibleDirectionCount;
foreach (var direction in Cardinal)
for (var j = 0; j < Atmospherics.Directions; j++)
{
var hasDirection = false;
for (var j = 0; j < eligibleDirectionCount; j++)
{
if (eligibleDirections[j] != direction) continue;
hasDirection = true;
break;
}
var direction = (AtmosDirection) (1 << j);
if (!eligibleDirections.HasFlag(direction)) continue;
if (hasDirection || !tile._adjacentTiles.TryGetValue(direction, out var tile2)) continue;
tile.AdjustEqMovement(direction, molesToMove);
tile._tileAtmosInfo.MoleDelta -= molesToMove;
tile2._tileAtmosInfo.MoleDelta += molesToMove;
tile._adjacentTiles[j]._tileAtmosInfo.MoleDelta += molesToMove;
}
ArrayPool<Direction>.Shared.Return(eligibleDirections);
}
giverTilesLength = 0;
@@ -393,7 +395,7 @@ namespace Content.Server.Atmos
for (var j = 0; j < giverTilesLength; j++)
{
var giver = giverTiles[j];
giver._tileAtmosInfo.CurrentTransferDirection = (Direction) (-1);
giver._tileAtmosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
giver._tileAtmosInfo.CurrentTransferAmount = 0;
var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl;
var queueLength = 0;
@@ -405,9 +407,11 @@ namespace Content.Server.Atmos
break; // We're done here now. Let's not do more work than needed.
var tile = queue[i];
foreach (var direction in Cardinal)
for (var k = 0; k < Atmospherics.Directions; k++)
{
if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) continue;
var direction = (AtmosDirection) (1 << k);
if (!tile._adjacentBits.HasFlag(direction)) continue;
var tile2 = tile._adjacentTiles[k];
if (giver._tileAtmosInfo.MoleDelta <= 0) break; // We're done here now. Let's not do more work than needed.
if (tile2._tileAtmosInfo.LastQueueCycle != queueCycle) continue;
if (tile2._tileAtmosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
@@ -441,15 +445,11 @@ namespace Content.Server.Atmos
for (var i = queueLength - 1; i >= 0; i--)
{
var tile = queue[i];
if (tile._tileAtmosInfo.CurrentTransferAmount != 0 &&
tile._tileAtmosInfo.CurrentTransferDirection != (Direction) (-1))
if (tile._tileAtmosInfo.CurrentTransferAmount != 0 && tile._tileAtmosInfo.CurrentTransferDirection != AtmosDirection.Invalid)
{
tile.AdjustEqMovement(tile._tileAtmosInfo.CurrentTransferDirection,
tile._tileAtmosInfo.CurrentTransferAmount);
if (tile._adjacentTiles.TryGetValue(tile._tileAtmosInfo.CurrentTransferDirection,
out var adjacent))
adjacent._tileAtmosInfo.CurrentTransferAmount +=
tile._tileAtmosInfo.CurrentTransferAmount;
tile.AdjustEqMovement(tile._tileAtmosInfo.CurrentTransferDirection, tile._tileAtmosInfo.CurrentTransferAmount);
tile._adjacentTiles[tile._tileAtmosInfo.CurrentTransferDirection.ToIndex()]
._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount;
tile._tileAtmosInfo.CurrentTransferAmount = 0;
}
}
@@ -463,7 +463,7 @@ namespace Content.Server.Atmos
for (var j = 0; j < takerTilesLength; j++)
{
var taker = takerTiles[j];
taker._tileAtmosInfo.CurrentTransferDirection = Direction.Invalid;
taker._tileAtmosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
taker._tileAtmosInfo.CurrentTransferAmount = 0;
var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl;
var queueLength = 0;
@@ -475,10 +475,11 @@ namespace Content.Server.Atmos
break; // We're done here now. Let's not do more work than needed.
var tile = queue[i];
foreach (var direction in Cardinal)
for (var k = 0; k < Atmospherics.Directions; k++)
{
if (!tile._adjacentTiles.ContainsKey(direction)) continue;
var tile2 = tile._adjacentTiles[direction];
var direction = (AtmosDirection) (1 << k);
if (!tile._adjacentBits.HasFlag(direction)) continue;
var tile2 = tile._adjacentTiles[k];
if (taker._tileAtmosInfo.MoleDelta >= 0) break; // We're done here now. Let's not do more work than needed.
if (tile2._tileAtmosInfo.LastQueueCycle != queueCycle) continue;
@@ -512,16 +513,14 @@ namespace Content.Server.Atmos
for (var i = queueLength - 1; i >= 0; i--)
{
var tile = queue[i];
if (tile._tileAtmosInfo.CurrentTransferAmount == 0 || tile._tileAtmosInfo.CurrentTransferDirection == Direction.Invalid)
if (tile._tileAtmosInfo.CurrentTransferAmount == 0 || tile._tileAtmosInfo.CurrentTransferDirection == AtmosDirection.Invalid)
continue;
tile.AdjustEqMovement(tile._tileAtmosInfo.CurrentTransferDirection, tile._tileAtmosInfo.CurrentTransferAmount);
if (tile._adjacentTiles.TryGetValue(tile._tileAtmosInfo.CurrentTransferDirection, out var adjacent))
{
adjacent._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount;
tile._tileAtmosInfo.CurrentTransferAmount = 0;
}
tile._adjacentTiles[tile._tileAtmosInfo.CurrentTransferDirection.ToIndex()]
._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount;
tile._tileAtmosInfo.CurrentTransferAmount = 0;
}
}
@@ -537,9 +536,11 @@ namespace Content.Server.Atmos
for (var i = 0; i < tileCount; i++)
{
var tile = tiles[i];
foreach (var direction in Cardinal)
for (var j = 0; j < Atmospherics.Directions; j++)
{
if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) continue;
var direction = (AtmosDirection) (1 << j);
if (!tile._adjacentBits.HasFlag(direction)) continue;
var tile2 = tile._adjacentTiles[j];
if (tile2?.Air?.Compare(Air) == GasMixture.GasCompareResult.NoExchange) continue;
_gridAtmosphereComponent.AddActiveTile(tile2);
break;
@@ -555,69 +556,68 @@ namespace Content.Server.Atmos
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void FinalizeEq()
{
var transferDirections = new Dictionary<Direction, float>();
var transferDirections = new float[Atmospherics.Directions];
var hasTransferDirs = false;
foreach (var direction in Cardinal)
for (var i = 0; i < Atmospherics.Directions; i++)
{
var amount = _tileAtmosInfo[direction];
var amount = _tileAtmosInfo[i];
if (amount == 0) continue;
transferDirections[direction] = amount;
_tileAtmosInfo[direction] = 0;
transferDirections[i] = amount;
_tileAtmosInfo[i] = 0; // Set them to 0 to prevent infinite recursion.
hasTransferDirs = true;
}
if (!hasTransferDirs) return;
foreach (var (direction, amount) in transferDirections)
for(var i = 0; i < Atmospherics.Directions; i++)
{
if (!_adjacentTiles.TryGetValue(direction, out var tile) || tile.Air == null) continue;
var direction = (AtmosDirection) (1 << i);
if (!_adjacentBits.HasFlag(direction)) continue;
var amount = transferDirections[i];
var tile = _adjacentTiles[i];
if (tile?.Air == null) continue;
if (amount > 0)
{
if (Air.TotalMoles < amount)
FinalizeEqNeighbors(transferDirections.Keys);
FinalizeEqNeighbors(transferDirections);
tile._tileAtmosInfo[direction.GetOpposite()] = 0;
tile.Air.Merge(Air.Remove(amount));
UpdateVisuals();
tile.UpdateVisuals();
ConsiderPressureDifference(direction, amount);
ConsiderPressureDifference(tile, amount);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void FinalizeEqNeighbors(IEnumerable<Direction> directions)
private void FinalizeEqNeighbors(in float[] transferDirs)
{
foreach (var direction in directions)
for (var i = 0; i < Atmospherics.Directions; i++)
{
var amount = _tileAtmosInfo[direction];
if(amount < 0 && _adjacentTiles.TryGetValue(direction, out var adjacent))
adjacent.FinalizeEq();
var direction = (AtmosDirection) (1 << i);
var amount = transferDirs[i];
if(amount < 0 && _adjacentBits.HasFlag(direction))
_adjacentTiles[i].FinalizeEq(); // A bit of recursion if needed.
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ConsiderPressureDifference(Direction direction, float difference)
private void ConsiderPressureDifference(TileAtmosphere other, float difference)
{
_gridAtmosphereComponent.AddHighPressureDelta(this);
if (difference > PressureDifference)
{
PressureDifference = difference;
_pressureDirection = difference < 0 ? direction.GetOpposite() : direction;
_pressureDirection = ((Vector2i)(GridIndices - other.GridIndices)).GetDir().ToAtmosDirection();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AdjustEqMovement(Direction direction, float molesToMove)
private void AdjustEqMovement(AtmosDirection direction, float amount)
{
_tileAtmosInfo[direction] += molesToMove;
if(direction != Direction.Invalid && _adjacentTiles.TryGetValue(direction, out var adj))
adj._tileAtmosInfo[direction.GetOpposite()] -= molesToMove;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ResetTileAtmosInfo()
{
_tileAtmosInfo = new TileAtmosInfo {CurrentTransferDirection = Direction.Invalid};
_tileAtmosInfo[direction] += amount;
_adjacentTiles[direction.ToIndex()]._tileAtmosInfo[direction.GetOpposite()] -= amount;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -635,9 +635,13 @@ namespace Content.Server.Atmos
_currentCycle = fireCount;
var adjacentTileLength = 0;
foreach (var (direction, enemyTile) in _adjacentTiles)
for(var i = 0; i < Atmospherics.Directions; i++)
{
// If the tile is null or has no air, we don't do anything
var direction = (AtmosDirection) (1 << i);
if (!_adjacentBits.HasFlag(direction)) continue;
var enemyTile = _adjacentTiles[i];
// If the tile is null or has no air, we don't do anything for it.
if(enemyTile?.Air == null) continue;
adjacentTileLength++;
if (fireCount <= enemyTile._currentCycle) continue;
@@ -685,11 +689,11 @@ namespace Content.Server.Atmos
// Space wind!
if (difference > 0)
{
ConsiderPressureDifference(direction, difference);
ConsiderPressureDifference(enemyTile, difference);
}
else
{
enemyTile.ConsiderPressureDifference(direction.GetOpposite(), -difference);
enemyTile.ConsiderPressureDifference(this, -difference);
}
LastShareCheck();
@@ -737,7 +741,7 @@ namespace Content.Server.Atmos
if (Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread)
{
var radiatedTemperature = Air.Temperature * Atmospherics.FireSpreadRadiosityScale;
foreach (var (_, tile) in _adjacentTiles)
foreach (var tile in _adjacentTiles)
{
if(!tile.Hotspot.Valid)
tile.HotspotExpose(radiatedTemperature, Atmospherics.CellVolume/4);
@@ -771,17 +775,19 @@ namespace Content.Server.Atmos
else
{
var affected = Air.RemoveRatio(Hotspot.Volume / Air.Volume);
if (affected != null)
{
affected.Temperature = Hotspot.Temperature;
affected.React(this);
Hotspot.Temperature = affected.Temperature;
Hotspot.Volume = affected.ReactionResults[GasReaction.Fire] * Atmospherics.FireGrowthRate;
AssumeAir(affected);
}
affected.Temperature = Hotspot.Temperature;
affected.React(this);
Hotspot.Temperature = affected.Temperature;
Hotspot.Volume = affected.ReactionResults[GasReaction.Fire] * Atmospherics.FireGrowthRate;
AssumeAir(affected);
}
// TODO ATMOS Let all entities in this tile know about the fire?
var tileRef = GridIndices.GetTileRef(GridIndex);
if (tileRef == null) return;
_gridAtmosphereComponent.Owner.EntityManager.
EventBus.QueueEvent(EventSource.Local, new FireActEvent(Hotspot.Temperature, Hotspot.Volume));
}
private bool ConsiderSuperconductivity()
@@ -806,24 +812,24 @@ namespace Content.Server.Atmos
public void Superconduct()
{
var directions = ConductivityDirections();
var adjacentTiles = _gridAtmosphereComponent.GetAdjacentTiles(GridIndices, true);
if (directions.Length > 0)
for(var i = 0; i < Atmospherics.Directions; i++)
{
foreach (var direction in directions)
{
if (!adjacentTiles.TryGetValue(direction, out var adjacent)) continue;
var direction = (AtmosDirection) (1 << i);
if (!directions.HasFlag(direction)) continue;
if (adjacent.ThermalConductivity == 0f)
continue;
var adjacent = _adjacentTiles[direction.ToIndex()];
if(adjacent._archivedCycle < _gridAtmosphereComponent.UpdateCounter)
adjacent.Archive(_gridAtmosphereComponent.UpdateCounter);
// TODO ATMOS handle adjacent being null.
if (adjacent == null || adjacent.ThermalConductivity == 0f)
continue;
adjacent.NeighborConductWithSource(this);
if(adjacent._archivedCycle < _gridAtmosphereComponent.UpdateCounter)
adjacent.Archive(_gridAtmosphereComponent.UpdateCounter);
adjacent.ConsiderSuperconductivity();
}
adjacent.NeighborConductWithSource(this);
adjacent.ConsiderSuperconductivity();
}
RadiateToSpace();
@@ -917,20 +923,20 @@ namespace Content.Server.Atmos
}
}
public Direction[] ConductivityDirections()
public AtmosDirection ConductivityDirections()
{
if(BlocksAir)
{
if(_archivedCycle < _gridAtmosphereComponent.UpdateCounter)
Archive(_gridAtmosphereComponent.UpdateCounter);
return Cardinal;
return AtmosDirection.All;
}
// TODO ATMOS check if this is correct
return Cardinal;
return AtmosDirection.All;
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ExplosivelyDepressurize(int cycleNum)
{
if (Air == null) return;
@@ -947,14 +953,13 @@ namespace Content.Server.Atmos
tiles[tileCount++] = this;
ResetTileAtmosInfo();
_tileAtmosInfo.LastQueueCycle = queueCycle;
_tileAtmosInfo = new TileAtmosInfo {LastQueueCycle = queueCycle};
for (var i = 0; i < tileCount; i++)
{
var tile = tiles[i];
tile._tileAtmosInfo.LastCycle = cycleNum;
tile._tileAtmosInfo.CurrentTransferDirection = Direction.Invalid;
tile._tileAtmosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
if (tile.Air.Immutable)
{
spaceTiles[spaceTileCount++] = tile;
@@ -962,18 +967,19 @@ namespace Content.Server.Atmos
}
else
{
foreach (var direction in Cardinal)
for (var j = 0; j < Atmospherics.Directions; j++)
{
if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) continue;
var direction = (AtmosDirection) (1 << j);
if (!tile._adjacentBits.HasFlag(direction)) continue;
var tile2 = tile._adjacentTiles[j];
if (tile2.Air == null) continue;
if (tile2._tileAtmosInfo.LastQueueCycle == queueCycle) continue;
tile.ConsiderFirelocks(tile2);
// The firelocks might have closed on us.
if (tile._adjacentTiles[direction]?.Air == null) continue;
tile2.ResetTileAtmosInfo();
tile2._tileAtmosInfo.LastQueueCycle = queueCycle;
if (!tile._adjacentBits.HasFlag(direction)) continue;
tile2._tileAtmosInfo = new TileAtmosInfo {LastQueueCycle = queueCycle};
tiles[tileCount++] = tile2;
}
}
@@ -991,18 +997,21 @@ namespace Content.Server.Atmos
var tile = spaceTiles[i];
progressionOrder[progressionCount++] = tile;
tile._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow;
tile._tileAtmosInfo.CurrentTransferDirection = Direction.Invalid;
tile._tileAtmosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
}
for (var i = 0; i < progressionCount; i++)
{
var tile = progressionOrder[i];
foreach (var direction in Cardinal)
for (var j = 0; j < Atmospherics.Directions; j++)
{
if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) continue;
var direction = (AtmosDirection) (1 << j);
// TODO ATMOS This is a terrible hack that accounts for the mess that are space TileAtmospheres.
if (!tile._adjacentBits.HasFlag(direction) && !tile.Air.Immutable) continue;
var tile2 = tile._adjacentTiles[j];
if (tile2?._tileAtmosInfo.LastQueueCycle != queueCycle) continue;
if (tile2._tileAtmosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
if(tile2.Air.Immutable) continue;
if(tile2.Air?.Immutable ?? false) continue;
tile2._tileAtmosInfo.CurrentTransferDirection = direction.GetOpposite();
tile2._tileAtmosInfo.CurrentTransferAmount = 0;
tile2.PressureSpecificTarget = tile.PressureSpecificTarget;
@@ -1014,10 +1023,11 @@ namespace Content.Server.Atmos
for (var i = progressionCount - 1; i >= 0; i--)
{
var tile = progressionOrder[i];
if (tile._tileAtmosInfo.CurrentTransferDirection == Direction.Invalid) continue;
if (tile._tileAtmosInfo.CurrentTransferDirection == AtmosDirection.Invalid) continue;
_gridAtmosphereComponent.AddHighPressureDelta(tile);
_gridAtmosphereComponent.AddActiveTile(tile);
if (!tile._adjacentTiles.TryGetValue(tile._tileAtmosInfo.CurrentTransferDirection, out var tile2) || tile2.Air == null) continue;
var tile2 = tile._adjacentTiles[tile._tileAtmosInfo.CurrentTransferDirection.ToIndex()];
if (tile2?.Air == null) continue;
var sum = tile2.Air.TotalMoles;
totalGasesRemoved += sum;
tile._tileAtmosInfo.CurrentTransferAmount += sum;
@@ -1025,7 +1035,7 @@ namespace Content.Server.Atmos
tile.PressureDifference = tile._tileAtmosInfo.CurrentTransferAmount;
tile._pressureDirection = tile._tileAtmosInfo.CurrentTransferDirection;
if (tile2._tileAtmosInfo.CurrentTransferDirection == Direction.Invalid)
if (tile2._tileAtmosInfo.CurrentTransferDirection == AtmosDirection.Invalid)
{
tile2.PressureDifference = tile2._tileAtmosInfo.CurrentTransferAmount;
tile2._pressureDirection = tile._tileAtmosInfo.CurrentTransferDirection;
@@ -1101,21 +1111,30 @@ namespace Content.Server.Atmos
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UpdateAdjacent()
{
foreach (var direction in Cardinal)
for (var i = 0; i < Atmospherics.Directions; i++)
{
if (!_gridAtmosphereComponent.IsAirBlocked(GridIndices.Offset(direction)))
var direction = (AtmosDirection) (1 << i);
var otherIndices = GridIndices.Offset(direction.ToDirection());
var isSpace = _gridAtmosphereComponent.IsSpace(GridIndices);
var adjacent = _gridAtmosphereComponent.GetTile(otherIndices, !isSpace);
_adjacentTiles[direction.ToIndex()] = adjacent;
adjacent?.UpdateAdjacent(direction.GetOpposite());
if (adjacent != null && !_gridAtmosphereComponent.IsAirBlocked(adjacent.GridIndices))
{
var adjacent = _gridAtmosphereComponent.GetTile(GridIndices.Offset(direction));
_adjacentTiles[direction] = adjacent;
adjacent.UpdateAdjacent(direction.GetOpposite());
_adjacentBits |= direction;
}
}
}
public void UpdateAdjacent(Direction direction)
public void UpdateAdjacent(AtmosDirection direction)
{
if (!_gridAtmosphereComponent.IsAirBlocked(GridIndices.Offset(direction)))
_adjacentTiles[direction] = _gridAtmosphereComponent.GetTile(GridIndices.Offset(direction));
if (!_gridAtmosphereComponent.IsAirBlocked(GridIndices.Offset(direction.ToDirection())))
{
_adjacentTiles[direction.ToIndex()] = _gridAtmosphereComponent.GetTile(GridIndices.Offset(direction.ToDirection()));
}
}
private void LastShareCheck()
@@ -1130,13 +1149,7 @@ namespace Content.Server.Atmos
}
}
private static readonly Direction[] Cardinal =
new Direction[]
{
Direction.North, Direction.East, Direction.South, Direction.West
};
public void TemperatureExpose(GasMixture mixture, float temperature, float cellVolume)
public void TemperatureExpose(GasMixture air, float temperature, float volume)
{
// TODO ATMOS do this
}