/* PRIVATE METHODS */ private void PackedSpin(Data.PRVessel v) { if (v.vessel.situation != Vessel.Situations.LANDED && v.vessel.situation != Vessel.Situations.SPLASHED && v.vessel.situation != Vessel.Situations.PRELAUNCH) { v.vessel.SetRotation(Quaternion.AngleAxis(v.momentum.magnitude * TimeWarp.CurrentRate, v.vessel.ReferenceTransform.rotation * v.momentum) * v.vessel.transform.rotation, true); } }
private void OnVesselGoOffRails(Vessel vessel) { Data.PRVessel v = data.FindPRVessel(vessel); if (vessel.situation != Vessel.Situations.LANDED && vessel.situation != Vessel.Situations.SPLASHED && vessel.situation != Vessel.Situations.PRELAUNCH) { if (v.rotationModeActive && v.storedAngularMomentum.magnitude > threshold) { if (GetStabilityMode(vessel) != StabilityMode.AUTOPILOT) { ApplyMomentumDelayed(v); } } else if (GetStabilityMode(vessel) != StabilityMode.ABSOLUTE) { if (GetStabilityMode(vessel) == StabilityMode.RELATIVE && !v.momentumModeActive) { Quaternion shift = Quaternion.Euler(0f, Vector3.Angle(Planetarium.right, v.planetariumRight), 0f); //Set relative rotation if there is a reference if (v.reference != null) { vessel.SetRotation(FromToRotation(shift * v.direction, (v.reference.GetTransform().position - vessel.transform.position).normalized) * (shift * v.rotation), true); } //Reset momentumModeActive heading vessel.Autopilot.SAS.lockedRotation = vessel.ReferenceTransform.rotation; } else { ApplyMomentumDelayed(v); } } } }
private void ApplyMomentumNow(Data.PRVessel v) { Vector3d angularmomentum = v.GoingOffRailsAngularMomentum; Vector3d MOI = v.vessel.MOI; //These shouldn't happen if (MOI.x == 0d) { MOI.x = 0.001d; } if (MOI.y == 0d) { MOI.y = 0.001d; } if (MOI.z == 0d) { MOI.z = 0.001d; } Vector3d angularvelocity = Vector3d.zero; angularvelocity.x = angularmomentum.x / MOI.x; angularvelocity.y = angularmomentum.y / MOI.y; angularvelocity.z = angularmomentum.z / MOI.z; //Vector3d av = v.GoingOffRailsAngularMomentum; Vector3d COM = v.vessel.CoMD; Quaternion rotation = v.vessel.ReferenceTransform.rotation; Vector3d av_by_rotation = rotation * angularvelocity; //KSPLog.print(string.Format("Apply angular vel: {0}, MOI: {1}, momentum: {3}", angularvelocity, MOI, angularmomentum)); //Applying force on every part foreach (Part p in v.vessel.parts) { if (!p.GetComponent <Rigidbody>()) { continue; } if (p.mass == 0f) { continue; } Rigidbody partrigidbody = p.GetComponent <Rigidbody> (); //Store the Rigidbody's max angular velocity for later restoration. if (!RigidBodyMaxAngularVelocityPairs.ContainsKey(partrigidbody)) { RigidBodyMaxAngularVelocityPairs[partrigidbody] = new RigidBodyMaxAngularVelocitySaveData(partrigidbody.maxAngularVelocity); } RigidBodyMaxAngularVelocityPairs[partrigidbody].FrameCounter = 10; partrigidbody.maxAngularVelocity *= 10f; partrigidbody.AddTorque(av_by_rotation, ForceMode.VelocityChange); partrigidbody.AddForce(Vector3d.Cross(av_by_rotation, (Vector3d)p.WCoM - COM), ForceMode.VelocityChange); } }
private void ApplyMomentumDelayed(Data.PRVessel v) { //Wait a few ticks to apply these. //Note that if the vessel immediately went back on rails, //these values would be updated when it came off again and all //would be well. v.GoingOffRailsFrameCounter = 3; v.GoingOffRailsAngularMomentum = v.storedAngularMomentum; }
private void PackedRotation(Data.PRVessel v) { Quaternion shift = Quaternion.Euler(0f, Vector3.Angle(Planetarium.right, v.planetariumRight), 0f); if (v.vessel.situation != Vessel.Situations.LANDED && v.vessel.situation != Vessel.Situations.SPLASHED && v.vessel.situation != Vessel.Situations.PRELAUNCH) { v.vessel.SetRotation(FromToRotation(shift * v.direction, (v.reference.GetTransform().position - v.vessel.transform.position).normalized) * (shift * v.rotation), true); } }
private void BodyGUI(int windowID) { Data.PRVessel v = data.FindPRVessel(activeVessel); GUILayout.BeginVertical(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button(close)) { showBodyWindow = false; } GUILayout.EndHorizontal(); GUILayout.Label("Select target in map \nto set as reference"); if (GUILayout.Button("Set", GUILayout.ExpandWidth(true))) { if (activeVessel.targetObject != null) { if (activeVessel.targetObject.GetType() == typeof(CelestialBody) || activeVessel.targetObject.GetType() == typeof(Vessel)) { v.reference = activeVessel.targetObject; } v.dynamicReference = false; } else { v.dynamicReference = false; v.reference = null; } } if (GUILayout.Button("Unset", GUILayout.ExpandWidth(true))) { v.reference = null; v.dynamicReference = false; } GUILayout.Space(10); if (GUILayout.Button("Sun", GUILayout.ExpandWidth(true))) { v.reference = Sun.Instance.sun; v.dynamicReference = false; } if (GUILayout.Button(activeVessel.mainBody.name, GUILayout.ExpandWidth(true))) { v.reference = activeVessel.mainBody; v.dynamicReference = false; } if (GUILayout.Button("Dynamic", GUILayout.ExpandWidth(true))) { v.dynamicReference = true; //v.reference = v.vessel.mainBody; --> This should not be necessary! } GUILayout.EndVertical(); GUI.DragWindow(); }
private void AdjustSAS(Data.PRVessel v) { if (v.reference != null) { if (v.lastTransform != null && v.lastPosition != null) { Vector3d newPosition = (Vector3d)v.lastTransform.position - v.reference.GetTransform().position; QuaternionD delta = FromToRotation(v.lastPosition, newPosition); QuaternionD adjusted = delta * (QuaternionD)v.vessel.Autopilot.SAS.lockedRotation; v.vessel.Autopilot.SAS.lockedRotation = adjusted; } } }
/* PRIVATE METHODS */ private void PackedSpin(Data.PRVessel v) { Vector3 _angularVelocity = Vector3.zero; _angularVelocity.x = v.storedAngularMomentum.x / v.vessel.MOI.x; _angularVelocity.y = v.storedAngularMomentum.y / v.vessel.MOI.y; _angularVelocity.z = v.storedAngularMomentum.z / v.vessel.MOI.z; if (v.vessel.situation != Vessel.Situations.LANDED && v.vessel.situation != Vessel.Situations.SPLASHED && v.vessel.situation != Vessel.Situations.PRELAUNCH) { v.vessel.SetRotation(Quaternion.AngleAxis(_angularVelocity.magnitude * TimeWarp.CurrentRate, v.vessel.ReferenceTransform.rotation * _angularVelocity) * v.vessel.transform.rotation, true); } }
private void OnVesselWillDestroy(Vessel vessel) { Debug.Log("[PR] Deleting " + vessel.vesselName + " as reference."); foreach (Vessel _vessel in FlightGlobals.Vessels) { Data.PRVessel v = data.FindPRVessel(_vessel); if (!object.ReferenceEquals(_vessel, vessel)) { if (object.ReferenceEquals(vessel, v.reference)) { v.reference = null; } } } }
private void ApplyMomentum(Data.PRVessel v) { Vector3 av = v.momentum; Vector3 COM = v.vessel.CoM; Quaternion rotation = v.vessel.ReferenceTransform.rotation; //Applying force on every part foreach (Part p in v.vessel.parts) { if (!p.GetComponent <Rigidbody>()) { continue; } p.GetComponent <Rigidbody>().AddTorque(rotation * av, ForceMode.VelocityChange); p.GetComponent <Rigidbody>().AddForce(Vector3.Cross(rotation * av, (p.transform.position - COM)), ForceMode.VelocityChange); } }
private void FixedUpdate() { if (activeVessel != FlightGlobals.ActiveVessel) { activeVessel = FlightGlobals.ActiveVessel; Interface.instance.desiredRPMstr = data.FindPRVessel(activeVessel).desiredRPM.ToString(); } foreach (Data.PRVessel v in data.PRVessels) { v.processed = false; } if (RigidBodyMaxAngularVelocityPairs.Count > 0) { List <Rigidbody> toremove = null; foreach (KeyValuePair <Rigidbody, RigidBodyMaxAngularVelocitySaveData> kp in RigidBodyMaxAngularVelocityPairs) { kp.Value.FrameCounter--; if (kp.Value.FrameCounter == 0) { try { kp.Key.maxAngularVelocity = kp.Value.OriginalValue; } catch { } if (toremove == null) { toremove = new List <Rigidbody>(); } toremove.Add(kp.Key); } } if (toremove != null) { for (int i = 0; i < toremove.Count; ++i) { RigidBodyMaxAngularVelocityPairs.Remove(toremove[i]); } } } #region ### Cycle through all vessels ### foreach (Vessel vessel in FlightGlobals.Vessels) { Data.PRVessel v = data.FindPRVessel(vessel); v.processed = true; if (v.dynamicReference) { if (v.reference == null || (v.reference.GetType() != typeof(CelestialBody) || v.reference.GetName() != vessel.mainBody.GetName())) //Main body mode; continuous update of reference to mainBody { Debug.Log("[PR] Updated the reference of " + v.vessel.vesselName + " from " + (v.reference != null ? v.reference.GetName() : "Null") + " to " + vessel.mainBody.name); v.reference = vessel.mainBody; v.direction = (v.reference.GetTransform().position - vessel.transform.position).normalized; v.rotation = vessel.transform.rotation; v.planetariumRight = Planetarium.right; v.lastActive = false; } } if (vessel.packed) { #region ### PACKED ### if (vessel.loaded) //is okay, rotation doesnt need to be persistent when rotating { var currentStabilityMode = GetStabilityMode(vessel); //Debug.Log("[PR] - currentStabilityMode: " + Enum.GetName(typeof(StabilityMode), currentStabilityMode)); if (currentStabilityMode == StabilityMode.PROGRADE) { var rotation = Quaternion.FromToRotation(vessel.transform.up.normalized, vessel.obt_velocity.normalized); vessel.transform.Rotate(rotation.eulerAngles, Space.World); v.vessel.SetRotation(vessel.transform.rotation); } else if (v.storedAngularMomentum.magnitude >= threshold) { if (currentStabilityMode != StabilityMode.AUTOPILOT) { PackedSpin(v); } } else if (currentStabilityMode != StabilityMode.ABSOLUTE) { if (currentStabilityMode == StabilityMode.RELATIVE && v.rotationModeActive && !v.momentumModeActive && v.storedAngularMomentum.magnitude < threshold) { if (v.rotationModeActive == true && v.reference != null) { if (v.reference == v.lastReference) { PackedRotation(v); } } } else { PackedSpin(v); } } } v.lastActive = false; #endregion } else { #region ### UNPACKED ### //Did this vessel just go off rails? if (v.GoingOffRailsFrameCounter != -1) { --v.GoingOffRailsFrameCounter; if (v.GoingOffRailsFrameCounter == 0) { ApplyMomentumNow(v); v.GoingOffRailsFrameCounter = -1; } } else { //Update Momentum when unpacked if (GetStabilityMode(vessel) != StabilityMode.OFF && !v.momentumModeActive && vessel.angularVelocity.magnitude < threshold) //C1 { v.storedAngularMomentum = Vector3.zero; } else { v.storedAngularMomentum = vessel.angularMomentum; //KSPLog.print(string.Format("SAVE angular vel: {0}, Momentum: {1}, MOI: {2}", vessel.angularVelocity, vessel.angularMomentum, vessel.MOI)); } } //Update mjMode when unpacked v.mjMode = MechJebWrapper.GetMode(vessel); v.rtMode = RemoteTechWrapper.GetMode(vessel); //Apply Momentum to activeVessel using Fly-By-Wire if (GetStabilityMode(vessel) == StabilityMode.RELATIVE && v.momentumModeActive) //C1 \ IsControllable { float desiredRPM = (vessel.angularVelocity.magnitude * 60f * (1f / Time.fixedDeltaTime)) / 360f; if (v.desiredRPM >= 0) { vessel.ctrlState.roll = Mathf.Clamp((v.desiredRPM - desiredRPM), -1f, +1f); } else { vessel.ctrlState.roll = -Mathf.Clamp((-v.desiredRPM - desiredRPM), -1f, +1f); } } //Update rotation v.rotation = vessel.transform.rotation; v.planetariumRight = Planetarium.right; //Adjust SAS for Relative Rotation if (v.rotationModeActive && v.reference != null) //C2 { //Update direction v.direction = (v.reference.GetTransform().position - vessel.transform.position).normalized; if (GetStabilityMode(vessel) == StabilityMode.RELATIVE && !v.momentumModeActive) { if (v.lastActive && v.reference == v.lastReference) { AdjustSAS(v); } v.lastActive = true; } else { v.lastActive = false; } v.lastPosition = (Vector3d)v.lastTransform.position - v.reference.GetTransform().position; } else { v.direction = Vector3.zero; v.lastPosition = Vector3.zero; v.lastActive = false; } #endregion } v.lastTransform = vessel.ReferenceTransform; v.lastReference = v.reference; } #endregion data.PRVessels.RemoveAll(v => v.processed == false); }
private void MainGUI(int windowID) { Data.PRVessel v = data.FindPRVessel(activeVessel); Texture toggle; if (MainWindowActive) { toggle = GameDatabase.Instance.GetTexture("PersistentRotation/Textures/minimize_w", false); } else { toggle = GameDatabase.Instance.GetTexture("PersistentRotation/Textures/maximize_w", false); } GUILayout.BeginVertical(); //Minimize und Option Buttons GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button(options)) { showConfigWindow = !showConfigWindow; } if (GUILayout.Button(toggle)) { MainWindowActive = !MainWindowActive; MainWindowRect = new Rect(MainWindowRect.x, MainWindowRect.y, 200, 10); } GUILayout.EndHorizontal(); //If maximized if (MainWindowActive) { if (activeVessel.IsControllable) { GUILayout.BeginHorizontal(); if (v.rotationModeActive) { GUI.contentColor = Color.green; } else { GUI.contentColor = Color.red; } if (GUILayout.Button("Rotation", GUILayout.ExpandWidth(true))) { mode = 1; } if (v.momentumModeActive) { GUI.contentColor = Color.green; } else { GUI.contentColor = Color.red; } if (GUILayout.Button("Momentum", GUILayout.ExpandWidth(true))) { mode = 2; } GUI.contentColor = Color.white; GUILayout.EndHorizontal(); GUILayout.Space(15f); if (mode == 1) { if (GUILayout.Button("Relative Rotation", GUILayout.ExpandWidth(true))) { showBodyWindow = !showBodyWindow; } if (v.reference != null) { if (v.dynamicReference) { GUILayout.Label("Reference: Dynamic (" + v.reference.GetName() + ")"); } else { GUILayout.Label("Reference: " + v.reference.GetName()); } } else { GUILayout.Label("Reference: None"); } string _text = "Activate"; if (v.rotationModeActive) { _text = "Deactivate"; } if (GUILayout.Button(_text, GUILayout.ExpandWidth(true))) { if (v.rotationModeActive == false) { v.rotationModeActive = true; v.momentumModeActive = false; if (v.reference != null) { v.direction = (v.reference.GetTransform().position - activeVessel.transform.position).normalized; } v.rotation = activeVessel.transform.rotation; v.planetariumRight = Planetarium.right; } else { v.rotationModeActive = false; } } } else if (mode == 2) { GUILayout.Label("Overwrite RPM:"); GUILayout.BeginHorizontal(); desiredRPMstr = GUILayout.TextField(desiredRPMstr); GUILayout.Label(" RPM"); GUILayout.EndHorizontal(); GUILayout.Space(10f); string _text = "Activate"; if (v.momentumModeActive) { _text = "Deactivate"; } if (GUILayout.Button(_text, GUILayout.ExpandWidth(true))) { v.rotationModeActive = false; if (v.momentumModeActive) { v.momentumModeActive = false; } else { try { v.desiredRPM = float.Parse(desiredRPMstr); v.momentumModeActive = true; } catch { desiredRPMstr = v.desiredRPM.ToString(); } } } } } else { GUILayout.Label("Vessel is not controllable."); } GUI.DragWindow(); } GUILayout.EndVertical(); }
private void FixedUpdate() { if (activeVessel != FlightGlobals.ActiveVessel) { activeVessel = FlightGlobals.ActiveVessel; Interface.instance.desiredRPMstr = data.FindPRVessel(activeVessel).desiredRPM.ToString(); } foreach (Data.PRVessel v in data.PRVessels) { v.processed = false; } #region ### Cycle through all vessels ### foreach (Vessel vessel in FlightGlobals.Vessels) { Data.PRVessel v = data.FindPRVessel(vessel); v.processed = true; if (v.dynamicReference) { if (v.reference == null || (v.reference.GetType() != typeof(CelestialBody) || v.reference.GetName() != vessel.mainBody.GetName())) //Main body mode; continuous update of reference to mainBody { Debug.Log("[PR] Updated the reference of " + v.vessel.vesselName + " from " + (v.reference != null ? v.reference.GetName() : "Null") + " to " + vessel.mainBody.name); v.reference = vessel.mainBody; v.direction = (v.reference.GetTransform().position - vessel.transform.position).normalized; v.rotation = vessel.transform.rotation; v.planetariumRight = Planetarium.right; v.lastActive = false; } } if (vessel.packed) { #region ### PACKED ### if (vessel.loaded) //is okay, rotation doesnt need to be persistent when rotating { if (v.momentum.magnitude >= threshold) { PackedSpin(v); } else if (GetStabilityMode(vessel) != StabilityMode.ABSOLUTE) { if (GetStabilityMode(vessel) == StabilityMode.RELATIVE && v.rotationModeActive && !v.momentumModeActive && v.momentum.magnitude < threshold) { if (v.rotationModeActive == true && v.reference != null) { if (v.reference == v.lastReference) { PackedRotation(v); } } } else { PackedSpin(v); } } } v.lastActive = false; #endregion } else { #region ### UNPACKED ### //Update Momentum when unpacked if (GetStabilityMode(vessel) != StabilityMode.OFF && !v.momentumModeActive && vessel.angularVelocity.magnitude < threshold) //C1 { v.momentum = Vector3.zero; } else { v.momentum = vessel.angularVelocity; } //Update mjMode when unpacked v.mjMode = MechJebWrapper.GetMode(vessel); v.rtMode = RemoteTechWrapper.GetMode(vessel); //Apply Momentum to activeVessel using Fly-By-Wire if (GetStabilityMode(vessel) == StabilityMode.RELATIVE && v.momentumModeActive) //C1 \ IsControllable { float desiredRPM = (vessel.angularVelocity.magnitude * 60f * (1f / Time.fixedDeltaTime)) / 360f; if (v.desiredRPM >= 0) { vessel.ctrlState.roll = Mathf.Clamp((v.desiredRPM - desiredRPM), -1f, +1f); } else { vessel.ctrlState.roll = -Mathf.Clamp((-v.desiredRPM - desiredRPM), -1f, +1f); } } //Update rotation v.rotation = vessel.transform.rotation; v.planetariumRight = Planetarium.right; //Adjust SAS for Relative Rotation if (v.rotationModeActive && v.reference != null) //C2 { //Update direction v.direction = (v.reference.GetTransform().position - vessel.transform.position).normalized; if (GetStabilityMode(vessel) == StabilityMode.RELATIVE && !v.momentumModeActive) { if (v.lastActive && v.reference == v.lastReference) { AdjustSAS(v); } v.lastActive = true; } else { v.lastActive = false; } v.lastPosition = (Vector3d)v.lastTransform.position - v.reference.GetTransform().position; } else { v.direction = Vector3.zero; v.lastPosition = Vector3.zero; v.lastActive = false; } #endregion } v.lastTransform = vessel.ReferenceTransform; v.lastReference = v.reference; } #endregion data.PRVessels.RemoveAll(v => v.processed == false); }