From 4acb236655475c8406b2c8be7c559aa4dbca2847 Mon Sep 17 00:00:00 2001 From: Anri Date: Sat, 17 Aug 2024 12:23:48 +0300 Subject: [PATCH] WorkingMonitoringConsole --- .../Observer/SuperMatterObserverComponent.cs | 3 +- .../SuperMatterObserverReceiverComponent.cs | 6 + .../Observer/SuperMatterObserverSystem.cs | 109 +++++++++++++++--- .../SuperMatter/Ui/SuperMatterObserverBUI.cs | 43 ++++--- .../Ui/SuperMatterObserverMenu.xaml | 22 +++- .../Ui/SuperMatterObserverMenu.xaml.cs | 81 +++++++++++-- .../Ui/SuperMatterObserverUIStates.cs | 31 +++++ .../SS220/UserInterface/PlotFigure/Plot.cs | 97 +++++++++------- .../PlotFigure/PlotSequencedView.cs | 28 +++-- .../PlotSupport/Color2DPointView.cs | 15 ++- .../PlotFigure/PlotSupport/LabelContainer.cs | 16 ++- .../PlotFigure/PlotSupport/PlotPoints2D.cs | 11 +- .../PlotFigure/Pseudo3DColoredView.cs | 25 +++- .../SuperMatterInternalProcess.cs | 11 +- .../Crystal/SuperMatterSystem.Database.cs | 12 +- .../SuperMatterSystem.EventHandlers.cs | 7 +- .../SuperMatter/Crystal/SuperMatterSystem.cs | 9 +- .../SS220/SuperMatter/UiComponent.cs | 11 ++ .../SuperMatter/Ui/SuperMatterObserverUI.cs | 9 +- .../Ui/SuperMatterUISharedComponents.cs | 8 ++ .../Structures/Machines/computers.yml | 3 + 21 files changed, 430 insertions(+), 127 deletions(-) create mode 100644 Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverReceiverComponent.cs create mode 100644 Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverUIStates.cs create mode 100644 Content.Server/SS220/SuperMatter/UiComponent.cs create mode 100644 Content.Shared/SS220/SuperMatter/Ui/SuperMatterUISharedComponents.cs diff --git a/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverComponent.cs b/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverComponent.cs index fd13f0376e07..4175f9dab174 100644 --- a/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverComponent.cs +++ b/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverComponent.cs @@ -1,9 +1,10 @@ // © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using Content.Shared.SS220.SuperMatter.Ui; namespace Content.Client.SS220.SuperMatter.Observer; [RegisterComponent] -public sealed partial class SuperMatterObserverComponent : Component +public sealed partial class SuperMatterObserverComponent : SharedSuperMatterObserverComponent { [ViewVariables(VVAccess.ReadOnly)] public Dictionary Names = new(); diff --git a/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverReceiverComponent.cs b/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverReceiverComponent.cs new file mode 100644 index 000000000000..94abfdfc48c9 --- /dev/null +++ b/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverReceiverComponent.cs @@ -0,0 +1,6 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +namespace Content.Client.SS220.SuperMatter.Observer; + +/// We use this component to mark entities which can receiver +[RegisterComponent] +public sealed partial class SuperMatterObserverReceiverComponent() : Component { } diff --git a/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverSystem.cs b/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverSystem.cs index 390305bf7192..a549ef14b1b5 100644 --- a/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverSystem.cs +++ b/Content.Client/SS220/SuperMatter/Observer/SuperMatterObserverSystem.cs @@ -1,59 +1,127 @@ // © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt using Content.Client.Power.Components; -using Content.Shared.Mobs; +using Robust.Client.GameObjects; using Content.Shared.SS220.SuperMatter.Ui; -using System.Linq; +using Content.Client.SS220.SuperMatter.Ui; +using Robust.Shared.Timing; namespace Content.Client.SS220.SuperMatter.Observer; public sealed class SuperMatterObserverSystem : EntitySystem { + [Dependency] private readonly UserInterfaceSystem _userInterface = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly EntityLookupSystem _entityLookup = default!; // 120 like 2 minutes with update rate 1 sec public const int MAX_CACHED_AMOUNT = 120; - private List> _observerComps = new(); + private const float UpdateDelay = 1f; + private HashSet> _observerEntities = new(); + private List _smReceiverUIOwnersToInit = new(); + private TimeSpan _nextUpdateTime = default!; + private HashSet> _receivers = new(); public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnComponentRemove); - + SubscribeLocalEvent(OnReceiverBoundUIOpened); + SubscribeLocalEvent(OnReceiverBoundUIClosed); SubscribeNetworkEvent(OnCrystalUpdate); } + public override void FrameUpdate(float frameTime) + { + base.FrameUpdate(frameTime); + + if (_gameTiming.CurTime > _nextUpdateTime) + { + // kinda simulate servers and clients working + _nextUpdateTime += TimeSpan.FromSeconds(UpdateDelay); + foreach (var smReceiverOwner in new List(_smReceiverUIOwnersToInit)) + { + if (!HasComp(smReceiverOwner) + || Transform(smReceiverOwner).GridUid == null) + continue; + + _entityLookup.GetChildEntities(Transform(smReceiverOwner).GridUid!.Value, _observerEntities); + foreach (var (observerUid, _) in _observerEntities) + { + if (TryComp(observerUid, out var powerReceiver) + && powerReceiver.Powered) + { + if (!_userInterface.HasUi(smReceiverOwner, SuperMatterObserverUiKey.Key)) + return; + if (TrySendToUIState(smReceiverOwner, + new SuperMatterObserverInitState(new List>(_observerEntities)))) + _smReceiverUIOwnersToInit.Remove(smReceiverOwner); + break; + } + } + _observerEntities.Clear(); + } + } + } private void OnCrystalUpdate(SuperMatterStateUpdate args) { // store values to simulate real working data observer&collectors manufacture - foreach (var observerEnt in _observerComps) + if (args.SMGridId == null) + return; + _entityLookup.GetChildEntities(EntityManager.GetEntity(args.SMGridId.Value), _observerEntities); + foreach (var observerEnt in _observerEntities) { + // To make possible many SMs on different grids var (observerUid, observerComp) = observerEnt; + if (!HasComp(observerUid)) + continue; + if (Transform(observerUid).GridUid != EntityManager.GetEntity(args.SMGridId)) + continue; // still it will store without power, cause, you know... caching =) observerComp.Names[args.Id] = args.Name; observerComp.DelaminationStatuses[args.Id] = args.Delaminate; + if (!observerComp.Integrities.ContainsKey(args.Id)) + { + observerComp.Integrities[args.Id] = new(); + observerComp.Pressures[args.Id] = new(); + observerComp.Temperatures[args.Id] = new(); + observerComp.Matters[args.Id] = new(); + observerComp.InternalEnergy[args.Id] = new(); + } AddToCacheList(observerComp.Integrities[args.Id], args.Integrity); AddToCacheList(observerComp.Pressures[args.Id], args.Pressure); AddToCacheList(observerComp.Temperatures[args.Id], args.Temperature); AddToCacheList(observerComp.Matters[args.Id], args.Matter); AddToCacheList(observerComp.InternalEnergy[args.Id], args.InternalEnergy); - // check if power is On on console + // here dispatches events to sprites of SM itself + // RaiseLocalEvent(GetIntegrityState changed then change sprite) + // check if console has power if (!(TryComp(observerUid, out var powerReceiver) && powerReceiver.Powered)) continue; // Send updateStates for opened UIs and panels + // think of the same way as with _observerEntities, but will have problems if SMObserver will be on other maps etc + _entityLookup.GetEntitiesOnMap(Transform(observerUid).MapID, _receivers); + // logic + foreach (var receiver in _receivers) + TrySendToUIState(receiver.Owner, new SuperMatterObserverUpdateState(args.Id, args.Name, args.Integrity, args.Pressure, + args.Temperature, args.Matter, args.InternalEnergy, args.Delaminate)); + _receivers.Clear(); + // RaiseLocalEvent(SMpanels -> accept information) } + _observerEntities.Clear(); } - private void OnComponentInit(Entity entity, ref ComponentInit args) + private void OnReceiverBoundUIOpened(Entity entity, ref BoundUIOpenedEvent args) { - // very aware of client crashes - _observerComps.Add(entity); - _observerComps = _observerComps.Distinct().ToList(); + if (!_userInterface.HasUi(entity, args.UiKey)) + return; + _smReceiverUIOwnersToInit.Add(entity.Owner); + } - private void OnComponentRemove(Entity entity, ref ComponentRemove args) + private void OnReceiverBoundUIClosed(Entity entity, ref BoundUIClosedEvent args) { - // very aware of client crashes - _observerComps = _observerComps.Distinct().ToList(); - _observerComps.Remove(entity); + if (!_userInterface.HasUi(entity, args.UiKey)) + return; + // Lest hope it wont duplicate + _smReceiverUIOwnersToInit.Remove(entity.Owner); } private void AddToCacheList(List listToAdd, T value) { @@ -61,4 +129,13 @@ private void AddToCacheList(List listToAdd, T value) listToAdd.RemoveAt(0); listToAdd.Add(value); } + private bool TrySendToUIState(EntityUid uid, BoundUserInterfaceState state) + { + if (!_userInterface.TryGetOpenUi(uid, SuperMatterObserverUiKey.Key, out var bui)) + { + return false; + } + ((SuperMatterObserverBUI)bui).DirectUpdateState(state); + return true; + } } diff --git a/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverBUI.cs b/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverBUI.cs index fdfdc70eba66..e5b8191f8758 100644 --- a/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverBUI.cs +++ b/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverBUI.cs @@ -1,4 +1,7 @@ // © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using Content.Shared.SS220.SuperMatter.Ui; +using Robust.Client.UserInterface; + namespace Content.Client.SS220.SuperMatter.Ui; public sealed class SuperMatterObserverBUI : BoundUserInterface @@ -10,23 +13,33 @@ public SuperMatterObserverBUI(EntityUid owner, Enum uiKey) : base(owner, uiKey) protected override void Open() { base.Open(); + _menu = this.CreateWindow(); - _menu = new SuperMatterObserverMenu(); - _menu.OnClose += Close; - _menu.OpenCentered(); - } - protected override void UpdateState(BoundUserInterfaceState state) - { - base.UpdateState(state); - - _menu?.UpdateState(); + _menu.OnServerButtonPressed += (args, observerComp) => + { + if (!args.Button.Pressed) + _menu.Observer = null; + else + _menu.Observer = observerComp; + _menu.CrystalKey = null; + _menu.LoadCrystal(); + }; + _menu.OnCrystalButtonPressed += (_, crystalKey) => + { + _menu.CrystalKey = crystalKey; + _menu.LoadCachedData(); + }; } - protected override void Dispose(bool disposing) + public void DirectUpdateState(BoundUserInterfaceState state) { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Close(); - _menu?.Dispose(); + switch (state) + { + case SuperMatterObserverInitState msg: + _menu?.LoadState(msg.ObserverEntity); + break; + case SuperMatterObserverUpdateState msg: + _menu?.UpdateState(msg); + break; + } } } diff --git a/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverMenu.xaml b/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverMenu.xaml index 130e9382a600..072eec7336d8 100644 --- a/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverMenu.xaml +++ b/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverMenu.xaml @@ -6,11 +6,23 @@ xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls" Title="{Loc 'supermatter-observer-title'}" Resizable="False" - MinSize="512 576" - SetSize="512 576" + MinSize="512 608" + SetSize="512 608" RectClipContent="False"> - - - + + + + + + + + + + + + + + + diff --git a/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverMenu.xaml.cs b/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverMenu.xaml.cs index 1141c887e6d7..5ed83a591d71 100644 --- a/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverMenu.xaml.cs +++ b/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverMenu.xaml.cs @@ -4,7 +4,12 @@ using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; using Robust.Shared.Timing; +using Robust.Client.UserInterface.Controls; +using Content.Shared.SS220.SuperMatter.Ui; +using Content.Client.SS220.UserInterface.PlotFigure; +using Content.Client.SS220.SuperMatter.Observer; using System.Numerics; +using System.Linq; namespace Content.Client.SS220.SuperMatter.Ui; @@ -12,6 +17,12 @@ namespace Content.Client.SS220.SuperMatter.Ui; [GenerateTypedNameReferences] public sealed partial class SuperMatterObserverMenu : FancyWindow { + + public event Action? OnServerButtonPressed; + public event Action? OnCrystalButtonPressed; + public SuperMatterObserverComponent? Observer; + public int? CrystalKey; + public const int MAX_DATA_LENGTH = 180; private int counter = 0; private float conterAbobaX = 0f; private float conterAbobaY = 0f; @@ -19,24 +30,76 @@ public SuperMatterObserverMenu() { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); - PlotValueOverTime.SetXLabel("t, с"); - PlotValueOverTime.SetYLabel("u, эрг"); - ColorState.MakeMeshgrid((100, 100, 25), (1000, 100, 400)); + PlotValueOverTime.SetLabels("time elapsed, s", " Integrity", " Crystal Integrity "); + ColorState.MakeMeshgrid((1, 100, 25), (1, 100, 100)); ColorState.EvalFunctionOnMeshgrid(GetIntegrityDamageMap); + ColorState.SetLabels("Matter, a.u.", "Internal energy, a.u.", " Safe operation "); } - public void UpdateState() + public void LoadState(List> observerEntities) { + ServerNavigationBar.RemoveAllChildren(); + foreach (var (observerUid, observerComp) in observerEntities) + { + var serverButton = new ServerButton + { + Text = observerUid.ToString(), + ObserverComponent = observerComp, + ToggleMode = true, + StyleClasses = { "OpenBoth" } + }; + serverButton.OnPressed += args => OnServerButtonPressed?.Invoke(args, serverButton.ObserverComponent); + ServerNavigationBar.AddChild(serverButton); + } + } + public void LoadCrystal() + { + CrystalNavigationBar.RemoveAllChildren(); + if (Observer == null) + return; + foreach (var (crystalKey, name) in Observer.Names) + { + var crystalButton = new CrystalButton + { + Text = name, + CrystalKey = crystalKey, + ToggleMode = true, + StyleClasses = { "OpenBoth" } + }; + + crystalButton.OnPressed += args => OnCrystalButtonPressed?.Invoke(args, crystalButton.CrystalKey); + CrystalNavigationBar.AddChild(crystalButton); + } + } + public void LoadCachedData() + { + if (Observer == null + || CrystalKey == null) + return; + PlotValueOverTime.LoadPlot2DTimePoints(new PlotPoints2D(MAX_DATA_LENGTH, Observer.Integrities[CrystalKey.Value], + -1f, -1f * Observer.Integrities[CrystalKey.Value].Count)); + ColorState.LoadMovingPoint(new Vector2(Observer.Matters[CrystalKey.Value].Last().Value, Observer.InternalEnergy[CrystalKey.Value].Last().Value), + new Vector2(Observer.Matters[CrystalKey.Value].Last().Derv, Observer.InternalEnergy[CrystalKey.Value].Last().Derv)); } - protected override void FrameUpdate(FrameEventArgs args) + public void UpdateState(SuperMatterObserverUpdateState msg) { - base.FrameUpdate(args); - PlotValueOverTime.AddPointToPlot(new Vector2(counter++, counter++)); - ColorState.LoadMovingPoint(new Vector2(conterAbobaX+=5, conterAbobaY+=80), new Vector2(5,80)); + if (Observer == null + || CrystalKey == null) + return; + PlotValueOverTime.AddPointToPlot(new Vector2(PlotValueOverTime.GetLastAddedPointX() + 1, msg.Integrity)); + ColorState.LoadMovingPoint(new Vector2(msg.Matter.Value, msg.InternalEnergy.Value), new Vector2(msg.Matter.Derivative, msg.InternalEnergy.Derivative)); } private float GetIntegrityDamageMap(float matter, float internalEnergy) { return SuperMatterFunctions.EnergyToMatterDamageFactorFunction( - internalEnergy - SuperMatterFunctions.SafeInternalEnergyToMatterFunction(matter)); + internalEnergy - SuperMatterFunctions.SafeInternalEnergyToMatterFunction(matter / SuperMatterFunctions.MatterNondimensionalization)); + } + private sealed class ServerButton : Button + { + public SuperMatterObserverComponent? ObserverComponent; + } + private sealed class CrystalButton : Button + { + public int CrystalKey; } } diff --git a/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverUIStates.cs b/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverUIStates.cs new file mode 100644 index 000000000000..9b1f39687e28 --- /dev/null +++ b/Content.Client/SS220/SuperMatter/Ui/SuperMatterObserverUIStates.cs @@ -0,0 +1,31 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using Content.Client.SS220.SuperMatter.Observer; + +namespace Content.Shared.SS220.SuperMatter.Ui; + + +[Serializable] +public sealed class SuperMatterObserverUpdateState(int id, string name, + float integrity, float pressure, + float temperature, + (float Value, float Derivative) matter, + (float Value, float Derivative) internalEnergy, + (bool Delaminates, TimeSpan ETOfDelamination) delaminate) + : BoundUserInterfaceState +{ + public int Id { get; } = id; + public string Name { get; } = name; + public float Pressure { get; } = pressure; + public float Integrity { get; } = integrity; + public float Temperature { get; } = temperature; + public (float Value, float Derivative) Matter { get; } = matter; + public (float Value, float Derivative) InternalEnergy { get; } = internalEnergy; + public (bool Delaminates, TimeSpan ETOfDelamination) Delaminate { get; } = delaminate; +} + +[Serializable] +public sealed class SuperMatterObserverInitState(List> observerEntities) + : BoundUserInterfaceState +{ + public List> ObserverEntity { get; } = observerEntities; +} diff --git a/Content.Client/SS220/UserInterface/PlotFigure/Plot.cs b/Content.Client/SS220/UserInterface/PlotFigure/Plot.cs index 2ced047515d6..7a56408076e6 100644 --- a/Content.Client/SS220/UserInterface/PlotFigure/Plot.cs +++ b/Content.Client/SS220/UserInterface/PlotFigure/Plot.cs @@ -10,12 +10,11 @@ namespace Content.Client.SS220.UserInterface.PlotFigure; internal abstract class Plot : Control { [Dependency] internal readonly IResourceCache ResourceCache = default!; - public Color AxisColor = Color.White; - public float AxisThickness = 4f; + public Color AxisColor = Color.WhiteSmoke; public List AxisSteps = new() { 0.2f, 0.4f, 0.6f, 0.8f }; - public float AxisBorderPosition = 20; - - public int SerifSize = 5; + public float AxisBorderPosition = 20f; + public float AxisThickness = 4f; + public float SerifSize = 5f; public int FontSize = 12; public Font AxisFont; @@ -37,10 +36,10 @@ internal void DrawThickLine(DrawingHandleScreen handle, Vector2 from, Vector2 to var fromToVector = to - from; var perpendicularClockwise = new Vector2(fromToVector.Y, -fromToVector.X); // bruh it lefthanded perpendicularClockwise.Normalize(); - var leftTop = from + perpendicularClockwise * thickness / 2; - var leftBottom = from - perpendicularClockwise * thickness / 2; - var rightBottom = to - perpendicularClockwise * thickness / 2; - var rightTop = to + perpendicularClockwise * thickness / 2; + var leftTop = from + perpendicularClockwise * thickness / 2f; + var leftBottom = from - perpendicularClockwise * thickness / 2f; + var rightBottom = to - perpendicularClockwise * thickness / 2f; + var rightTop = to + perpendicularClockwise * thickness / 2f; // look to this properly cause idk how it works, but in handle it the same... var pointList = new List { leftBottom, leftTop, rightBottom, rightTop }; DrawVertexUV2D[] pointSpan = new DrawVertexUV2D[pointList.Count]; @@ -50,42 +49,28 @@ internal void DrawThickLine(DrawingHandleScreen handle, Vector2 from, Vector2 to } handle.DrawPrimitives(DrawPrimitiveTopology.TriangleStrip, Texture.White, pointSpan, color); } - internal Vector2 CorrectVector(float x, float y) - { - return new Vector2(GetCorrectX(x), GetCorrectY(y)); - } - internal Vector2 CorrectVector(Vector2 vector) - { - return new Vector2(GetCorrectX(vector.X), GetCorrectY(vector.Y)); - } - internal float GetCorrectX(float x) - { - return Math.Clamp(x, 0f, PixelWidth); - } - internal float GetCorrectY(float y) - { - return Math.Clamp(PixelHeight - y, 0f, PixelHeight); - } internal void DrawAxis(DrawingHandleScreen handle, LabelContainer? mainLabels = null, LabelContainer? secondLabels = null) { - // TODO think of adding AxisDots here or in childs. - //start with drawing axises - DrawAxisLine(handle, CorrectVector(AxisBorderPosition, AxisBorderPosition), CorrectVector(PixelWidth, AxisBorderPosition)); - DrawAxisLine(handle, CorrectVector(AxisBorderPosition, AxisBorderPosition), CorrectVector(AxisBorderPosition, PixelHeight)); + //Drawing axises + // X, first one to make axises smoothly on each other + DrawAxisLine(handle, CorrectVector(AxisBorderPosition - AxisThickness / 2f, AxisBorderPosition), CorrectVector(PixelWidth, AxisBorderPosition)); + DrawArrowHeadHat(handle, CorrectVector(PixelWidth - SerifSize, AxisBorderPosition), CorrectVector(PixelWidth, AxisBorderPosition), + SerifSize, AxisColor, new Vector2(0, 1)); + // Y + DrawAxisLine(handle, CorrectVector(AxisBorderPosition, AxisBorderPosition), CorrectVector(AxisBorderPosition, PixelHeight - SerifSize)); + DrawArrowHeadHat(handle, CorrectVector(AxisBorderPosition, PixelHeight - AxisBorderPosition), CorrectVector(AxisBorderPosition, PixelHeight - SerifSize), + SerifSize, AxisColor, new Vector2(1, 0)); foreach (var step in AxisSteps) { // X DrawAxisLine(handle, CorrectVector(PixelWidth * step + AxisBorderPosition, AxisBorderPosition), CorrectVector(PixelWidth * step + AxisBorderPosition, AxisBorderPosition + SerifSize)); - //handle.DrawString(AxisFont, CorrectVector(PixelWidth * step, AxisBorderPosition), $"{step * maxX:0.}"); // Y DrawAxisLine(handle, CorrectVector(AxisBorderPosition, PixelHeight * step), CorrectVector(AxisBorderPosition + SerifSize, PixelHeight * step)); - //handle.DrawString(AxisFont, CorrectVector(AxisBorderPosition + SerifSize, PixelHeight * step), $"{step * maxY:0.}"); } - //handle.DrawString(AxisFont, CorrectVector(AxisBorderPosition + 2 * SerifSize, AxisBorderPosition), $"{-xWidth:0.}"); - // here goes labels + // adding labels AddAxisLabels(handle, mainLabels); AddAxisLabels(handle, secondLabels); } @@ -95,16 +80,42 @@ private void AddAxisLabels(DrawingHandleScreen handle, LabelContainer? labels) if (labels == null) return; if (labels.YLabel != null) - handle.DrawString(AxisFont, CorrectVector(AxisBorderPosition + SerifSize, PixelHeight), $"{labels.YLabel}"); + handle.DrawString(AxisFont, CorrectVector(AxisBorderPosition + SerifSize, PixelHeight - SerifSize), labels.YLabel, AxisColor); if (labels.XLabel != null) - handle.DrawString(AxisFont, CorrectVector(PixelWidth - labels.XLabel.Length * FontSize, AxisBorderPosition), $"{labels.XLabel}"); - if (labels.Label != null) - handle.DrawString(AxisFont, CorrectVector(PixelWidth / 2 - labels.Label.Length * FontSize / 2, PixelHeight / 2), $"{labels.Label}"); + handle.DrawString(AxisFont, CorrectVector(PixelWidth - FontSize * 3f / 4f * labels.XLabel.Length, 2f * AxisBorderPosition + SerifSize), labels.XLabel, AxisColor); + if (labels.Title != null) + handle.DrawString(AxisFont, CorrectVector(PixelWidth / 2f - FontSize * labels.Title.Length / 4f, PixelHeight), labels.Title, AxisColor); + } + internal Vector2 CorrectVector(float x, float y) + { + return new Vector2(GetCorrectX(x), GetCorrectY(y)); + } + internal Vector2 CorrectVector(Vector2 vector) + { + return new Vector2(GetCorrectX(vector.X), GetCorrectY(vector.Y)); + } + internal float GetCorrectX(float x) + { + return Math.Clamp(x, 0f, PixelWidth); + } + internal float GetCorrectY(float y) + { + return Math.Clamp(PixelHeight - y, 0f, PixelHeight); + } + private void DrawArrowHeadHat(DrawingHandleScreen handle, Vector2 from, Vector2 to, float arrowRange, Color color, Vector2 perpendicularClockwise) + { + DrawTriangleStrip(handle, [ to + perpendicularClockwise * arrowRange, + to + (to - from) * (arrowRange - 1f) / (to - from).Length(), + to, + to - perpendicularClockwise * arrowRange], color); + } + private void DrawTriangleStrip(DrawingHandleScreen handle, Vector2[] vectors, Color color) + { + Span toSpanVector = new DrawVertexUV2D[vectors.Length]; + for (var i = 0; i < vectors.Length; i++) + { + toSpanVector[i] = new DrawVertexUV2D(vectors[i], new Vector2(0.5f, 0.5f)); + } + handle.DrawPrimitives(DrawPrimitiveTopology.TriangleStrip, Texture.White, toSpanVector, color); } -} - -public enum GraphicSeniorityEnum -{ - First = 1, // make it more obvious - Second } diff --git a/Content.Client/SS220/UserInterface/PlotFigure/PlotSequencedView.cs b/Content.Client/SS220/UserInterface/PlotFigure/PlotSequencedView.cs index 7dc2e9ce5e51..b40307ef66a4 100644 --- a/Content.Client/SS220/UserInterface/PlotFigure/PlotSequencedView.cs +++ b/Content.Client/SS220/UserInterface/PlotFigure/PlotSequencedView.cs @@ -1,5 +1,6 @@ // © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt using Robust.Client.Graphics; +using System.Linq; using System.Numerics; namespace Content.Client.SS220.UserInterface.PlotFigure; @@ -20,23 +21,36 @@ private void DrawFirstGraphicLine(DrawingHandleScreen handle, Vector2 from, Vect public PlotSequencedView() : base() { _font = AxisFont; - RectClipContent = true; + RectClipContent = false; IoCManager.InjectDependencies(this); _plotPoints = new PlotPoints2D(128); } - public void LoadPlot2DTimePoints(PlotPoints2D plotPoints) + public void LoadPlot2DTimePoints(PlotPoints2D plotPoints, LabelContainer? label = null) { + if (label == null) + plotPoints.CopyLabels(_plotPoints); + else + plotPoints.CopyLabels(label); _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; - public void SetLabel(string label) => _plotPoints.Label = label; - + public void SetLabels(string? xLabel, string? yLabel, string? title) + { + _plotPoints.XLabel = xLabel; + _plotPoints.YLabel = yLabel; + _plotPoints.Title = title; + } + public float GetLastAddedPointX() + { + if (_plotPoints.Point2Ds == null) + return float.NaN; + return _plotPoints.Point2Ds.Last().X; + } protected override void Draw(DrawingHandleScreen handle) { if (_plotPoints == null) @@ -68,7 +82,7 @@ protected override void Draw(DrawingHandleScreen handle) } private void DrawAxis(DrawingHandleScreen handle, float maxY, float xWidth) { - base.DrawAxis(handle, _plotPoints); + DrawAxis(handle, _plotPoints); //start with drawing axises foreach (var step in AxisSteps) diff --git a/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/Color2DPointView.cs b/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/Color2DPointView.cs index abb4595a7a84..d2c9a2498db0 100644 --- a/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/Color2DPointView.cs +++ b/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/Color2DPointView.cs @@ -18,16 +18,25 @@ public sealed class Color2DPointView : LabelContainer private List _points3D = new() { }; private List _x; private List _y; - - public Color2DPointView(List x, List y) : base() + public Color2DPointView(List x, List y, LabelContainer? labelContainer = null) : base() { _x = x; _y = y; + if (labelContainer != null) + { + this.CopyLabels(labelContainer); + } } - public Color2DPointView((float xOffset, float xSize, float xStep) xParams, (float yOffset, float ySize, float yStep) yParams) : base() + public Color2DPointView((float xOffset, float xSize, float xStep) xParams, + (float yOffset, float ySize, float yStep) yParams, + LabelContainer? labelContainer = null) : base() { _x = MakeCoordFrom(xParams.xOffset, xParams.xSize, xParams.xStep); _y = MakeCoordFrom(yParams.yOffset, yParams.ySize, yParams.yStep); + if (labelContainer != null) + { + this.CopyLabels(labelContainer); + } } public void EvalFunction(Func func) { diff --git a/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/LabelContainer.cs b/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/LabelContainer.cs index 5b347ccbc6b1..539a12491f2b 100644 --- a/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/LabelContainer.cs +++ b/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/LabelContainer.cs @@ -5,7 +5,19 @@ public abstract class LabelContainer() { public string? XLabel; public string? YLabel; - public string? Label; - // think of it also should contain a axis text... + public string? Title; + public LabelContainer(string xLabel, string yLabel, string title) : this() + { + XLabel = xLabel; + YLabel = yLabel; + Title = title; + } + public void CopyLabels(LabelContainer otherLabelContainer) + { + XLabel = otherLabelContainer.XLabel; + YLabel = otherLabelContainer.YLabel; + Title = otherLabelContainer.Title; + } + // think of it also should contain a axis text... } diff --git a/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/PlotPoints2D.cs b/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/PlotPoints2D.cs index 03aa8c57d81c..4dcd58929ac0 100644 --- a/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/PlotPoints2D.cs +++ b/Content.Client/SS220/UserInterface/PlotFigure/PlotSupport/PlotPoints2D.cs @@ -14,7 +14,16 @@ public sealed class PlotPoints2D(int maxPoints) : LabelContainer public int MaxLength => _maxAmountOfPoints; private List? _point2Ds; private int _maxAmountOfPoints = maxPoints; - + /// Inits plots with existing list + /// If values have more entries than maxPoints. + public PlotPoints2D(int maxPoints, List values, float xDelta, float xOffset) : this(maxPoints) + { + if (values.Count > maxPoints) + throw new Exception("Tried to init PlotPoints2D with longer list than maxPoints in PlotPoints2D"); + _point2Ds = new(maxPoints); + for (var i = 0; i < values.Count; i++) + _point2Ds.Add(new Vector2(i * xDelta + xOffset, values[i])); + } public void AddPoint(Vector2 point) { _point2Ds ??= new() { point }; diff --git a/Content.Client/SS220/UserInterface/PlotFigure/Pseudo3DColoredView.cs b/Content.Client/SS220/UserInterface/PlotFigure/Pseudo3DColoredView.cs index fb1fb8bc4327..6641612040d7 100644 --- a/Content.Client/SS220/UserInterface/PlotFigure/Pseudo3DColoredView.cs +++ b/Content.Client/SS220/UserInterface/PlotFigure/Pseudo3DColoredView.cs @@ -14,20 +14,34 @@ internal sealed class Pseudo3DColoredView : Plot private UIBox2 _uIBox2 = new(); private Vector3 _curPoint = new(); private (float xMax, float xMin, float yMax, float yMin) _meshgridBorders = new(); + private ((float Offset, float Size, float Step) x, (float Offset, float Size, float Step) y) _initCachedParams; private ((float Offset, float Size, float Step) x, (float Offset, float Size, float Step) y) _cachedParams; private Func? _cachedFunction; private float _maxZ = 0f; private float _minZ = 0f; + public void SetLabels(string? xLabel, string? yLabel, string? title) + { + if (_color2DPoint == null) + return; + _color2DPoint.XLabel = xLabel; + _color2DPoint.YLabel = yLabel; + _color2DPoint.Title = title; + } public void LoadColor2DPoint(List vector3) => _color2DPoint?.LoadData(vector3); public void MakeMeshgrid((float Offset, float Size, float Step) xParams, (float Offset, float Size, float Step) yParams) { + if (_color2DPoint == null) + { + _initCachedParams.x = xParams; + _initCachedParams.y = yParams; + } _cachedParams.x = xParams; _cachedParams.y = yParams; - _color2DPoint = new Color2DPointView(xParams, yParams); + _color2DPoint = new Color2DPointView(xParams, yParams, _color2DPoint); } - public void MakeMeshgrid(List x, List y) => _color2DPoint = new Color2DPointView(x, y); + public void MakeMeshgrid(List x, List y) => _color2DPoint = new Color2DPointView(x, y, _color2DPoint); public void EvalFunctionOnMeshgrid(Func func) { _cachedFunction = func; @@ -40,8 +54,8 @@ public void LoadMovingPoint(Vector2 position, Vector2 moveDirection) || position.Y > _cachedParams.y.Offset + (_cachedParams.y.Size - 1) * _cachedParams.y.Step || position.X < _cachedParams.x.Offset || position.Y < _cachedParams.x.Offset) { - MakeMeshgrid((MakeOffsetFromCoord(position.X, _cachedParams.x.Offset), _cachedParams.x.Size, _cachedParams.x.Step), - (MakeOffsetFromCoord(position.Y, _cachedParams.x.Offset), _cachedParams.y.Size, _cachedParams.y.Step)); + MakeMeshgrid((MakeOffsetFromCoord(position.X, _initCachedParams.x.Offset), _initCachedParams.x.Size, _initCachedParams.x.Step), + (MakeOffsetFromCoord(position.Y, _initCachedParams.x.Offset), _initCachedParams.y.Size, _initCachedParams.y.Step)); if (_cachedFunction != null) EvalFunctionOnMeshgrid(_cachedFunction); } @@ -90,7 +104,7 @@ protected override void Draw(DrawingHandleScreen handle) _movingPoint.DrawMovingDirection(handle); _movingPoint.DrawPoint(handle); } - DrawAxis(handle); + foreach (var step in AxisSteps) { // X @@ -98,6 +112,7 @@ protected override void Draw(DrawingHandleScreen handle) // Y handle.DrawString(AxisFont, CorrectVector(AxisBorderPosition + SerifSize, PixelHeight * step), $"{_color2DPoint.Y[(int) (_color2DPoint.Y.Count * step)]:0.}"); } + base.DrawAxis(handle, _color2DPoint); } /// Adjust vector to borders also offsets it with AxisBorderPosition diff --git a/Content.Server/SS220/SuperMatter/Crystal/SuperMatterInterior/SuperMatterInternalProcess.cs b/Content.Server/SS220/SuperMatter/Crystal/SuperMatterInterior/SuperMatterInternalProcess.cs index 6f663e16492e..26aa4f118c5d 100644 --- a/Content.Server/SS220/SuperMatter/Crystal/SuperMatterInterior/SuperMatterInternalProcess.cs +++ b/Content.Server/SS220/SuperMatter/Crystal/SuperMatterInterior/SuperMatterInternalProcess.cs @@ -35,15 +35,16 @@ public static float GetDeltaChemistryPotential(float temperature, float pressure // maybe compress value here? return DeltaChemistryPotentialFunction(temperature, pressure); } + private const float BASE_HEAT_CAPACITY = 20f; /// Defines how many J you need to raise the temperature to 1 grad /// heat capacity in J/K public static float GetHeatCapacity(float temperature, float matter) { - if (temperature < Atmospherics.Tmax / 50) - return 11 / 2 * Atmospherics.R * matter; - if (temperature < Atmospherics.Tmax / 10) - return 15 / 2 * Atmospherics.R * matter; - return 27 / 2 * Atmospherics.R * matter; + if (temperature < Atmospherics.Tmax / 50f) + return BASE_HEAT_CAPACITY + 11f / 2f * Atmospherics.R * matter; + if (temperature < Atmospherics.Tmax / 10f) + return BASE_HEAT_CAPACITY + 15f / 2f * Atmospherics.R * matter; + return BASE_HEAT_CAPACITY + 27f / 2f * Atmospherics.R * matter; } /// /// Value from 0.0002 to 0.03 diff --git a/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.Database.cs b/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.Database.cs index 5572761ee7dc..a3d3dc257114 100644 --- a/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.Database.cs +++ b/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.Database.cs @@ -8,6 +8,7 @@ namespace Content.Server.SS220.SuperMatterCrystal; // TODO: added: Fun! public sealed partial class SuperMatterSystem : EntitySystem { + // TODO add shifts counter for not delaminate public void BroadcastData(Entity crystal) { var (uid, comp) = crystal; @@ -17,8 +18,15 @@ public void BroadcastData(Entity crystal) var pressure = comp.PressureAccumulator / comp.UpdatesBetweenBroadcast; comp.Name ??= MetaData(crystal.Owner).EntityName; - var ev = new SuperMatterStateUpdate(uid.Id, comp.Name, GetIntegrity(comp), - pressure, comp.Temperature, + // just in case... + if (!HasComp(uid)) + { + Log.Error($" Tried to get TransformComp of {EntityManager.ToPrettyString(crystal)}, but it hasnt it"); + return; + } + + var ev = new SuperMatterStateUpdate(uid.Id, EntityManager.GetNetEntity(Transform(uid).GridUid), + comp.Name, GetIntegrity(comp), pressure, comp.Temperature, (comp.Matter, matterDerv), (comp.InternalEnergy, internalEnergyDerv), (comp.IsDelaminate, comp.TimeOfDelamination)); diff --git a/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.EventHandlers.cs b/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.EventHandlers.cs index 31700f573162..9250df74898e 100644 --- a/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.EventHandlers.cs +++ b/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.EventHandlers.cs @@ -35,6 +35,7 @@ private void OnComponentInit(Entity entity, ref ComponentI radiationSource.Enabled = false; arcShooterComponent.Enabled = false; + arcShooterComponent.ShootRange = 3f; entity.Comp.InternalEnergy = GetSafeInternalEnergyToMatterValue(entity.Comp.Matter); } private void OnHandInteract(Entity entity, ref InteractHandEvent args) @@ -44,7 +45,7 @@ private void OnHandInteract(Entity entity, ref InteractHan } private void OnItemInteract(Entity entity, ref InteractUsingEvent args) { - entity.Comp.Matter += MatterNondimensionalization / 4; + entity.Comp.Matter += MatterNondimensionalization / 10f; ConsumeObject(args.User, entity); } private void OnCollideEvent(Entity entity, ref StartCollideEvent args) @@ -54,8 +55,8 @@ private void OnCollideEvent(Entity entity, ref StartCollid if (TryComp(args.OtherEntity, out var projectile)) entity.Comp.InternalEnergy += CHEMISTRY_POTENTIAL_BASE * MathF.Max((float) projectile.Damage.GetTotal(), 0f); - entity.Comp.Matter += MatterNondimensionalization / 4; - ConsumeObject(args.OtherEntity, entity, HasComp(args.OtherEntity)); + entity.Comp.Matter += MatterNondimensionalization / 10f; + ConsumeObject(args.OtherEntity, entity, false); } private void OnActivationEvent(Entity entity, ref SuperMatterActivationEvent args) { diff --git a/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.cs b/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.cs index f8f2eeb7989e..2d65a01b1f73 100644 --- a/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.cs +++ b/Content.Server/SS220/SuperMatter/Crystal/SuperMatterSystem.cs @@ -34,11 +34,13 @@ public override void Update(float frameTime) var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var smComp)) { + var crystal = new Entity(uid, smComp); + UpdateDelayed(crystal, frameTime); if (!smComp.Activated) continue; - var crystal = new Entity(uid, smComp); + SuperMatterUpdate(crystal, frameTime); - UpdateDelayed(crystal, frameTime); + } } @@ -83,7 +85,8 @@ private void SuperMatterUpdate(Entity crystal, float frame } private void UpdateDelayed(Entity crystal, float frameTime) { - if (crystal.Comp.NextOutputEnergySourceUpdate < _gameTiming.CurTime) + if (_gameTiming.CurTime > crystal.Comp.NextOutputEnergySourceUpdate + && crystal.Comp.Activated) { ReleaseEnergy(crystal); crystal.Comp.AccumulatedRadiationEnergy = 0; diff --git a/Content.Server/SS220/SuperMatter/UiComponent.cs b/Content.Server/SS220/SuperMatter/UiComponent.cs new file mode 100644 index 000000000000..497dda209c9c --- /dev/null +++ b/Content.Server/SS220/SuperMatter/UiComponent.cs @@ -0,0 +1,11 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using Content.Shared.SS220.SuperMatter.Ui; + +namespace Content.Server.SS220.SuperMatter; + +[RegisterComponent] +public sealed partial class SuperMatterObserverComponent : SharedSuperMatterObserverComponent { } + +/// We use this component to mark entities which can receiver +[RegisterComponent] +public sealed partial class SuperMatterObserverReceiverComponent : SharedSuperMatterObserverReceiverComponent { } diff --git a/Content.Shared/SS220/SuperMatter/Ui/SuperMatterObserverUI.cs b/Content.Shared/SS220/SuperMatter/Ui/SuperMatterObserverUI.cs index 317fe9ed1dba..bb42fcfe77ca 100644 --- a/Content.Shared/SS220/SuperMatter/Ui/SuperMatterObserverUI.cs +++ b/Content.Shared/SS220/SuperMatter/Ui/SuperMatterObserverUI.cs @@ -9,16 +9,10 @@ public enum SuperMatterObserverUiKey : byte Key } -// [Serializable, NetSerializable] -// public sealed class SuperMatterObserverUpdateState : BoundUserInterfaceState -// { - -// } - - [Serializable, NetSerializable] public sealed class SuperMatterStateUpdate( int id, + NetEntity? smGridId, string name, float integrity, float pressure, @@ -31,6 +25,7 @@ public sealed class SuperMatterStateUpdate( // Id of SM crystal, uses for handling many SMs public int Id { get; } = id; public string Name { get; } = name; + public NetEntity? SMGridId { get; } = smGridId; public float Pressure { get; } = pressure; public float Integrity { get; } = integrity; public float Temperature { get; } = temperature; diff --git a/Content.Shared/SS220/SuperMatter/Ui/SuperMatterUISharedComponents.cs b/Content.Shared/SS220/SuperMatter/Ui/SuperMatterUISharedComponents.cs new file mode 100644 index 000000000000..bbd5447caaca --- /dev/null +++ b/Content.Shared/SS220/SuperMatter/Ui/SuperMatterUISharedComponents.cs @@ -0,0 +1,8 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt + +namespace Content.Shared.SS220.SuperMatter.Ui; + +public abstract partial class SharedSuperMatterObserverComponent : Component { } + +/// We use this component to mark entities which can receiver +public abstract partial class SharedSuperMatterObserverReceiverComponent : Component { } diff --git a/Resources/Prototypes/SS220/Entities/Structures/Machines/computers.yml b/Resources/Prototypes/SS220/Entities/Structures/Machines/computers.yml index 59686cde5139..c2882fd7dceb 100644 --- a/Resources/Prototypes/SS220/Entities/Structures/Machines/computers.yml +++ b/Resources/Prototypes/SS220/Entities/Structures/Machines/computers.yml @@ -62,6 +62,9 @@ color: "#ffb800" # check it # - type: Computer # board: PowerComputerCircuitboard DOIT + - type: SuperMatterObserver + - type: SuperMatterObserverReceiver + - type: ActivatableUIRequiresPower - type: ActivatableUI singleUser: true key: enum.SuperMatterObserverUiKey.Key