diff --git a/Source/RealismOverhaul.csproj b/Source/RealismOverhaul.csproj
index d1c4982b88..c348812d80 100644
--- a/Source/RealismOverhaul.csproj
+++ b/Source/RealismOverhaul.csproj
@@ -111,6 +111,9 @@
+
+
+
diff --git a/Source/VesselModuleRotationRO.cs b/Source/VesselModuleRotationRO.cs
index d6fdcd7bad..83fbba4f73 100644
--- a/Source/VesselModuleRotationRO.cs
+++ b/Source/VesselModuleRotationRO.cs
@@ -11,6 +11,14 @@ public class VesselModuleRotationRO : VesselModule
[KSPField(isPersistant = true)]
public Vector3 angularVelocity;
+ [KSPField(isPersistant = true)]
+ public Quaternion vesselRot;
+
+ private static int VERSION = 2;
+ [KSPField(isPersistant = true)]
+ public int loadedVersion = 0;
+
+
// True if we are keeping the vessel oriented toward the SAS target
[KSPField(isPersistant = true)]
public bool autopilotTargetHold;
@@ -48,55 +56,110 @@ public class VesselModuleRotationRO : VesselModule
public int autopilotContextCurrent;
// SAS target direction is made available for the ModuleTorqueController
+ [KSPField(isPersistant = true)]
public Vector3 targetDirection;
- // Note this is the magnitude, so 0.5 implies 0.3deg/sec in each axis, give or take.
private const float RotationThreshold = 0.1f * Mathf.Deg2Rad;
private const float RotationThresholdSAS = 0.5f * Mathf.Deg2Rad;
- private static double GetUT() => HighLogic.LoadedSceneIsEditor ? HighLogic.CurrentGame.UniversalTime : Planetarium.GetUniversalTime();
+ private static Vector3d ToPlanetarium(Vector3d vec)
+ {
+ return Planetarium.Zup.LocalToWorld(vec.xzy);
+ }
- private bool isEnabled = true;
- private bool shouldCheckEnabled = true;
+ private static Vector3 ToUnity(Vector3d vec)
+ {
+ return Planetarium.Zup.WorldToLocal(vec).xzy;
+ }
- private bool CheckEnabled()
+ private Vector3 ToVesselLocal(Vector3d vec)
{
- shouldCheckEnabled = false;
+ return Quaternion.Inverse(vessel.GetTransform().rotation) * ToUnity(vec);
+ }
+
+ private static bool _isEnabled = true;
+ private static bool _shouldCheckEnabled = true;
+
+ private static bool CheckEnabled()
+ {
+ _shouldCheckEnabled = false;
foreach (var a in AssemblyLoader.loadedAssemblies)
{
// ksp_plugin_adapter is Principia
if (a.name == "PersistentRotation" || a.name == "PersistentRotationUpgraded" || a.name == "ksp_plugin_adapter" || a.name == "MandatoryRCS")
{
- isEnabled = false;
+ _isEnabled = false;
break;
}
}
- return isEnabled;
+ return _isEnabled;
}
- private bool IsEnabled => shouldCheckEnabled ? CheckEnabled() : isEnabled;
+ private static bool IsEnabled => _shouldCheckEnabled ? CheckEnabled() : _isEnabled;
private bool IsOverThreshold(Vector3 rot)
{
- float thresh = Vessel.Autopilot.Enabled ? RotationThresholdSAS : RotationThreshold;
+ float thresh = vessel.Autopilot.Enabled ? RotationThresholdSAS : RotationThreshold;
return Mathf.Abs(rot.x) > thresh || Mathf.Abs(rot.y) > thresh || Mathf.Abs(rot.z) > thresh;
}
+ private void StoreRot()
+ {
+ QuaternionD rot = vessel.transform.rotation;
+ vesselRot = Planetarium.Zup.Rotation * rot.swizzle;
+ }
+
+ private Quaternion UnityRot()
+ {
+ return (QuaternionD.Inverse(Planetarium.Zup.Rotation) * (QuaternionD)vesselRot).swizzle;
+ }
+
+ private void SetRot()
+ {
+ if (IgnoreRot)
+ return;
+
+ vessel.SetRotation(UnityRot(), true);
+ }
+
+ private bool IgnoreRot => vessel.situation == Vessel.Situations.PRELAUNCH || vessel.situation == Vessel.Situations.LANDED || vessel.situation == Vessel.Situations.SPLASHED;
+
+ protected override void OnLoad(ConfigNode node)
+ {
+ base.OnLoad(node);
+ if (loadedVersion < VERSION)
+ {
+ if (loadedVersion < 2)
+ {
+ angularVelocity = Vector3d.zero;
+ targetDirection = ToPlanetarium(vessel.GetTransform().up);
+ StoreRot();
+ }
+ loadedVersion = VERSION;
+ }
+
+ SetRot();
+ }
+
+ public override void OnUnloadVessel()
+ {
+ base.OnUnloadVessel();
+ StoreRot();
+ }
+
private void FixedUpdate()
{
if (!IsEnabled)
return;
bool packRotate = false;
- if (Vessel.loaded)
+ if (vessel.loaded)
{
- targetDirection = AutopilotTargetDirection();
-
// Vessel is loaded but not in physics, either because
// - It is in the physics bubble but in non-physics timewarp
// - It has gone outside of the physics bubble
// - It was just loaded, is in the physics bubble and will be unpacked in a few frames
- if (Vessel.packed)
+ if (vessel.packed)
{
// Check if target / maneuver is modified/deleted during timewarp
if (autopilotTargetHold && TimeWarp.WarpMode == TimeWarp.Modes.HIGH && TimeWarp.CurrentRateIndex > 0)
@@ -126,15 +189,15 @@ private void FixedUpdate()
{
if (autopilotContext == autopilotContextCurrent) // Abort if the navball context (orbit/surface/target) has changed
{
- // Debug.Log("[US] " + Vessel.vesselName + " going OFF rails : applying rotation toward SAS target, autopilotMode=" + autopilotMode + ", targetMode=" + autopilotContext);
+ // Debug.Log("[US] " + vessel.vesselName + " going OFF rails : applying rotation toward SAS target, autopilotMode=" + autopilotMode + ", targetMode=" + autopilotContext);
RotateTowardTarget();
}
restoreAutopilotTarget = false;
}
if (restoreAngularVelocity) // Restoring saved rotation if it was above the threshold
{
- // Debug.Log("[US] " + Vessel.vesselName + " going OFF rails : restoring angular velocity, angvel=" + angularVelocity.magnitude);
- if (IsOverThreshold(angularVelocity))
+ // Debug.Log("[US] " + vessel.vesselName + " going OFF rails : restoring angular velocity, angvel=" + angularVelocity.magnitude);
+ if (IsOverThreshold(ToVesselLocal(angularVelocity)))
{
ApplyAngularVelocity();
okToSaveAngularVelocity = false;
@@ -164,27 +227,30 @@ private void FixedUpdate()
// Saving angular velocity (if we can), SAS mode, and check target hold status
SaveOffRailsStatus(okToSaveAngularVelocity);
}
- else if (FlightGlobals.ready)
+ }
+ else if (FlightGlobals.ready)
+ {
+ packRotate = true;
+ }
+
+ if (packRotate)
+ {
+ // If angular velocity is over the threshold, rotate--even if we have SAS on. No cheating Newton!
+ if (IsOverThreshold(ToVesselLocal(angularVelocity)))
{
- packRotate = true;
+ RotatePacked();
+ StoreRot();
}
-
- if (packRotate)
+ // We keep the vessel rotated toward the SAS target
+ else if (autopilotTargetHold)
{
- // If angular velocity is over the threshold, rotate--even if we have SAS on. No cheating Newton!
- if (IsOverThreshold(angularVelocity))
- {
- RotatePacked();
- }
- // We keep the vessel rotated toward the SAS target
- else if (autopilotTargetHold)
- {
- RotateTowardTarget();
- }
+ RotateTowardTarget();
+ StoreRot();
}
-
- lastUT = GetUT();
}
+
+ lastUT = Planetarium.GetUniversalTime();
+
// Saving this FixedUpdate target, autopilot context and maneuver node, to check if they have changed in the next FixedUpdate
SaveLastUpdateStatus();
}
@@ -203,21 +269,21 @@ public override void OnGoOffRails()
private void ApplyAngularVelocity()
{
- if (Vessel.situation == Vessel.Situations.PRELAUNCH || Vessel.situation == Vessel.Situations.LANDED || Vessel.situation == Vessel.Situations.SPLASHED)
+ if (IgnoreRot)
{
return;
}
- // Debug.Log("[US] Restoring " + Vessel.vesselName + "rotation after timewarp/load" );
- Vector3 COM = Vessel.CoM;
- Quaternion rotation = Vessel.ReferenceTransform.rotation;
+ // Debug.Log("[US] Restoring " + vessel.vesselName + "rotation after timewarp/load" );
+ Vector3 COM = vessel.CoM;
+ Vector3 angVel = ToUnity(angularVelocity);
// Applying force on every part
- foreach (Part p in Vessel.parts)
+ foreach (Part p in vessel.parts)
{
if (!p.GetComponent()) continue;
- p.GetComponent().AddTorque(rotation * angularVelocity, ForceMode.VelocityChange);
- p.GetComponent().AddForce(Vector3.Cross(rotation * angularVelocity, (p.transform.position - COM)), ForceMode.VelocityChange);
+ p.GetComponent().AddTorque(angVel, ForceMode.VelocityChange);
+ p.GetComponent().AddForce(Vector3.Cross(angVel, (p.transform.position - COM)), ForceMode.VelocityChange);
// Doing this through rigidbody is deprecated but I can't find a reliable way to use the 1.2 part.addforce/addtorque so they provide reliable results
// see 1.2 patchnotes and unity docs for ForceMode.VelocityChange/ForceMode.Force
@@ -226,37 +292,32 @@ private void ApplyAngularVelocity()
private void RotateTowardTarget()
{
- if (Vessel.situation == Vessel.Situations.PRELAUNCH || Vessel.situation == Vessel.Situations.LANDED || Vessel.situation == Vessel.Situations.SPLASHED)
+ if (IgnoreRot)
{
return;
}
- Vessel.SetRotation(FromToRotation(Vessel.GetTransform().up, targetDirection) * Vessel.transform.rotation, true); // SetPos=false seems to break the game on some occasions...
+ vessel.SetRotation(FromToRotation(vessel.GetTransform().up, ToUnity(targetDirection)) * vessel.transform.rotation, true); // SetPos=false seems to break the game on some occasions...
}
private void RotatePacked()
{
- if (Vessel.situation == Vessel.Situations.PRELAUNCH || Vessel.situation == Vessel.Situations.LANDED || Vessel.situation == Vessel.Situations.SPLASHED)
+ if (IgnoreRot)
{
return;
}
- double timestep = lastUT < 0 ? TimeWarp.fixedDeltaTime : (GetUT() - lastUT);
+ double timestep = lastUT < 0 ? TimeWarp.fixedDeltaTime : (Planetarium.GetUniversalTime() - lastUT);
timestep *= 50d; // for some reason we need to divide out normal fixed delta time of 0.02s
- double rotAngle = (double)angularVelocity.magnitude * timestep;
- int subMult = (int)(rotAngle / 360d);
- if (subMult > 0)
- {
- rotAngle -= subMult * 360d;
- }
+ double rotAngleRadians = (double)angularVelocity.magnitude * timestep;
- Vessel.SetRotation(Quaternion.AngleAxis((float)rotAngle, Vessel.ReferenceTransform.rotation * angularVelocity) * Vessel.transform.rotation, true); // false seems to fix the "infinite roll bug"
+ vessel.SetRotation(Quaternion.AngleAxis((float)rotAngleRadians, ToUnity(angularVelocity)) * UnityRot(), true); // false seems to fix the "infinite roll bug"
}
private bool RestoreSASMode(int mode)
{
- if (Vessel.Autopilot.Enabled)
+ if (vessel.Autopilot.Enabled)
{
- return Vessel.Autopilot.SetMode((VesselAutopilot.AutopilotMode)mode);
+ return vessel.Autopilot.SetMode((VesselAutopilot.AutopilotMode)mode);
}
else
{
@@ -271,45 +332,63 @@ private void SaveOffRailsStatus(bool okToSaveAngularVelocity)
// otherwise we might zero it out by mistake.
if (okToSaveAngularVelocity)
{
- if (IsOverThreshold(Vessel.angularVelocity))
+ if (IsOverThreshold(vessel.angularVelocity))
{
- angularVelocity = Vessel.angularVelocity;
+ float mass = 0f;
+ Vector3 aVel = Vector3.zero;
+ foreach (var p in vessel.Parts)
+ {
+ if (p.rb != null)
+ {
+ float m = (float)p.physicsMass;
+ aVel += p.rb.angularVelocity * m;
+ mass += m;
+ }
+ }
+ if (mass > 0f)
+ aVel /= mass;
+ angularVelocity = ToPlanetarium(aVel);
+ //angularVelocity = ToPlanetarium(Quaternion.Inverse(vessel.ReferenceTransform.rotation) * vessel.angularVelocity);
}
else
{
- angularVelocity = Vector3.zero;
+ angularVelocity = Vector3d.zero;
}
}
// Checking if the autopilot hold mode should be enabled
- if (Vessel.Autopilot.Enabled
- && !(Vessel.Autopilot.Mode.Equals(VesselAutopilot.AutopilotMode.StabilityAssist))
- && !IsOverThreshold(angularVelocity) // The vessel isn't rotating too much
- && Vector3.Dot(Vessel.Autopilot.SAS.targetOrientation.normalized, Vessel.GetTransform().up.normalized) > 0.999f) // about 2.5 degrees
+ if (vessel.Autopilot.Enabled
+ && !(vessel.Autopilot.Mode.Equals(VesselAutopilot.AutopilotMode.StabilityAssist))
+ && !IsOverThreshold(ToVesselLocal(angularVelocity)) // The vessel isn't rotating too much
+ && Vector3.Dot(vessel.Autopilot.SAS.targetOrientation.normalized, vessel.GetTransform().up.normalized) > 0.999f) // about 2.5 degrees
{
autopilotTargetHold = true;
+ targetDirection = ToPlanetarium(AutopilotTargetDirection());
}
else
{
autopilotTargetHold = false;
+ targetDirection = Vector3d.zero;
}
// Saving the current SAS mode
- autopilotMode = (int)Vessel.Autopilot.Mode;
+ autopilotMode = (int)vessel.Autopilot.Mode;
+
+ StoreRot();
}
private void SaveLastUpdateStatus()
{
// Saving the current target
- lastTarget = Vessel.targetObject;
+ lastTarget = vessel.targetObject;
// Saving the current autopilot context
autopilotContext = autopilotContextCurrent;
// Saving the maneuver vector magnitude
- if (Vessel.patchedConicSolver != null)
+ if (vessel.patchedConicSolver != null)
{
- if (Vessel.patchedConicSolver.maneuverNodes.Count > 0)
+ if (vessel.patchedConicSolver.maneuverNodes.Count > 0)
{
- lastManeuverParameters = Vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude + Vessel.patchedConicSolver.maneuverNodes[0].UT;
+ lastManeuverParameters = vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude + vessel.patchedConicSolver.maneuverNodes[0].UT;
}
}
}
@@ -323,7 +402,7 @@ private bool TargetHoldValidity()
}
// Disable target hold if target was modified
- if ((autopilotMode == 7 || autopilotMode == 8 || autopilotContext == 2) && Vessel.targetObject != lastTarget)
+ if ((autopilotMode == 7 || autopilotMode == 8 || autopilotContext == 2) && vessel.targetObject != lastTarget)
{
return false;
}
@@ -331,11 +410,11 @@ private bool TargetHoldValidity()
// Disable target hold if the maneuver node was modified or deleted
if (autopilotMode == 9)
{
- if (Vessel.patchedConicSolver.maneuverNodes.Count == 0)
+ if (vessel.patchedConicSolver.maneuverNodes.Count == 0)
{
return false;
}
- else if (Math.Abs(Vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude + Vessel.patchedConicSolver.maneuverNodes[0].UT) - Math.Abs(lastManeuverParameters) > 0.01f)
+ else if (Math.Abs(vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude + vessel.patchedConicSolver.maneuverNodes[0].UT) - Math.Abs(lastManeuverParameters) > 0.01f)
{
return false;
}
@@ -353,15 +432,15 @@ private Vector3 AutopilotTargetDirection()
if (autopilotMode == 1 || autopilotMode == 2)
{
if (autopilotContext == 0) // Orbit prograde
- target = Vessel.obt_velocity;
+ target = vessel.obt_velocity;
else if (autopilotContext == 1) // Surface prograde
- target = Vessel.srf_velocity;
+ target = vessel.srf_velocity;
else if (autopilotContext == 2) // Target prograde
{
- if (Vessel.targetObject != null)
- target = -(Vessel.targetObject.GetObtVelocity() - Vessel.obt_velocity);
+ if (vessel.targetObject != null)
+ target = -(vessel.targetObject.GetObtVelocity() - vessel.obt_velocity);
else
- return Vessel.GetTransform().up;
+ return vessel.GetTransform().up;
}
if (autopilotMode == 2) // Invert vector for retrograde
@@ -374,14 +453,14 @@ private Vector3 AutopilotTargetDirection()
else if (autopilotMode == 3 || autopilotMode == 4 || autopilotMode == 5 || autopilotMode == 6)
{
// Get body up vector
- Vector3 planetUp = (Vessel.rootPart.transform.position - Vessel.mainBody.position).normalized;
+ Vector3 planetUp = (vessel.rootPart.transform.position - vessel.mainBody.position).normalized;
// Get normal vector
Vector3 normal = new Vector3();
if (autopilotContext == 0) // Orbit
- normal = Vector3.Cross(Vessel.obt_velocity, planetUp).normalized;
+ normal = Vector3.Cross(vessel.obt_velocity, planetUp).normalized;
else if (autopilotContext == 1 || autopilotContext == 2) // Surface/Target (seems to be the same for normal/radial)
- normal = Vector3.Cross(Vessel.srf_velocity, planetUp).normalized;
+ normal = Vector3.Cross(vessel.srf_velocity, planetUp).normalized;
// Return normal/antinormal or calculate radial
if (autopilotMode == 3) // Normal
@@ -393,9 +472,9 @@ private Vector3 AutopilotTargetDirection()
// Get RadialIn vector
Vector3 radial = new Vector3();
if (autopilotContext == 0) // Orbit
- radial = Vector3.Cross(Vessel.obt_velocity, normal).normalized;
+ radial = Vector3.Cross(vessel.obt_velocity, normal).normalized;
else if (autopilotContext == 1 || autopilotContext == 2) // Surface/Target (seems to be the same for normal/radial)
- radial = Vector3.Cross(Vessel.srf_velocity, normal).normalized;
+ radial = Vector3.Cross(vessel.srf_velocity, normal).normalized;
// Return radial vector
if (autopilotMode == 5) // Radial In
@@ -408,31 +487,31 @@ private Vector3 AutopilotTargetDirection()
// Target/Antitarget
else if (autopilotMode == 7 || autopilotMode == 8)
{
- if (Vessel.targetObject != null)
+ if (vessel.targetObject != null)
{
if (autopilotMode == 7) // Target
- target = Vessel.targetObject.GetTransform().position - Vessel.transform.position;
+ target = vessel.targetObject.GetTransform().position - vessel.GetTransform().position;
else if (autopilotMode == 8) // AntiTarget
- target = -(Vessel.targetObject.GetTransform().position - Vessel.transform.position);
+ target = -(vessel.targetObject.GetTransform().position - vessel.GetTransform().position);
}
else
{
// No orientation keeping if target is null
- return Vessel.GetTransform().up;
+ return vessel.GetTransform().up;
}
}
// Maneuver
else if (autopilotMode == 9)
{
- if (Vessel.patchedConicSolver.maneuverNodes.Count > 0)
+ if (vessel.patchedConicSolver.maneuverNodes.Count > 0)
{
- target = Vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(Vessel.orbit);
+ target = vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(vessel.orbit);
}
else
{
// No orientation keeping if there is no more maneuver node
- return Vessel.GetTransform().up;
+ return vessel.GetTransform().up;
}
}
@@ -441,7 +520,7 @@ private Vector3 AutopilotTargetDirection()
{
// Abort orientation keeping
// autopilotTargetHold = false;
- return Vessel.GetTransform().up;
+ return vessel.GetTransform().up;
}
return target;
@@ -457,4 +536,4 @@ private Quaternion FromToRotation(Vector3d fromv, Vector3d tov) //Stock FromToRo
return new QuaternionD(cross.x * norm, cross.y * norm, cross.z * norm, wval * norm);
}
}
-}
+}
\ No newline at end of file