From 58ec2c97aabc6293709cd3313523a3d11e9f2b2e Mon Sep 17 00:00:00 2001 From: siimav Date: Sat, 5 Oct 2024 02:52:11 +0300 Subject: [PATCH] Add option to create world-space joints for vessels in prelaunch --- .../KerbalJointReinforcement/config.xml | 4 +- .../KJRGroundJointModule.cs | 127 ++++++++++++++++++ .../KerbalJointReinforcement/KJRJointUtils.cs | 3 +- .../KJRLaunchClampReinforcementModule.cs | 77 +---------- .../KerbalJointReinforcement/KJRManager.cs | 49 +++++-- .../KerbalJointReinforcement/KJRSettings.cs | 14 +- .../KerbalJointReinforcement.csproj | 1 + README.md | 8 +- 8 files changed, 188 insertions(+), 95 deletions(-) create mode 100644 KerbalJointReinforcement/KerbalJointReinforcement/KJRGroundJointModule.cs diff --git a/GameData/KerbalJointReinforcement/Plugin/PluginData/KerbalJointReinforcement/config.xml b/GameData/KerbalJointReinforcement/Plugin/PluginData/KerbalJointReinforcement/config.xml index 87ea24f..3931674 100644 --- a/GameData/KerbalJointReinforcement/Plugin/PluginData/KerbalJointReinforcement/config.xml +++ b/GameData/KerbalJointReinforcement/Plugin/PluginData/KerbalJointReinforcement/config.xml @@ -3,8 +3,8 @@ 1 1 1 - 1 - 0 + 0 + 1 1 0 diff --git a/KerbalJointReinforcement/KerbalJointReinforcement/KJRGroundJointModule.cs b/KerbalJointReinforcement/KerbalJointReinforcement/KJRGroundJointModule.cs new file mode 100644 index 0000000..ced4a2ea --- /dev/null +++ b/KerbalJointReinforcement/KerbalJointReinforcement/KJRGroundJointModule.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace KerbalJointReinforcement +{ + public class KJRGroundJointModule : PartModule + { + private const int PartsToPick = 3; + + private List pickedMassiveParts = new List(); + private List clampParts; + private Dictionary joints = new Dictionary(); + private bool alreadyUnpacked = false; + private bool subscribedToEvents = false; + + public void Init(List clampParts) + { + this.clampParts = clampParts; + + Part[] orderedParts = vessel.parts.OrderByDescending(p => p.physicsMass).ToArray(); + int i = 0; + int uniquePartsPicked = 0; + while (uniquePartsPicked < PartsToPick && i < orderedParts.Length) + { + Part mPart = orderedParts[i]; + i++; + + if (clampParts.Contains(mPart) || pickedMassiveParts.Contains(mPart)) + continue; + + pickedMassiveParts.Add(mPart); + uniquePartsPicked++; + + // Add all symmetry counterparts too but they do not count towards the number of unique parts that should get selected + if (mPart.symmetryCounterparts.Count > 0) + { + pickedMassiveParts.AddRange(mPart.symmetryCounterparts); + } + } + } + + public void OnPartUnpack() + { + if (alreadyUnpacked) + return; + + alreadyUnpacked = true; + + foreach (Part part in pickedMassiveParts) + { + if (part == null) continue; + + FixedJoint newJoint = part.gameObject.AddComponent(); + joints.Add(part, newJoint); + + newJoint.connectedBody = null; + newJoint.anchor = Vector3.zero; + newJoint.axis = Vector3.up; + newJoint.breakForce = Mathf.Infinity; + newJoint.breakTorque = Mathf.Infinity; + + if (KJRJointUtils.settings.debug) + Debug.Log($"[KJR] {part.partInfo.title} connected to ground"); + } + + if (joints.Count > 0) + { + GameEvents.onVesselWasModified.Add(OnVesselWasModified); + subscribedToEvents = true; + } + else + { + part.RemoveModule(this); + } + } + + private void OnVesselWasModified(Vessel v) + { + BreakAllInvalidJoints(); + } + + private void BreakAllInvalidJoints() + { + foreach (Part key in joints.Keys.ToArray()) + { + if (key == null || !clampParts.Find(cp => cp != null && cp.vessel == key.vessel)) + { + // All clamps gone, remove the joint + Destroy(joints[key]); + joints.Remove(key); + } + } + + if (joints.Count == 0) + part.RemoveModule(this); + } + + public void OnPartPack() + { + if (subscribedToEvents) + { + GameEvents.onVesselWasModified.Remove(OnVesselWasModified); + subscribedToEvents = false; + } + + foreach (FixedJoint j in joints.Values) + Destroy(j); + + joints.Clear(); + alreadyUnpacked = false; + } + + public void OnDestroy() + { + if (subscribedToEvents) + { + GameEvents.onVesselWasModified.Remove(OnVesselWasModified); + } + + foreach (FixedJoint j in joints.Values) + Destroy(j); + + joints.Clear(); + } + } +} diff --git a/KerbalJointReinforcement/KerbalJointReinforcement/KJRJointUtils.cs b/KerbalJointReinforcement/KerbalJointReinforcement/KJRJointUtils.cs index 9056a81..3d561fe 100644 --- a/KerbalJointReinforcement/KerbalJointReinforcement/KJRJointUtils.cs +++ b/KerbalJointReinforcement/KerbalJointReinforcement/KJRJointUtils.cs @@ -152,7 +152,6 @@ public static void ConnectLaunchClampToGround(Part clamp) public static void AddLaunchClampReinforcementModule(Part p) { var pm = (KJRLaunchClampReinforcementModule)p.AddModule(nameof(KJRLaunchClampReinforcementModule)); - pm.clampJointHasInfiniteStrength = settings.clampJointHasInfiniteStrength; pm.OnPartUnpack(); if (settings.debug) Debug.Log("[KJR] Added KJRLaunchClampReinforcementModule to part " + p.partInfo.title); @@ -176,7 +175,7 @@ public static void LoadConstants() debugString.AppendLine("Reinforce Attach Nodes: " + settings.reinforceAttachNodes); debugString.AppendLine("Reinforce Decouplers Further: " + settings.reinforceDecouplersFurther); debugString.AppendLine("Reinforce Launch Clamps Further: " + settings.reinforceLaunchClampsFurther); - debugString.AppendLine("Clamp Joint Has Infinite Strength: " + settings.clampJointHasInfiniteStrength); + debugString.AppendLine("World Space Joints: " + settings.worldSpaceJoints); debugString.AppendLine("Use Volume For Calculations, Not Area: " + settings.useVolumeNotArea); debugString.AppendLine("\n\rMass For Joint Adjustment: " + settings.massForAdjustment); diff --git a/KerbalJointReinforcement/KerbalJointReinforcement/KJRLaunchClampReinforcementModule.cs b/KerbalJointReinforcement/KerbalJointReinforcement/KJRLaunchClampReinforcementModule.cs index aad2bfe..023e38c 100644 --- a/KerbalJointReinforcement/KerbalJointReinforcement/KJRLaunchClampReinforcementModule.cs +++ b/KerbalJointReinforcement/KerbalJointReinforcement/KJRLaunchClampReinforcementModule.cs @@ -28,20 +28,15 @@ namespace KerbalJointReinforcement //This class adds an extra joint between a launch clamp and the part it is connected to for stiffness public class KJRLaunchClampReinforcementModule : PartModule { - public bool clampJointHasInfiniteStrength = false; - - private bool createHackedJoints = false; bool alreadyUnpacked = false; private bool subscribedToEvents = false; private List joints; - private List hackedJoints; private List neighbours = new List(); public override void OnAwake() { base.OnAwake(); joints = new List(); - hackedJoints = new List(); } public void OnPartUnpack() @@ -61,15 +56,7 @@ public void OnPartUnpack() if (part.parent.Rigidbody != null) { - if (clampJointHasInfiniteStrength) - { - createHackedJoints = true; - StartCoroutine(CreateInfiniteStrengthJointRoutine()); - } - else - { - StrutConnectParts(part, part.parent); - } + StrutConnectParts(part, part.parent); } if (KJRJointUtils.settings.debug) @@ -78,7 +65,7 @@ public void OnPartUnpack() Debug.Log(debugString.ToString()); } - if (joints.Count > 0 || createHackedJoints) + if (joints.Count > 0) { GameEvents.onVesselWasModified.Add(OnVesselWasModified); subscribedToEvents = true; @@ -87,14 +74,6 @@ public void OnPartUnpack() private void OnVesselWasModified(Vessel v) { - // When cheating a vessel into orbit, checking whether the clamp is on a different vessel (decoupled) does not work. - // So hacked joints need to be destroyed without the checks below, otherwise an extremely nasty Kraken attack will ensue. - foreach (ConfigurableJoint hj in hackedJoints) - GameObject.Destroy(hj); - - hackedJoints.Clear(); - createHackedJoints = false; - foreach (Part p in neighbours) { if (p.vessel == part.vessel) @@ -117,15 +96,10 @@ public void OnPartPack() } foreach (ConfigurableJoint j in joints) - GameObject.Destroy(j); - - foreach (ConfigurableJoint hj in hackedJoints) - GameObject.Destroy(hj); + Destroy(j); joints.Clear(); - hackedJoints.Clear(); neighbours.Clear(); - createHackedJoints = false; alreadyUnpacked = false; } @@ -144,7 +118,7 @@ private void BreakAllInvalidJoints() subscribedToEvents = false; foreach (ConfigurableJoint j in joints) - GameObject.Destroy(j); + Destroy(j); joints.Clear(); @@ -171,12 +145,12 @@ private void BreakAllInvalidJoints() { if (j.connectedBody == null) { - GameObject.Destroy(j); + Destroy(j); continue; } Part cp = j.connectedBody.GetComponent(); if (cp != null && cp.vessel != p.vessel) - GameObject.Destroy(j); + Destroy(j); } } } @@ -206,44 +180,5 @@ private void StrutConnectParts(Part partWithJoint, Part partConnectedByJoint) joints.Add(newJoint); } - - private IEnumerator CreateInfiniteStrengthJointRoutine() - { - const int maxFramesWaited = 250; - int i = 0; - do - { - yield return new WaitForFixedUpdate(); - } while (part.vessel.packed && i++ < maxFramesWaited); - - if (part.parent != null && part.parent.Rigidbody != null) - { - CreateInfiniteStrengthJoint(part.parent); - } - } - - private void CreateInfiniteStrengthJoint(Part parentOfClamp) - { - Vector3 anchor, axis; - anchor = Vector3.zero; - axis = Vector3.right; - - // Adding a joint that connects the parent part to itself. - // This causes Unity to bug out slightly and the connection between clamp and it's parent becomes completely rigid. - Debug.Log("[KJR] Ignore the illegal joint error below, this is supposed to happen: "); - ConfigurableJoint newJoint = parentOfClamp.gameObject.AddComponent(); - newJoint.connectedBody = parentOfClamp.rb; - newJoint.anchor = anchor; - newJoint.axis = axis; - newJoint.secondaryAxis = Vector3.forward; - newJoint.breakForce = Mathf.Infinity; - newJoint.breakTorque = Mathf.Infinity; - - newJoint.xMotion = newJoint.yMotion = newJoint.zMotion = ConfigurableJointMotion.Locked; - newJoint.angularXMotion = newJoint.angularYMotion = newJoint.angularZMotion = ConfigurableJointMotion.Locked; - newJoint.projectionMode = JointProjectionMode.PositionAndRotation; - - hackedJoints.Add(newJoint); - } } } diff --git a/KerbalJointReinforcement/KerbalJointReinforcement/KJRManager.cs b/KerbalJointReinforcement/KerbalJointReinforcement/KJRManager.cs index 40acfb2..0b971e0 100644 --- a/KerbalJointReinforcement/KerbalJointReinforcement/KJRManager.cs +++ b/KerbalJointReinforcement/KerbalJointReinforcement/KJRManager.cs @@ -168,7 +168,6 @@ private void OnVesselOffRails(Vessel v) { Debug.Log("[KJR] easing " + v.vesselName); vesselOffRails.Add(v); - List jointList = new List(); for (int i = 0; i < v.Parts.Count; ++i) { Part p = v.Parts[i]; @@ -184,7 +183,6 @@ private void OnVesselOffRails(Vessel v) { if (j.connectedBody == null) { - jointList.Remove(j); GameObject.Destroy(j); KJRJointUtils.ConnectLaunchClampToGround(p); break; @@ -278,8 +276,10 @@ private void RunVesselJointUpdateFunction(Vessel v) Debug.Log($"[KJR] Processing vessel {v.id} ({v.GetName()}); root {v.rootPart.partInfo.name} ({v.rootPart.flightID})"); } + bool shouldProcessClamps = v.LandedOrSplashed && (KJRJointUtils.settings.worldSpaceJoints || KJRJointUtils.settings.reinforceLaunchClampsFurther); bool child_parts = false; bool success = false; + var clampParts = new List(); foreach (Part p in v.Parts) { @@ -302,17 +302,14 @@ private void RunVesselJointUpdateFunction(Vessel v) continue; } - if ((KJRJointUtils.settings.reinforceLaunchClampsFurther || KJRJointUtils.settings.clampJointHasInfiniteStrength) && - p.parent != null && p.isLaunchClamp()) + if (shouldProcessClamps && p.isLaunchClamp()) { - p.breakingForce = Mathf.Infinity; - p.breakingTorque = Mathf.Infinity; - p.mass = (float)Math.Max(p.physicsMass, p.parent.physicsMass * 0.01); //We do this to make sure that there is a mass ratio of 100:1 between the clamp and what it's connected to. This helps counteract some of the wobbliness simply, but also allows some give and springiness to absorb the initial physics kick - if (KJRJointUtils.settings.debug) - Debug.Log("[KJR] Launch Clamp Break Force / Torque increased"); + clampParts.Add(p); - if (!p.Modules.Contains()) - KJRJointUtils.AddLaunchClampReinforcementModule(p); + if (KJRJointUtils.settings.reinforceLaunchClampsFurther && p.parent != null) + { + ReinforceClamps(p); + } } } @@ -325,6 +322,11 @@ private void RunVesselJointUpdateFunction(Vessel v) multiJointManager.ClearTempLists(); decouplerJointManager.ClearTempLists(); + if (KJRJointUtils.settings.worldSpaceJoints && clampParts.Count > 0) + { + HandleWorldSpaceJoints(v, clampParts); + } + Profiler.EndSample(); if (KJRJointUtils.settings.debug) Debug.Log($"[KJR] RunVesselJointUpdateFunction finished in {sw.Elapsed.TotalMilliseconds}ms"); } @@ -1054,6 +1056,31 @@ public void MultiPartJointTreeChildren(Vessel v) } } + private void ReinforceClamps(Part p) + { + p.breakingForce = Mathf.Infinity; + p.breakingTorque = Mathf.Infinity; + p.mass = (float)Math.Max(p.physicsMass, p.parent.physicsMass * 0.01); //We do this to make sure that there is a mass ratio of 100:1 between the clamp and what it's connected to. This helps counteract some of the wobbliness simply, but also allows some give and springiness to absorb the initial physics kick + if (KJRJointUtils.settings.debug) + Debug.Log("[KJR] Launch Clamp Break Force / Torque increased"); + + if (!p.Modules.Contains()) + KJRJointUtils.AddLaunchClampReinforcementModule(p); + } + + private void HandleWorldSpaceJoints(Vessel v, List clampParts) + { + Part p = v.rootPart; + if (!p.Modules.Contains()) + { + var pm = (KJRGroundJointModule)p.AddModule(nameof(KJRGroundJointModule)); + pm.Init(clampParts); + pm.OnPartUnpack(); + if (KJRJointUtils.settings.debug) + Debug.Log("[KJR] Added KJRGroundJointModule to part " + p.partInfo.title); + } + } + private void GatherAndShowDebugInformation() { if (jointRenderers != null) diff --git a/KerbalJointReinforcement/KerbalJointReinforcement/KJRSettings.cs b/KerbalJointReinforcement/KerbalJointReinforcement/KJRSettings.cs index caa4275..92d381e 100644 --- a/KerbalJointReinforcement/KerbalJointReinforcement/KJRSettings.cs +++ b/KerbalJointReinforcement/KerbalJointReinforcement/KJRSettings.cs @@ -30,11 +30,11 @@ public class KJRSettings : GameParameters.CustomParameterNode public bool reinforceDecouplersFurther = true; [GameParameters.CustomParameterUI("Toggle stiffening of launch clamp connections", autoPersistance = false)] - public bool reinforceLaunchClampsFurther = true; + public bool reinforceLaunchClampsFurther = false; - [GameParameters.CustomParameterUI("Toggle clamp connections that are completely rigid", autoPersistance = false, - toolTip = "With this option enabled, even the heaviest of rockets shouldn't move a millimeter when loaded onto the launch pad")] - public bool clampJointHasInfiniteStrength = false; + [GameParameters.CustomParameterUI("Attach vessel to ground", autoPersistance = false, + toolTip = "Connects the heaviest parts of the vessel directly to ground if it is waiting to be launched and has launch clamps")] + public bool worldSpaceJoints = true; [GameParameters.CustomParameterUI("Calculate by area", autoPersistance = false, toolTip = "Switches to calculating connection area based on volume, not area; not technically correct, but allows a better approximation of very large rockets")] @@ -81,8 +81,8 @@ public override void OnLoad(ConfigNode node) reinforceAttachNodes = config.GetValue(nameof(reinforceAttachNodes), true); multiPartAttachNodeReinforcement = config.GetValue(nameof(multiPartAttachNodeReinforcement), true); reinforceDecouplersFurther = config.GetValue(nameof(reinforceDecouplersFurther), true); - reinforceLaunchClampsFurther = config.GetValue(nameof(reinforceLaunchClampsFurther), true); - clampJointHasInfiniteStrength = config.GetValue(nameof(clampJointHasInfiniteStrength), false); + reinforceLaunchClampsFurther = config.GetValue(nameof(reinforceLaunchClampsFurther), false); + worldSpaceJoints = config.GetValue(nameof(worldSpaceJoints), true); useVolumeNotArea = config.GetValue(nameof(useVolumeNotArea), true); debug = config.GetValue(nameof(debug), false); @@ -139,7 +139,7 @@ public override void OnSave(ConfigNode node) isDirty |= UpdateConfigValue(config, "multiPartAttachNodeReinforcement", multiPartAttachNodeReinforcement); isDirty |= UpdateConfigValue(config, "reinforceDecouplersFurther", reinforceDecouplersFurther); isDirty |= UpdateConfigValue(config, "reinforceLaunchClampsFurther", reinforceLaunchClampsFurther); - isDirty |= UpdateConfigValue(config, "clampJointHasInfiniteStrength", clampJointHasInfiniteStrength); + isDirty |= UpdateConfigValue(config, "worldSpaceJoints", worldSpaceJoints); isDirty |= UpdateConfigValue(config, "useVolumeNotArea", useVolumeNotArea); isDirty |= UpdateConfigValue(config, "debug", debug); diff --git a/KerbalJointReinforcement/KerbalJointReinforcement/KerbalJointReinforcement.csproj b/KerbalJointReinforcement/KerbalJointReinforcement/KerbalJointReinforcement.csproj index da5b987..c349918 100644 --- a/KerbalJointReinforcement/KerbalJointReinforcement/KerbalJointReinforcement.csproj +++ b/KerbalJointReinforcement/KerbalJointReinforcement/KerbalJointReinforcement.csproj @@ -56,6 +56,7 @@ + diff --git a/README.md b/README.md index 2cc45fd..e6ca899 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Kerbal Joint Reinforcement, v3.7.5 +Kerbal Joint Reinforcement, v3.8.0 ========================== Physics stabilizer plugin for Kerbal Space Program @@ -61,7 +61,7 @@ General Values bool multiPartAttachNodeReinforcement 1 --Toggles additional stiffening by connecting parts in a stack one part further, but at a weaker strength bool reinforceDecouplersFurther 1 --Toggles stiffening of interstage connections bool reinforceLaunchClampsFurther 1 --Toggles stiffening of launch clamp connections - bool clampJointHasInfiniteStrength 0 --Toggles clamp joints that are completely rigid + bool worldSpaceJoints 1 --Connects the heaviest parts of the vessel directly to ground if it is waiting to be launched and has launch clamps bool useVolumeNotArea 1 --Switches to calculating connection area based on volume, not area; not technically correct, but allows a better approximation of very large rockets bool debug 0 --Toggles debug output to log; please activate and provide log if making a bug report float massForAdjustment 0.01 --Parts below this mass will not be stiffened @@ -112,6 +112,10 @@ Decoupler Stiffening Extension Types *********************** ****** CHANGELOG ****** *********************** +v3.8.0 + + --Add option to connect the heaviest parts of the vessel directly to ground. Replaces the lampJointHasInfiniteStrength option. + v3.7.5 --Fix another case of inter-vessel joints getting created on decoupling