using Content.Server.Atmos.Components;
using System.Numerics;
using Robust.Shared.Map.Components;
using Content.Shared.Atmos;
namespace Content.Server.Atmos.EntitySystems;
// WELCOME TO THE MATRIX AIRFLOW SYSTEM.
public sealed partial class AtmosphereSystem
{
# pragma warning disable IDE1006
///
/// The standard issue "Search Pattern" used by the Matrix Airflow System.
///
private readonly List<(int, int, AtmosDirection)> MASSearchPattern = new List<(int, int, AtmosDirection)>
{
(-1,1, AtmosDirection.SouthEast), (0,1, AtmosDirection.South), (1,1, AtmosDirection.SouthWest),
(-1,0, AtmosDirection.East), (1,0, AtmosDirection.West),
(-1,-1, AtmosDirection.NorthEast), (0,-1, AtmosDirection.North), (1,-1, AtmosDirection.NorthWest)
};
# pragma warning restore IDE1006
///
/// This function solves for the flow of air across a given tile, expressed in the format of (Vector) kg/ms^2.
/// Multiply this output against any "Area"(such as a human cross section) in the form of meters squared to get the force of air flowing against that object in Newtons.
/// From there, you can divide by the object's mass (in kg) to get the object's acceleration in meters per second squared.
/// To solve for the object's change in velocity per CPU tick, you then multiply by frameTime to get Delta-V.
///
///
/// This function is a direct implementation of the Navier-Stokes system of partial differential equations.
/// Simplified since we don't need to account for fluid viscosity(yet) as this is currently only being used to handle breathable atmosphere.
///
public Vector2 GetPressureVectorFromTile(GridAtmosphereComponent gridAtmos, TileAtmosphere tile)
{
if (!HasComp(tile.GridIndex))
return new Vector2(0, 0);
var centerPressure = tile.Air?.Pressure ?? 0f;
var pressureVector = new Vector2(0, 0);
foreach (var (x, y, dir) in MASSearchPattern)
{
var offsetVector = new Vector2(x, y);
// If the tile checked doesn't exist, or has no air, or it's space,
// then there's nothing to "push back" against our center tile's air.
if (!gridAtmos.Tiles.TryGetValue(tile.GridIndices + (x, y), out var tileAtmosphere)
|| tileAtmosphere.Space)
{
pressureVector += offsetVector * centerPressure;
continue;
}
// If the tile checked is blocking airflow from this direction, the center tile's air "Bounces" off it and into the
// opposite direction.
if (tileAtmosphere.AirtightData.BlockedDirections is AtmosDirection.All
|| tileAtmosphere.AirtightData.BlockedDirections.HasFlag(dir)
|| tileAtmosphere.Air is null)
{
pressureVector -= offsetVector * centerPressure;
continue;
}
// Center tile now transfers its pressure across the target.
var pressureDiff = centerPressure - tileAtmosphere.Air.Pressure;
pressureVector += offsetVector * pressureDiff;
// And finally, the pressure in the target tile is resisting the original target pressure.
pressureVector -= offsetVector * tileAtmosphere.Air.Pressure;
}
// from TCJ: By this point in the equation, all possible conditions are now checked, and for any airtight vessel with a standard atmosphere, the final output will be <0, 0>.
// Should any holes exist in the ship, the air will now flow at an exponential rate towards it, while deflecting around walls.
return pressureVector;
}
}