1
0

PowerMonitoringConsoleNavMapControl.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. using Content.Client.Pinpointer.UI;
  2. using Content.Shared.Pinpointer;
  3. using Content.Shared.Power;
  4. using Robust.Client.Graphics;
  5. using Robust.Shared.Collections;
  6. using Robust.Shared.Map.Components;
  7. using System.Numerics;
  8. using static Content.Shared.Power.SharedPowerMonitoringConsoleSystem;
  9. namespace Content.Client.Power;
  10. public sealed partial class PowerMonitoringConsoleNavMapControl : NavMapControl
  11. {
  12. [Dependency] private readonly IEntityManager _entManager = default!;
  13. // Cable indexing
  14. // 0: CableType.HighVoltage
  15. // 1: CableType.MediumVoltage
  16. // 2: CableType.Apc
  17. private readonly Color[] _powerCableColors = { Color.OrangeRed, Color.Yellow, Color.LimeGreen };
  18. private readonly Vector2[] _powerCableOffsets = { new Vector2(-0.2f, -0.2f), Vector2.Zero, new Vector2(0.2f, 0.2f) };
  19. private Dictionary<Color, Color> _sRGBLookUp = new Dictionary<Color, Color>();
  20. public PowerMonitoringCableNetworksComponent? PowerMonitoringCableNetworks;
  21. public List<PowerMonitoringConsoleLineGroup> HiddenLineGroups = new();
  22. public List<PowerMonitoringConsoleLine> PowerCableNetwork = new();
  23. public List<PowerMonitoringConsoleLine> FocusCableNetwork = new();
  24. private Dictionary<Vector2i, Vector2i>[] _horizLines = [new(), new(), new()];
  25. private Dictionary<Vector2i, Vector2i>[] _horizLinesReversed = [new(), new(), new()];
  26. private Dictionary<Vector2i, Vector2i>[] _vertLines = [new(), new(), new()];
  27. private Dictionary<Vector2i, Vector2i>[] _vertLinesReversed = [new(), new(), new()];
  28. private MapGridComponent? _grid;
  29. public PowerMonitoringConsoleNavMapControl() : base()
  30. {
  31. // Set colors
  32. TileColor = new Color(30, 57, 67);
  33. WallColor = new Color(102, 164, 217);
  34. BackgroundColor = Color.FromSrgb(TileColor.WithAlpha(BackgroundOpacity));
  35. PostWallDrawingAction += DrawAllCableNetworks;
  36. }
  37. protected override void UpdateNavMap()
  38. {
  39. base.UpdateNavMap();
  40. if (Owner == null)
  41. return;
  42. if (!_entManager.TryGetComponent<PowerMonitoringCableNetworksComponent>(Owner, out var cableNetworks))
  43. return;
  44. PowerCableNetwork = GetDecodedPowerCableChunks(cableNetworks.AllChunks);
  45. FocusCableNetwork = GetDecodedPowerCableChunks(cableNetworks.FocusChunks);
  46. }
  47. public void DrawAllCableNetworks(DrawingHandleScreen handle)
  48. {
  49. if (!_entManager.TryGetComponent(MapUid, out _grid))
  50. return;
  51. // Draw full cable network
  52. if (PowerCableNetwork != null && PowerCableNetwork.Count > 0)
  53. {
  54. var modulator = (FocusCableNetwork != null && FocusCableNetwork.Count > 0) ? Color.DimGray : Color.White;
  55. DrawCableNetwork(handle, PowerCableNetwork, modulator);
  56. }
  57. // Draw focus network
  58. if (FocusCableNetwork != null && FocusCableNetwork.Count > 0)
  59. DrawCableNetwork(handle, FocusCableNetwork, Color.White);
  60. }
  61. public void DrawCableNetwork(DrawingHandleScreen handle, List<PowerMonitoringConsoleLine> fullCableNetwork, Color modulator)
  62. {
  63. if (!_entManager.TryGetComponent(MapUid, out _grid))
  64. return;
  65. var offset = GetOffset();
  66. offset = offset with { Y = -offset.Y };
  67. if (WorldRange / WorldMaxRange > 0.5f)
  68. {
  69. var cableNetworks = new ValueList<Vector2>[3];
  70. foreach (var line in fullCableNetwork)
  71. {
  72. if (HiddenLineGroups.Contains(line.Group))
  73. continue;
  74. var cableOffset = _powerCableOffsets[(int) line.Group];
  75. var start = ScalePosition(line.Origin + cableOffset - offset);
  76. var end = ScalePosition(line.Terminus + cableOffset - offset);
  77. cableNetworks[(int) line.Group].Add(start);
  78. cableNetworks[(int) line.Group].Add(end);
  79. }
  80. for (int cableNetworkIdx = 0; cableNetworkIdx < cableNetworks.Length; cableNetworkIdx++)
  81. {
  82. var cableNetwork = cableNetworks[cableNetworkIdx];
  83. if (cableNetwork.Count > 0)
  84. {
  85. var color = _powerCableColors[cableNetworkIdx] * modulator;
  86. if (!_sRGBLookUp.TryGetValue(color, out var sRGB))
  87. {
  88. sRGB = Color.ToSrgb(color);
  89. _sRGBLookUp[color] = sRGB;
  90. }
  91. handle.DrawPrimitives(DrawPrimitiveTopology.LineList, cableNetwork.Span, sRGB);
  92. }
  93. }
  94. }
  95. else
  96. {
  97. var cableVertexUVs = new ValueList<Vector2>[3];
  98. foreach (var line in fullCableNetwork)
  99. {
  100. if (HiddenLineGroups.Contains(line.Group))
  101. continue;
  102. var cableOffset = _powerCableOffsets[(int) line.Group];
  103. var leftTop = ScalePosition(new Vector2
  104. (Math.Min(line.Origin.X, line.Terminus.X) - 0.1f,
  105. Math.Min(line.Origin.Y, line.Terminus.Y) - 0.1f)
  106. + cableOffset - offset);
  107. var rightTop = ScalePosition(new Vector2
  108. (Math.Max(line.Origin.X, line.Terminus.X) + 0.1f,
  109. Math.Min(line.Origin.Y, line.Terminus.Y) - 0.1f)
  110. + cableOffset - offset);
  111. var leftBottom = ScalePosition(new Vector2
  112. (Math.Min(line.Origin.X, line.Terminus.X) - 0.1f,
  113. Math.Max(line.Origin.Y, line.Terminus.Y) + 0.1f)
  114. + cableOffset - offset);
  115. var rightBottom = ScalePosition(new Vector2
  116. (Math.Max(line.Origin.X, line.Terminus.X) + 0.1f,
  117. Math.Max(line.Origin.Y, line.Terminus.Y) + 0.1f)
  118. + cableOffset - offset);
  119. cableVertexUVs[(int) line.Group].Add(leftBottom);
  120. cableVertexUVs[(int) line.Group].Add(leftTop);
  121. cableVertexUVs[(int) line.Group].Add(rightBottom);
  122. cableVertexUVs[(int) line.Group].Add(leftTop);
  123. cableVertexUVs[(int) line.Group].Add(rightBottom);
  124. cableVertexUVs[(int) line.Group].Add(rightTop);
  125. }
  126. for (int cableNetworkIdx = 0; cableNetworkIdx < cableVertexUVs.Length; cableNetworkIdx++)
  127. {
  128. var cableVertexUV = cableVertexUVs[cableNetworkIdx];
  129. if (cableVertexUV.Count > 0)
  130. {
  131. var color = _powerCableColors[cableNetworkIdx] * modulator;
  132. if (!_sRGBLookUp.TryGetValue(color, out var sRGB))
  133. {
  134. sRGB = Color.ToSrgb(color);
  135. _sRGBLookUp[color] = sRGB;
  136. }
  137. handle.DrawPrimitives(DrawPrimitiveTopology.TriangleList, cableVertexUV.Span, sRGB);
  138. }
  139. }
  140. }
  141. }
  142. public List<PowerMonitoringConsoleLine> GetDecodedPowerCableChunks(Dictionary<Vector2i, PowerCableChunk>? chunks)
  143. {
  144. var decodedOutput = new List<PowerMonitoringConsoleLine>();
  145. if (!_entManager.TryGetComponent(MapUid, out _grid))
  146. return decodedOutput;
  147. if (chunks == null)
  148. return decodedOutput;
  149. Array.ForEach(_horizLines, x=> x.Clear());
  150. Array.ForEach(_horizLinesReversed, x=> x.Clear());
  151. Array.ForEach(_vertLines, x=> x.Clear());
  152. Array.ForEach(_vertLinesReversed, x=> x.Clear());
  153. foreach (var (chunkOrigin, chunk) in chunks)
  154. {
  155. for (var cableIdx = 0; cableIdx < 3; cableIdx++)
  156. {
  157. var horizLines = _horizLines[cableIdx];
  158. var horizLinesReversed = _horizLinesReversed[cableIdx];
  159. var vertLines = _vertLines[cableIdx];
  160. var vertLinesReversed = _vertLinesReversed[cableIdx];
  161. var chunkMask = chunk.PowerCableData[cableIdx];
  162. for (var chunkIdx = 0; chunkIdx < ChunkSize * ChunkSize; chunkIdx++)
  163. {
  164. var value = 1 << chunkIdx;
  165. var mask = chunkMask & value;
  166. if (mask == 0x0)
  167. continue;
  168. var relativeTile = GetTileFromIndex(chunkIdx);
  169. var tile = (chunk.Origin * ChunkSize + relativeTile) * _grid.TileSize;
  170. tile = tile with { Y = -tile.Y };
  171. PowerCableChunk neighborChunk;
  172. bool neighbor;
  173. // Note: we only check the north and east neighbors
  174. // East
  175. if (relativeTile.X == ChunkSize - 1)
  176. {
  177. neighbor = chunks.TryGetValue(chunkOrigin + new Vector2i(1, 0), out neighborChunk) &&
  178. (neighborChunk.PowerCableData[cableIdx] & GetFlag(new Vector2i(0, relativeTile.Y))) != 0x0;
  179. }
  180. else
  181. {
  182. var flag = GetFlag(relativeTile + new Vector2i(1, 0));
  183. neighbor = (chunkMask & flag) != 0x0;
  184. }
  185. if (neighbor)
  186. {
  187. // Add points
  188. AddOrUpdateNavMapLine(tile, tile + new Vector2i(_grid.TileSize, 0), horizLines, horizLinesReversed);
  189. }
  190. // North
  191. if (relativeTile.Y == ChunkSize - 1)
  192. {
  193. neighbor = chunks.TryGetValue(chunkOrigin + new Vector2i(0, 1), out neighborChunk) &&
  194. (neighborChunk.PowerCableData[cableIdx] & GetFlag(new Vector2i(relativeTile.X, 0))) != 0x0;
  195. }
  196. else
  197. {
  198. var flag = GetFlag(relativeTile + new Vector2i(0, 1));
  199. neighbor = (chunkMask & flag) != 0x0;
  200. }
  201. if (neighbor)
  202. {
  203. // Add points
  204. AddOrUpdateNavMapLine(tile + new Vector2i(0, -_grid.TileSize), tile, vertLines, vertLinesReversed);
  205. }
  206. }
  207. }
  208. }
  209. var gridOffset = new Vector2(_grid.TileSize * 0.5f, -_grid.TileSize * 0.5f);
  210. for (var index = 0; index < _horizLines.Length; index++)
  211. {
  212. var horizLines = _horizLines[index];
  213. foreach (var (origin, terminal) in horizLines)
  214. {
  215. decodedOutput.Add(new PowerMonitoringConsoleLine(origin + gridOffset, terminal + gridOffset,
  216. (PowerMonitoringConsoleLineGroup) index));
  217. }
  218. }
  219. for (var index = 0; index < _vertLines.Length; index++)
  220. {
  221. var vertLines = _vertLines[index];
  222. foreach (var (origin, terminal) in vertLines)
  223. {
  224. decodedOutput.Add(new PowerMonitoringConsoleLine(origin + gridOffset, terminal + gridOffset,
  225. (PowerMonitoringConsoleLineGroup) index));
  226. }
  227. }
  228. return decodedOutput;
  229. }
  230. }
  231. public struct PowerMonitoringConsoleLine
  232. {
  233. public readonly Vector2 Origin;
  234. public readonly Vector2 Terminus;
  235. public readonly PowerMonitoringConsoleLineGroup Group;
  236. public PowerMonitoringConsoleLine(Vector2 origin, Vector2 terminus, PowerMonitoringConsoleLineGroup group)
  237. {
  238. Origin = origin;
  239. Terminus = terminus;
  240. Group = group;
  241. }
  242. }
  243. public enum PowerMonitoringConsoleLineGroup : byte
  244. {
  245. HighVoltage,
  246. MediumVoltage,
  247. Apc,
  248. }