diff --git a/MechJeb2/MechJebModuleStageStats.cs b/MechJeb2/MechJebModuleStageStats.cs index da8dce01a..df680f534 100644 --- a/MechJeb2/MechJebModuleStageStats.cs +++ b/MechJeb2/MechJebModuleStageStats.cs @@ -154,6 +154,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.PrintVessel(); if (!_vesselManagerAtmo.TryStartFuelFlowSimulationJob()) throw new Exception("[MechJebModuleStageStats] could not start atmo stats job"); } diff --git a/MechJebLib/FuelFlowSimulation/PartModules/SimLaunchClamp.cs b/MechJebLib/FuelFlowSimulation/PartModules/SimLaunchClamp.cs index 2bbc79442..6c337b773 100644 --- a/MechJebLib/FuelFlowSimulation/PartModules/SimLaunchClamp.cs +++ b/MechJebLib/FuelFlowSimulation/PartModules/SimLaunchClamp.cs @@ -27,6 +27,6 @@ private static void Clear(SimLaunchClamp m) { } - public override string ToString() => Invariant($"SimLaunchClamp: {CommonFields()}"); + public override string ToString() => ModuleLine("SimLaunchClamp", CommonFieldList()); } } diff --git a/MechJebLib/FuelFlowSimulation/PartModules/SimModuleAvionics.cs b/MechJebLib/FuelFlowSimulation/PartModules/SimModuleAvionics.cs index 100e5df29..b876f5b08 100644 --- a/MechJebLib/FuelFlowSimulation/PartModules/SimModuleAvionics.cs +++ b/MechJebLib/FuelFlowSimulation/PartModules/SimModuleAvionics.cs @@ -3,6 +3,7 @@ * 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.Collections.Generic; using MechJebLib.Utils; using static System.FormattableString; @@ -30,7 +31,11 @@ private static void Clear(SimModuleAvionics m) { } - public override string ToString() => - Invariant($"SimModuleAvionics: {CommonFields()} ControllableMass={ControllableMass}"); + public override string ToString() + { + List fields = CommonFieldList(); + AddField(fields, "ControllableMass", ControllableMass, 0); + return ModuleLine("SimModuleAvionics", fields); + } } } diff --git a/MechJebLib/FuelFlowSimulation/PartModules/SimModuleDecouple.cs b/MechJebLib/FuelFlowSimulation/PartModules/SimModuleDecouple.cs index 29e6d1ce2..0104ec48b 100644 --- a/MechJebLib/FuelFlowSimulation/PartModules/SimModuleDecouple.cs +++ b/MechJebLib/FuelFlowSimulation/PartModules/SimModuleDecouple.cs @@ -3,6 +3,7 @@ * 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.Collections.Generic; using MechJebLib.Utils; using static System.FormattableString; @@ -12,9 +13,9 @@ public class SimModuleDecouple : SimPartModule { private static readonly ObjectPool _pool = new ObjectPool(New, Clear); - public bool IsDecoupled; - public bool IsOmniDecoupler; - public bool Staged; + public bool IsDecoupled = false; + public bool IsOmniDecoupler = false; + public bool Staged = false; public SimPart? AttachedPart; public override void Dispose() => _pool.Release(this); @@ -30,8 +31,15 @@ public static SimModuleDecouple Borrow(SimPart part) private static void Clear(SimModuleDecouple m) => m.AttachedPart = null; - public override string ToString() => - Invariant( - $"SimModuleDecouple: {CommonFields()} IsDecoupled={IsDecoupled} IsOmniDecoupler={IsOmniDecoupler} Staged={Staged} AttachedPart={AttachedPart?.Name ?? "null"}"); + public override string ToString() + { + List fields = CommonFieldList(); + AddField(fields, "IsDecoupled", IsDecoupled, false); + AddField(fields, "IsOmniDecoupler", IsOmniDecoupler, false); + AddField(fields, "Staged", Staged, false); + if (AttachedPart != null) + fields.Add(Invariant($"AttachedPart={AttachedPart.Ident}")); + return ModuleLine("SimModuleDecouple", fields); + } } } diff --git a/MechJebLib/FuelFlowSimulation/PartModules/SimModuleDockingNode.cs b/MechJebLib/FuelFlowSimulation/PartModules/SimModuleDockingNode.cs index e9cb04d8a..ce51a3c9b 100644 --- a/MechJebLib/FuelFlowSimulation/PartModules/SimModuleDockingNode.cs +++ b/MechJebLib/FuelFlowSimulation/PartModules/SimModuleDockingNode.cs @@ -3,6 +3,7 @@ * 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.Collections.Generic; using MechJebLib.Utils; using static System.FormattableString; @@ -12,7 +13,7 @@ public class SimModuleDockingNode : SimPartModule { private static readonly ObjectPool _pool = new ObjectPool(New, Clear); - public bool Staged; + public bool Staged = false; public SimPart? AttachedPart; public override void Dispose() => _pool.Release(this); @@ -28,7 +29,13 @@ public static SimModuleDockingNode Borrow(SimPart part) private static void Clear(SimModuleDockingNode m) => m.AttachedPart = null; - public override string ToString() => - Invariant($"SimModuleDockingNode: {CommonFields()} Staged={Staged} AttachedPart={AttachedPart?.Name ?? "null"}"); + public override string ToString() + { + List fields = CommonFieldList(); + AddField(fields, "Staged", Staged, false); + if (AttachedPart != null) + fields.Add(Invariant($"AttachedPart={AttachedPart.Ident}")); + return ModuleLine("SimModuleDockingNode", fields); + } } } diff --git a/MechJebLib/FuelFlowSimulation/PartModules/SimModuleEngines.cs b/MechJebLib/FuelFlowSimulation/PartModules/SimModuleEngines.cs index f03283b45..aeff58e43 100644 --- a/MechJebLib/FuelFlowSimulation/PartModules/SimModuleEngines.cs +++ b/MechJebLib/FuelFlowSimulation/PartModules/SimModuleEngines.cs @@ -393,7 +393,7 @@ private void SetConsumptionRates() public override string ToString() { var sb = new StringBuilder(); - sb.AppendLine(Invariant($"SimModuleEngines: {CommonFields()}")); + sb.AppendLine(ModuleLine("SimModuleEngines", CommonFieldList())); sb.AppendLine(Invariant( $" IsOperational={IsOperational} IsEnabled={IsEnabled} IsUnrestartableDeadEngine={IsUnrestartableDeadEngine} NoPropellants={NoPropellants}")); sb.AppendLine(Invariant($" MaxFuelFlow={MaxFuelFlow} MinFuelFlow={MinFuelFlow} MaxThrust={MaxThrust} MinThrust={MinThrust} G={G}")); @@ -404,14 +404,21 @@ public override string ToString() $" AtmChangeFlow={AtmChangeFlow} UseAtmCurve={UseAtmCurve} UseAtmCurveIsp={UseAtmCurveIsp} UseThrottleIspCurve={UseThrottleIspCurve} UseThrustCurve={UseThrustCurve} UseVelCurve={UseVelCurve} UseVelCurveIsp={UseVelCurveIsp}")); sb.AppendLine(Invariant( $" ModuleResiduals={ModuleResiduals} ModuleSpoolupTime={ModuleSpoolupTime} AutoCutoff={AutoCutoff} IsModuleEnginesRf={IsModuleEnginesRf} Ullage={Ullage}")); - sb.AppendLine(Invariant($" AtmosphereCurve: {AtmosphereCurve}")); - sb.AppendLine(Invariant($" ThrustCurve: {ThrustCurve}")); - sb.AppendLine(Invariant($" ThrottleIspCurve: {ThrottleIspCurve}")); - sb.AppendLine(Invariant($" ThrottleIspCurveAtmStrength: {ThrottleIspCurveAtmStrength}")); - sb.AppendLine(Invariant($" VelCurve: {VelCurve}")); - sb.AppendLine(Invariant($" VelCurveIsp: {VelCurveIsp}")); - sb.AppendLine(Invariant($" ATMCurve: {ATMCurve}")); - sb.AppendLine(Invariant($" ATMCurveIsp: {ATMCurveIsp}")); + void AppendCurve(string name, H1 curve) + { + // empty curves are the default and very common, so omit them to keep the dump readable + if (!curve.IsEmpty) + sb.AppendLine(Invariant($" {name}: {curve}")); + } + + AppendCurve("AtmosphereCurve", AtmosphereCurve); + AppendCurve("ThrustCurve", ThrustCurve); + AppendCurve("ThrottleIspCurve", ThrottleIspCurve); + AppendCurve("ThrottleIspCurveAtmStrength", ThrottleIspCurveAtmStrength); + AppendCurve("VelCurve", VelCurve); + AppendCurve("VelCurveIsp", VelCurveIsp); + AppendCurve("ATMCurve", ATMCurve); + AppendCurve("ATMCurveIsp", ATMCurveIsp); sb.Append(" ThrustTransformMultipliers:"); foreach (double m in ThrustTransformMultipliers) diff --git a/MechJebLib/FuelFlowSimulation/PartModules/SimModuleRCS.cs b/MechJebLib/FuelFlowSimulation/PartModules/SimModuleRCS.cs index f5d82227f..ca4d36227 100644 --- a/MechJebLib/FuelFlowSimulation/PartModules/SimModuleRCS.cs +++ b/MechJebLib/FuelFlowSimulation/PartModules/SimModuleRCS.cs @@ -188,7 +188,7 @@ private void SetConsumptionRates() public override string ToString() { var sb = new StringBuilder(); - sb.AppendLine(Invariant($"SimModuleRCS: {CommonFields()}")); + sb.AppendLine(ModuleLine("SimModuleRCS", CommonFieldList())); sb.AppendLine(Invariant( $" G={G} Isp={Isp} Thrust={Thrust} RcsEnabled={RcsEnabled} ISPMult={ISPMult} ThrustPercentage={ThrustPercentage} MaxFuelFlow={MaxFuelFlow} MassFlowRate={MassFlowRate}")); sb.AppendLine(Invariant($" AtmosphereCurve: {AtmosphereCurve}")); diff --git a/MechJebLib/FuelFlowSimulation/PartModules/SimProceduralFairingDecoupler.cs b/MechJebLib/FuelFlowSimulation/PartModules/SimProceduralFairingDecoupler.cs index cdba42a2b..8335cf97e 100644 --- a/MechJebLib/FuelFlowSimulation/PartModules/SimProceduralFairingDecoupler.cs +++ b/MechJebLib/FuelFlowSimulation/PartModules/SimProceduralFairingDecoupler.cs @@ -3,6 +3,7 @@ * 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.Collections.Generic; using MechJebLib.Utils; using static System.FormattableString; @@ -12,7 +13,7 @@ public class SimProceduralFairingDecoupler : SimPartModule { private static readonly ObjectPool _pool = new ObjectPool(New, Clear); - public bool IsDecoupled; + public bool IsDecoupled = false; public override void Dispose() => _pool.Release(this); @@ -29,7 +30,11 @@ private static void Clear(SimProceduralFairingDecoupler m) { } - public override string ToString() => - Invariant($"SimProceduralFairingDecoupler: {CommonFields()} IsDecoupled={IsDecoupled}"); + public override string ToString() + { + List fields = CommonFieldList(); + AddField(fields, "IsDecoupled", IsDecoupled, false); + return ModuleLine("SimProceduralFairingDecoupler", fields); + } } } diff --git a/MechJebLib/FuelFlowSimulation/SimPart.cs b/MechJebLib/FuelFlowSimulation/SimPart.cs index 3bb84b5f4..39b0a9cec 100644 --- a/MechJebLib/FuelFlowSimulation/SimPart.cs +++ b/MechJebLib/FuelFlowSimulation/SimPart.cs @@ -24,29 +24,32 @@ public class SimPart private readonly Dictionary _resourceDrains = new Dictionary(); private readonly Dictionary _rcsDrains = new Dictionary(); - public int DecoupledInStage; - public bool StagingOn; - public int InverseStage; + public int DecoupledInStage = -1; + public bool StagingOn = true; + public int InverseStage = -1; public SimVessel Vessel; public string Name; + public uint PersistentId; - public bool ActivatesEvenIfDisconnected; - public bool IsThrottleLocked; - public int ResourcePriority; - public double ResourceRequestRemainingThreshold; - public bool IsEnabled; + public string Ident => Invariant($"{Name}-{PersistentId}"); + + public bool ActivatesEvenIfDisconnected = true; + public bool IsThrottleLocked = false; + public int ResourcePriority = 0; + public double ResourceRequestRemainingThreshold = 1E-12; + public bool IsEnabled = false; public double Mass; public double DryMass; - public double CrewMass; - public double ModulesStagedMass; - public double ModulesUnstagedMass; - public double DisabledResourcesMass; - public double EngineResiduals; - - public bool IsRoot; - public bool IsLaunchClamp; - public bool IsEngine; + public double CrewMass = 0; + public double ModulesStagedMass = 0; + public double ModulesUnstagedMass = 0; + public double DisabledResourcesMass = 0; + public double EngineResiduals = 0; + + public bool IsRoot = false; + public bool IsLaunchClamp = false; + public bool IsEngine = false; public bool IsSepratron => IsEngine && IsThrottleLocked && ActivatesEvenIfDisconnected && InverseStage == DecoupledInStage; private SimPart() @@ -224,40 +227,81 @@ public double RCSMaxTime() public override string ToString() { var sb = new StringBuilder(); - sb.AppendLine(Invariant($"SimPart '{Name}':")); - sb.AppendLine(Invariant($" InverseStage={InverseStage} DecoupledInStage={DecoupledInStage} StagingOn={StagingOn}")); - sb.AppendLine(Invariant( - $" IsRoot={IsRoot} IsEngine={IsEngine} IsLaunchClamp={IsLaunchClamp} IsThrottleLocked={IsThrottleLocked} ActivatesEvenIfDisconnected={ActivatesEvenIfDisconnected} IsEnabled={IsEnabled}")); - sb.AppendLine(Invariant($" ResourcePriority={ResourcePriority} ResourceRequestRemainingThreshold={ResourceRequestRemainingThreshold}")); - sb.AppendLine(Invariant( - $" Mass={Mass} DryMass={DryMass} CrewMass={CrewMass} ModulesStagedMass={ModulesStagedMass} ModulesUnstagedMass={ModulesUnstagedMass} DisabledResourcesMass={DisabledResourcesMass} EngineResiduals={EngineResiduals}")); - - sb.Append(" Links:"); - foreach (SimPart p in Links) - sb.Append(Invariant($" {p.Name}")); - sb.AppendLine(); + sb.AppendLine(Invariant($"SimPart '{Ident}':")); - sb.Append(" SymmetryCounterParts:"); - foreach (SimPart p in SymmetryCounterParts) - sb.Append(Invariant($" {p.Name}")); - sb.AppendLine(); + // only emit fields that differ from their declared default, so the dump focuses on what a fixture needs to set + var fields = new List(); - sb.Append(" CrossFeedPartSet:"); - foreach (SimPart p in CrossFeedPartSet) - sb.Append(Invariant($" {p.Name}")); - sb.AppendLine(); + void B(string name, bool val, bool def) + { + if (val != def) fields.Add(Invariant($"{name}={val}")); + } - sb.Append(" Resources:"); - foreach (SimResource r in Resources.Values) - sb.Append(Invariant( - $" [id={r.Id} amount={r.Amount} maxAmount={r.MaxAmount} density={r.Density} free={r.Free} residual={r.Residual}]")); - sb.AppendLine(); + void I(string name, int val, int def) + { + if (val != def) fields.Add(Invariant($"{name}={val}")); + } - sb.AppendLine(Invariant($" Modules ({Modules.Count}):")); - foreach (SimPartModule m in Modules) - sb.AppendLine(m.ToString().Indent(4)); + void D(string name, double val, double def) + { + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (val != def) fields.Add(Invariant($"{name}={val}")); + } + + I("InverseStage", InverseStage, -1); + I("DecoupledInStage", DecoupledInStage, -1); + B("StagingOn", StagingOn, true); + B("IsRoot", IsRoot, false); + B("IsEngine", IsEngine, false); + B("IsLaunchClamp", IsLaunchClamp, false); + B("IsThrottleLocked", IsThrottleLocked, false); + B("ActivatesEvenIfDisconnected", ActivatesEvenIfDisconnected, true); + B("IsEnabled", IsEnabled, false); + I("ResourcePriority", ResourcePriority, 0); + D("ResourceRequestRemainingThreshold", ResourceRequestRemainingThreshold, 1E-12); + D("Mass", Mass, 0); + D("DryMass", DryMass, 0); + D("CrewMass", CrewMass, 0); + D("ModulesStagedMass", ModulesStagedMass, 0); + D("ModulesUnstagedMass", ModulesUnstagedMass, 0); + D("DisabledResourcesMass", DisabledResourcesMass, 0); + D("EngineResiduals", EngineResiduals, 0); + + if (fields.Count > 0) + sb.AppendLine(" " + string.Join(" ", fields)); + + AppendParts(sb, "Links", Links); + AppendParts(sb, "SymmetryCounterParts", SymmetryCounterParts); + AppendParts(sb, "CrossFeedPartSet", CrossFeedPartSet); + + if (Resources.Count > 0) + { + sb.Append(" Resources:"); + foreach (SimResource r in Resources.Values) + sb.Append(Invariant( + $" [id={r.Id} amount={r.Amount} maxAmount={r.MaxAmount} density={r.Density} free={r.Free} residual={r.Residual}]")); + sb.AppendLine(); + } + + if (Modules.Count > 0) + { + sb.AppendLine(Invariant($" Modules ({Modules.Count}):")); + foreach (SimPartModule m in Modules) + sb.AppendLine(m.ToString().Indent(4)); + } return sb.ToString().TrimEnd(); } + + private static void AppendParts(StringBuilder sb, string name, List parts) + { + if (parts.Count == 0) + return; + + sb.Append(Invariant($" {name}:")); + foreach (SimPart p in parts) + sb.Append(Invariant($" {p.Ident}")); + sb.AppendLine(); + } } } diff --git a/MechJebLib/FuelFlowSimulation/SimPartModule.cs b/MechJebLib/FuelFlowSimulation/SimPartModule.cs index 9414a5282..300a7fe88 100644 --- a/MechJebLib/FuelFlowSimulation/SimPartModule.cs +++ b/MechJebLib/FuelFlowSimulation/SimPartModule.cs @@ -4,21 +4,46 @@ */ using System; +using System.Collections.Generic; using static System.FormattableString; namespace MechJebLib.FuelFlowSimulation { public abstract class SimPartModule : IDisposable { - public bool IsEnabled; + public bool IsEnabled = false; public SimPart Part = null!; - public bool ModuleIsEnabled; - public bool StagingEnabled; + public bool ModuleIsEnabled = true; + public bool StagingEnabled = true; public abstract void Dispose(); - // The fields common to every SimPartModule, for the concrete ToString() debug dumps to include. - protected string CommonFields() => - Invariant($"IsEnabled={IsEnabled} ModuleIsEnabled={ModuleIsEnabled} StagingEnabled={StagingEnabled}"); + // Adds "name=value" to the token list only when the value differs from its declared default, so the concrete + // ToString() debug dumps stay focused on what a fixture actually needs to set. + protected static void AddField(List fields, string name, bool val, bool def) + { + if (val != def) fields.Add(Invariant($"{name}={val}")); + } + + protected static void AddField(List fields, string name, double val, double def) + { + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (val != def) fields.Add(Invariant($"{name}={val}")); + } + + // The fields common to every SimPartModule, for the concrete ToString() dumps to prepend to their own fields. + protected List CommonFieldList() + { + var fields = new List(); + AddField(fields, "IsEnabled", IsEnabled, false); + AddField(fields, "ModuleIsEnabled", ModuleIsEnabled, true); + AddField(fields, "StagingEnabled", StagingEnabled, true); + return fields; + } + + // Composes the header line of a module dump ("SimModuleX: tok tok ..."), with no trailing space when no fields + // differ from their defaults. + protected static string ModuleLine(string type, List fields) => + fields.Count == 0 ? type + ":" : type + ": " + string.Join(" ", fields); } } diff --git a/MechJebLib/Primitives/H1.cs b/MechJebLib/Primitives/H1.cs index e8e91dc18..210d3e75e 100644 --- a/MechJebLib/Primitives/H1.cs +++ b/MechJebLib/Primitives/H1.cs @@ -49,6 +49,8 @@ protected override double Interpolant(double x1, double y1, double yp1, double x private static void Clear(H1 h) => h.Clear(); + public bool IsEmpty => _list.Count == 0; + // Debug dump of the raw keyframes, in a form that mirrors HBase.Add(time, value, inTangent, outTangent) so the // curve can be transcribed into a test fixture. HBase/H3/Hn are effectively deprecated so this lives only on H1. public override string ToString() diff --git a/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs b/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs index 5a707b00c..30a3581d6 100644 --- a/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs +++ b/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs @@ -147,6 +147,7 @@ private SimPart BuildPart(Part kspPart) var part = SimPart.Borrow(_vessel, kspPart.partName); part.InverseStage = kspPart.inverseStage; + part.PersistentId = kspPart.persistentId; part.ActivatesEvenIfDisconnected = kspPart.ActivatesEvenIfDisconnected; part.StagingOn = kspPart.stagingOn; part.ResourcePriority = kspPart.GetResourcePriority(); diff --git a/MechJebLibBindings/FuelFlowSimulation/SimVesselManager.cs b/MechJebLibBindings/FuelFlowSimulation/SimVesselManager.cs index 8107283a7..7d816727d 100644 --- a/MechJebLibBindings/FuelFlowSimulation/SimVesselManager.cs +++ b/MechJebLibBindings/FuelFlowSimulation/SimVesselManager.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using MechJebLib.FuelFlowSimulation; using MechJebLib.Primitives; +using static MechJebLib.Utils.Statics; namespace MechJebLibBindings.FuelFlowSimulation { @@ -52,6 +53,8 @@ public void Build(IShipconstruct vessel) _builder.UpdateEngineSet(); } + public void PrintVessel() => Print($"{_vessel}"); + public void Update() => _updater.Update(); public void SetConditions(double atmDensity, double atmPressure, double machNumber) =>