Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Atmospheric network monitor #32294

Merged
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
f011de6
Updated to latest master version
chromiumboy Aug 31, 2024
d2992c4
Merge branch 'master' of https://github.com/space-wizards/space-stati…
chromiumboy Sep 8, 2024
1ed4598
Added gas pipe analyzer
chromiumboy Sep 10, 2024
273567b
Completed prototype
chromiumboy Sep 10, 2024
1c9f543
Playing with UI display
chromiumboy Sep 10, 2024
61c3fc9
Refinement of the main UI
chromiumboy Sep 11, 2024
bfc4afa
Renamed gas pipe analyzer to gas pipe sensor
chromiumboy Sep 11, 2024
98335ef
Added focus network highlighting and map icons for gas pipe sensors
chromiumboy Sep 12, 2024
51ede04
Added construction graph for gas pipe sensor
chromiumboy Sep 13, 2024
49dc5b7
Improved efficiency of atmos pipe and focus pipe network data storage
chromiumboy Sep 13, 2024
6d07ccf
Added gas pipe sensor variants
chromiumboy Sep 13, 2024
a0abaf0
Fixed gas pipe sensor nav map icon not highlighting on focus
chromiumboy Sep 13, 2024
a40b118
Rendered pipe lines now get merged together
chromiumboy Sep 13, 2024
ae30a1a
Merge branch 'master' of https://github.com/space-wizards/space-stati…
chromiumboy Sep 14, 2024
512fcdf
Set up appearance handling for the gas pipe sensor, but setting the l…
chromiumboy Sep 14, 2024
eeef3b0
Gas pipe sensor lights turn off when the device is unpowered
chromiumboy Sep 15, 2024
3349937
Renamed console
chromiumboy Sep 16, 2024
965944a
The gas pipe sensor is now a pipe. Redistributed components between i…
chromiumboy Sep 16, 2024
fb35d72
AtmosMonitors can now optionally monitor their internal pipe network …
chromiumboy Sep 16, 2024
47fd136
Massive code clean up
chromiumboy Sep 16, 2024
6eae69c
Added delta states to handle pipe net updates, fixed entity deletion …
chromiumboy Sep 17, 2024
40cc5eb
Nav map blip data has been replaced with prototypes
chromiumboy Sep 17, 2024
13b6a17
Nav map blip fixes
chromiumboy Sep 17, 2024
9c9b36e
Nav map colors are now set by the console component
chromiumboy Sep 17, 2024
c87c8a6
Made the nav map more responsive to changes in focus
chromiumboy Sep 17, 2024
ea75de1
Merge branch 'master' of https://github.com/space-wizards/space-stati…
chromiumboy Sep 17, 2024
0fb5fe1
Updated nav map icons
chromiumboy Sep 18, 2024
5f9593f
Reverted unnecessary namespace changes
chromiumboy Sep 18, 2024
f84907f
Code tidy up
chromiumboy Sep 18, 2024
9283dbb
Merge branch 'master' of https://github.com/space-wizards/space-stati…
chromiumboy Sep 18, 2024
5dd3dd6
Updated sprites and construction graph for gas pipe sensor
chromiumboy Sep 19, 2024
66f75f1
Updated localization files
chromiumboy Sep 19, 2024
4e35a1c
Misc bug fixes
chromiumboy Sep 19, 2024
d33f70c
Added missing comment
chromiumboy Sep 19, 2024
e91ed46
Fixed issue with the circuit board for the monitor
chromiumboy Sep 19, 2024
1889fcc
Embellished the background of the console network entries
chromiumboy Sep 20, 2024
2268ae6
Merge branch 'master' of https://github.com/space-wizards/space-stati…
chromiumboy Sep 24, 2024
b176a10
Updated console to account for PR #32273
chromiumboy Sep 24, 2024
69fa0dd
Removed gas pipe sensor
chromiumboy Nov 3, 2024
562db7f
Fixing merge conflict
chromiumboy Dec 2, 2024
f6dd937
Merge branch 'master' of https://github.com/space-wizards/space-stati…
chromiumboy Dec 2, 2024
3e8c40a
Update
chromiumboy Dec 2, 2024
3b179ac
Merge branch 'master' of https://github.com/space-wizards/space-stati…
chromiumboy Dec 14, 2024
2559a1b
Addressing reviews part 1
chromiumboy Dec 14, 2024
bc95c3b
Addressing review part 2
chromiumboy Dec 15, 2024
b26e034
Addressing reviews part 3
chromiumboy Dec 15, 2024
1162b90
Removed unnecessary references
chromiumboy Dec 15, 2024
55003f7
Side panel values will be grayed out if there is no gas present in th…
chromiumboy Dec 15, 2024
51f5e1c
Declaring colors at the start of some files
chromiumboy Dec 16, 2024
4a6d216
Added a colored stripe to the side of the atmos network entries
chromiumboy Dec 16, 2024
95739aa
Fixed an issue with pipe sensor blip coloration
chromiumboy Dec 16, 2024
d45d65a
Fixed delay that occurs when toggling gas sensors on/off
chromiumboy Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 2 additions & 14 deletions Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Content.Client.Stylesheets;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.Consoles;
using Content.Shared.Atmos.Monitor;
using Content.Shared.FixedPoint;
using Content.Shared.Temperature;
Expand Down Expand Up @@ -31,19 +32,6 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
[AtmosAlarmType.Danger] = "atmos-alerts-window-danger-state",
};

private Dictionary<Gas, string> _gasShorthands = new Dictionary<Gas, string>()
{
[Gas.Ammonia] = "NH₃",
[Gas.CarbonDioxide] = "CO₂",
[Gas.Frezon] = "F",
[Gas.Nitrogen] = "N₂",
[Gas.NitrousOxide] = "N₂O",
[Gas.Oxygen] = "O₂",
[Gas.Plasma] = "P",
[Gas.Tritium] = "T",
[Gas.WaterVapor] = "H₂O",
};

public AtmosAlarmEntryContainer(NetEntity uid, EntityCoordinates? coordinates)
{
RobustXamlLoader.Load(this);
Expand Down Expand Up @@ -163,7 +151,7 @@ public void UpdateEntry(AtmosAlertsComputerEntry entry, bool isFocus, AtmosAlert
var gasPercent = (FixedPoint2)0f;
gasPercent = percent * 100f;

if (!_gasShorthands.TryGetValue(gas, out var gasShorthand))
if (!SharedAtmosAlertsComputerSystem.GasShorthands.TryGetValue(gas, out var gasShorthand))
gasShorthand = "X";

var gasLabel = new Label()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Content.Shared.Atmos.Components;

namespace Content.Client.Atmos.Consoles;

public sealed class AtmosMonitoringConsoleBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private AtmosMonitoringConsoleWindow? _menu;

public AtmosMonitoringConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { }

protected override void Open()
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved
{
_menu = new AtmosMonitoringConsoleWindow(this, Owner);
_menu.OpenCentered();
_menu.OnClose += Close;

EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved
}

protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);

var castState = (AtmosMonitoringConsoleBoundInterfaceState)state;

if (castState == null)
return;
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved

EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
_menu?.UpdateUI(xform?.Coordinates, castState.AtmosNetworks);
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;

_menu?.Dispose();
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved
}
}
293 changes: 293 additions & 0 deletions Content.Client/Atmos/Consoles/AtmosMonitoringConsoleNavMapControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
using Content.Client.Pinpointer.UI;
using Content.Shared.Atmos.Components;
using Content.Shared.Pinpointer;
using Robust.Client.Graphics;
using Robust.Shared.Collections;
using Robust.Shared.Map.Components;
using System;
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved
using System.Linq;
using System.Numerics;

namespace Content.Client.Atmos.Consoles;

public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
{
[Dependency] private readonly IEntityManager _entManager = default!;

public bool ShowPipeNetwork = true;
public int? FocusNetId = null;

private const int ChunkSize = 4;

private List<AtmosMonitoringConsoleLine> _atmosPipeNetwork = new();
private Dictionary<Color, Color> _sRGBLookUp = new Dictionary<Color, Color>();

// Look up tables for merging continuous lines. Indexed by line color
private Dictionary<Color, Dictionary<Vector2i, Vector2i>> _horizLines = new();
private Dictionary<Color, Dictionary<Vector2i, Vector2i>> _horizLinesReversed = new();
private Dictionary<Color, Dictionary<Vector2i, Vector2i>> _vertLines = new();
private Dictionary<Color, Dictionary<Vector2i, Vector2i>> _vertLinesReversed = new();

public AtmosMonitoringConsoleNavMapControl() : base()
{
PostWallDrawingAction += DrawAllPipeNetworks;
}

protected override void UpdateNavMap()
{
base.UpdateNavMap();

if (!_entManager.TryGetComponent<AtmosMonitoringConsoleComponent>(Owner, out var console))
return;

if (!_entManager.TryGetComponent<MapGridComponent>(MapUid, out var grid))
return;

_atmosPipeNetwork = GetDecodedAtmosPipeChunks(console.AtmosPipeChunks, grid);
}

private void DrawAllPipeNetworks(DrawingHandleScreen handle)
{
if (!ShowPipeNetwork)
return;

// Draw networks
if (_atmosPipeNetwork != null && _atmosPipeNetwork.Any())
DrawPipeNetwork(handle, _atmosPipeNetwork);
}

private void DrawPipeNetwork(DrawingHandleScreen handle, List<AtmosMonitoringConsoleLine> atmosPipeNetwork)
{
var offset = GetOffset();
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved
var area = new Box2(-WorldRange, -WorldRange, WorldRange + 1f, WorldRange + 1f).Translated(offset);
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved

if (WorldRange / WorldMaxRange > 0.5f)
{
var pipeNetworks = new Dictionary<Color, ValueList<Vector2>>();

foreach (var chunkedLine in atmosPipeNetwork)
{
var start = ScalePosition(chunkedLine.Origin - new Vector2(offset.X, -offset.Y));
var end = ScalePosition(chunkedLine.Terminus - new Vector2(offset.X, -offset.Y));

if (!pipeNetworks.TryGetValue(chunkedLine.Color, out var subNetwork))
subNetwork = new ValueList<Vector2>();

subNetwork.Add(start);
subNetwork.Add(end);

pipeNetworks[chunkedLine.Color] = subNetwork;
}

foreach ((var color, var subNetwork) in pipeNetworks)
{
if (subNetwork.Count > 0)
handle.DrawPrimitives(DrawPrimitiveTopology.LineList, subNetwork.Span, color);
}
}

else
{
var pipeVertexUVs = new Dictionary<Color, ValueList<Vector2>>();

foreach (var chunkedLine in atmosPipeNetwork)
{
var leftTop = ScalePosition(new Vector2
(Math.Min(chunkedLine.Origin.X, chunkedLine.Terminus.X) - 0.1f,
Math.Min(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) - 0.1f)
- new Vector2(offset.X, -offset.Y));

var rightTop = ScalePosition(new Vector2
(Math.Max(chunkedLine.Origin.X, chunkedLine.Terminus.X) + 0.1f,
Math.Min(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) - 0.1f)
- new Vector2(offset.X, -offset.Y));

var leftBottom = ScalePosition(new Vector2
(Math.Min(chunkedLine.Origin.X, chunkedLine.Terminus.X) - 0.1f,
Math.Max(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) + 0.1f)
- new Vector2(offset.X, -offset.Y));

var rightBottom = ScalePosition(new Vector2
(Math.Max(chunkedLine.Origin.X, chunkedLine.Terminus.X) + 0.1f,
Math.Max(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) + 0.1f)
- new Vector2(offset.X, -offset.Y));

if (!pipeVertexUVs.TryGetValue(chunkedLine.Color, out var pipeVertexUV))
pipeVertexUV = new ValueList<Vector2>();

pipeVertexUV.Add(leftBottom);
pipeVertexUV.Add(leftTop);
pipeVertexUV.Add(rightBottom);
pipeVertexUV.Add(leftTop);
pipeVertexUV.Add(rightBottom);
pipeVertexUV.Add(rightTop);

pipeVertexUVs[chunkedLine.Color] = pipeVertexUV;
}

foreach ((var color, var pipeVertexUV) in pipeVertexUVs)
{
if (pipeVertexUV.Count > 0)
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleList, pipeVertexUV.Span, color);
}
}
}

private List<AtmosMonitoringConsoleLine> GetDecodedAtmosPipeChunks(Dictionary<Vector2i, AtmosPipeChunk>? chunks, MapGridComponent? grid)
{
var decodedOutput = new List<AtmosMonitoringConsoleLine>();

if (chunks == null || grid == null)
return decodedOutput;

// Clear stale look up table values
_horizLines.Clear();
_horizLinesReversed.Clear();
_vertLines.Clear();
_vertLinesReversed.Clear();

// Generate masks
var northMask = (ulong)1 << 0;
var southMask = (ulong)1 << 1;
var westMask = (ulong)1 << 2;
var eastMask = (ulong)1 << 3;

foreach ((var chunkOrigin, var chunk) in chunks)
{
var list = new List<AtmosMonitoringConsoleLine>();

foreach (var ((netId, hexColor), atmosPipeData) in chunk.AtmosPipeData)
{
// Determine the correct coloration for the pipe
var color = Color.FromHex(hexColor) * Color.LightGray;

if (FocusNetId != null && FocusNetId != netId)
color *= Color.DimGray;

// Get the associated line look up tables
if (!_horizLines.TryGetValue(color, out var horizLines))
{
horizLines = new();
_horizLines[color] = horizLines;
}

if (!_horizLinesReversed.TryGetValue(color, out var horizLinesReversed))
{
horizLinesReversed = new();
_horizLinesReversed[color] = horizLinesReversed;
}

if (!_vertLines.TryGetValue(color, out var vertLines))
{
vertLines = new();
_vertLines[color] = vertLines;
}

if (!_vertLinesReversed.TryGetValue(color, out var vertLinesReversed))
{
vertLinesReversed = new();
_vertLinesReversed[color] = vertLinesReversed;
}

// Loop over the chunk
for (var tileIdx = 0; tileIdx < ChunkSize * ChunkSize; tileIdx++)
{
if (atmosPipeData == 0)
continue;

var mask = (ulong)SharedNavMapSystem.AllDirMask << tileIdx * SharedNavMapSystem.Directions;

if ((atmosPipeData & mask) == 0)
continue;

var relativeTile = GetTileFromIndex(tileIdx);
var tile = (chunk.Origin * ChunkSize + relativeTile) * grid.TileSize;
tile = tile with { Y = -tile.Y };

// Calculate the draw point offsets
var vertLineOrigin = (atmosPipeData & northMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 1f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);

var vertLineTerminus = (atmosPipeData & southMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);

var horizLineOrigin = (atmosPipeData & eastMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
new Vector2(grid.TileSize * 1f, -grid.TileSize * 0.5f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);

var horizLineTerminus = (atmosPipeData & westMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
new Vector2(grid.TileSize * 0f, -grid.TileSize * 0.5f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);

// Since we can have pipe lines that have a length of a half tile,
// double the vectors and convert to vector2i so we can merge them
AddOrUpdateNavMapLine(ConvertVector2ToVector2i(tile + horizLineOrigin, 2), ConvertVector2ToVector2i(tile + horizLineTerminus, 2), horizLines, horizLinesReversed);
AddOrUpdateNavMapLine(ConvertVector2ToVector2i(tile + vertLineOrigin, 2), ConvertVector2ToVector2i(tile + vertLineTerminus, 2), vertLines, vertLinesReversed);
}
}
}

// Scale the vector2is back down and convert to vector2
foreach (var (color, horizLines) in _horizLines)
{
// Get the corresponding sRBG color
var sRGB = GetsRGBColor(color);

foreach (var (origin, terminal) in horizLines)
decodedOutput.Add(new AtmosMonitoringConsoleLine
(ConvertVector2iToVector2(origin, 0.5f), ConvertVector2iToVector2(terminal, 0.5f), sRGB));
}

foreach (var (color, vertLines) in _vertLines)
{
// Get the corresponding sRBG color
var sRGB = GetsRGBColor(color);

foreach (var (origin, terminal) in vertLines)
decodedOutput.Add(new AtmosMonitoringConsoleLine
(ConvertVector2iToVector2(origin, 0.5f), ConvertVector2iToVector2(terminal, 0.5f), sRGB));
}

return decodedOutput;
}

private Vector2 ConvertVector2iToVector2(Vector2i vector, float scale = 1f)
{
return new Vector2(vector.X * scale, vector.Y * scale);
}

private Vector2i ConvertVector2ToVector2i(Vector2 vector, float scale = 1f)
{
return new Vector2i((int)MathF.Round(vector.X * scale), (int)MathF.Round(vector.Y * scale));
}

private Vector2i GetTileFromIndex(int index)
{
var x = index / ChunkSize;
var y = index % ChunkSize;
return new Vector2i(x, y);
}

private Color GetsRGBColor(Color color)
{
if (!_sRGBLookUp.TryGetValue(color, out var sRGB))
{
sRGB = Color.ToSrgb(color);
_sRGBLookUp[color] = sRGB;
}

return sRGB;
}
}

public struct AtmosMonitoringConsoleLine
{
public readonly Vector2 Origin;
public readonly Vector2 Terminus;
public readonly Color Color;

public AtmosMonitoringConsoleLine(Vector2 origin, Vector2 terminus, Color color)
{
Origin = origin;
Terminus = terminus;
Color = color;
}
}
Loading
Loading