diff --git a/.idea/.idea.MechJeb2/.idea/.name b/.idea/.idea.MechJeb2/.idea/.name
new file mode 100644
index 000000000..43692dea2
--- /dev/null
+++ b/.idea/.idea.MechJeb2/.idea/.name
@@ -0,0 +1 @@
+MechJeb2
\ No newline at end of file
diff --git a/MechJeb2.sln.DotSettings b/MechJeb2.sln.DotSettings
index feb718a5d..3bb805e6a 100644
--- a/MechJeb2.sln.DotSettings
+++ b/MechJeb2.sln.DotSettings
@@ -24,6 +24,7 @@
KSP
LAN
LD
+ LH
LQR
MET
MJ
@@ -32,6 +33,8 @@
PVG
RC
RCS
+ RH
+ RHS
RK
RO
SI
diff --git a/MechJeb2/Maneuver/TransferCalculator.cs b/MechJeb2/Maneuver/TransferCalculator.cs
index e94e8897e..cc8ae8027 100644
--- a/MechJeb2/Maneuver/TransferCalculator.cs
+++ b/MechJeb2/Maneuver/TransferCalculator.cs
@@ -351,11 +351,11 @@ private void AdjustPeriapsis(ManeuverParameters maneuver, ref double utArrival)
Debug.Log("maneuver guess dV: " + maneuver.dV);
Debug.Log("maneuver guess UT: " + maneuver.UT);
Debug.Log("arrival guess UT: " + utArrival);
- _initialOrbit.GetOrbitalStateVectorsAtUT(maneuver.UT, out Vector3d r1, out Vector3d v1);
+ _initialOrbit.FixedGetOrbitalStateVectorsAtUT(maneuver.UT, out Vector3d r1, out Vector3d v1);
Debug.Log($"initial orbit at {maneuver.UT} x = {r1}; v = {v1}");
- _initialOrbit.referenceBody.orbit.GetOrbitalStateVectorsAtUT(maneuver.UT, out Vector3d r2, out Vector3d v2);
+ _initialOrbit.referenceBody.orbit.FixedGetOrbitalStateVectorsAtUT(maneuver.UT, out Vector3d r2, out Vector3d v2);
Debug.Log($"source at {maneuver.UT} x = {r2}; v = {v2}");
- _targetBody.orbit.GetOrbitalStateVectorsAtUT(utArrival, out Vector3d r3, out Vector3d v3);
+ _targetBody.orbit.FixedGetOrbitalStateVectorsAtUT(utArrival, out Vector3d r3, out Vector3d v3);
Debug.Log($"source at {utArrival} x = {r3}; v = {v3}");
_impulseScale = maneuver.dV.magnitude;
diff --git a/MechJeb2/MechJebCore.cs b/MechJeb2/MechJebCore.cs
index 36f6f2881..cf9333768 100644
--- a/MechJeb2/MechJebCore.cs
+++ b/MechJeb2/MechJebCore.cs
@@ -787,7 +787,7 @@ public override void OnLoad(ConfigNode sfsNode)
LoadComputerModules();
var global = new ConfigNode("MechJebGlobalSettings");
- if (File.Exists("mechjeb_settings_global.cfg"))
+ if (MuUtils.FileExistsCreateDirectory(MuUtils.GetCfgPath("mechjeb_settings_global.cfg")))
{
try
{
@@ -809,7 +809,7 @@ public override void OnLoad(ConfigNode sfsNode)
vessel != null
? string.Join("_", vessel.vesselName.Split(Path.GetInvalidFileNameChars()))
: ""; // Strip illegal char from the filename
- if (vessel != null && File.Exists("mechjeb_settings_type_" + vesselName + ".cfg"))
+ if (vessel != null && MuUtils.FileExistsCreateDirectory(MuUtils.GetCfgPath("mechjeb_settings_type_" + vesselName + ".cfg")))
{
try
{
diff --git a/MechJeb2/MechJebModuleAscentMenu.cs b/MechJeb2/MechJebModuleAscentMenu.cs
index 92ae1c1ec..d8f1117da 100644
--- a/MechJeb2/MechJebModuleAscentMenu.cs
+++ b/MechJeb2/MechJebModuleAscentMenu.cs
@@ -49,18 +49,11 @@ private bool _launchingToLan
private bool _launchingWithAnyPlaneControl => _launchingToPlane || _launchingToRendezvous || _launchingToMatchLan || _launchingToLan;
- private MechJebModuleAscentBaseAutopilot _autopilot => Core.Ascent;
- private MechJebModuleAscentSettings _ascentSettings => Core.AscentSettings;
- private MechJebModuleAscentClassicPathMenu _classicPathMenu;
- private MechJebModuleAscentPVGSettingsMenu _pvgSettingsMenu;
- private MechJebModuleAscentSettingsMenu _settingsMenu;
-
- public override void OnStart(PartModule.StartState state)
- {
- _pvgSettingsMenu = Core.GetComputerModule();
- _settingsMenu = Core.GetComputerModule();
- _classicPathMenu = Core.GetComputerModule();
- }
+ private MechJebModuleAscentBaseAutopilot _autopilot => Core.Ascent;
+ private MechJebModuleAscentSettings _ascentSettings => Core.AscentSettings;
+ private MechJebModuleAscentClassicPathMenu _classicPathMenu => Core.GetComputerModule();
+ private MechJebModuleAscentPVGSettingsMenu _pvgSettingsMenu => Core.GetComputerModule();
+ private MechJebModuleAscentSettingsMenu _settingsMenu => Core.GetComputerModule();
[UsedImplicitly]
[Persistent(pass = (int)Pass.GLOBAL)]
diff --git a/MechJeb2/MechJebModuleNodeExecutor.cs b/MechJeb2/MechJebModuleNodeExecutor.cs
index 83473513a..dffee32e2 100644
--- a/MechJeb2/MechJebModuleNodeExecutor.cs
+++ b/MechJeb2/MechJebModuleNodeExecutor.cs
@@ -300,7 +300,7 @@ private void StateBurn()
private void SetAttitude()
{
- Core.Attitude.attitudeTo(_worldDirection, AttitudeReference.INERTIAL, this, killRollRotation:KillRollRotation);
+ Core.Attitude.attitudeTo(_worldDirection, AttitudeReference.INERTIAL_COT, this, killRollRotation:KillRollRotation);
}
private bool ShouldTerminatePrincipia()
diff --git a/MechJeb2/MechJebModuleStagingController.cs b/MechJeb2/MechJebModuleStagingController.cs
index 9ef5e7c1b..ef3364a31 100644
--- a/MechJeb2/MechJebModuleStagingController.cs
+++ b/MechJeb2/MechJebModuleStagingController.cs
@@ -684,7 +684,7 @@ private bool HasFairingUncached(int inverseStage)
// payload fairing now (fixing payload fairings causing stacks to not decouple).
// if a user requires an interstage fairing that is alone in a stage with no stack decoupler, engine, or
// anything else in the stage (for cinematics?) then the user MUST use proc fairings.
- return _partsInStage.Slinq().All(p => p.IsDecoupler() && !p.IsLaunchClamp() && p.children.Count == 0);
+ return _partsInStage.Slinq().All(p => ((p.IsDecoupler() && p.children.Count == 0) || p.HasModule() ) && !p.IsLaunchClamp());
}
}
}
diff --git a/MechJeb2/MechJebModuleWaypointWindow.cs b/MechJeb2/MechJebModuleWaypointWindow.cs
index 5e3a50dca..de00bfff7 100644
--- a/MechJeb2/MechJebModuleWaypointWindow.cs
+++ b/MechJeb2/MechJebModuleWaypointWindow.cs
@@ -366,7 +366,7 @@ public override void OnLoad(ConfigNode local, ConfigNode type, ConfigNode global
if (!FlightGlobals.ready) return; // bodies not loaded yet
var wps = new ConfigNode("Routes");
- if (File.Exists("mechjeb_routes.cfg"))
+ if (MuUtils.FileExistsCreateDirectory(MuUtils.GetCfgPath("mechjeb_routes.cfg")))
{
try
{
diff --git a/MechJeb2/MuUtils.cs b/MechJeb2/MuUtils.cs
index b7fbdf829..4458776cb 100644
--- a/MechJeb2/MuUtils.cs
+++ b/MechJeb2/MuUtils.cs
@@ -11,6 +11,15 @@ public static class MuUtils
public static string GetCfgPath(string file) => Path.Combine(_cfgPath, file);
+ // Duplicates the KSP.IO.File.Exist style API where it creates the directory if it doesn't exist
+ public static bool FileExistsCreateDirectory(string path)
+ {
+ string directoryName = Path.GetDirectoryName(path);
+ if (directoryName != null && !Directory.Exists(directoryName))
+ Directory.CreateDirectory(directoryName);
+ return File.Exists(path);
+ }
+
public static string PadPositive(double x, string format = "F3")
{
string s = x.ToString(format);
diff --git a/MechJeb2/OrbitExtensions.cs b/MechJeb2/OrbitExtensions.cs
index 26cae7de2..6450e0163 100644
--- a/MechJeb2/OrbitExtensions.cs
+++ b/MechJeb2/OrbitExtensions.cs
@@ -71,10 +71,21 @@ public static class OrbitExtensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static (V3 pos, V3 vel) RightHandedStateVectorsAtUT(this Orbit o, double ut)
{
- o.GetOrbitalStateVectorsAtUT(ut, out Vector3d pos, out Vector3d vel);
+ // GetOrbitalStateVectorsAtUT() uses a crazy future-rotation-at-UT to rotate vectors, so carefully avoid it.
+ o.GetOrbitalStateVectorsAtTrueAnomaly(o.TrueAnomalyAtT(o.getObtAtUT(ut)), ut, false, out Vector3d pos, out Vector3d vel);
+ pos = Planetarium.Zup.WorldToLocal(pos);
+ vel = Planetarium.Zup.WorldToLocal(vel);
return (pos.ToV3(), vel.ToV3());
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void FixedGetOrbitalStateVectorsAtUT(this Orbit o, double ut, out Vector3d pos, out Vector3d vel)
+ {
+ o.GetOrbitalStateVectorsAtTrueAnomaly(o.TrueAnomalyAtT(o.getObtAtUT(ut)), ut, false, out pos, out vel);
+ pos = Planetarium.Zup.WorldToLocal(pos);
+ vel = Planetarium.Zup.WorldToLocal(vel);
+ }
+
//normalized vector perpendicular to the orbital plane
//convention: as you look down along the orbit normal, the satellite revolves counterclockwise
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -120,51 +131,6 @@ public static Vector3d North(this Orbit o, double ut) =>
public static Orbit PerturbedOrbit(this Orbit o, double ut, Vector3d dV) =>
MuUtils.OrbitFromStateVectors(o.WorldPositionAtUT(ut), o.WorldOrbitalVelocityAtUT(ut) + dV, o.referenceBody, ut);
- // returns a new orbit that is identical to the current one (although the epoch will change)
- // (i tried many different APIs in the orbit class, but the GetOrbitalStateVectors/UpdateFromStateVectors route was the only one that worked)
- public static Orbit Clone(this Orbit o, double ut = double.NegativeInfinity)
- {
- // hack up a dynamic default value to the current time
- if (double.IsNegativeInfinity(ut))
- ut = Planetarium.GetUniversalTime();
-
- var newOrbit = new Orbit();
- o.GetOrbitalStateVectorsAtUT(ut, out Vector3d pos, out Vector3d vel);
- newOrbit.UpdateFromStateVectors(pos, vel, o.referenceBody, ut);
-
- return newOrbit;
- }
-
- // calculate the next patch, which makes patchEndTransition be valid
- //
- public static Orbit CalculateNextOrbit(this Orbit o, double ut = double.NegativeInfinity)
- {
- var solverParameters = new PatchedConics.SolverParameters();
-
- // hack up a dynamic default value to the current time
- if (double.IsNegativeInfinity(ut))
- ut = Planetarium.GetUniversalTime();
-
- o.StartUT = ut;
- o.EndUT = o.eccentricity >= 1.0 ? o.period : ut + o.period;
- var nextOrbit = new Orbit();
- PatchedConics.CalculatePatch(o, nextOrbit, ut, solverParameters, null);
-
- return nextOrbit;
- }
-
- // This does not allocate a new orbit object and the caller should call new Orbit if/when required
- public static void MutatedOrbit(this Orbit o, double periodOffset = double.NegativeInfinity)
- {
- double ut = Planetarium.GetUniversalTime();
-
- if (!periodOffset.IsFinite())
- return;
-
- o.GetOrbitalStateVectorsAtUT(ut + o.period * periodOffset, out Vector3d pos, out Vector3d vel);
- o.UpdateFromStateVectors(pos, vel, o.referenceBody, ut);
- }
-
// circular orbital speed at this instant
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double CircularOrbitSpeed(this Orbit o) => Astro.CircularVelocity(o.referenceBody.gravParameter, o.radius);
diff --git a/MechJeb2/Properties/AssemblyInfo.cs b/MechJeb2/Properties/AssemblyInfo.cs
index b70c7f70d..0a1df9a5d 100644
--- a/MechJeb2/Properties/AssemblyInfo.cs
+++ b/MechJeb2/Properties/AssemblyInfo.cs
@@ -23,18 +23,9 @@
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a903d9fe-4604-47b8-b9d9-95728538f769")]
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.5.1.0")] // We should not change it anymore. It break mods that links MJ ( cf http://support.microsoft.com/kb/556041 )
-[assembly: AssemblyFileVersion("2.15.2.0")] // this one we can change all we want
+// We use a 2.[Major].[Minor/Patch].0 naming convention
+[assembly: AssemblyVersion("2.15.0.0")] // This should be bumped for major versions/breaking changes when the 2nd number changes
+[assembly: AssemblyFileVersion("2.15.3.0")] // this one is bumped every single time for both minor/patch
[assembly: AssemblyInformationalVersion("")] // Displayed in the window title if not empty (used to display dev #)
-[assembly: KSPAssembly("MechJeb2", 2, 5)]
+[assembly: KSPAssembly("MechJeb2", 2, 15, 3)] // this one is bumped every single time for both minor/patch