Program.UI.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. using System;
  2. using System.Collections.Generic;
  3. using ImGuiNET;
  4. using Robust.Shared.Maths;
  5. using static ImGuiNET.ImGui;
  6. using Color = System.Drawing.Color;
  7. using Vector2 = System.Numerics.Vector2;
  8. using RobustVec2 = System.Numerics.Vector2;
  9. using static Content.Server.Power.Pow3r.PowerState;
  10. namespace Pow3r
  11. {
  12. internal sealed partial class Program
  13. {
  14. private bool _showDemo;
  15. private Dictionary<NodeId, DisplayLoad> _displayLoads = new();
  16. private Dictionary<NodeId, DisplayBattery> _displayBatteries = new();
  17. private Dictionary<NodeId, DisplayNetwork> _displayNetworks = new();
  18. private Dictionary<NodeId, DisplaySupply> _displaySupplies = new();
  19. private void DoUI(float frameTime)
  20. {
  21. if (BeginMainMenuBar())
  22. {
  23. _showDemo ^= MenuItem("Demo");
  24. EndMainMenuBar();
  25. }
  26. SetNextWindowSize(new Vector2(150, 200));
  27. Begin("CreateButtons",
  28. ImGuiWindowFlags.NoTitleBar |
  29. ImGuiWindowFlags.NoCollapse |
  30. ImGuiWindowFlags.NoResize);
  31. if (Button("Generator"))
  32. {
  33. var supply = new Supply();
  34. _state.Supplies.Allocate(out supply.Id) = supply;
  35. _displaySupplies.Add(supply.Id, new DisplaySupply());
  36. }
  37. if (Button("Load"))
  38. {
  39. var load = new Load();
  40. _state.Loads.Allocate(out load.Id) = load;
  41. _displayLoads.Add(load.Id, new DisplayLoad());
  42. }
  43. if (Button("Network"))
  44. {
  45. var network = new Network();
  46. _state.Networks.Allocate(out network.Id) = network;
  47. _state.GroupedNets = null;
  48. _displayNetworks.Add(network.Id, new DisplayNetwork());
  49. }
  50. if (Button("Battery"))
  51. {
  52. var battery = new Battery();
  53. _state.Batteries.Allocate(out battery.Id) = battery;
  54. _displayBatteries.Add(battery.Id, new DisplayBattery());
  55. _state.GroupedNets = null;
  56. }
  57. Checkbox("Paused", ref _paused);
  58. SliderInt("TPS", ref _tps, 1, 120);
  59. SetNextItemWidth(-1);
  60. Combo("", ref _currentSolver, _solverNames, _solverNames.Length);
  61. if (Button("Single step"))
  62. RunSingleStep();
  63. End();
  64. Begin("Simulating timing");
  65. PlotLines("Tick time (ms)", ref _simTickTimes[0], MaxTickData, _tickDataIdx + 1,
  66. $"{_simTickTimes[_tickDataIdx]:N2}",
  67. 0,
  68. 0.1f, new Vector2(250, 150));
  69. End();
  70. Begin("Frame timings");
  71. PlotLines("Frame (ms)", ref _frameTimings[0], _frameTimings.Length, _frameTimeIdx + 1,
  72. $"{_frameTimings[_frameTimeIdx]:N2}",
  73. 0,
  74. 33.333f, new Vector2(250, 150));
  75. End();
  76. {
  77. Begin("Memory");
  78. var heap = GC.GetTotalMemory(false);
  79. Text($"Managed heap: {heap>>20} MiB");
  80. End();
  81. }
  82. foreach (var network in _state.Networks.Values)
  83. {
  84. var displayNetwork = _displayNetworks[network.Id];
  85. Begin($"Network {network.Id}##Gen{network.Id}");
  86. Text($"Height: {network.Height}");
  87. displayNetwork.CurrentWindowPos = CalcWindowCenter();
  88. if (Button("Delete"))
  89. {
  90. _remQueue.Enqueue(network);
  91. if (_linking == network)
  92. {
  93. _linking = null;
  94. }
  95. }
  96. SameLine();
  97. if (_linking != null)
  98. {
  99. if (_linking == network && Button("Cancel"))
  100. {
  101. _linking = null;
  102. }
  103. }
  104. else
  105. {
  106. if (Button("Link..."))
  107. {
  108. _linking = network;
  109. }
  110. }
  111. End();
  112. }
  113. foreach (var load in _state.Loads.Values)
  114. {
  115. var displayLoad = _displayLoads[load.Id];
  116. Begin($"Load {load.Id}##Load{load.Id}");
  117. Checkbox("Enabled", ref load.Enabled);
  118. SliderFloat("Desired", ref load.DesiredPower, 0, 1000, "%.0f W");
  119. displayLoad.CurrentWindowPos = CalcWindowCenter();
  120. PlotLines("", ref displayLoad.ReceivedPowerData[0], MaxTickData, _tickDataIdx + 1,
  121. $"Receiving: {load.ReceivingPower:N1} W",
  122. 0,
  123. load.DesiredPower, new Vector2(250, 150));
  124. if (Button("Delete"))
  125. {
  126. _remQueue.Enqueue(load);
  127. }
  128. SameLine();
  129. if (_linking != null)
  130. {
  131. if (Button("Link"))
  132. {
  133. _linking.Loads.Add(load.Id);
  134. _linking = null;
  135. RefreshLinks();
  136. }
  137. }
  138. else
  139. {
  140. if (load.LinkedNetwork != default && Button("Unlink"))
  141. {
  142. var net = _state.Networks[load.LinkedNetwork];
  143. net.Loads.Remove(load.Id);
  144. load.LinkedNetwork = default;
  145. }
  146. }
  147. End();
  148. }
  149. foreach (var supply in _state.Supplies.Values)
  150. {
  151. var displaySupply = _displaySupplies[supply.Id];
  152. Begin($"Generator {supply.Id}##Gen{supply.Id}");
  153. Checkbox("Enabled", ref supply.Enabled);
  154. SliderFloat("Available", ref supply.MaxSupply, 0, 1000, "%.0f W");
  155. SliderFloat("Ramp", ref supply.SupplyRampRate, 0, 100, "%.0f W/s");
  156. SliderFloat("Tolerance", ref supply.SupplyRampTolerance, 0, 100, "%.0f W");
  157. displaySupply.CurrentWindowPos = CalcWindowCenter();
  158. Text($"Ramp Position: {supply.SupplyRampPosition:N1}");
  159. PlotLines("", ref displaySupply.SuppliedPowerData[0], MaxTickData, _tickDataIdx + 1,
  160. $"Supply: {supply.CurrentSupply:N1} W",
  161. 0, supply.MaxSupply, new Vector2(250, 150));
  162. if (Button("Delete"))
  163. {
  164. _remQueue.Enqueue(supply);
  165. }
  166. SameLine();
  167. if (_linking != null)
  168. {
  169. if (Button("Link"))
  170. {
  171. _linking.Supplies.Add(supply.Id);
  172. _linking = null;
  173. RefreshLinks();
  174. }
  175. }
  176. else
  177. {
  178. if (supply.LinkedNetwork != default && Button("Unlink"))
  179. {
  180. var net = _state.Networks[supply.LinkedNetwork];
  181. net.Supplies.Remove(supply.Id);
  182. supply.LinkedNetwork = default;
  183. }
  184. }
  185. End();
  186. }
  187. foreach (var battery in _state.Batteries.Values)
  188. {
  189. var displayBattery = _displayBatteries[battery.Id];
  190. Begin($"Battery {battery.Id}##Bat{battery.Id}");
  191. Checkbox("Enabled", ref battery.Enabled);
  192. Checkbox("CanDischarge", ref battery.CanDischarge);
  193. Checkbox("CanCharge", ref battery.CanCharge);
  194. SliderFloat("Capacity", ref battery.Capacity, 0, 100000, "%.0f J");
  195. SliderFloat("Max charge rate", ref battery.MaxChargeRate, 0, 1000, "%.0f W");
  196. SliderFloat("Max supply", ref battery.MaxSupply, 0, 1000, "%.0f W");
  197. SliderFloat("Ramp", ref battery.SupplyRampRate, 0, 100, "%.0f W/s");
  198. SliderFloat("Tolerance", ref battery.SupplyRampTolerance, 0, 100, "%.0f W");
  199. var percent = 100 * battery.Efficiency;
  200. SliderFloat("Efficiency", ref percent, 0, 100, "%.0f %%");
  201. battery.Efficiency = percent / 100;
  202. displayBattery.CurrentWindowPos = CalcWindowCenter();
  203. SliderFloat("Ramp position", ref battery.SupplyRampPosition, 0, battery.MaxSupply, "%.0f W");
  204. PlotLines("", ref displayBattery.SuppliedPowerData[0], MaxTickData, _tickDataIdx + 1,
  205. $"OUT: {battery.CurrentSupply:N1} W",
  206. 0, battery.MaxSupply + 1000, new Vector2(250, 75));
  207. PlotLines("", ref displayBattery.ReceivingPowerData[0], MaxTickData, _tickDataIdx + 1,
  208. $"IN: {battery.CurrentReceiving:N1} W",
  209. 0, battery.MaxChargeRate + 1000, new Vector2(250, 75));
  210. PlotLines("", ref displayBattery.StoredPowerData[0], MaxTickData, _tickDataIdx + 1,
  211. $"Charge: {battery.CurrentStorage:N1} J",
  212. 0, battery.Capacity, new Vector2(250, 75));
  213. if (Button("Delete"))
  214. {
  215. _remQueue.Enqueue(battery);
  216. }
  217. SameLine();
  218. if (_linking != null)
  219. {
  220. if (battery.LinkedNetworkCharging == default && Button("Link as load"))
  221. {
  222. _linking.BatteryLoads.Add(battery.Id);
  223. _state.GroupedNets = null;
  224. _linking = null;
  225. RefreshLinks();
  226. }
  227. else
  228. {
  229. SameLine();
  230. if (battery.LinkedNetworkDischarging == default && Button("Link as supply"))
  231. {
  232. _linking.BatterySupplies.Add(battery.Id);
  233. _state.GroupedNets = null;
  234. _linking = null;
  235. RefreshLinks();
  236. }
  237. }
  238. }
  239. else
  240. {
  241. if (battery.LinkedNetworkCharging != default && Button("Unlink loading"))
  242. {
  243. var net = _state.Networks[battery.LinkedNetworkCharging];
  244. net.BatteryLoads.Remove(battery.Id);
  245. _state.GroupedNets = null;
  246. battery.LinkedNetworkCharging = default;
  247. }
  248. else
  249. {
  250. SameLine();
  251. if (battery.LinkedNetworkDischarging != default && Button("Unlink supplying"))
  252. {
  253. var net = _state.Networks[battery.LinkedNetworkDischarging];
  254. net.BatterySupplies.Remove(battery.Id);
  255. _state.GroupedNets = null;
  256. battery.LinkedNetworkDischarging = default;
  257. }
  258. }
  259. }
  260. if (Button("Empty"))
  261. battery.CurrentStorage = 0;
  262. SameLine();
  263. if (Button("Fill"))
  264. battery.CurrentStorage = battery.Capacity;
  265. End();
  266. }
  267. var bgDrawList = GetBackgroundDrawList();
  268. foreach (var network in _state.Networks.Values)
  269. {
  270. var displayNet = _displayNetworks[network.Id];
  271. foreach (var supplyId in network.Supplies)
  272. {
  273. var supply = _displaySupplies[supplyId];
  274. DrawArrowLine(bgDrawList, displayNet.CurrentWindowPos, supply.CurrentWindowPos, Color.LawnGreen);
  275. }
  276. foreach (var loadId in network.Loads)
  277. {
  278. var load = _displayLoads[loadId];
  279. DrawArrowLine(bgDrawList, load.CurrentWindowPos, displayNet.CurrentWindowPos, Color.Red);
  280. }
  281. foreach (var batteryId in network.BatteryLoads)
  282. {
  283. var battery = _displayBatteries[batteryId];
  284. DrawArrowLine(bgDrawList, battery.CurrentWindowPos, displayNet.CurrentWindowPos, Color.Purple);
  285. }
  286. foreach (var batteryId in network.BatterySupplies)
  287. {
  288. var battery = _displayBatteries[batteryId];
  289. DrawArrowLine(bgDrawList, displayNet.CurrentWindowPos, battery.CurrentWindowPos, Color.Cyan);
  290. }
  291. }
  292. if (_showDemo)
  293. {
  294. ShowDemoWindow();
  295. }
  296. var reLink = false;
  297. while (_remQueue.TryDequeue(out var item))
  298. {
  299. switch (item)
  300. {
  301. case Network n:
  302. _state.Networks.Free(n.Id);
  303. _displayNetworks.Remove(n.Id);
  304. _state.GroupedNets = null;
  305. reLink = true;
  306. break;
  307. case Supply s:
  308. _state.Supplies.Free(s.Id);
  309. _state.Networks.Values.ForEach(n => n.Supplies.Remove(s.Id));
  310. _displaySupplies.Remove(s.Id);
  311. break;
  312. case Load l:
  313. _state.Loads.Free(l.Id);
  314. _state.Networks.Values.ForEach(n => n.Loads.Remove(l.Id));
  315. _displayLoads.Remove(l.Id);
  316. break;
  317. case Battery b:
  318. _state.Batteries.Free(b.Id);
  319. _state.Networks.Values.ForEach(n => n.BatteryLoads.Remove(b.Id));
  320. _state.Networks.Values.ForEach(n => n.BatterySupplies.Remove(b.Id));
  321. _displayBatteries.Remove(b.Id);
  322. _state.GroupedNets = null;
  323. break;
  324. }
  325. }
  326. if (reLink)
  327. RefreshLinks();
  328. }
  329. private void DrawArrowLine(ImDrawListPtr ptr, Vector2 a, Vector2 b, Color color)
  330. {
  331. // A: to
  332. // B: from
  333. const float wingLength = 15;
  334. const float thickness = 3;
  335. var cvtColor = CvtColor(color);
  336. ptr.AddLine(a, b, cvtColor, thickness);
  337. var angleA = Angle.FromDegrees(45);
  338. var angleB = Angle.FromDegrees(-45);
  339. var mid = (a + b) / 2;
  340. var dir = -Vector2.Normalize(a - b);
  341. var rVec = new RobustVec2(dir.X, dir.Y);
  342. var wingADir = CvtVec(angleA.RotateVec(rVec));
  343. var wingBDir = CvtVec(angleB.RotateVec(rVec));
  344. var wingA = wingADir * wingLength + mid;
  345. var wingB = wingBDir * wingLength + mid;
  346. ptr.AddLine(mid, wingA, cvtColor, thickness);
  347. ptr.AddLine(mid, wingB, cvtColor, thickness);
  348. }
  349. private static uint CvtColor(Color color)
  350. {
  351. return color.R | ((uint) color.G << 8) | ((uint) color.B << 16) | ((uint) color.A << 24);
  352. }
  353. private static Vector2 CalcWindowCenter()
  354. {
  355. return GetWindowPos() + GetWindowSize() / 2;
  356. }
  357. private static Vector2 CvtVec(RobustVec2 vec)
  358. {
  359. return new Vector2(vec.X, vec.Y);
  360. }
  361. private sealed class DisplayNetwork
  362. {
  363. public Vector2 CurrentWindowPos;
  364. }
  365. private sealed class DisplayBattery
  366. {
  367. public Vector2 CurrentWindowPos;
  368. public readonly float[] ReceivingPowerData = new float[MaxTickData];
  369. public readonly float[] SuppliedPowerData = new float[MaxTickData];
  370. public readonly float[] StoredPowerData = new float[MaxTickData];
  371. }
  372. private sealed class DisplayLoad
  373. {
  374. public Vector2 CurrentWindowPos;
  375. public readonly float[] ReceivedPowerData = new float[MaxTickData];
  376. }
  377. private sealed class DisplaySupply
  378. {
  379. public Vector2 CurrentWindowPos;
  380. public readonly float[] SuppliedPowerData = new float[MaxTickData];
  381. }
  382. }
  383. }