diff --git a/MechJeb2/MechJebModuleStageStats.cs b/MechJeb2/MechJebModuleStageStats.cs index 52d00675..d677b525 100644 --- a/MechJeb2/MechJebModuleStageStats.cs +++ b/MechJeb2/MechJebModuleStageStats.cs @@ -1,4 +1,4 @@ -extern alias JetBrainsAnnotations; +extern alias JetBrainsAnnotations; using System.Collections.Generic; using System.Diagnostics; using MechJebLib.FuelFlowSimulation; @@ -19,6 +19,10 @@ public class MechJebModuleStageStats : ComputerModule public double AltSLT = 0; public double Mach = 0; + public int HalfStageIndex => _vesselManagerVac.HalfStageIndex; + [Persistent(pass = (int)(Pass.TYPE | Pass.GLOBAL))] + public readonly EditableDoubleMult HalfStageEndMass = new EditableDoubleMult(0, 0.001); + private int _vabRebuildTimer = 1; public readonly List AtmoStats = new List(); @@ -124,6 +128,7 @@ private void RunSimulation() _vesselManagerVac.SetConditions(0, 0, 0); _vesselManagerVac.SetInitial(VesselState.time, VesselState.orbitalPosition.WorldToV3Rotated(), VesselState.orbitalVelocity.WorldToV3Rotated(), VesselState.forward.WorldToV3Rotated()); + _vesselManagerVac.SetupStageAndAHalf(HalfStageEndMass); _vesselManagerVac.StartFuelFlowSimulationJob(); } @@ -133,6 +138,7 @@ private void RunSimulation() _vesselManagerAtmo.SetConditions(atmDensity, staticPressureKpa * PhysicsGlobals.KpaToAtmospheres, mach); _vesselManagerAtmo.SetInitial(VesselState.time, VesselState.orbitalPosition.WorldToV3Rotated(), VesselState.orbitalVelocity.WorldToV3Rotated(), VesselState.forward.WorldToV3Rotated()); + _vesselManagerAtmo.SetupStageAndAHalf(HalfStageEndMass); _vesselManagerAtmo.StartFuelFlowSimulationJob(); } } diff --git a/MechJeb2/MechJebModuleStagingController.cs b/MechJeb2/MechJebModuleStagingController.cs index 458de9ca..d7845da9 100644 --- a/MechJeb2/MechJebModuleStagingController.cs +++ b/MechJeb2/MechJebModuleStagingController.cs @@ -290,6 +290,9 @@ public override void OnUpdate() UpdateActiveModuleEngines(_allModuleEngines); UpdateBurnedResources(); + if (Vessel.currentStage == _stats.HalfStageIndex && Vessel.totalMass <= _stats.HalfStageEndMass) + Stage(); + // don't decouple active or idle engines or tanks if (InverseStageDecouplesActiveOrIdleEngineOrTank(Vessel.currentStage - 1, _burnedResources, _activeModuleEngines) && !InverseStageReleasesClamps(Vessel.currentStage - 1)) diff --git a/MechJeb2/MechJebStageStatsHelper.cs b/MechJeb2/MechJebStageStatsHelper.cs index d07e824a..726e5af1 100644 --- a/MechJeb2/MechJebStageStatsHelper.cs +++ b/MechJeb2/MechJebStageStatsHelper.cs @@ -294,6 +294,15 @@ public void AllStageStats() Profiler.EndSample(); + if (stats.HalfStageIndex != -1) + { + GUILayout.BeginHorizontal(); + GUILayout.Label($"Half-stage index: {stats.HalfStageIndex}", GUILayout.Width(130)); + GUILayout.Space(30); + GuiUtils.SimpleTextBox("End mass: ", stats.HalfStageEndMass, "kg"); + GUILayout.EndHorizontal(); + } + Profiler.BeginSample("AllStageStats.DrawColumns"); GUILayout.BeginHorizontal(); diff --git a/MechJebLib/FuelFlowSimulation/FuelFlowSimulation.cs b/MechJebLib/FuelFlowSimulation/FuelFlowSimulation.cs index 743941d4..d86bb35d 100644 --- a/MechJebLib/FuelFlowSimulation/FuelFlowSimulation.cs +++ b/MechJebLib/FuelFlowSimulation/FuelFlowSimulation.cs @@ -1,10 +1,11 @@ -/* +/* * Copyright Lamont Granquist, Sebastien Gaggini and the MechJeb contributors * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ */ using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.CompilerServices; using MechJebLib.FuelFlowSimulation.PartModules; using MechJebLib.Utils; @@ -113,7 +114,19 @@ private void SimulateStage(SimVessel vessel) if (AllowedToStage(vessel)) return; + int earliestDroppedEgineInStage = vessel.ActiveEngines.Max(x => x.Part.DecoupledInStage); + int earliestDroppedTankInStage = _sources.Max(x => x.DecoupledInStage); + if (earliestDroppedEgineInStage > earliestDroppedTankInStage) + { + vessel.HalfStageIndex = earliestDroppedEgineInStage + 1; + } + double dt = MinimumTimeStep(); + if (_currentSegment.KSPStage == vessel.HalfStageIndex) + { + double massFlow = ResourceMaxMassFlow(vessel); + dt = Min(dt, (_currentSegment.StartMass - vessel.HalfStageEndMass) / massFlow); + } // FIXME: if we have constructed a segment which is > 0 dV, but less than 0.02s, and there's a // prior > 0dV segment in the same kspStage we should add those together to reduce clutter. @@ -379,6 +392,17 @@ private double ResourceMaxTime() return maxTime; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private double ResourceMaxMassFlow(SimVessel vessel) + { + double massFlow = 0; + + foreach (SimModuleEngines engine in vessel.ActiveEngines) + massFlow += engine.MassFlowRate; + + return massFlow; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void FinishRcsSegment(bool max, double deltaTime, double startMass, double endMass, double rcsThrust) { @@ -453,6 +477,9 @@ private static bool AllowedToStage(SimVessel vessel) if (vessel.ActiveEngines.Count == 0) return true; + if (vessel.CurrentStage == vessel.HalfStageIndex && vessel.Mass <= vessel.HalfStageEndMass + 0.001) + return true; + for (int i = 0; i < vessel.ActiveEngines.Count; i++) { SimModuleEngines e = vessel.ActiveEngines[i]; diff --git a/MechJebLib/FuelFlowSimulation/SimVessel.cs b/MechJebLib/FuelFlowSimulation/SimVessel.cs index deff7eaf..0b3b5607 100644 --- a/MechJebLib/FuelFlowSimulation/SimVessel.cs +++ b/MechJebLib/FuelFlowSimulation/SimVessel.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright Lamont Granquist, Sebastien Gaggini and the MechJeb contributors * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ */ @@ -42,6 +42,9 @@ public class SimVessel : IDisposable public double T; public V3 R, V, U; + public int HalfStageIndex = -1; + public double HalfStageEndMass = 0; + // CurrentStage gets scribbled over by the FuelFlowSimulation, SetCurrentStage() is intended to be used in // the VesselBuilder and DecouplingAnalyzer to figure out the right value, ResetCurrentStage() is called by // the VesselUpdater to reset it back. @@ -76,6 +79,15 @@ public void SetInitial(double t, V3 r, V3 v, V3 u) U = u; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetupStageAndAHalf(double endMass) + { + if (HalfStageIndex != -1) + { + HalfStageEndMass = endMass; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void UpdateMass() { diff --git a/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs b/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs index 5af63f1f..7ce3fa6f 100644 --- a/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs +++ b/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright Lamont Granquist, Sebastien Gaggini and the MechJeb contributors * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ */ @@ -29,17 +29,9 @@ public class SimVesselBuilder private static readonly CrewMass _crewMassDelegate; - private SimVessel _vessel - { - get => _manager._vessel; - set => _manager._vessel = value; - } + private SimVessel _vessel => _manager._vessel; - private IShipconstruct _kspVessel - { - get => _manager._kspVessel; - set => _manager._kspVessel = value; - } + private IShipconstruct _kspVessel => _manager._kspVessel; private readonly SimVesselManager _manager; private static readonly Type? _rfType; @@ -68,7 +60,7 @@ static SimVesselBuilder() private static double CrewMassNew(ProtoCrewMember crew) => PhysicsGlobals.KerbalCrewMass + crew.ResourceMass() + crew.InventoryMass(); - public SimVesselBuilder(SimVesselManager manager) + internal SimVesselBuilder(SimVesselManager manager) { _manager = manager; } @@ -126,14 +118,12 @@ internal void UpdateSymmetryParts() } } - internal void BuildVessel(IShipconstruct kspVessel) + internal void BuildVessel() { - _vessel.Dispose(); - _vessel = SimVessel.Borrow(); - _kspVessel = kspVessel; + BuildParts(); } - internal void BuildParts() + private void BuildParts() { _vessel.SetCurrentStage(StageManager.CurrentStage); diff --git a/MechJebLibBindings/FuelFlowSimulation/SimVesselManager.cs b/MechJebLibBindings/FuelFlowSimulation/SimVesselManager.cs index bea60aec..08af089f 100644 --- a/MechJebLibBindings/FuelFlowSimulation/SimVesselManager.cs +++ b/MechJebLibBindings/FuelFlowSimulation/SimVesselManager.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright Lamont Granquist, Sebastien Gaggini and the MechJeb contributors * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ */ @@ -13,8 +13,6 @@ namespace MechJebLibBindings.FuelFlowSimulation // need to link against KSP GameObjects (MechJebLibBindings.dll or something like that) public partial class SimVesselManager { - public List Segments => FuelFlowSimulation.Segments; - private readonly SimVesselBuilder _builder; private readonly SimVesselUpdater _updater; private SimVessel _vessel; @@ -31,6 +29,8 @@ public partial class SimVesselManager public V3 V => _vessel.V; public V3 U => _vessel.U; + public int HalfStageIndex => _vessel.HalfStageIndex; + public SimVesselManager() { _builder = new SimVesselBuilder(this); @@ -41,9 +41,12 @@ public SimVesselManager() public void Build(IShipconstruct vessel) { + _vessel.Dispose(); + _vessel = SimVessel.Borrow(); + _kspVessel = vessel; + Clear(); - _builder.BuildVessel(vessel); - _builder.BuildParts(); + _builder.BuildVessel(); Update(); _builder.UpdateLinks(); _builder.UpdateCrossFeedSet(); @@ -59,6 +62,8 @@ public void SetConditions(double atmDensity, double atmPressure, double machNumb public void SetInitial(double t, V3 r, V3 v, V3 u) => _vessel.SetInitial(t, r, v, u); + public void SetupStageAndAHalf(double endMass) => _vessel.SetupStageAndAHalf(endMass); + public void StartFuelFlowSimulationJob() { FuelFlowSimulation.DVLinearThrust = DVLinearThrust; diff --git a/MechJebLibBindings/FuelFlowSimulation/SimVesselUpdater.cs b/MechJebLibBindings/FuelFlowSimulation/SimVesselUpdater.cs index 6265c795..a7d1adef 100644 --- a/MechJebLibBindings/FuelFlowSimulation/SimVesselUpdater.cs +++ b/MechJebLibBindings/FuelFlowSimulation/SimVesselUpdater.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright Lamont Granquist, Sebastien Gaggini and the MechJeb contributors * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ */ @@ -49,7 +49,7 @@ static SimVesselUpdater() } } - public SimVesselUpdater(SimVesselManager manager) + internal SimVesselUpdater(SimVesselManager manager) { _manager = manager; }