Atmos Debug Overlay expansion (#2626)
* Atmos Debug Overlay: Add a way of showing blocked directions * Atmos Debug Overlay: Adjustable modes client-side * Atmos Debug Overlay: Fix atvrange help text * Atmos Debug Overlay: More flexible and clear gas ID specification
This commit is contained in:
@@ -54,7 +54,7 @@ namespace Content.Client.Atmos
|
||||
|
||||
var gridBounds = new Box2(mapGrid.WorldToLocal(worldBounds.BottomLeft), mapGrid.WorldToLocal(worldBounds.TopRight));
|
||||
|
||||
for (var pass = 0; pass < 3; pass++)
|
||||
for (var pass = 0; pass < 2; pass++)
|
||||
{
|
||||
foreach (var tile in mapGrid.GetTilesIntersecting(gridBounds))
|
||||
{
|
||||
@@ -64,17 +64,65 @@ namespace Content.Client.Atmos
|
||||
var data = (SharedAtmosDebugOverlaySystem.AtmosDebugOverlayData) dataMaybeNull!;
|
||||
if (pass == 0)
|
||||
{
|
||||
// -- Mole Count --
|
||||
float total = 0;
|
||||
foreach (float f in data.Moles)
|
||||
{
|
||||
total += f;
|
||||
switch (_atmosDebugOverlaySystem.CfgMode) {
|
||||
case AtmosDebugOverlayMode.TotalMoles:
|
||||
foreach (float f in data.Moles)
|
||||
{
|
||||
total += f;
|
||||
}
|
||||
break;
|
||||
case AtmosDebugOverlayMode.GasMoles:
|
||||
total = data.Moles[_atmosDebugOverlaySystem.CfgSpecificGas];
|
||||
break;
|
||||
case AtmosDebugOverlayMode.Temperature:
|
||||
total = data.Temperature;
|
||||
break;
|
||||
}
|
||||
var interp = total / (Atmospherics.MolesCellStandard * 2);
|
||||
var res = Color.InterpolateBetween(Color.Red, Color.Green, interp).WithAlpha(0.75f);
|
||||
var interp = ((total - _atmosDebugOverlaySystem.CfgBase) / _atmosDebugOverlaySystem.CfgScale);
|
||||
Color res;
|
||||
if (_atmosDebugOverlaySystem.CfgCBM)
|
||||
{
|
||||
// Greyscale interpolation
|
||||
res = Color.InterpolateBetween(Color.Black, Color.White, interp);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Red-Green-Blue interpolation
|
||||
if (interp < 0.5f)
|
||||
{
|
||||
res = Color.InterpolateBetween(Color.Red, Color.Green, interp * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = Color.InterpolateBetween(Color.Green, Color.Blue, (interp - 0.5f) * 2);
|
||||
}
|
||||
}
|
||||
res = res.WithAlpha(0.75f);
|
||||
drawHandle.DrawRect(Box2.FromDimensions(mapGrid.LocalToWorld(new Vector2(tile.X, tile.Y)), new Vector2(1, 1)), res);
|
||||
}
|
||||
else if (pass == 1)
|
||||
{
|
||||
// -- Blocked Directions --
|
||||
void CheckAndShowBlockDir(AtmosDirection dir)
|
||||
{
|
||||
if (data.BlockDirection.HasFlag(dir))
|
||||
{
|
||||
var atmosAngle = dir.ToAngle();
|
||||
var atmosAngleOfs = atmosAngle.ToVec() * 0.45f;
|
||||
var atmosAngleOfsR90 = new Vector2(atmosAngleOfs.Y, -atmosAngleOfs.X);
|
||||
var tileCentre = new Vector2(tile.X + 0.5f, tile.Y + 0.5f);
|
||||
var basisA = mapGrid.LocalToWorld(tileCentre + atmosAngleOfs - atmosAngleOfsR90);
|
||||
var basisB = mapGrid.LocalToWorld(tileCentre + atmosAngleOfs + atmosAngleOfsR90);
|
||||
drawHandle.DrawLine(basisA, basisB, Color.Azure);
|
||||
}
|
||||
}
|
||||
CheckAndShowBlockDir(AtmosDirection.North);
|
||||
CheckAndShowBlockDir(AtmosDirection.South);
|
||||
CheckAndShowBlockDir(AtmosDirection.East);
|
||||
CheckAndShowBlockDir(AtmosDirection.West);
|
||||
// -- Pressure Direction --
|
||||
if (data.PressureDirection != AtmosDirection.Invalid)
|
||||
{
|
||||
var atmosAngle = data.PressureDirection.ToAngle();
|
||||
@@ -84,9 +132,7 @@ namespace Content.Client.Atmos
|
||||
var basisB = mapGrid.LocalToWorld(tileCentre + atmosAngleOfs);
|
||||
drawHandle.DrawLine(basisA, basisB, Color.Blue);
|
||||
}
|
||||
}
|
||||
else if (pass == 2)
|
||||
{
|
||||
// -- Excited Groups --
|
||||
if (data.InExcitedGroup)
|
||||
{
|
||||
var tilePos = new Vector2(tile.X, tile.Y);
|
||||
|
||||
125
Content.Client/Commands/AtmosDebugCommands.cs
Normal file
125
Content.Client/Commands/AtmosDebugCommands.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Content.Client.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Content.Shared.Atmos;
|
||||
using System;
|
||||
|
||||
namespace Content.Client.Commands
|
||||
{
|
||||
[UsedImplicitly]
|
||||
internal sealed class AtvRangeCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "atvrange";
|
||||
public string Description => "Sets the atmos debug range (as two floats, start [red] and end [blue])";
|
||||
public string Help => "atvrange <start> <end>";
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
if (args.Length != 2)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
}
|
||||
if (!float.TryParse(args[0], out var xStart))
|
||||
{
|
||||
console.AddLine("Bad float START");
|
||||
return false;
|
||||
}
|
||||
if (!float.TryParse(args[1], out var xEnd))
|
||||
{
|
||||
console.AddLine("Bad float END");
|
||||
return false;
|
||||
}
|
||||
if (xStart == xEnd)
|
||||
{
|
||||
console.AddLine("Scale cannot be zero, as this would cause a division by zero in AtmosDebugOverlay.");
|
||||
return false;
|
||||
}
|
||||
var sys = EntitySystem.Get<AtmosDebugOverlaySystem>();
|
||||
sys.CfgBase = xStart;
|
||||
sys.CfgScale = xEnd - xStart;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
internal sealed class AtvModeCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "atvmode";
|
||||
public string Description => "Sets the atmos debug mode. This will automatically reset the scale.";
|
||||
public string Help => "atvmode <TotalMoles/GasMoles/Temperature> [<gas ID (for GasMoles)>]";
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
}
|
||||
if (!Enum.TryParse<AtmosDebugOverlayMode>(args[0], out var xMode))
|
||||
{
|
||||
console.AddLine("Invalid mode");
|
||||
return false;
|
||||
}
|
||||
int xSpecificGas = 0;
|
||||
float xBase = 0;
|
||||
float xScale = Atmospherics.MolesCellStandard * 2;
|
||||
if (xMode == AtmosDebugOverlayMode.GasMoles)
|
||||
{
|
||||
if (args.Length != 2)
|
||||
{
|
||||
console.AddLine("A target gas must be provided for this mode.");
|
||||
return false;
|
||||
}
|
||||
if (!AtmosCommandUtils.TryParseGasID(args[1], out xSpecificGas))
|
||||
{
|
||||
console.AddLine("Gas ID not parsable or out of range.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
console.AddLine("No further information is required for this mode.");
|
||||
return false;
|
||||
}
|
||||
if (xMode == AtmosDebugOverlayMode.Temperature)
|
||||
{
|
||||
// Red is 100C, Green is 20C, Blue is -60C
|
||||
xBase = Atmospherics.T20C + 80;
|
||||
xScale = -160;
|
||||
}
|
||||
}
|
||||
var sys = EntitySystem.Get<AtmosDebugOverlaySystem>();
|
||||
sys.CfgMode = xMode;
|
||||
sys.CfgSpecificGas = xSpecificGas;
|
||||
sys.CfgBase = xBase;
|
||||
sys.CfgScale = xScale;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
internal sealed class AtvCBMCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "atvcbm";
|
||||
public string Description => "Changes from red/green/blue to greyscale";
|
||||
public string Help => "atvcbm <true/false>";
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
}
|
||||
if (!bool.TryParse(args[0], out var xFlag))
|
||||
{
|
||||
console.AddLine("Invalid flag");
|
||||
return false;
|
||||
}
|
||||
var sys = EntitySystem.Get<AtmosDebugOverlaySystem>();
|
||||
sys.CfgCBM = xFlag;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Atmos;
|
||||
using Content.Shared.GameObjects.EntitySystems.Atmos;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.GameTicking;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
@@ -20,6 +21,19 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
private readonly Dictionary<GridId, AtmosDebugOverlayMessage> _tileData =
|
||||
new();
|
||||
|
||||
// Configuration set by debug commands and used by AtmosDebugOverlay {
|
||||
/// <summary>Value source for display</summary>
|
||||
public AtmosDebugOverlayMode CfgMode;
|
||||
/// <summary>This is subtracted from value (applied before CfgScale)</summary>
|
||||
public float CfgBase = 0;
|
||||
/// <summary>The value is divided by this (applied after CfgBase)</summary>
|
||||
public float CfgScale = Atmospherics.MolesCellStandard * 2;
|
||||
/// <summary>Gas ID used by GasMoles mode</summary>
|
||||
public int CfgSpecificGas = 0;
|
||||
/// <summary>Uses black-to-white interpolation (as opposed to red-green-blue) for colourblind users</summary>
|
||||
public bool CfgCBM = false;
|
||||
// }
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -83,4 +97,11 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
return srcMsg.OverlayData[relative.X + (relative.Y * LocalViewRange)];
|
||||
}
|
||||
}
|
||||
|
||||
internal enum AtmosDebugOverlayMode
|
||||
{
|
||||
TotalMoles,
|
||||
GasMoles,
|
||||
Temperature
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,20 +144,13 @@ namespace Content.Server.Atmos
|
||||
public string Help => "addgas <X> <Y> <GridId> <Gas> <moles>";
|
||||
public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
|
||||
{
|
||||
var gasId = -1;
|
||||
var gas = (Gas) (-1);
|
||||
if (args.Length < 5) return;
|
||||
if(!int.TryParse(args[0], out var x)
|
||||
|| !int.TryParse(args[1], out var y)
|
||||
|| !int.TryParse(args[2], out var id)
|
||||
|| !(int.TryParse(args[3], out gasId) || Enum.TryParse(args[3], true, out gas))
|
||||
|| !(AtmosCommandUtils.TryParseGasID(args[3], out var gasId))
|
||||
|| !float.TryParse(args[4], out var moles)) return;
|
||||
|
||||
if (gas != (Gas) (-1))
|
||||
{
|
||||
gasId = (int)gas;
|
||||
}
|
||||
|
||||
var gridId = new GridId(id);
|
||||
|
||||
var mapMan = IoCManager.Resolve<IMapManager>();
|
||||
@@ -198,14 +191,7 @@ namespace Content.Server.Atmos
|
||||
return;
|
||||
}
|
||||
|
||||
if (gasId != -1)
|
||||
{
|
||||
tile.Air.AdjustMoles(gasId, moles);
|
||||
gam.Invalidate(indices);
|
||||
return;
|
||||
}
|
||||
|
||||
tile.Air.AdjustMoles(gas, moles);
|
||||
tile.Air.AdjustMoles(gasId, moles);
|
||||
gam.Invalidate(indices);
|
||||
}
|
||||
}
|
||||
@@ -218,16 +204,11 @@ namespace Content.Server.Atmos
|
||||
public string Help => "fillgas <GridId> <Gas> <moles>";
|
||||
public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
|
||||
{
|
||||
var gasId = -1;
|
||||
var gas = (Gas) (-1);
|
||||
if (args.Length < 3) return;
|
||||
if(!int.TryParse(args[0], out var id)
|
||||
|| !(int.TryParse(args[1], out gasId) || Enum.TryParse(args[1], true, out gas))
|
||||
|| !(AtmosCommandUtils.TryParseGasID(args[1], out var gasId))
|
||||
|| !float.TryParse(args[2], out var moles)) return;
|
||||
|
||||
if (gas != (Gas) (-1))
|
||||
gasId = (int)gas;
|
||||
|
||||
var gridId = new GridId(id);
|
||||
|
||||
var mapMan = IoCManager.Resolve<IMapManager>();
|
||||
@@ -256,14 +237,7 @@ namespace Content.Server.Atmos
|
||||
|
||||
foreach (var tile in gam)
|
||||
{
|
||||
if (gasId != -1)
|
||||
{
|
||||
tile.Air?.AdjustMoles(gasId, moles);
|
||||
gam.Invalidate(tile.GridIndices);
|
||||
continue;
|
||||
}
|
||||
|
||||
tile.Air?.AdjustMoles(gas, moles);
|
||||
tile.Air?.AdjustMoles(gasId, moles);
|
||||
gam.Invalidate(tile.GridIndices);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace Content.Server.GameObjects.EntitySystems.Atmos
|
||||
var gases = new float[Atmospherics.TotalNumberOfGases];
|
||||
if (tile?.Air == null)
|
||||
{
|
||||
return new AtmosDebugOverlayData(0, gases, AtmosDirection.Invalid, false);
|
||||
return new AtmosDebugOverlayData(0, gases, AtmosDirection.Invalid, false, tile?.BlockedAirflow ?? AtmosDirection.Invalid);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -112,7 +112,7 @@ namespace Content.Server.GameObjects.EntitySystems.Atmos
|
||||
{
|
||||
gases[i] = tile.Air.GetMoles(i);
|
||||
}
|
||||
return new AtmosDebugOverlayData(tile.Air.Temperature, gases, tile.PressureDirectionForDebugOverlay, tile.ExcitedGroup != null);
|
||||
return new AtmosDebugOverlayData(tile.Air.Temperature, gases, tile.PressureDirectionForDebugOverlay, tile.ExcitedGroup != null, tile.BlockedAirflow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
28
Content.Shared/Atmos/AtmosCommandUtils.cs
Normal file
28
Content.Shared/Atmos/AtmosCommandUtils.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Shared.Atmos;
|
||||
|
||||
namespace Content.Shared.Atmos
|
||||
{
|
||||
public class AtmosCommandUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Gas ID parser for atmospherics commands.
|
||||
/// This is so there's a central place for this logic for if the Gas enum gets removed.
|
||||
/// </summary>
|
||||
public static bool TryParseGasID(string str, out int x)
|
||||
{
|
||||
x = -1;
|
||||
if (Enum.TryParse<Gas>(str, true, out var gas))
|
||||
{
|
||||
x = (int) gas;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!int.TryParse(str, out x))
|
||||
return false;
|
||||
}
|
||||
return ((x >= 0) && (x < Atmospherics.TotalNumberOfGases));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,13 +23,15 @@ namespace Content.Shared.GameObjects.EntitySystems.Atmos
|
||||
public readonly float[] Moles;
|
||||
public readonly AtmosDirection PressureDirection;
|
||||
public readonly bool InExcitedGroup;
|
||||
public readonly AtmosDirection BlockDirection;
|
||||
|
||||
public AtmosDebugOverlayData(float temperature, float[] moles, AtmosDirection pressureDirection, bool inExcited)
|
||||
public AtmosDebugOverlayData(float temperature, float[] moles, AtmosDirection pressureDirection, bool inExcited, AtmosDirection blockDirection)
|
||||
{
|
||||
Temperature = temperature;
|
||||
Moles = moles;
|
||||
PressureDirection = pressureDirection;
|
||||
InExcitedGroup = inExcited;
|
||||
BlockDirection = blockDirection;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user