diff --git a/Source/Harmony/OrbitDriver.cs b/Source/Harmony/OrbitDriver.cs
new file mode 100644
index 0000000000..300cf359f3
--- /dev/null
+++ b/Source/Harmony/OrbitDriver.cs
@@ -0,0 +1,65 @@
+using HarmonyLib;
+using UnityEngine;
+
+namespace RealismOverhaul.Harmony
+{
+ [HarmonyPatch(typeof(OrbitDriver))]
+ internal class PatchOrbitDriver
+ {
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(OrbitDriver.updateFromParameters), typeof(bool))]
+ internal static bool Prefix_updateFromParameters(OrbitDriver __instance, bool setPosition)
+ {
+ if (!setPosition
+ || !VesselModuleRotationRO.IsEnabled
+ || __instance.vessel == null
+ || (__instance.vessel.loaded && !__instance.vessel.packed)
+ || (VesselModuleRotationRO.IgnoreRot(__instance.vessel)))
+ return true;
+
+ __instance.updateUT = Planetarium.GetUniversalTime();
+ __instance.orbit.UpdateFromUT(__instance.updateUT);
+ __instance.pos = __instance.orbit.pos;
+ __instance.vel = __instance.orbit.vel;
+ __instance.pos.Swizzle();
+ __instance.vel.Swizzle();
+ if (double.IsNaN(__instance.pos.x))
+ {
+ MonoBehaviour.print("ObT : " + __instance.orbit.ObT + "\nM : " + __instance.orbit.meanAnomaly + "\nE : " + __instance.orbit.eccentricAnomaly + "\nV : "
+ + __instance.orbit.trueAnomaly + "\nRadius: " + __instance.orbit.radius + "\nvel: " + __instance.vel.ToString() + "\nAN: " + __instance.orbit.an.ToString()
+ + "\nperiod: " + __instance.orbit.period + "\n");
+
+ Debug.LogWarning("[OrbitDriver Warning!]: " + __instance.vessel.GetDisplayName() + " had a NaN Orbit and was removed.");
+ __instance.vessel.Unload();
+ UnityEngine.Object.Destroy(__instance.vessel.gameObject);
+ return false;
+ }
+ VesselModuleRotationRO mod = null;
+ foreach (var vm in __instance.vessel.vesselModules)
+ {
+ if (vm is VesselModuleRotationRO vmr)
+ {
+ mod = vmr;
+ break;
+ }
+ }
+ if (!__instance.reverse)
+ {
+ Vector3d offset = (QuaternionD)__instance.driverTransform.rotation * (Vector3d)__instance.vessel.localCoM;
+ Vector3d pos = __instance.referenceBody.position + __instance.pos - offset;
+ if (mod != null)
+ mod.RailsUpdate(pos);
+ else
+ __instance.vessel.SetPosition(pos);
+ }
+ else
+ {
+ __instance.referenceBody.position = ((Vector3d)__instance.driverTransform.position) - __instance.pos;
+ if (mod != null)
+ mod.RailsUpdate(__instance.vessel.vesselTransform.position);
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/Source/RealismOverhaul.csproj b/Source/RealismOverhaul.csproj
index 230ed9806b..586e1aed86 100644
--- a/Source/RealismOverhaul.csproj
+++ b/Source/RealismOverhaul.csproj
@@ -40,6 +40,7 @@
+
diff --git a/Source/VesselModuleRotationRO.cs b/Source/VesselModuleRotationRO.cs
index 0ff6e89b5e..79752080c8 100644
--- a/Source/VesselModuleRotationRO.cs
+++ b/Source/VesselModuleRotationRO.cs
@@ -95,7 +95,7 @@ private static bool CheckEnabled()
return _isEnabled;
}
- private static bool IsEnabled => _shouldCheckEnabled ? CheckEnabled() : _isEnabled;
+ public static bool IsEnabled => _shouldCheckEnabled ? CheckEnabled() : _isEnabled;
private bool IsOverThreshold(Vector3 rot)
{
@@ -116,13 +116,31 @@ private Quaternion UnityRot()
private void SetRot()
{
- if (IgnoreRot)
+ if (IgnoreRot(vessel))
return;
vessel.SetRotation(UnityRot(), true);
}
- private bool IgnoreRot => vessel.situation == Vessel.Situations.PRELAUNCH || vessel.situation == Vessel.Situations.LANDED || vessel.situation == Vessel.Situations.SPLASHED;
+ private void SetPosRot(Quaternion rotation, Vector3d position)
+ {
+ if (!vessel.loaded)
+ {
+ vessel.vesselTransform.rotation = rotation;
+ vessel.vesselTransform.position = position;
+ return;
+ }
+ int count = vessel.parts.Count;
+ QuaternionD rotD = rotation;
+ for (int i = 0; i < count; i++)
+ {
+ Part part = vessel.parts[i];
+ part.partTransform.rotation = rotation * part.orgRot;
+ part.partTransform.position = position + rotD * part.orgPos;
+ }
+ }
+
+ public static bool IgnoreRot(Vessel vessel) => vessel.situation == Vessel.Situations.PRELAUNCH || vessel.situation == Vessel.Situations.LANDED || vessel.situation == Vessel.Situations.SPLASHED;
protected override void OnLoad(ConfigNode node)
{
@@ -148,15 +166,11 @@ protected override void OnLoad(ConfigNode node)
SetRot();
}
- private void FixedUpdate()
+ public void RestoreState()
{
- if (!IsEnabled)
- return;
-
if (_restoreManeuverHash)
StoreManeuverHash();
- bool packRotate = false;
if (vessel.loaded)
{
if (_restoreTarget)
@@ -165,18 +179,8 @@ private void FixedUpdate()
_lastTarget = vessel.targetObject;
}
- // 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)
- {
- packRotate = true;
- }
- else if (FlightGlobals.ready) // The vessel is in physics simulation and fully loaded
+ if (!vessel.packed && FlightGlobals.ready)
{
- bool okToSaveAngularVelocity = true;
-
// Restoring previous SAS selection
if (_restoreSAS)
{
@@ -188,18 +192,9 @@ private void FixedUpdate()
_retrySASCount = 10;
}
}
-
- 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);
- ApplyAngularVelocity();
- okToSaveAngularVelocity = false;
- _restoreAngularVelocity = false;
- }
-
// When a vessel loads, VesselAutopilot gets enabled in Update based on SAS actiongroup being on
// (the actiongroup is what's persisted). So we're going to run (in FixedUpdate) before that happens.
- if (_retrySAS)
+ else if (_retrySAS)
{
if (_retrySASCount > 0)
{
@@ -216,51 +211,93 @@ private void FixedUpdate()
// Debug.Log("[US] can't set autopilot mode.");
}
}
-
- // Saving angular velocity (if we can), SAS mode, and check target hold status
- SaveOffRailsStatus(okToSaveAngularVelocity);
}
}
- else if (FlightGlobals.ready)
+ else
{
- packRotate = true;
if (_restoreTarget)
{
_restoreTarget = false;
_lastTarget = vessel.protoVessel.targetInfo?.FindTarget();
}
}
+ }
- if (packRotate)
- {
- // Check if target / maneuver is modified/deleted during timewarp
- bool holdValid = false;
- if (autopilotTargetHold)
- {
- holdValid = TargetHoldValidity();
- if (TimeWarp.WarpMode == TimeWarp.Modes.HIGH && TimeWarp.CurrentRateIndex > 0)
- autopilotTargetHold = holdValid;
- }
+ private void FixedUpdate()
+ {
+ if (!IsEnabled)
+ return;
+
+ RestoreState();
- // if we don't have over-thresh angular velocity and we do
- // have a target, orient to the target
- if (angularVelocity == Vector3.zero && autopilotTargetHold && holdValid)
+ //bool packRotate = false;
+ if (vessel.loaded)
+ {
+ // 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)
{
- RotateTowardTarget();
- StoreRot();
+ //packRotate = true;
}
- else
+ else if (FlightGlobals.ready) // The vessel is in physics simulation and fully loaded
{
- RotatePacked();
- // We don't store rot here, it relies on lastUT
- // and original orientation
+ bool okToSaveAngularVelocity = true;
+
+ 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);
+ ApplyAngularVelocity();
+ okToSaveAngularVelocity = false;
+ _restoreAngularVelocity = false;
+ }
+
+ // Saving angular velocity (if we can), SAS mode, and check target hold status
+ SaveOffRailsStatus(okToSaveAngularVelocity);
}
}
+ //else
+ //{
+ // packRotate = true;
+
+ //}
+
+ //if (packRotate)
+ //{
+ // RailsUpdate(vessel.vesselTransform.position);
+ //}
// Saving this FixedUpdate target, autopilot context and maneuver node, to check if they have changed in the next FixedUpdate
SaveLastUpdateStatus();
}
+ public void RailsUpdate(Vector3d pos)
+ {
+ // Check if target / maneuver is modified/deleted during timewarp
+ bool holdValid = false;
+ if (autopilotTargetHold)
+ {
+ holdValid = TargetHoldValidity();
+ if (TimeWarp.WarpMode == TimeWarp.Modes.HIGH && TimeWarp.CurrentRateIndex > 0)
+ autopilotTargetHold = holdValid;
+ }
+
+ // if we don't have over-thresh angular velocity and we do
+ // have a target, orient to the target
+ if (angularVelocity == Vector3.zero && autopilotTargetHold && holdValid)
+ {
+ RotateTowardTarget(pos);
+ StoreRot();
+ }
+ else
+ {
+ RotatePacked(pos);
+ // We don't store rot here, it relies on lastUT
+ // and original orientation
+ }
+ }
+
// Vessel is entering physics simulation, either by being loaded or getting out of timewarp
// Don't restore rotation/angular velocity here because the vessel/scene isn't fully loaded
// Mark it to be done in a latter FixedUpdate, where we can check for FlightGlobals.ready
@@ -291,7 +328,7 @@ public override void OnUnloadVessel()
private void ApplyAngularVelocity()
{
- if (IgnoreRot)
+ if (IgnoreRot(vessel))
{
return;
}
@@ -312,9 +349,9 @@ private void ApplyAngularVelocity()
}
}
- private void RotateTowardTarget()
+ private void RotateTowardTarget(Vector3d pos)
{
- if (IgnoreRot)
+ if (IgnoreRot(vessel))
{
return;
}
@@ -323,12 +360,12 @@ private void RotateTowardTarget()
Vector3 up = vessel.transform.TransformDirection(referenceUpLocal);
float dot = Vector3.Dot(tgt, up);
if (!vessel.loaded || dot < 0.99999f)
- vessel.SetRotation(FromToRotation(up, tgt) * vessel.transform.rotation, true); // SetPos=false seems to break the game on some occasions...
+ SetPosRot(FromToRotation(up, tgt) * vessel.transform.rotation, pos);
}
- private void RotatePacked()
+ private void RotatePacked(Vector3d pos)
{
- if (IgnoreRot)
+ if (IgnoreRot(vessel))
{
return;
}
@@ -337,7 +374,7 @@ private void RotatePacked()
// If we don't have angular velocity, just update our rotation
if (angularVelocity == Vector3.zero)
{
- vessel.SetRotation(unityRot, true);
+ SetPosRot(unityRot, pos);
return;
}
@@ -347,7 +384,7 @@ private void RotatePacked()
double fullRotations = Math.Floor(rotAngle * (1d / 360d));
rotAngle -= fullRotations * 360d;
- vessel.SetRotation(Quaternion.AngleAxis((float)rotAngle, ToUnity(angularVelocity)) * UnityRot(), true); // false seems to fix the "infinite roll bug"
+ SetPosRot(Quaternion.AngleAxis((float)rotAngle, ToUnity(angularVelocity)) * UnityRot(), pos);
}
private bool RestoreSASMode(int mode)