Skip to content

Commit

Permalink
Add option to create world-space joints for vessels in prelaunch
Browse files Browse the repository at this point in the history
  • Loading branch information
siimav committed Oct 5, 2024
1 parent 862f025 commit af2a277
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<bool name="reinforceAttachNodes">1</bool>
<bool name="multiPartAttachNodeReinforcement">1</bool>
<bool name="reinforceDecouplersFurther">1</bool>
<bool name="reinforceLaunchClampsFurther">1</bool>
<bool name="clampJointHasInfiniteStrength">0</bool>
<bool name="reinforceLaunchClampsFurther">0</bool>
<bool name="worldSpaceJoints">1</bool>
<bool name="useVolumeNotArea">1</bool>
<bool name="debug">0</bool>

Expand Down
Original file line number Diff line number Diff line change
@@ -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<Part> pickedMassiveParts = new List<Part>();
private List<Part> clampParts;
private Dictionary<Part, FixedJoint> joints = new Dictionary<Part, FixedJoint>();
private bool alreadyUnpacked = false;
private bool subscribedToEvents = false;

public void Init(List<Part> 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<FixedJoint>();
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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ConfigurableJoint> joints;
private List<ConfigurableJoint> hackedJoints;
private List<Part> neighbours = new List<Part>();

public override void OnAwake()
{
base.OnAwake();
joints = new List<ConfigurableJoint>();
hackedJoints = new List<ConfigurableJoint>();
}

public void OnPartUnpack()
Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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;
}

Expand All @@ -144,7 +118,7 @@ private void BreakAllInvalidJoints()
subscribedToEvents = false;

foreach (ConfigurableJoint j in joints)
GameObject.Destroy(j);
Destroy(j);

joints.Clear();

Expand All @@ -171,12 +145,12 @@ private void BreakAllInvalidJoints()
{
if (j.connectedBody == null)
{
GameObject.Destroy(j);
Destroy(j);
continue;
}
Part cp = j.connectedBody.GetComponent<Part>();
if (cp != null && cp.vessel != p.vessel)
GameObject.Destroy(j);
Destroy(j);
}
}
}
Expand Down Expand Up @@ -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<ConfigurableJoint>();
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);
}
}
}
49 changes: 38 additions & 11 deletions KerbalJointReinforcement/KerbalJointReinforcement/KJRManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ private void OnVesselOffRails(Vessel v)
{
Debug.Log("[KJR] easing " + v.vesselName);
vesselOffRails.Add(v);
List<Joint> jointList = new List<Joint>();
for (int i = 0; i < v.Parts.Count; ++i)
{
Part p = v.Parts[i];
Expand All @@ -184,7 +183,6 @@ private void OnVesselOffRails(Vessel v)
{
if (j.connectedBody == null)
{
jointList.Remove(j);
GameObject.Destroy(j);
KJRJointUtils.ConnectLaunchClampToGround(p);
break;
Expand Down Expand Up @@ -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<Part>();

foreach (Part p in v.Parts)
{
Expand All @@ -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<KJRLaunchClampReinforcementModule>())
KJRJointUtils.AddLaunchClampReinforcementModule(p);
if (KJRJointUtils.settings.reinforceLaunchClampsFurther && p.parent != null)
{
ReinforceClamps(p);
}
}
}

Expand All @@ -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");
}
Expand Down Expand Up @@ -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<KJRLaunchClampReinforcementModule>())
KJRJointUtils.AddLaunchClampReinforcementModule(p);
}

private void HandleWorldSpaceJoints(Vessel v, List<Part> clampParts)
{
Part p = v.rootPart;
if (!p.Modules.Contains<KJRGroundJointModule>())
{
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)
Expand Down
Loading

0 comments on commit af2a277

Please sign in to comment.