From c206ba6d0ce5cbf4422feb9402f170c980c65f7a Mon Sep 17 00:00:00 2001 From: Lamont Granquist Date: Fri, 30 Jun 2023 17:03:26 -0700 Subject: [PATCH] Update to C# 9.0, add partial suicide burn overhaul This is kinda weird, its got a half-finished fully numerical suicide burn overhaul I did which needs to be finished, also bumps the version to C# 9 and fixes a problem with the FlightRecorder using the 'record' newly reserved word, along with some support for BackgroundJob in the MechJebUtils class. What I really want is that support for BackgroundJobs to use with the delta-V overhaul, and all this work is drifting and merge conflicting as I rename things, so I'm going to merge the suicide burn timer a bit half-done. The module isn't wired up anywhere so shouldn't run. Signed-off-by: Lamont Granquist --- MechJeb2/MechJeb2.csproj | 7 +- MechJeb2/MechJebLib/Suicide.cs | 24 ++++++ MechJeb2/MechJebLib/SuicideBuilder.cs | 38 +++++++++ MechJeb2/MechJebLib/Utils/BackgroundJob.cs | 52 ++++++++++++ .../MechJebModuleAscentClassicPathMenu.cs | 2 +- MechJeb2/MechJebModuleFlightRecorder.cs | 10 +-- MechJeb2/MechJebModuleFlightRecorderGraph.cs | 4 +- MechJeb2/MechJebModulePVGGlueBall.cs | 8 +- MechJeb2/MechJebModuleSuicideTimer.cs | 85 +++++++++++++++++++ MechJeb2/VesselExtensions.cs | 8 +- 10 files changed, 220 insertions(+), 18 deletions(-) create mode 100644 MechJeb2/MechJebLib/Suicide.cs create mode 100644 MechJeb2/MechJebLib/SuicideBuilder.cs create mode 100644 MechJeb2/MechJebLib/Utils/BackgroundJob.cs create mode 100644 MechJeb2/MechJebModuleSuicideTimer.cs diff --git a/MechJeb2/MechJeb2.csproj b/MechJeb2/MechJeb2.csproj index 66dc3f28..52910215 100644 --- a/MechJeb2/MechJeb2.csproj +++ b/MechJeb2/MechJeb2.csproj @@ -15,6 +15,7 @@ + 9 true @@ -26,7 +27,6 @@ 4 false false - 8.0 None @@ -37,7 +37,6 @@ 4 AnyCPU false - 8.0 MechJeb2.ruleset @@ -153,6 +152,9 @@ + + + @@ -204,6 +206,7 @@ + diff --git a/MechJeb2/MechJebLib/Suicide.cs b/MechJeb2/MechJebLib/Suicide.cs new file mode 100644 index 00000000..0bd660d8 --- /dev/null +++ b/MechJeb2/MechJebLib/Suicide.cs @@ -0,0 +1,24 @@ +using MechJebLib.Primitives; +using MechJebLib.Utils; + +namespace MuMech.MechJebLib +{ + public partial class Suicide : BackgroundJob + { + public struct SuicideResult + { + public V3 Rf; + public double Tf; + } + + public static SuicideBuilder Builder() + { + return new SuicideBuilder(); + } + + protected override SuicideResult Execute() + { + throw new System.NotImplementedException(); + } + } +} diff --git a/MechJeb2/MechJebLib/SuicideBuilder.cs b/MechJeb2/MechJebLib/SuicideBuilder.cs new file mode 100644 index 00000000..7b5ab5e1 --- /dev/null +++ b/MechJeb2/MechJebLib/SuicideBuilder.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using MechJebLib.Primitives; +using MechJebLib.PVG; + +namespace MuMech.MechJebLib +{ + public partial class Suicide + { + public class SuicideBuilder + { + private readonly List _phases = new List(); + + public Suicide Build() + { + var suicide = new Suicide(); + + return suicide; + } + + public SuicideBuilder Initial(V3 r0, V3 v0, V3 u0, double t0, double mu, double rbody) + { + return this; + } + + public SuicideBuilder AddStageUsingFinalMass(double m0, double mf, double isp, double bt, int kspStage) + { + _phases.Add(Phase.NewStageUsingFinalMass(m0, mf, isp, bt, kspStage)); + + return this; + } + + public SuicideBuilder SetGround(double height) + { + return this; + } + } + } +} diff --git a/MechJeb2/MechJebLib/Utils/BackgroundJob.cs b/MechJeb2/MechJebLib/Utils/BackgroundJob.cs new file mode 100644 index 00000000..be8a4449 --- /dev/null +++ b/MechJeb2/MechJebLib/Utils/BackgroundJob.cs @@ -0,0 +1,52 @@ +using System; +using System.Threading.Tasks; + +#nullable enable + +namespace MechJebLib.Utils +{ + // TODO: + // - cancellation + // - timeout + public abstract class BackgroundJob + { + private Task? _task; + public T Result = default!; + + protected abstract T Execute(); + + public void Cancel() + { + throw new NotImplementedException(); + } + + public bool IsRunning() + { + return _task is not { IsCompleted: true }; + } + + protected virtual void OnTaskCompleted(Task task) + { + Result = task.Result; + _task = null; + } + + protected virtual void OnTaskFaulted(Task task) + { + _task = null; + } + + protected virtual void OnTaskCancelled(Task task) + { + _task = null; + } + + public void Run() + { + _task = Task.Run(Execute); + _task.ContinueWith(OnTaskCompleted, TaskContinuationOptions.OnlyOnRanToCompletion); + _task.ContinueWith(OnTaskFaulted, TaskContinuationOptions.OnlyOnFaulted); + _task.ContinueWith(OnTaskCancelled, TaskContinuationOptions.OnlyOnCanceled); + } + } +} diff --git a/MechJeb2/MechJebModuleAscentClassicPathMenu.cs b/MechJeb2/MechJebModuleAscentClassicPathMenu.cs index b37941af..78c179ff 100644 --- a/MechJeb2/MechJebModuleAscentClassicPathMenu.cs +++ b/MechJeb2/MechJebModuleAscentClassicPathMenu.cs @@ -198,7 +198,7 @@ private void DrawnTrajectory(Rect r, MechJebModuleFlightRecorder recorder) while (t <= recorder.historyIdx && t < recorder.history.Length) { - MechJebModuleFlightRecorder.record rec = recorder.history[t]; + MechJebModuleFlightRecorder.RecordStruct rec = recorder.history[t]; p2.x = r.xMin + (float)(rec.downRange / scale); p2.y = r.yMax - (float)(rec.altitudeASL / scale); diff --git a/MechJeb2/MechJebModuleFlightRecorder.cs b/MechJeb2/MechJebModuleFlightRecorder.cs index e2bd230c..5af19fb8 100644 --- a/MechJeb2/MechJebModuleFlightRecorder.cs +++ b/MechJeb2/MechJebModuleFlightRecorder.cs @@ -10,7 +10,7 @@ namespace MuMech public class MechJebModuleFlightRecorder : ComputerModule { // TODO : this is already nearly an array so use a list and allow to add any generic ValueInfoItem - public struct record + public struct RecordStruct { public double timeSinceMark; public int currentStage; @@ -102,7 +102,7 @@ public enum recordType DeltaVExpended } - public record[] history = new record[1]; + public RecordStruct[] history = new RecordStruct[1]; public int historyIdx = -1; @@ -237,7 +237,7 @@ public MechJebModuleFlightRecorder(MechJebCore core) public override void OnStart(PartModule.StartState state) { if (history.Length != historySize) - history = new record[historySize]; + history = new RecordStruct[historySize]; Users.Add(this); //flight recorder should always run. } @@ -347,8 +347,8 @@ public void DumpCSV() for (int idx = 0; idx <= historyIdx; idx++) { - record r = history[idx]; - writer.Write(r[0]); + RecordStruct r = history[idx]; + writer.Write(r[(recordType)0]); for (int i = 1; i < typeCount; i++) { writer.Write(','); diff --git a/MechJeb2/MechJebModuleFlightRecorderGraph.cs b/MechJeb2/MechJebModuleFlightRecorderGraph.cs index 9260634c..22e554a6 100644 --- a/MechJeb2/MechJebModuleFlightRecorderGraph.cs +++ b/MechJeb2/MechJebModuleFlightRecorderGraph.cs @@ -622,7 +622,7 @@ private void DrawnPath(Rect r, MechJebModuleFlightRecorder.recordType type, floa while (t <= recorder.historyIdx && t < recorder.history.Length) { - MechJebModuleFlightRecorder.record rec = recorder.history[t]; + MechJebModuleFlightRecorder.RecordStruct rec = recorder.history[t]; p2.x = xBase + (float)((downRange ? rec.downRange : rec.timeSinceMark) * invScaleX); p2.y = yBase - (float)(rec[type] * invScaleY); @@ -651,7 +651,7 @@ private void DrawnStages(Rect r, double scaleX, bool downRange) int t = 1; while (t <= recorder.historyIdx && t < recorder.history.Length) { - MechJebModuleFlightRecorder.record rec = recorder.history[t]; + MechJebModuleFlightRecorder.RecordStruct rec = recorder.history[t]; if (rec.currentStage != lastStage) { lastStage = rec.currentStage; diff --git a/MechJeb2/MechJebModulePVGGlueBall.cs b/MechJeb2/MechJebModulePVGGlueBall.cs index 374fff96..e227dec6 100644 --- a/MechJeb2/MechJebModulePVGGlueBall.cs +++ b/MechJeb2/MechJebModulePVGGlueBall.cs @@ -72,12 +72,6 @@ private void HandleStageEvent(int data) _blockOptimizerUntilTime = VesselState.time + _ascentSettings.OptimizerPauseTime; } - private bool VesselOffGround() - { - return Vessel.situation != Vessel.Situations.LANDED && Vessel.situation != Vessel.Situations.PRELAUNCH && - Vessel.situation != Vessel.Situations.SPLASHED; - } - private bool IsUnguided(int s) { return _ascentSettings.UnguidedStages.Contains(s); @@ -153,7 +147,7 @@ public void SetTarget(double peR, double apR, double attR, double inclination, d attR = apR; } - if (VesselOffGround()) + if (Vessel.VesselOffGround()) { bool hasGuided = false; diff --git a/MechJeb2/MechJebModuleSuicideTimer.cs b/MechJeb2/MechJebModuleSuicideTimer.cs new file mode 100644 index 00000000..1d8a8e4b --- /dev/null +++ b/MechJeb2/MechJebModuleSuicideTimer.cs @@ -0,0 +1,85 @@ +#nullable enable + +using System.Threading.Tasks; +using JetBrains.Annotations; +using MechJebLib.Primitives; +using MuMech.MechJebLib; + +namespace MuMech +{ + [UsedImplicitly] + public class MechJebModuleSuicideTimer : ComputerModule + { + private Suicide? _suicide; + private Suicide.SuicideResult _lastResult; + public Vector3d Rf => _lastResult.Rf.V3ToWorldRotated(); + + public MechJebModuleSuicideTimer(MechJebCore core) : base(core) + { + } + + protected override void OnModuleEnabled() + { + Reset(); + } + + protected override void OnModuleDisabled() + { + Reset(); + } + + private void Reset() + { + _lastResult.Rf = V3.zero; + _lastResult.Tf = VesselState.time; + _suicide?.Cancel(); + _suicide = null; + } + + + private double GetGroundHeight() + { + if (Rf == Vector3d.zero) + return MainBody.Radius; + + Vector3d latlng = MainBody.GetLatitudeAndLongitude(Rf, true); + return MainBody.TerrainAltitude(latlng[0], latlng[1]); + } + + public override void OnFixedUpdate() + { + if (!Vessel.VesselOffGround()) + return; + + // make sure our orbit at least dips into the atmosphere, or bodyRadius plus some maximum height of mountains + + Core.StageStats.RequestUpdate(this); + + if (Core.StageStats.vacStats.Length <= 0) + return; + + if (_suicide != null) + { + if (_suicide.IsRunning()) + return; + + _lastResult = _suicide.Result; + } + + Suicide.SuicideBuilder suicideBuilder = Suicide.Builder() + .Initial(VesselState.orbitalPosition.WorldToV3Rotated(), VesselState.orbitalVelocity.WorldToV3Rotated(), + VesselState.forward.WorldToV3Rotated(), VesselState.time, MainBody.gravParameter, MainBody.Radius) + .SetGround(GetGroundHeight()); + + for (int i = Core.StageStats.vacStats.Length - 1; i >= 0; i--) + { + FuelFlowSimulation.FuelStats fuelStats = Core.StageStats.vacStats[i]; + + suicideBuilder.AddStageUsingFinalMass(fuelStats.StartMass * 1000, fuelStats.EndMass * 1000, fuelStats.Isp, fuelStats.DeltaTime, i); + } + + _suicide = suicideBuilder.Build(); + _suicide.Run(); + } + } +} diff --git a/MechJeb2/VesselExtensions.cs b/MechJeb2/VesselExtensions.cs index aa8038b4..00500297 100644 --- a/MechJeb2/VesselExtensions.cs +++ b/MechJeb2/VesselExtensions.cs @@ -9,6 +9,12 @@ namespace MuMech { public static class VesselExtensions { + public static bool VesselOffGround(this Vessel vessel) + { + return vessel.situation is Vessel.Situations.FLYING or Vessel.Situations.ESCAPING + or Vessel.Situations.ORBITING or Vessel.Situations.SUB_ORBITAL; + } + public static List GetTargetables(this Vessel vessel) { List parts; @@ -76,7 +82,7 @@ public static List GetTargetables(this Vessel vessel) } private static float lastFixedTime; - private static readonly Dictionary masterMechJeb = new Dictionary(); + private static readonly Dictionary masterMechJeb = new(); public static MechJebCore GetMasterMechJeb(this Vessel vessel) {