From 357ec466fc656a24ce55e20ce37fbbe6fdbec9f7 Mon Sep 17 00:00:00 2001 From: Anri Date: Wed, 7 Aug 2024 23:37:20 +0300 Subject: [PATCH] Added2DPlots --- .../SuperMatterObserverBUI.cs | 31 ++++++ .../SuperMatterObserverMenu.xaml | 13 +++ .../SuperMatterObserverMenu.xaml.cs | 29 ++++++ .../PlotFigure/Plot2DTimeView.cs | 95 +++++++++++++++++++ .../UserInterface/PlotFigure/Point2DHelper.cs | 57 +++++++++++ ...SuperMatterSpecificConsumableComponent.cs} | 2 +- .../SuperMatterCrystal/SuperMatterSystem.cs | 3 + .../SuperMatterObserverUI.cs | 15 +++ .../Structures/Machines/computers.yml | 32 ++++++- 9 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverBUI.cs create mode 100644 Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverMenu.xaml create mode 100644 Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverMenu.xaml.cs create mode 100644 Content.Client/SS220/UserInterface/PlotFigure/Plot2DTimeView.cs create mode 100644 Content.Client/SS220/UserInterface/PlotFigure/Point2DHelper.cs rename Content.Server/SS220/SuperMatterCrystal/Components/{SuperMatterSpecificConsumable.cs => SuperMatterSpecificConsumableComponent.cs} (79%) create mode 100644 Content.Shared/SS220/SuperMatterCrystalUI/SuperMatterObserverUI.cs diff --git a/Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverBUI.cs b/Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverBUI.cs new file mode 100644 index 00000000000000..b6f94cb0a0e130 --- /dev/null +++ b/Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverBUI.cs @@ -0,0 +1,31 @@ +namespace Content.Client.SS220.SuperMatterCrystalUIs; + +public sealed class SuperMatterObserverBUI : BoundUserInterface +{ + [ViewVariables] + private SuperMatterObserverMenu? _menu; + + public SuperMatterObserverBUI(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } + protected override void Open() + { + base.Open(); + + _menu = new SuperMatterObserverMenu(); + _menu.OnClose += Close; + _menu.OpenCentered(); + } + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + _menu?.UpdateState(); + } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + _menu?.Close(); + _menu?.Dispose(); + } +} diff --git a/Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverMenu.xaml b/Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverMenu.xaml new file mode 100644 index 00000000000000..bb086137ba2748 --- /dev/null +++ b/Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverMenu.xaml @@ -0,0 +1,13 @@ + + + + + diff --git a/Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverMenu.xaml.cs b/Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverMenu.xaml.cs new file mode 100644 index 00000000000000..229f8aae468560 --- /dev/null +++ b/Content.Client/SS220/SuperMatterCrystalUIs/SuperMatterObserverMenu.xaml.cs @@ -0,0 +1,29 @@ +using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow; +using System.Numerics; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Timing; + +namespace Content.Client.SS220.SuperMatterCrystalUIs; + +[GenerateTypedNameReferences] +public sealed partial class SuperMatterObserverMenu : FancyWindow +{ + private int counter = 0; + public SuperMatterObserverMenu() + { + IoCManager.InjectDependencies(this); + RobustXamlLoader.Load(this); + PlotView2D.SetXLabel("t, с"); + PlotView2D.SetYLabel("u, эрг"); + } + public void UpdateState() + { + // PlotView2D.AddPointToPlot(new Vector2(counter++, counter++)); + } + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + PlotView2D.AddPointToPlot(new Vector2(counter++, counter++)); + } +} diff --git a/Content.Client/SS220/UserInterface/PlotFigure/Plot2DTimeView.cs b/Content.Client/SS220/UserInterface/PlotFigure/Plot2DTimeView.cs new file mode 100644 index 00000000000000..b975dc64d8a795 --- /dev/null +++ b/Content.Client/SS220/UserInterface/PlotFigure/Plot2DTimeView.cs @@ -0,0 +1,95 @@ +using Content.Client.Resources; +using Robust.Client.ResourceManagement; +using Robust.Client.UserInterface; +using Robust.Client.Graphics; +using System.Numerics; + +namespace Content.Client.SS220.UserInterface.PlotFigure; + +internal sealed class Plot2DTimeView : Control +{ + [Dependency] private readonly IResourceCache _cache = default!; + private Plot2DTimePoints _plotPoints; + private const int SerifSize = 5; + private const int FontSize = 12; + private readonly List _steps = new() { 0.2f, 0.4f, 0.6f, 0.8f }; + private readonly Font _font; + private const int AxisBorderPosition = 20; + public Plot2DTimeView() + { + RectClipContent = true; + IoCManager.InjectDependencies(this); + _plotPoints = new Plot2DTimePoints(128); + + _font = _cache.GetFont("/Fonts/NotoSans/NotoSans-Regular.ttf", FontSize); + } + public void LoadPlot2DTimePoints(Plot2DTimePoints plotPoints) + { + _plotPoints = plotPoints; + } + public void AddPointToPlot(Vector2 point) + { + _plotPoints.AddPoint(point); + } + public void SetXLabel(string label) => _plotPoints.XLabel = label; + public void SetYLabel(string label) => _plotPoints.YLabel = label; + + protected override void Draw(DrawingHandleScreen handle) + { + if (_plotPoints == null) + return; + if (_plotPoints.Point2Ds == null) + return; + if (!_plotPoints.TryGetDeltaBetweenMaxMinX(out var xWidth)) + return; + if (!_plotPoints.TryGetMaxY(out var yMax)) + return; + if (!(PixelWidth - AxisBorderPosition > 0)) + return; + + var yMaxResult = (yMax + 0.1f) * 1.1f ?? 0.1f; + var xWidthResult = xWidth ?? 1f; + var deltaXWidth = (PixelWidth - (float) AxisBorderPosition) / _plotPoints.Point2Ds.Count; + var yNormalizer = PixelHeight / yMaxResult; + + var point2Ds = _plotPoints.Point2Ds; + for (var i = 1; i < point2Ds.Count; i++) + { + var firstPoint = CorrectVector(deltaXWidth * (i - 1) + AxisBorderPosition, point2Ds[i - 1].Y * yNormalizer); + var secondPoint = CorrectVector(deltaXWidth * i + AxisBorderPosition, point2Ds[i].Y * yNormalizer); + + handle.DrawLine(firstPoint, secondPoint, Color.Black); + } + //Draw axis here to draw it on top of other + DrawAxis(handle, yMaxResult, xWidthResult); + } + private void DrawAxis(DrawingHandleScreen handle, float maxY, float xWidth) + { + + //start with drawing axises + handle.DrawLine(CorrectVector(AxisBorderPosition, AxisBorderPosition), CorrectVector(PixelWidth, AxisBorderPosition), Color.Black); + handle.DrawLine(CorrectVector(AxisBorderPosition, AxisBorderPosition), CorrectVector(AxisBorderPosition, PixelHeight), Color.Black); + foreach (var step in _steps) + { + // X + handle.DrawLine(CorrectVector(PixelWidth * step + AxisBorderPosition, AxisBorderPosition), + CorrectVector(PixelWidth * step + AxisBorderPosition, AxisBorderPosition + SerifSize), Color.Black); + handle.DrawString(_font, CorrectVector(PixelWidth * step, AxisBorderPosition), $"{step * xWidth - xWidth:0.}"); + // Y + handle.DrawLine(CorrectVector(AxisBorderPosition, PixelHeight * step), + CorrectVector(AxisBorderPosition + SerifSize, PixelHeight * step), Color.Black); + handle.DrawString(_font, CorrectVector(AxisBorderPosition + SerifSize, PixelHeight * step), $"{step * maxY:0.}"); + } + handle.DrawString(_font, CorrectVector(AxisBorderPosition + 2 * SerifSize, AxisBorderPosition), $"{-xWidth:0.}"); + // here goes labels + handle.DrawString(_font, CorrectVector(AxisBorderPosition + SerifSize, PixelHeight), $"{_plotPoints.YLabel}"); + if (_plotPoints.XLabel != null) + handle.DrawString(_font, CorrectVector(PixelWidth - _plotPoints.XLabel.Length * FontSize, AxisBorderPosition), $"{_plotPoints.XLabel}"); + } + private Vector2 CorrectVector(float x, float y) + { + var newX = Math.Clamp(x, 1f, PixelWidth); + var newY = Math.Clamp(PixelHeight - y, 1f, PixelHeight); + return new Vector2(newX, newY); + } +} diff --git a/Content.Client/SS220/UserInterface/PlotFigure/Point2DHelper.cs b/Content.Client/SS220/UserInterface/PlotFigure/Point2DHelper.cs new file mode 100644 index 00000000000000..fe872edbb462a3 --- /dev/null +++ b/Content.Client/SS220/UserInterface/PlotFigure/Point2DHelper.cs @@ -0,0 +1,57 @@ +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Linq; + +namespace Content.Client.SS220.UserInterface.PlotFigure; +/// +/// This class make working with time dependent plot easier +/// It is designed to have the newest dots in the end and oldest at the start +/// +public sealed class Plot2DTimePoints(int maxPoints) +{ + public string? XLabel; + public string? YLabel; + public List? Point2Ds => _point2Ds; + public int MaxLength => _maxAmountOfPoints; + private List? _point2Ds; + private int _maxAmountOfPoints = maxPoints; + + public void AddPoint(Vector2 point) + { + _point2Ds ??= new() { point }; + + if (_point2Ds.Count == _maxAmountOfPoints) + { + _point2Ds.RemoveAt(0); + } + if (_point2Ds[_point2Ds.Count - 1].X > point.X) + throw new Exception("To Plot2DTimePoints added value with lesser X then last element"); + _point2Ds.Add(point); + } + public bool TryGetDeltaBetweenMaxMinX([NotNullWhen(true)] out float? delta) + { + delta = null; + if (_point2Ds == null) + return false; + + var xList = _point2Ds.Select(element => element.X); + var maxX = xList.Max(); + var minX = xList.Min(); + var deltaMaxMinX = maxX - minX; + if (deltaMaxMinX == 0) + return false; + + delta = deltaMaxMinX; + return true; + } + public bool TryGetMaxY([NotNullWhen(true)] out float? maxY) + { + maxY = null; + if (_point2Ds == null) + return false; + + var yList = _point2Ds.Select(element => element.Y); + maxY = yList.Max(); + return true; + } +} diff --git a/Content.Server/SS220/SuperMatterCrystal/Components/SuperMatterSpecificConsumable.cs b/Content.Server/SS220/SuperMatterCrystal/Components/SuperMatterSpecificConsumableComponent.cs similarity index 79% rename from Content.Server/SS220/SuperMatterCrystal/Components/SuperMatterSpecificConsumable.cs rename to Content.Server/SS220/SuperMatterCrystal/Components/SuperMatterSpecificConsumableComponent.cs index 18fc14a05c6c97..6b839ad554425b 100644 --- a/Content.Server/SS220/SuperMatterCrystal/Components/SuperMatterSpecificConsumable.cs +++ b/Content.Server/SS220/SuperMatterCrystal/Components/SuperMatterSpecificConsumableComponent.cs @@ -2,7 +2,7 @@ namespace Content.Server.SS220.SuperMatterCrystal.Components; [RegisterComponent] -public sealed partial class SuperMatterSpecificConsumable : Component +public sealed partial class SuperMatterSpecificConsumableComponent : Component { [DataField] public float AdditionalEnergyOnConsumption = 0f; diff --git a/Content.Server/SS220/SuperMatterCrystal/SuperMatterSystem.cs b/Content.Server/SS220/SuperMatterCrystal/SuperMatterSystem.cs index 362da67cb7930d..74ac1be90e1f70 100644 --- a/Content.Server/SS220/SuperMatterCrystal/SuperMatterSystem.cs +++ b/Content.Server/SS220/SuperMatterCrystal/SuperMatterSystem.cs @@ -64,10 +64,13 @@ private void UpdateSuperMatter(Entity crystal, float frame var releasedEnergyPerFrame = crystal.Comp.InternalEnergy * GetReleaseEnergyConversionEfficiency(crystalTemperature, pressure); crystal.Comp.AccumulatedRadiationEnergy += releasedEnergyPerFrame * GetZapToRadiationRatio(crystalTemperature, pressure, smState); crystal.Comp.AccumulatedZapEnergy += releasedEnergyPerFrame * (1 - GetZapToRadiationRatio(crystalTemperature, pressure, smState)); + crystal.Comp.InternalEnergy -= releasedEnergyPerFrame; if (crystal.Comp.NextOutputEnergySourceUpdate < _gameTiming.CurTime) { ReleaseEnergy(crystal); + crystal.Comp.AccumulatedRadiationEnergy = 0; + crystal.Comp.AccumulatedZapEnergy = 0; crystal.Comp.NextOutputEnergySourceUpdate = _gameTiming.CurTime + crystal.Comp.OutputEnergySourceUpdateDelay; } diff --git a/Content.Shared/SS220/SuperMatterCrystalUI/SuperMatterObserverUI.cs b/Content.Shared/SS220/SuperMatterCrystalUI/SuperMatterObserverUI.cs new file mode 100644 index 00000000000000..5d9761073a364e --- /dev/null +++ b/Content.Shared/SS220/SuperMatterCrystalUI/SuperMatterObserverUI.cs @@ -0,0 +1,15 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Store; + +[Serializable, NetSerializable] +public enum SuperMatterObserverUiKey : byte +{ + Key +} + +// [Serializable, NetSerializable] +// public sealed class SuperMatterObserverUpdateState : BoundUserInterfaceState +// { + +// } diff --git a/Resources/Prototypes/SS220/Entities/Structures/Machines/computers.yml b/Resources/Prototypes/SS220/Entities/Structures/Machines/computers.yml index 79bbdc2a067466..59686cde513948 100644 --- a/Resources/Prototypes/SS220/Entities/Structures/Machines/computers.yml +++ b/Resources/Prototypes/SS220/Entities/Structures/Machines/computers.yml @@ -38,4 +38,34 @@ suffix: LoneOps components: - type: CommunicationsConsole - title: comms-console-announcement-title-solo-nukie \ No newline at end of file + title: comms-console-announcement-title-solo-nukie + +- type: entity + parent: BaseComputer + id: SuperMatterObserverConsole + name: Super Matter Observer + description: Allows to monitor super matter crystal status + components: + - type: Sprite + layers: + - map: ["computerLayerBody"] + state: computer + - map: ["computerLayerKeyboard"] + state: generic_keyboard + - map: ["computerLayerScreen"] + state: power_monitor + - map: ["computerLayerKeys"] + state: power_key + - type: PointLight + radius: 1.5 + energy: 1.6 + color: "#ffb800" # check it + # - type: Computer + # board: PowerComputerCircuitboard DOIT + - type: ActivatableUI + singleUser: true + key: enum.SuperMatterObserverUiKey.Key + - type: UserInterface + interfaces: + enum.SuperMatterObserverUiKey.Key: + type: SuperMatterObserverBUI