Ejemplo n.º 1
0
        public bool TrySetValidLinkedSet(Part linkPart1, Part linkPart2)
        {
            linkedSet.Clear();
            tempPartList.Clear();

            while (linkPart1 != null)
            {
                linkedSet.Add(linkPart1);
                linkPart1 = KJRJointUtils.IsJointAdjustmentAllowed(linkPart1) ? linkPart1.parent : null;
            }

            while (linkPart2 != null)
            {
                tempPartList.Add(linkPart2);
                linkPart2 = KJRJointUtils.IsJointAdjustmentAllowed(linkPart2) ? linkPart2.parent : null;
            }

            int i = linkedSet.Count - 1;
            int j = tempPartList.Count - 1;

            if (linkedSet[i] != tempPartList[j])
            {
                return(false); // not same root, so they can never be in a valid set
            }
            while ((i >= 0) && (j >= 0) && (linkedSet[i] == tempPartList[j]))
            {
                --i; --j;
            }

            linkedSet.AddRange(tempPartList.GetRange(0, j + 1));

            return(linkedSet.Count > 1);
        }
        public void OnPartUnpack()
        {
            if (part.parent == null)
            {
                return;
            }

            neighbours.Add(part.parent);

            StringBuilder debugString = null;

            if (Log.debuglevel > 3)
            {
                debugString = new StringBuilder();
                debugString.AppendLine("The following joints added by " + part.partInfo.title + " to increase stiffness:");
            }

            if (part.parent.Rigidbody != null)
            {
                joints.Add(KJRJointUtils.BuildJoint(part, part.parent));
            }

            if (Log.debuglevel > 3)
            {
                debugString.AppendLine(part.parent.partInfo.title + " connected to part " + part.partInfo.title);
                Log.dbg("{0}", debugString);
            }

            if (joints.Count > 0)
            {
                GameEvents.onVesselWasModified.Add(OnVesselWasModified);
            }
        }
        public void Awake()
        {
            KJRJointUtils.LoadConstants();
            updatedVessels    = new List <Vessel>();
            easingVessels     = new HashSet <Vessel>();
            multiJointManager = new KJRMultiJointManager();
            updatingVessels   = new List <Vessel>();

#if Compatible
            ModuleDecoupleType = Type.GetType("ModuleDecouple, Assembly-CSharp");
            isDecoupledField   = ModuleDecoupleType.GetField("isDecoupled");

            // >= 1.7.1
            KJRJointUtils.IRoboticServoType = Type.GetType("Expansions.Serenity.IRoboticServo, Assembly-CSharp");             // >= 1.7.1

            // 1.7.1 detection
            onRoboticPartLockChangingField = typeof(GameEvents).GetField("onRoboticPartLockChanging");             // >= 1.7.2
            if (onRoboticPartLockChangingField == null)
            {
                KJRJointUtils.BaseServoType = Type.GetType("Expansions.Serenity.BaseServo, Assembly-CSharp");                 // 1.7.1 only
            }
#endif

            _instance = this;
        }
        public void OnEaseStop(Vessel v)
        {
            if (!easingVessels.Contains(v))
            {
                return;                 // we expect, that in this case, we are in an OnDestroy and should not get this call at all
            }
            foreach (Part p in v.Parts)
            {
                if (KJRJointUtils.IsJointUnlockable(p))
                {
                    continue;                     // exclude those actions from joints that can be dynamically unlocked
                }
                p.crashTolerance = p.crashTolerance / 10000f;
                if (p.attachJoint)
                {
                    p.attachJoint.SetUnbreakable(false, false);
                }
            }

            if (!updatingVessels.Contains(v))
            {
                updatingVessels.Add(v);
                StartCoroutine(RunVesselJointUpdateFunctionDelayed(v));
            }
        }
        private void RunVesselJointUpdateFunction(Vessel v)
        {
            if (KJRJointUtils.debug)
            {
                Debug.Log("KJR: Processing vessel " + v.id + " (" + v.GetName() + "); root " +
                          v.rootPart.partInfo.name + " (" + v.rootPart.flightID + ")");
            }

            bool bReinforced = false;

            foreach (Part p in v.Parts)
            {
                if (KJRJointUtils.reinforceAttachNodes)
                {
                    if ((p.parent != null) && (p.physicalSignificance == Part.PhysicalSignificance.FULL))
                    {
                        bReinforced = true;
                        UpdatePartJoint(p);
                    }
                }

                if (KJRJointUtils.reinforceDecouplersFurther)
                {
                    if ((p.Modules.Contains <ModuleDecouple>() || p.Modules.Contains <ModuleAnchoredDecoupler>()) &&
                        !p.Modules.Contains <KJRDecouplerReinforcementModule>())
                    {
                        KJRJointUtils.AddDecouplerJointReinforcementModule(p);
                        continue;
                    }
                }

                if (KJRJointUtils.reinforceLaunchClampsFurther)
                {
                    if ((p.parent != null) && p.Modules.Contains <LaunchClamp>() &&
                        !p.Modules.Contains <KJRLaunchClampReinforcementModule>())
                    {
                        p.breakingForce  = Mathf.Infinity;
                        p.breakingTorque = Mathf.Infinity;
                        p.mass           = Mathf.Max(p.mass, (p.parent.mass + p.parent.GetResourceMass()) * 0.01f); //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.debug)
                        {
                            Debug.Log("KJR: Launch Clamp Break Force / Torque increased");
                        }

                        KJRJointUtils.AddLaunchClampReinforcementModule(p);
                    }
                }
            }

            if (bReinforced)
            {
                updatedVessels.Add(v);
            }

            if (KJRJointUtils.reinforceAttachNodes && KJRJointUtils.multiPartAttachNodeReinforcement)
            {
                MultiPartJointTreeChildren(v);
            }
        }
Ejemplo n.º 6
0
 public void Awake()
 {
     KJRJointUtils.LoadConstants();
     updatedVessels          = new List <Vessel>();
     vesselOffRails          = new HashSet <Vessel>();
     vesselJointStrengthened = new Dictionary <Vessel, List <Joint> >();
     multiJointManager       = new KJRMultiJointManager();
 }
        private void MultiPartJointBuildJoint(Part p, Part linkPart)
        {
            if (multiJointManager.CheckMultiJointBetweenParts(p, linkPart) || !multiJointManager.TrySetValidLinkedSet(p, linkPart))
            {
                return;
            }

            multiJointManager.RegisterMultiJointBetweenParts(p, linkPart, KJRJointUtils.BuildJoint(p, linkPart));
        }
 public void Awake()
 {
     Log.dbg("Awake");
     try
     {
         KJRJointUtils.LoadConstants();
     }
     catch (Exception e)
     {
         Log.ex(this, e);
         Log.err("An error [{0}] was caught on initialization! The plugin WILL NOT work as expected!", e.Message);
     }
     updatedVessels          = new List <Vessel>();
     vesselOffRails          = new HashSet <Vessel>();
     vesselJointStrengthened = new Dictionary <Vessel, List <Joint> >();
     multiJointManager       = new KJRMultiJointManager();
 }
        private void MultiPartJointBuildJoint(Part part, Part linkPart, KJRMultiJointManager.Reason jointReason)
        {
            if (multiJointManager.CheckDirectJointBetweenParts(part, linkPart) ||
                !multiJointManager.TrySetValidLinkedSet(part, linkPart))
            {
                return;
            }

            ConfigurableJoint joint = KJRJointUtils.BuildJoint(part, linkPart);

            multiJointManager.RegisterMultiJoint(part, joint, true, jointReason);
            multiJointManager.RegisterMultiJoint(linkPart, joint, true, jointReason);

            foreach (Part p in multiJointManager.linkedSet)
            {
                multiJointManager.RegisterMultiJoint(p, joint, false, jointReason);
            }
        }
Ejemplo n.º 10
0
        public bool TrySetValidLinkedSet(Part part1, Part part2)
        {
            linkedSet.Clear();
            tempPartList.Clear();

            while (part1 != null)
            {
                linkedSet.Add(part1);
                part1 = KJRJointUtils.IsJointAdjustmentAllowed(part1) ? part1.parent : null;
            }

            while (part2 != null)
            {
                tempPartList.Add(part2);
                part2 = KJRJointUtils.IsJointAdjustmentAllowed(part2) ? part2.parent : null;
            }

            int i = linkedSet.Count - 1;
            int j = tempPartList.Count - 1;

            if (linkedSet[i] != tempPartList[j])
            {
                return(false);                // not same root, so they can never be in a valid set
            }
            while ((i >= 0) && (j >= 0) && (linkedSet[i] == tempPartList[j]))
            {
                --i; --j;
            }

            if (linkedSet.Count > i + 2)
            {
                linkedSet.RemoveRange(i + 2, linkedSet.Count - i - 2);
            }
            linkedSet.RemoveAt(0);

            if ((tempPartList.Count > 1) && (j > 0))
            {
                linkedSet.AddRange(tempPartList.GetRange(1, j));
            }

            return(linkedSet.Count > 1);
        }
        private void OnVesselOffRails(Vessel v)
        {
            if (v is null || v.isEVA)
            {
                return;
            }

            RunVesselJointUpdateFunction(v);

            if (!vesselOffRails.Contains(v) && v.precalc.isEasingGravity)
            {
                Log.info("KJR easing {0}", v.vesselName);

                vesselOffRails.Add(v);

                for (int i = 0; i < v.Parts.Count; ++i)
                {
                    Part p = v.Parts[i];
                    p.crashTolerance = p.crashTolerance * 10000f;
                    if (p.attachJoint)
                    {
                        p.attachJoint.SetUnbreakable(true, false);
                    }

                    Joint[] partJoints = p.GetComponents <Joint>();

                    if (p.Modules.Contains <LaunchClamp>())
                    {
                        foreach (Joint j in partJoints)
                        {
                            if (j.connectedBody == null)
                            {
                                GameObject.Destroy(j);
                                KJRJointUtils.ConnectLaunchClampToGround(p);
                                break;
                            }
                        }
                    }
                }
            }
        }
        public void OnEaseStart(Vessel v)
        {
            if (KJRJointUtils.debug)
            {
                Debug.Log("KJR easing " + v.vesselName);
            }

            foreach (Part p in v.Parts)
            {
                if (KJRJointUtils.IsJointUnlockable(p))
                {
                    continue;                     // exclude those actions from joints that can be dynamically unlocked
                }
                p.crashTolerance = p.crashTolerance * 10000f;
                if (p.attachJoint)
                {
                    p.attachJoint.SetUnbreakable(true, false);
                }

                Joint[] partJoints = p.GetComponents <Joint>();

                if (p.Modules.Contains <LaunchClamp>())
                {
                    for (int j = 0; j < partJoints.Length; j++)
                    {
                        if (partJoints[j].connectedBody == null)
                        {
                            GameObject.Destroy(partJoints[j]);
                            KJRJointUtils.ConnectLaunchClampToGround(p);
                            break;
                        }
                    }
                }
            }

            easingVessels.Add(v);
        }
        private void AddExtraJoints()
        {
            List <Part> childParts  = new List <Part>();
            List <Part> parentParts = new List <Part>();

            parentParts = KJRJointUtils.DecouplerPartStiffeningList(part.parent, false, true);
            foreach (Part p in part.children)
            {
                childParts.AddRange(KJRJointUtils.DecouplerPartStiffeningList(p, true, true));
                if (!childParts.Contains(p))
                {
                    childParts.Add(p);
                }
            }

            neighbours.Clear();
            neighbours.AddRange(parentParts);
            neighbours.AddRange(childParts);
            neighbours.Remove(part);

            parentParts.Add(part);

            StringBuilder debugString = null;

            if (KJRJointUtils.settings.debug)
            {
                debugString = new StringBuilder();
                debugString.AppendLine(parentParts.Count + " parts above decoupler to be connected to " + childParts.Count + " below decoupler.");
                debugString.AppendLine("The following joints added by " + part.partInfo.title + " to increase stiffness:");
            }

            foreach (Part p in parentParts)
            {
                if (p == null || p.rb == null || p.Modules.Contains("ProceduralFairingDecoupler") || !KJRJointUtils.JointAdjustmentValid(p))
                {
                    continue;
                }
                foreach (Part q in childParts)
                {
                    if (q == null || q.rb == null || q.Modules.Contains("ProceduralFairingDecoupler") || p == q || !KJRJointUtils.JointAdjustmentValid(q))
                    {
                        continue;
                    }

                    StrutConnectParts(p, q);

                    if (KJRJointUtils.settings.debug)
                    {
                        debugString.AppendLine(p.partInfo.title + " connected to part " + q.partInfo.title);
                    }
                }
            }

            if (joints.Count > 0)
            {
                GameEvents.onVesselWasModified.Add(OnVesselWasModified);
                GameEvents.onVesselCreate.Add(OnVesselWasModified);
            }

            if (KJRJointUtils.settings.debug)
            {
                Debug.Log(debugString.ToString());
            }
        }
Ejemplo n.º 14
0
        private void OnVesselOffRails(Vessel v)
        {
            if ((object)v == null || v.isEVA)
            {
                return;
            }

            bool vesselHasLaunchClamps = false;

            RunVesselJointUpdateFunction(v);
            if (!vesselOffRails.Contains(v) && v.precalc.isEasingGravity)
            {
                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];
                    p.crashTolerance = p.crashTolerance * 10000f;
                    if (p.attachJoint)
                    {
                        p.attachJoint.SetUnbreakable(true, false);
                    }

                    Joint[] partJoints = p.GetComponents <Joint>();

                    if (p.Modules.Contains <LaunchClamp>())
                    {
                        vesselHasLaunchClamps = true;
                        foreach (Joint j in partJoints)
                        {
                            if (j.connectedBody == null)
                            {
                                jointList.Remove(j);
                                GameObject.Destroy(j);
                                KJRJointUtils.ConnectLaunchClampToGround(p);
                                break;
                            }
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < v.Parts.Count; ++i)
                {
                    Part p = v.Parts[i];

                    if (p.Modules.Contains <LaunchClamp>())
                    {
                        vesselHasLaunchClamps = true;
                    }
                }
            }
            // if we had launch clamps and our situation is not PRELAUNCH then assume some physics issue has bounced us into landed or flying situation.
            if (vesselHasLaunchClamps && v.situation != Vessel.Situations.PRELAUNCH)
            {
                Debug.Log("KJR: Vessel has launch clamps and is not PRELAUNCH: Moving back to PRELAUNCH");
                v.situation   = Vessel.Situations.PRELAUNCH;
                v.launchTime  = 0;
                v.missionTime = 0;

                if (Versioning.version_minor > 3)
                {
                    // The following field didn't exist pre KSP v1.4
                    var fInf = v.GetType().GetField("skipGroundPositioning");
                    fInf.SetValue(v, false);
                }
            }
        }
Ejemplo n.º 15
0
        public void MultiPartJointTreeChildren(Vessel v)
        {
            if (v.Parts.Count <= 1)
            {
                return;
            }

            List <Part> childPartsToConnect = new List <Part>();

            for (int i = 0; i < v.Parts.Count; ++i)
            {
                Part p = v.Parts[i];
                if (p.children.Count == 0 && !p.Modules.Contains("LaunchClamp") && KJRJointUtils.MaximumPossiblePartMass(p) > KJRJointUtils.settings.massForAdjustment)
                {
                    if (p.rb == null && p.Rigidbody != null)
                    {
                        p = p.RigidBodyPart;
                    }
                    childPartsToConnect.Add(p);
                }
            }


            Rigidbody rootRb = v.rootPart.Rigidbody;

            for (int i = 0; i < childPartsToConnect.Count; ++i)
            {
                Part p        = childPartsToConnect[i];
                Part linkPart = childPartsToConnect[i + 1 >= childPartsToConnect.Count ? 0 : i + 1];

                Rigidbody rigidBody = linkPart.Rigidbody;
                if (!p.rb || !rigidBody || p.rb == rigidBody)
                {
                    continue;
                }

                if (!multiJointManager.CheckMultiJointBetweenParts(p, linkPart) && multiJointManager.TrySetValidLinkedSet(p, linkPart))
                {
                    ConfigurableJoint betweenChildJoint;

                    betweenChildJoint = p.gameObject.AddComponent <ConfigurableJoint>();

                    betweenChildJoint.connectedBody = rigidBody;
                    betweenChildJoint.anchor        = Vector3.zero;
                    betweenChildJoint.axis          = Vector3.right;
                    betweenChildJoint.secondaryAxis = Vector3.forward;
                    betweenChildJoint.breakForce    = KJRJointUtils.settings.decouplerAndClampJointStrength;
                    betweenChildJoint.breakTorque   = KJRJointUtils.settings.decouplerAndClampJointStrength;

                    betweenChildJoint.xMotion        = betweenChildJoint.yMotion = betweenChildJoint.zMotion = ConfigurableJointMotion.Locked;
                    betweenChildJoint.angularXMotion = betweenChildJoint.angularYMotion = betweenChildJoint.angularZMotion = ConfigurableJointMotion.Locked;

                    multiJointManager.RegisterMultiJointBetweenParts(p, linkPart, betweenChildJoint);
                    //multiJointManager.RegisterMultiJoint(p, betweenChildJoint);
                    //multiJointManager.RegisterMultiJoint(linkPart, betweenChildJoint);
                }

                Part linkPart2;

                int part2Index = i + childPartsToConnect.Count / 2;
                if (part2Index >= childPartsToConnect.Count)
                {
                    part2Index -= childPartsToConnect.Count;
                }

                linkPart2 = childPartsToConnect[part2Index];
                rigidBody = linkPart2.Rigidbody;

                if (!p.rb || !rigidBody || p.rb == rigidBody)
                {
                    continue;
                }

                if (!multiJointManager.CheckMultiJointBetweenParts(p, linkPart2) && multiJointManager.TrySetValidLinkedSet(p, linkPart2))
                {
                    ConfigurableJoint betweenChildJoint2;

                    betweenChildJoint2 = p.gameObject.AddComponent <ConfigurableJoint>();

                    betweenChildJoint2.connectedBody = rigidBody;
                    betweenChildJoint2.anchor        = Vector3.zero;
                    betweenChildJoint2.axis          = Vector3.right;
                    betweenChildJoint2.secondaryAxis = Vector3.forward;
                    betweenChildJoint2.breakForce    = KJRJointUtils.settings.decouplerAndClampJointStrength;
                    betweenChildJoint2.breakTorque   = KJRJointUtils.settings.decouplerAndClampJointStrength;

                    betweenChildJoint2.xMotion        = betweenChildJoint2.yMotion = betweenChildJoint2.zMotion = ConfigurableJointMotion.Locked;
                    betweenChildJoint2.angularXMotion = betweenChildJoint2.angularYMotion = betweenChildJoint2.angularZMotion = ConfigurableJointMotion.Locked;

                    multiJointManager.RegisterMultiJointBetweenParts(p, linkPart2, betweenChildJoint2);
                    //multiJointManager.RegisterMultiJoint(p, betweenChildJoint2);
                    //multiJointManager.RegisterMultiJoint(linkPart2, betweenChildJoint2);
                }


                if (!rootRb || p.rb == rootRb)
                {
                    continue;
                }

                if (multiJointManager.CheckMultiJointBetweenParts(p, v.rootPart) && multiJointManager.TrySetValidLinkedSet(p, v.rootPart))
                {
                    ConfigurableJoint toRootJoint;

                    toRootJoint = p.gameObject.AddComponent <ConfigurableJoint>();

                    toRootJoint.connectedBody = rootRb;
                    toRootJoint.anchor        = Vector3.zero;
                    toRootJoint.axis          = Vector3.right;
                    toRootJoint.secondaryAxis = Vector3.forward;
                    toRootJoint.breakForce    = KJRJointUtils.settings.decouplerAndClampJointStrength;
                    toRootJoint.breakTorque   = KJRJointUtils.settings.decouplerAndClampJointStrength;

                    toRootJoint.xMotion        = toRootJoint.yMotion = toRootJoint.zMotion = ConfigurableJointMotion.Locked;
                    toRootJoint.angularXMotion = toRootJoint.angularYMotion = toRootJoint.angularZMotion = ConfigurableJointMotion.Locked;

                    multiJointManager.RegisterMultiJointBetweenParts(p, v.rootPart, toRootJoint);
                    //multiJointManager.RegisterMultiJoint(p, toRootJoint);
                    //multiJointManager.RegisterMultiJoint(v.rootPart, toRootJoint);
                }
            }
        }
Ejemplo n.º 16
0
        private void UpdatePartJoint(Part p)
        {
            if (!KJRJointUtils.JointAdjustmentValid(p) || p.rb == null || p.attachJoint == null)
            {
                return;
            }

            if (p.attachMethod == AttachNodeMethod.LOCKED_JOINT)
            {
                if (KJRJointUtils.settings.debug)
                {
                    Debug.Log("KJR: Already processed part before: " + p.partInfo.name + " (" + p.flightID + ") -> " +
                              p.parent.partInfo.name + " (" + p.parent.flightID + ")");
                }

                return;
            }
            List <ConfigurableJoint> jointList;

            if (p.Modules.Contains <CModuleStrut>())
            {
                CModuleStrut s = p.Modules.GetModule <CModuleStrut>();

                if (!(s.jointTarget == null || s.jointRoot == null))
                {
                    jointList = KJRJointUtils.GetJointListFromAttachJoint(s.strutJoint);

                    if (jointList != null)
                    {
                        for (int i = 0; i < jointList.Count; i++)
                        {
                            ConfigurableJoint j = jointList[i];

                            if (j == null)
                            {
                                continue;
                            }

                            JointDrive strutDrive = j.angularXDrive;
                            strutDrive.positionSpring = KJRJointUtils.settings.decouplerAndClampJointStrength;
                            strutDrive.maximumForce   = KJRJointUtils.settings.decouplerAndClampJointStrength;
                            j.xDrive = j.yDrive = j.zDrive = j.angularXDrive = j.angularYZDrive = strutDrive;

                            j.xMotion        = j.yMotion = j.zMotion = ConfigurableJointMotion.Locked;
                            j.angularXMotion = j.angularYMotion = j.angularZMotion = ConfigurableJointMotion.Locked;

                            //float scalingFactor = (s.jointTarget.mass + s.jointTarget.GetResourceMass() + s.jointRoot.mass + s.jointRoot.GetResourceMass()) * 0.01f;

                            j.breakForce  = KJRJointUtils.settings.decouplerAndClampJointStrength;
                            j.breakTorque = KJRJointUtils.settings.decouplerAndClampJointStrength;
                        }

                        p.attachMethod = AttachNodeMethod.LOCKED_JOINT;
                    }
                }
            }


            jointList = KJRJointUtils.GetJointListFromAttachJoint(p.attachJoint);
            if (jointList == null)
            {
                return;
            }

            StringBuilder debugString = new StringBuilder();

            bool addAdditionalJointToParent = KJRJointUtils.settings.multiPartAttachNodeReinforcement;

            //addAdditionalJointToParent &= !(p.Modules.Contains("LaunchClamp") || (p.parent.Modules.Contains("ModuleDecouple") || p.parent.Modules.Contains("ModuleAnchoredDecoupler")));
            addAdditionalJointToParent &= !p.Modules.Contains <CModuleStrut>();

            float partMass = p.mass + p.GetResourceMass();

            for (int i = 0; i < jointList.Count; i++)
            {
                ConfigurableJoint j = jointList[i];
                if (j == null)
                {
                    continue;
                }

                String    jointType     = j.GetType().Name;
                Rigidbody connectedBody = j.connectedBody;

                Part  connectedPart = connectedBody.GetComponent <Part>() ?? p.parent;
                float parentMass    = connectedPart.mass + connectedPart.GetResourceMass();

                if (partMass < KJRJointUtils.settings.massForAdjustment || parentMass < KJRJointUtils.settings.massForAdjustment)
                {
                    if (KJRJointUtils.settings.debug)
                    {
                        Debug.Log("KJR: Part mass too low, skipping: " + p.partInfo.name + " (" + p.flightID + ")");
                    }

                    continue;
                }

                // Check attachment nodes for better orientation data
                AttachNode attach   = p.FindAttachNodeByPart(p.parent);
                AttachNode p_attach = p.parent.FindAttachNodeByPart(p);
                AttachNode node     = attach ?? p_attach;

                if (node == null)
                {
                    // Check if it's a pair of coupled docking ports
                    var dock1 = p.Modules.GetModule <ModuleDockingNode>();
                    var dock2 = p.parent.Modules.GetModule <ModuleDockingNode>();

                    //Debug.Log(dock1 + " " + (dock1 ? ""+dock1.dockedPartUId : "?") + " " + dock2 + " " + (dock2 ? ""+dock2.dockedPartUId : "?"));

                    if (dock1 && dock2 && (dock1.dockedPartUId == p.parent.flightID || dock2.dockedPartUId == p.flightID))
                    {
                        attach   = p.FindAttachNode(dock1.referenceAttachNode);
                        p_attach = p.parent.FindAttachNode(dock2.referenceAttachNode);
                        node     = attach ?? p_attach;
                    }
                }

                // If still no node and apparently surface attached, use the normal one if it's there
                if (node == null && p.attachMode == AttachModes.SRF_ATTACH)
                {
                    node = attach = p.srfAttachNode;
                }

                if (KJRJointUtils.settings.debug)
                {
                    debugString.AppendLine("Original joint from " + p.partInfo.title + " to " + p.parent.partInfo.title);
                    debugString.AppendLine("  " + p.partInfo.name + " (" + p.flightID + ") -> " + p.parent.partInfo.name + " (" + p.parent.flightID + ")");
                    debugString.AppendLine("");
                    debugString.AppendLine(p.partInfo.title + " Inertia Tensor: " + p.rb.inertiaTensor + " " + p.parent.partInfo.name + " Inertia Tensor: " + connectedBody.inertiaTensor);
                    debugString.AppendLine("");


                    debugString.AppendLine("Std. Joint Parameters");
                    debugString.AppendLine("Connected Body: " + p.attachJoint.Joint.connectedBody);
                    debugString.AppendLine("Attach mode: " + p.attachMode + " (was " + jointType + ")");
                    if (attach != null)
                    {
                        debugString.AppendLine("Attach node: " + attach.id + " - " + attach.nodeType + " " + attach.size);
                    }
                    if (p_attach != null)
                    {
                        debugString.AppendLine("Parent node: " + p_attach.id + " - " + p_attach.nodeType + " " + p_attach.size);
                    }
                    debugString.AppendLine("Anchor: " + p.attachJoint.Joint.anchor);
                    debugString.AppendLine("Axis: " + p.attachJoint.Joint.axis);
                    debugString.AppendLine("Sec Axis: " + p.attachJoint.Joint.secondaryAxis);
                    debugString.AppendLine("Break Force: " + p.attachJoint.Joint.breakForce);
                    debugString.AppendLine("Break Torque: " + p.attachJoint.Joint.breakTorque);
                    debugString.AppendLine("");

                    debugString.AppendLine("Joint Motion Locked: " + Convert.ToString(p.attachJoint.Joint.xMotion == ConfigurableJointMotion.Locked));

                    debugString.AppendLine("X Drive");
                    debugString.AppendLine("Position Spring: " + p.attachJoint.Joint.xDrive.positionSpring);
                    debugString.AppendLine("Position Damper: " + p.attachJoint.Joint.xDrive.positionDamper);
                    debugString.AppendLine("Max Force: " + p.attachJoint.Joint.xDrive.maximumForce);
                    debugString.AppendLine("");

                    debugString.AppendLine("Y Drive");
                    debugString.AppendLine("Position Spring: " + p.attachJoint.Joint.yDrive.positionSpring);
                    debugString.AppendLine("Position Damper: " + p.attachJoint.Joint.yDrive.positionDamper);
                    debugString.AppendLine("Max Force: " + p.attachJoint.Joint.yDrive.maximumForce);
                    debugString.AppendLine("");

                    debugString.AppendLine("Z Drive");
                    debugString.AppendLine("Position Spring: " + p.attachJoint.Joint.zDrive.positionSpring);
                    debugString.AppendLine("Position Damper: " + p.attachJoint.Joint.zDrive.positionDamper);
                    debugString.AppendLine("Max Force: " + p.attachJoint.Joint.zDrive.maximumForce);
                    debugString.AppendLine("");

                    debugString.AppendLine("Angular X Drive");
                    debugString.AppendLine("Position Spring: " + p.attachJoint.Joint.angularXDrive.positionSpring);
                    debugString.AppendLine("Position Damper: " + p.attachJoint.Joint.angularXDrive.positionDamper);
                    debugString.AppendLine("Max Force: " + p.attachJoint.Joint.angularXDrive.maximumForce);
                    debugString.AppendLine("");

                    debugString.AppendLine("Angular YZ Drive");
                    debugString.AppendLine("Position Spring: " + p.attachJoint.Joint.angularYZDrive.positionSpring);
                    debugString.AppendLine("Position Damper: " + p.attachJoint.Joint.angularYZDrive.positionDamper);
                    debugString.AppendLine("Max Force: " + p.attachJoint.Joint.angularYZDrive.maximumForce);
                    debugString.AppendLine("");


                    //Debug.Log(debugString.ToString());
                }


                float   breakForce      = Math.Min(p.breakingForce, connectedPart.breakingForce) * KJRJointUtils.settings.breakForceMultiplier;
                float   breakTorque     = Math.Min(p.breakingTorque, connectedPart.breakingTorque) * KJRJointUtils.settings.breakTorqueMultiplier;
                Vector3 anchor          = j.anchor;
                Vector3 connectedAnchor = j.connectedAnchor;
                Vector3 axis            = j.axis;

                float radius          = 0;
                float area            = 0;
                float momentOfInertia = 0;

                if (node != null)
                {
                    // Part that owns the node. For surface attachment,
                    // this can only be parent if docking flips hierarchy.
                    Part main = (node == attach) ? p : p.parent;

                    // Orientation and position of the node in owner's local coords
                    Vector3 ndir = node.orientation.normalized;
                    Vector3 npos = node.position + node.offset;

                    // And in the current part's local coords
                    Vector3 dir = axis = p.transform.InverseTransformDirection(main.transform.TransformDirection(ndir));

                    if (node.nodeType == AttachNode.NodeType.Surface)
                    {
                        // Guessed main axis; for parts with stack nodes should be the axis of the stack
                        Vector3 up = KJRJointUtils.GuessUpVector(main).normalized;

                        // if guessed up direction is same as node direction, it's basically stack
                        // for instance, consider a radially-attached docking port
                        if (Mathf.Abs(Vector3.Dot(up, ndir)) > 0.9f)
                        {
                            radius = Mathf.Min(KJRJointUtils.CalculateRadius(main, ndir), KJRJointUtils.CalculateRadius(connectedPart, ndir));
                            if (radius <= 0.001)
                            {
                                radius = node.size * 1.25f;
                            }
                            area            = Mathf.PI * radius * radius;           //Area of cylinder
                            momentOfInertia = area * radius * radius / 4;           //Moment of Inertia of cylinder
                        }
                        else
                        {
                            // x along surface, y along ndir normal to surface, z along surface & main axis (up)
                            var size1 = KJRJointUtils.CalculateExtents(main, ndir, up);

                            var size2 = KJRJointUtils.CalculateExtents(connectedPart, ndir, up);

                            // use average of the sides, since we don't know which one is used for attaching
                            float width1 = (size1.x + size1.z) / 2;
                            float width2 = (size2.x + size2.z) / 2;
                            if (size1.y * width1 > size2.y * width2)
                            {
                                area   = size1.y * width1;
                                radius = Mathf.Max(size1.y, width1);
                            }
                            else
                            {
                                area   = size2.y * width2;
                                radius = Mathf.Max(size2.y, width2);
                            }

                            momentOfInertia = area * radius / 12;          //Moment of Inertia of a rectangle bending along the longer length
                        }
                    }
                    else
                    {
                        radius = Mathf.Min(KJRJointUtils.CalculateRadius(p, dir), KJRJointUtils.CalculateRadius(connectedPart, dir));
                        if (radius <= 0.001)
                        {
                            radius = node.size * 1.25f;
                        }
                        area            = Mathf.PI * radius * radius;           //Area of cylinder
                        momentOfInertia = area * radius * radius / 4;           //Moment of Inertia of cylinder
                    }
                }
                //Assume part is attached along its "up" cross section; use a cylinder to approximate properties
                else if (p.attachMode == AttachModes.STACK)
                {
                    radius = Mathf.Min(KJRJointUtils.CalculateRadius(p, Vector3.up), KJRJointUtils.CalculateRadius(connectedPart, Vector3.up));
                    if (radius <= 0.001)
                    {
                        radius = node.size * 1.25f;
                    }
                    area            = Mathf.PI * radius * radius;           //Area of cylinder
                    momentOfInertia = area * radius * radius / 4;           //Moment of Inertia of cylinder
                }
                else if (p.attachMode == AttachModes.SRF_ATTACH)
                {
                    // x,z sides, y along main axis
                    Vector3 up1   = KJRJointUtils.GuessUpVector(p);
                    var     size1 = KJRJointUtils.CalculateExtents(p, up1);

                    Vector3 up2   = KJRJointUtils.GuessUpVector(connectedPart);
                    var     size2 = KJRJointUtils.CalculateExtents(connectedPart, up2);

                    // use average of the sides, since we don't know which one is used for attaching
                    float width1 = (size1.x + size1.z) / 2;
                    float width2 = (size2.x + size2.z) / 2;
                    if (size1.y * width1 > size2.y * width2)
                    {
                        area   = size1.y * width1;
                        radius = Mathf.Max(size1.y, width1);
                    }
                    else
                    {
                        area   = size2.y * width2;
                        radius = Mathf.Max(size2.y, width2);
                    }
                    momentOfInertia = area * radius / 12;          //Moment of Inertia of a rectangle bending along the longer length
                }

                if (KJRJointUtils.settings.useVolumeNotArea)       //If using volume, raise al stiffness-affecting parameters to the 1.5 power
                {
                    area            = Mathf.Pow(area, 1.5f);
                    momentOfInertia = Mathf.Pow(momentOfInertia, 1.5f);
                }


                breakForce  = Mathf.Max(KJRJointUtils.settings.breakStrengthPerArea * area, breakForce);
                breakTorque = Mathf.Max(KJRJointUtils.settings.breakTorquePerMOI * momentOfInertia, breakTorque);

                JointDrive angDrive = j.angularXDrive;
                angDrive.positionSpring = Mathf.Max(momentOfInertia * KJRJointUtils.settings.angularDriveSpring, angDrive.positionSpring);
                angDrive.positionDamper = Mathf.Max(momentOfInertia * KJRJointUtils.settings.angularDriveDamper * 0.1f, angDrive.positionDamper);
                angDrive.maximumForce   = breakTorque;

                /*float moi_avg = p.rb.inertiaTensor.magnitude;
                 *
                 * moi_avg += (p.transform.localToWorldMatrix.MultiplyPoint(p.CoMOffset) - p.parent.transform.position).sqrMagnitude * p.rb.mass;
                 *
                 * if (moi_avg * 2f / drive.positionDamper < 0.08f)
                 * {
                 *  drive.positionDamper = moi_avg / (0.04f);
                 *
                 *  drive.positionSpring = drive.positionDamper * drive.positionDamper / moi_avg;
                 * }*/
                j.angularXDrive = j.angularYZDrive = j.slerpDrive = angDrive;

                JointDrive linDrive = j.xDrive;
                linDrive.maximumForce = breakForce;
                j.xDrive = j.yDrive = j.zDrive = linDrive;

                SoftJointLimit lim = new SoftJointLimit();
                lim.limit      = 0;
                lim.bounciness = 0;

                SoftJointLimitSpring limSpring = new SoftJointLimitSpring();

                limSpring.spring = 0;
                limSpring.damper = 0;

                j.linearLimit       = j.angularYLimit = j.angularZLimit = j.lowAngularXLimit = j.highAngularXLimit = lim;
                j.linearLimitSpring = j.angularYZLimitSpring = j.angularXLimitSpring = limSpring;

                j.targetAngularVelocity = Vector3.zero;
                j.targetVelocity        = Vector3.zero;
                j.targetRotation        = Quaternion.identity;
                j.targetPosition        = Vector3.zero;

                j.breakForce  = breakForce;
                j.breakTorque = breakTorque;
                p.attachJoint.SetBreakingForces(j.breakForce, j.breakTorque);

                p.attachMethod = AttachNodeMethod.LOCKED_JOINT;

                if (addAdditionalJointToParent && p.parent.parent != null)
                {
                    addAdditionalJointToParent = false;
                    if (!KJRJointUtils.JointAdjustmentValid(p.parent) || !KJRJointUtils.JointAdjustmentValid(p.parent.parent))
                    {
                        continue;
                    }

                    /*if (ValidDecoupler(p) || ValidDecoupler(p.parent))
                     *  continue;*/
                    Part newConnectedPart = p.parent.parent;

                    bool massRatioBelowThreshold = false;
                    int  numPartsFurther         = 0;

                    float       partMaxMass          = KJRJointUtils.MaximumPossiblePartMass(p);
                    List <Part> partsCrossed         = new List <Part>();
                    List <Part> possiblePartsCrossed = new List <Part>();

                    partsCrossed.Add(p);
                    partsCrossed.Add(p.parent);
                    partsCrossed.Add(newConnectedPart);

                    Rigidbody connectedRb = newConnectedPart.rb;

                    do
                    {
                        float massRat1, massRat2;
                        massRat1 = partMaxMass / newConnectedPart.mass;
                        if (massRat1 < 1)
                        {
                            massRat1 = 1 / massRat1;
                        }

                        massRat2 = p.mass / KJRJointUtils.MaximumPossiblePartMass(newConnectedPart);
                        if (massRat2 < 1)
                        {
                            massRat2 = 1 / massRat2;
                        }

                        if (massRat1 > KJRJointUtils.settings.stiffeningExtensionMassRatioThreshold || massRat2 > KJRJointUtils.settings.stiffeningExtensionMassRatioThreshold)
                        {
                            if (newConnectedPart.parent != null)
                            {
                                if (!KJRJointUtils.JointAdjustmentValid(newConnectedPart.parent))
                                {
                                    break;
                                }

                                newConnectedPart = newConnectedPart.parent;
                                if (newConnectedPart.rb == null)
                                {
                                    possiblePartsCrossed.Add(newConnectedPart);
                                }
                                else
                                {
                                    connectedRb = newConnectedPart.rb;
                                    partsCrossed.AddRange(possiblePartsCrossed);
                                    partsCrossed.Add(newConnectedPart);
                                    possiblePartsCrossed.Clear();
                                }
                            }
                            else
                            {
                                break;
                            }
                            numPartsFurther++;
                        }
                        else
                        {
                            massRatioBelowThreshold = true;
                        }
                    } while (!massRatioBelowThreshold);// && numPartsFurther < 5);

                    if (connectedRb != null && !multiJointManager.CheckMultiJointBetweenParts(p, newConnectedPart))
                    {
                        ConfigurableJoint newJoint = p.gameObject.AddComponent <ConfigurableJoint>();

                        newJoint.connectedBody   = connectedRb;
                        newJoint.axis            = Vector3.right;
                        newJoint.secondaryAxis   = Vector3.forward;
                        newJoint.anchor          = Vector3.zero;
                        newJoint.connectedAnchor = p.transform.worldToLocalMatrix.MultiplyPoint(newConnectedPart.transform.position);

                        //if(massRatioBelowThreshold)
                        //{

                        newJoint.angularXDrive = newJoint.angularYZDrive = newJoint.slerpDrive = j.angularXDrive;

                        newJoint.xDrive = j.xDrive;
                        newJoint.yDrive = j.yDrive;
                        newJoint.zDrive = j.zDrive;

                        newJoint.linearLimit = newJoint.angularYLimit = newJoint.angularZLimit = newJoint.lowAngularXLimit = newJoint.highAngularXLimit = lim;

                        /*newJoint.targetAngularVelocity = Vector3.zero;
                         * newJoint.targetVelocity = Vector3.zero;
                         * newJoint.targetRotation = Quaternion.identity;
                         * newJoint.targetPosition = Vector3.zero;*/
                        /*}
                         * else
                         * {
                         *  newJoint.xMotion = newJoint.yMotion = newJoint.zMotion = ConfigurableJointMotion.Locked;
                         *  newJoint.angularXMotion = newJoint.angularYMotion = newJoint.angularZMotion = ConfigurableJointMotion.Locked;
                         * }*/

                        newJoint.breakForce  = breakForce;
                        newJoint.breakTorque = breakTorque;

                        //jointList.Add(newJoint);
                        for (int k = 0; k < partsCrossed.Count; k++)
                        {
                            multiJointManager.RegisterMultiJoint(partsCrossed[k], newJoint);
                        }
                    }

                    /*if(p.symmetryCounterparts != null && p.symmetryCounterparts.Count > 0)
                     * {
                     *  Part linkPart = null;
                     *  Vector3 center = p.transform.position;
                     *  float cross = float.NegativeInfinity;
                     *  for(int k = 0; k < p.symmetryCounterparts.Count; k++)
                     *  {
                     *      center += p.symmetryCounterparts[k].transform.position;
                     *  }
                     *  center /= (p.symmetryCounterparts.Count + 1);
                     *
                     *  for(int k = 0; k < p.symmetryCounterparts.Count; k++)
                     *  {
                     *      Part counterPart = p.symmetryCounterparts[k];
                     *      if (counterPart.parent == p.parent && counterPart.rb != null)
                     *      {
                     *          float tmpCross = Vector3.Dot(Vector3.Cross(center - p.transform.position, counterPart.transform.position - p.transform.position), p.transform.up);
                     *          if(tmpCross > cross)
                     *          {
                     *              cross = tmpCross;
                     *              linkPart = counterPart;
                     *          }
                     *      }
                     *  }
                     *  if (linkPart)
                     *  {
                     *      Rigidbody rigidBody = linkPart.rb;
                     *      if (!linkPart.rb)
                     *          continue;
                     *      ConfigurableJoint newJoint;
                     *
                     *      newJoint = p.gameObject.AddComponent<ConfigurableJoint>();
                     *
                     *      newJoint.connectedBody = rigidBody;
                     *      newJoint.anchor = Vector3.zero;
                     *      newJoint.axis = Vector3.right;
                     *      newJoint.secondaryAxis = Vector3.forward;
                     *      newJoint.breakForce = KJRJointUtils.decouplerAndClampJointStrength;
                     *      newJoint.breakTorque = KJRJointUtils.decouplerAndClampJointStrength;
                     *
                     *      newJoint.xMotion = newJoint.yMotion = newJoint.zMotion = ConfigurableJointMotion.Locked;
                     *      newJoint.angularXMotion = newJoint.angularYMotion = newJoint.angularZMotion = ConfigurableJointMotion.Locked;
                     *
                     *      multiJointManager.RegisterMultiJoint(p, newJoint);
                     *      multiJointManager.RegisterMultiJoint(linkPart, newJoint);
                     *  }
                     * }*/
                }

                if (KJRJointUtils.settings.debug)
                {
                    debugString.AppendLine("Updated joint from " + p.partInfo.title + " to " + p.parent.partInfo.title);
                    debugString.AppendLine("  " + p.partInfo.name + " (" + p.flightID + ") -> " + p.parent.partInfo.name + " (" + p.parent.flightID + ")");
                    debugString.AppendLine("");
                    debugString.AppendLine(p.partInfo.title + " Inertia Tensor: " + p.rb.inertiaTensor + " " + p.parent.partInfo.name + " Inertia Tensor: " + connectedBody.inertiaTensor);
                    debugString.AppendLine("");


                    debugString.AppendLine("Std. Joint Parameters");
                    debugString.AppendLine("Connected Body: " + p.attachJoint.Joint.connectedBody);
                    debugString.AppendLine("Attach mode: " + p.attachMode + " (was " + jointType + ")");
                    if (attach != null)
                    {
                        debugString.AppendLine("Attach node: " + attach.id + " - " + attach.nodeType + " " + attach.size);
                    }
                    if (p_attach != null)
                    {
                        debugString.AppendLine("Parent node: " + p_attach.id + " - " + p_attach.nodeType + " " + p_attach.size);
                    }
                    debugString.AppendLine("Anchor: " + p.attachJoint.Joint.anchor);
                    debugString.AppendLine("Axis: " + p.attachJoint.Joint.axis);
                    debugString.AppendLine("Sec Axis: " + p.attachJoint.Joint.secondaryAxis);
                    debugString.AppendLine("Break Force: " + p.attachJoint.Joint.breakForce);
                    debugString.AppendLine("Break Torque: " + p.attachJoint.Joint.breakTorque);
                    debugString.AppendLine("");

                    debugString.AppendLine("Joint Motion Locked: " + Convert.ToString(p.attachJoint.Joint.xMotion == ConfigurableJointMotion.Locked));

                    debugString.AppendLine("Angular Drive");
                    debugString.AppendLine("Position Spring: " + angDrive.positionSpring);
                    debugString.AppendLine("Position Damper: " + angDrive.positionDamper);
                    debugString.AppendLine("Max Force: " + angDrive.maximumForce);
                    debugString.AppendLine("");

                    debugString.AppendLine("Cross Section Properties");
                    debugString.AppendLine("Radius: " + radius);
                    debugString.AppendLine("Area: " + area);
                    debugString.AppendLine("Moment of Inertia: " + momentOfInertia);
                }
            }
            if (KJRJointUtils.settings.debug)
            {
                Debug.Log(debugString.ToString());
            }
        }
Ejemplo n.º 17
0
        public bool TrySetValidLinkedSet(Part linkPart1, Part linkPart2)
        {
            linkPart1List.Clear();
            linkPart2List.Clear();
            linkedSet.Clear();

            if (!KJRJointUtils.JointAdjustmentValid(linkPart1) || !KJRJointUtils.JointAdjustmentValid(linkPart2))
            {
                return(false);
            }

            //Add the parts we're connecting to their respective lists
            linkPart1List.Add(linkPart1);
            linkPart2List.Add(linkPart2);

            //iterate through each part's parents, making them the new linkPart and then adding them to their respective lists.  LinkPart.parent will not be null until it reaches the root part
            while ((object)linkPart1.parent != null)
            {
                linkPart1 = linkPart1.parent;
                linkPart1List.Add(linkPart1);
            }
            while ((object)linkPart2.parent != null)
            {
                linkPart2 = linkPart2.parent;
                linkPart2List.Add(linkPart2);
            }

            int index1, index2;

            index1 = linkPart1List.Count - 1;
            index2 = linkPart2List.Count - 1;
            bool reachedMergeNode = false;

            //Start iterating through the lists, starting from the last indices.  Due to the way the lists were created, index 0 = connected part, while index = Count - 1 = root part
            while (true)
            {
                Part p = null, q = null;

                //if the indices are valid, get those particular parts
                if (index1 >= 0)
                {
                    p = linkPart1List[index1];
                }
                if (index2 >= 0)
                {
                    q = linkPart2List[index2];
                }

                //decrement indices for next iteration
                index1--;
                index2--;

                //if p and q are the same, this is the merge we care about; set variable noting this now
                if (p == q)
                {
                    reachedMergeNode = true;
                }

                //if we haven't reached the merge yet, go back to the beginning of the loop
                if (!reachedMergeNode)
                {
                    continue;
                }

                //if we have reached the merge, all the remaining parts are parts of the line connecting these parts and should be set to be disconnected
                if ((object)p != null)
                {
                    if (KJRJointUtils.JointAdjustmentValid(p))
                    {
                        linkedSet.Add(p);
                    }
                    else
                    {
                        return(false);
                    }
                }
                if ((object)q != null)
                {
                    if (KJRJointUtils.JointAdjustmentValid(q))
                    {
                        linkedSet.Add(q);
                    }
                    else
                    {
                        return(false);
                    }
                }

                //if both p and q are null, that means we've reached the end of both lines and so all the parts have been added
                if ((object)p == null && (object)q == null)
                {
                    break;
                }
            }

            return(true);
        }
        // FEHLER, überarbeiten... ist das nicht etwas sehr viel was wir hier aufbauen???
        private void ReinforceDecouplers(Part part)
        {
            List <Part> childParts  = new List <Part>();
            List <Part> parentParts = new List <Part>();

            parentParts = KJRJointUtils.DecouplerPartStiffeningListParents(part.parent);

            foreach (Part p in part.children)
            {
                if (KJRJointUtils.IsJointAdjustmentAllowed(p))
                {
                    childParts.AddRange(KJRJointUtils.DecouplerPartStiffeningListChildren(p));
                    if (!childParts.Contains(p))
                    {
                        childParts.Add(p);
                    }
                }
            }

            parentParts.Add(part);

            StringBuilder debugString = null;

            if (KJRJointUtils.debug)
            {
                debugString = new StringBuilder();
                debugString.AppendLine(parentParts.Count + " parts above decoupler to be connected to " + childParts.Count + " below decoupler.");
                debugString.AppendLine("The following joints added by " + part.partInfo.title + " to increase stiffness:");
            }

            foreach (Part p in parentParts)
            {
                if (p == null || p.rb == null || p.Modules.Contains("ProceduralFairingDecoupler"))
                {
                    continue;
                }

                foreach (Part q in childParts)
                {
                    if (q == null || q.rb == null || p == q || q.Modules.Contains("ProceduralFairingDecoupler"))
                    {
                        continue;
                    }

                    if (p.vessel != q.vessel)
                    {
                        continue;
                    }

                    MultiPartJointBuildJoint(p, q, KJRMultiJointManager.Reason.ReinforceDecoupler);

                    if (KJRJointUtils.debug)
                    {
                        debugString.AppendLine(p.partInfo.title + " connected to part " + q.partInfo.title);
                    }
                }
            }


            if (KJRJointUtils.debug)
            {
                Debug.Log(debugString.ToString());
            }
        }
/*        public void LateUpdate()
 *      {
 *          if (!FlightDriver.Pause && FlightGlobals.fetch && FlightGlobals.Vessels != null)
 *          {
 *              foreach (Vessel v in FlightGlobals.Vessels)
 *              {
 *                  if (!v.loaded)
 *                      continue;
 *
 * //                    int tick = 0;
 * //                    float scalingFactor = 1;
 *                  //This scales up the inertia tensor over a few frames rather than trying to initialize with massive inertia tensors
 * //                    if (vesselOffRailsTick.TryGetValue(v, out tick))
 * //                    {
 * //                        scalingFactor = 1 - physicsEasingCurve.Evaluate(tick);
 * //                    }
 *
 *                  //ScreenMessages.PostScreenMessage("Scaling Factor: " + scalingFactor, TimeWarp.deltaTime, ScreenMessageStyle.UPPER_LEFT);
 *
 *                  foreach (Part p in v.Parts)
 *                  {
 *                      //if (p.Modules.Contains("LaunchClamp"))
 *                      //    continue;
 *                      // This relies on KSP resetting the tensors to a constant in Update
 *                      if (p.started && p.State != PartStates.DEAD && p.rb)
 *                      {
 *                          float mass = p.rb.mass;// *scalingFactor;
 *
 *                          if (mass > 1f)
 *                              p.rb.inertiaTensor *= mass;
 *                      }
 *                  }
 *              }
 *          }
 *      }*/

        public void FixedUpdate()
        {
            if (FlightGlobals.ready && FlightGlobals.Vessels != null)
            {
                for (int i = 0; i < updatedVessels.Count; ++i)
                {
                    Vessel v = updatedVessels[i];
                    if (v == null || !vesselOffRailsTick.ContainsKey(v))
                    {
                        continue;
                    }

                    int tick = vesselOffRailsTick[v];
                    if (tick > 0)
                    {
                        float physicsScalingFactor = physicsEasingCurve.Evaluate(tick);
                        if (tick >= numTicksForEasing)
                        {
                            List <Joint> jointList = new List <Joint>();
                            foreach (Part p in v.Parts)
                            {
                                p.crashTolerance = p.crashTolerance * 10000f;
                                if (p.attachJoint)
                                {
                                    p.attachJoint.SetUnbreakable(true);
                                }

                                Joint[] partJoints = p.GetComponents <Joint>();

/*                                foreach (Joint j in partJoints)
 *                              {
 * //                                    j.breakForce *= 1000000000000000000;
 * //                                    j.breakTorque *= 1000000000000000000;
 *                                  jointList.Add(j);
 *                                  Debug.Log("Part: " + p.partInfo.title + " BreakForce = " + j.breakForce + " BreakTorque = " + j.breakTorque);
 *                              }*/
                                if (p.Modules.Contains <LaunchClamp>())
                                {
                                    foreach (Joint j in partJoints)
                                    {
                                        if (j.connectedBody == null)
                                        {
                                            jointList.Remove(j);
                                            GameObject.Destroy(j);
                                            KJRJointUtils.ConnectLaunchClampToGround(p);
                                            break;
                                        }
                                    }
                                }
                            }
                            //vesselJointStrengthened.Add(v, jointList);
                        }
                        bool easing = false;
                        if (v.situation == Vessel.Situations.PRELAUNCH || v.situation == Vessel.Situations.LANDED || v.situation == Vessel.Situations.SPLASHED)
                        {
                            easing = true;
                        }
                        else
                        {
                            foreach (Part p in v.Parts)
                            {
                                if (p.Modules.Contains <LaunchClamp>())
                                {
                                    easing = true;
                                    break;
                                }
                            }
                        }
                        if (easing)
                        {
                            Vector3d vesselPos          = v.GetWorldPos3D();
                            Vector3d vesselVel          = v.obt_velocity;
                            Vector3d vesselAcceleration = FlightGlobals.getGeeForceAtPosition(vesselPos) + FlightGlobals.getCentrifugalAcc(vesselPos, FlightGlobals.currentMainBody) + FlightGlobals.getCoriolisAcc(vesselVel, FlightGlobals.currentMainBody);
                            vesselAcceleration *= physicsScalingFactor;
                            foreach (Part p in v.Parts)
                            {
                                if (p.rb)
                                {
                                    p.rb.AddForce(-vesselAcceleration * p.rb.mass);
                                }
                            }
                        }
                        if (v == FlightGlobals.ActiveVessel)
                        {
                            if (InputLockManager.GetControlLock("KJRLoadLock") != ControlTypes.ALL_SHIP_CONTROLS)
                            {
                                InputLockManager.SetControlLock(ControlTypes.ALL_SHIP_CONTROLS, "KJRLoadLock");
                            }
                            ScreenMessages.PostScreenMessage("KJR stabilizing physics load...", TimeWarp.fixedDeltaTime, ScreenMessageStyle.UPPER_RIGHT);
                        }
                        else
                        if (InputLockManager.GetControlLock("KJRLoadLock") == ControlTypes.ALL_SHIP_CONTROLS)
                        {
                            InputLockManager.RemoveControlLock("KJRLoadLock");
                        }

                        tick--;
                        vesselOffRailsTick[v] = tick;
                    }
                    else if (tick == 0)
                    {
                        foreach (Part p in v.Parts)
                        {
                            p.crashTolerance = p.crashTolerance / 10000f;
                            if (p.attachJoint)
                            {
                                p.attachJoint.SetUnbreakable(false);
                            }
                        }

                        vesselOffRailsTick.Remove(v);
                        if (InputLockManager.GetControlLock("KJRLoadLock") == ControlTypes.ALL_SHIP_CONTROLS)
                        {
                            InputLockManager.RemoveControlLock("KJRLoadLock");
                        }
                    }
                    else
                    {
                        foreach (Part p in v.Parts)
                        {
                            p.crashTolerance = p.crashTolerance / 10000f;
                            if (p.attachJoint)
                            {
                                p.attachJoint.SetUnbreakable(false);
                            }
                        }

                        vesselOffRailsTick.Remove(v);
                        if (InputLockManager.GetControlLock("KJRLoadLock") == ControlTypes.ALL_SHIP_CONTROLS)
                        {
                            InputLockManager.RemoveControlLock("KJRLoadLock");
                        }
                    }
                }
            }
        }
        // attachJoint's are always joints from a part to its parent
        private void ReinforceAttachJoints(Part p)
        {
            if (p.rb == null || p.attachJoint == null || !KJRJointUtils.IsJointAdjustmentAllowed(p))
            {
                return;
            }

            if ((p.attachMethod == AttachNodeMethod.LOCKED_JOINT) &&
                KJRJointUtils.debug)
            {
                Debug.Log("KJR: Already processed part before: " + p.partInfo.name + " (" + p.flightID + ") -> " +
                          p.parent.partInfo.name + " (" + p.parent.flightID + ")");
            }

            List <ConfigurableJoint> jointList;

            if (p.Modules.Contains <CModuleStrut>())
            {
                CModuleStrut s = p.Modules.GetModule <CModuleStrut>();

                if ((s.jointTarget != null) && (s.jointRoot != null))
                {
                    jointList = s.strutJoint.joints;

                    if (jointList != null)
                    {
                        for (int i = 0; i < jointList.Count; i++)
                        {
                            ConfigurableJoint j = jointList[i];

                            if (j == null)
                            {
                                continue;
                            }

                            JointDrive strutDrive = j.angularXDrive;
                            strutDrive.positionSpring = KJRJointUtils.decouplerAndClampJointStrength;
                            strutDrive.maximumForce   = KJRJointUtils.decouplerAndClampJointStrength;
                            j.xDrive = j.yDrive = j.zDrive = j.angularXDrive = j.angularYZDrive = strutDrive;

                            j.xMotion        = j.yMotion = j.zMotion = ConfigurableJointMotion.Locked;
                            j.angularXMotion = j.angularYMotion = j.angularZMotion = ConfigurableJointMotion.Locked;

                            //float scalingFactor = (s.jointTarget.mass + s.jointTarget.GetResourceMass() + s.jointRoot.mass + s.jointRoot.GetResourceMass()) * 0.01f;

                            j.breakForce  = KJRJointUtils.decouplerAndClampJointStrength;
                            j.breakTorque = KJRJointUtils.decouplerAndClampJointStrength;
                        }

                        p.attachMethod = AttachNodeMethod.LOCKED_JOINT;
                    }
                }
            }

            jointList = p.attachJoint.joints;

            if (jointList == null)
            {
                return;
            }

            StringBuilder debugString = new StringBuilder();

            bool addAdditionalJointToParent = KJRJointUtils.multiPartAttachNodeReinforcement;

            //addAdditionalJointToParent &= !(p.Modules.Contains("LaunchClamp") || (p.parent.Modules.Contains("ModuleDecouple") || p.parent.Modules.Contains("ModuleAnchoredDecoupler")));
            addAdditionalJointToParent &= !p.Modules.Contains <CModuleStrut>();

            if (!KJRJointUtils.IsJointUnlockable(p))            // exclude those actions from joints that can be dynamically unlocked
            {
                float partMass = p.mass + p.GetResourceMass();
                for (int i = 0; i < jointList.Count; i++)
                {
                    ConfigurableJoint j = jointList[i];
                    if (j == null)
                    {
                        continue;
                    }

                    String    jointType     = j.GetType().Name;
                    Rigidbody connectedBody = j.connectedBody;

                    Part  connectedPart = connectedBody.GetComponent <Part>() ?? p.parent;
                    float parentMass    = connectedPart.mass + connectedPart.GetResourceMass();

                    if (partMass < KJRJointUtils.massForAdjustment || parentMass < KJRJointUtils.massForAdjustment)
                    {
                        if (KJRJointUtils.debug)
                        {
                            Debug.Log("KJR: Part mass too low, skipping: " + p.partInfo.name + " (" + p.flightID + ")");
                        }

                        continue;
                    }

                    // Check attachment nodes for better orientation data
                    AttachNode attach   = p.FindAttachNodeByPart(p.parent);
                    AttachNode p_attach = p.parent.FindAttachNodeByPart(p);
                    AttachNode node     = attach ?? p_attach;

                    if (node == null)
                    {
                        // Check if it's a pair of coupled docking ports
                        var dock1 = p.Modules.GetModule <ModuleDockingNode>();
                        var dock2 = p.parent.Modules.GetModule <ModuleDockingNode>();

                        //Debug.Log(dock1 + " " + (dock1 ? ""+dock1.dockedPartUId : "?") + " " + dock2 + " " + (dock2 ? ""+dock2.dockedPartUId : "?"));

                        if (dock1 && dock2 && (dock1.dockedPartUId == p.parent.flightID || dock2.dockedPartUId == p.flightID))
                        {
                            attach   = p.FindAttachNode(dock1.referenceAttachNode);
                            p_attach = p.parent.FindAttachNode(dock2.referenceAttachNode);
                            node     = attach ?? p_attach;
                        }
                    }

                    // If still no node and apparently surface attached, use the normal one if it's there
                    if (node == null && p.attachMode == AttachModes.SRF_ATTACH)
                    {
                        node = attach = p.srfAttachNode;
                    }

                    if (KJRJointUtils.debug)
                    {
                        debugString.AppendLine("Original joint from " + p.partInfo.title + " to " + p.parent.partInfo.title);
                        debugString.AppendLine("  " + p.partInfo.name + " (" + p.flightID + ") -> " + p.parent.partInfo.name + " (" + p.parent.flightID + ")");
                        debugString.AppendLine("");
                        debugString.AppendLine(p.partInfo.title + " Inertia Tensor: " + p.rb.inertiaTensor + " " + p.parent.partInfo.name + " Inertia Tensor: " + connectedBody.inertiaTensor);
                        debugString.AppendLine("");


                        debugString.AppendLine("Std. Joint Parameters");
                        debugString.AppendLine("Connected Body: " + p.attachJoint.Joint.connectedBody);
                        debugString.AppendLine("Attach mode: " + p.attachMode + " (was " + jointType + ")");
                        if (attach != null)
                        {
                            debugString.AppendLine("Attach node: " + attach.id + " - " + attach.nodeType + " " + attach.size);
                        }
                        if (p_attach != null)
                        {
                            debugString.AppendLine("Parent node: " + p_attach.id + " - " + p_attach.nodeType + " " + p_attach.size);
                        }
                        debugString.AppendLine("Anchor: " + p.attachJoint.Joint.anchor);
                        debugString.AppendLine("Axis: " + p.attachJoint.Joint.axis);
                        debugString.AppendLine("Sec Axis: " + p.attachJoint.Joint.secondaryAxis);
                        debugString.AppendLine("Break Force: " + p.attachJoint.Joint.breakForce);
                        debugString.AppendLine("Break Torque: " + p.attachJoint.Joint.breakTorque);
                        debugString.AppendLine("");

                        debugString.AppendLine("Joint Motion Locked: " + Convert.ToString(p.attachJoint.Joint.xMotion == ConfigurableJointMotion.Locked));

                        debugString.AppendLine("X Drive");
                        debugString.AppendLine("Position Spring: " + p.attachJoint.Joint.xDrive.positionSpring);
                        debugString.AppendLine("Position Damper: " + p.attachJoint.Joint.xDrive.positionDamper);
                        debugString.AppendLine("Max Force: " + p.attachJoint.Joint.xDrive.maximumForce);
                        debugString.AppendLine("");

                        debugString.AppendLine("Y Drive");
                        debugString.AppendLine("Position Spring: " + p.attachJoint.Joint.yDrive.positionSpring);
                        debugString.AppendLine("Position Damper: " + p.attachJoint.Joint.yDrive.positionDamper);
                        debugString.AppendLine("Max Force: " + p.attachJoint.Joint.yDrive.maximumForce);
                        debugString.AppendLine("");

                        debugString.AppendLine("Z Drive");
                        debugString.AppendLine("Position Spring: " + p.attachJoint.Joint.zDrive.positionSpring);
                        debugString.AppendLine("Position Damper: " + p.attachJoint.Joint.zDrive.positionDamper);
                        debugString.AppendLine("Max Force: " + p.attachJoint.Joint.zDrive.maximumForce);
                        debugString.AppendLine("");

                        debugString.AppendLine("Angular X Drive");
                        debugString.AppendLine("Position Spring: " + p.attachJoint.Joint.angularXDrive.positionSpring);
                        debugString.AppendLine("Position Damper: " + p.attachJoint.Joint.angularXDrive.positionDamper);
                        debugString.AppendLine("Max Force: " + p.attachJoint.Joint.angularXDrive.maximumForce);
                        debugString.AppendLine("");

                        debugString.AppendLine("Angular YZ Drive");
                        debugString.AppendLine("Position Spring: " + p.attachJoint.Joint.angularYZDrive.positionSpring);
                        debugString.AppendLine("Position Damper: " + p.attachJoint.Joint.angularYZDrive.positionDamper);
                        debugString.AppendLine("Max Force: " + p.attachJoint.Joint.angularYZDrive.maximumForce);
                        debugString.AppendLine("");


                        //Debug.Log(debugString.ToString());
                    }


                    float   breakForce      = Math.Min(p.breakingForce, connectedPart.breakingForce) * KJRJointUtils.breakForceMultiplier;
                    float   breakTorque     = Math.Min(p.breakingTorque, connectedPart.breakingTorque) * KJRJointUtils.breakTorqueMultiplier;
                    Vector3 anchor          = j.anchor;
                    Vector3 connectedAnchor = j.connectedAnchor;
                    Vector3 axis            = j.axis;

                    float radius          = 0;
                    float area            = 0;
                    float momentOfInertia = 0;

                    if (node != null)
                    {
                        // Part that owns the node. For surface attachment,
                        // this can only be parent if docking flips hierarchy.
                        Part main = (node == attach) ? p : p.parent;

                        // Orientation and position of the node in owner's local coords
                        Vector3 ndir = node.orientation.normalized;
                        Vector3 npos = node.position + node.offset;

                        // And in the current part's local coords
                        Vector3 dir = axis = p.transform.InverseTransformDirection(main.transform.TransformDirection(ndir));

                        if (node.nodeType == AttachNode.NodeType.Surface)
                        {
                            // Guessed main axis; for parts with stack nodes should be the axis of the stack
                            Vector3 up = KJRJointUtils.GuessUpVector(main).normalized;

                            // if guessed up direction is same as node direction, it's basically stack
                            // for instance, consider a radially-attached docking port
                            if (Mathf.Abs(Vector3.Dot(up, ndir)) > 0.9f)
                            {
                                radius = Mathf.Min(KJRJointUtils.CalculateRadius(main, ndir), KJRJointUtils.CalculateRadius(connectedPart, ndir));
                                if (radius <= 0.001)
                                {
                                    radius = node.size * 1.25f;
                                }
                                area            = Mathf.PI * radius * radius;                                              //Area of cylinder
                                momentOfInertia = area * radius * radius / 4;                                              //Moment of Inertia of cylinder
                            }
                            else
                            {
                                // x along surface, y along ndir normal to surface, z along surface & main axis (up)
                                var size1 = KJRJointUtils.CalculateExtents(main, ndir, up);

                                var size2 = KJRJointUtils.CalculateExtents(connectedPart, ndir, up);

                                // use average of the sides, since we don't know which one is used for attaching
                                float width1 = (size1.x + size1.z) / 2;
                                float width2 = (size2.x + size2.z) / 2;
                                if (size1.y * width1 > size2.y * width2)
                                {
                                    area   = size1.y * width1;
                                    radius = Mathf.Max(size1.y, width1);
                                }
                                else
                                {
                                    area   = size2.y * width2;
                                    radius = Mathf.Max(size2.y, width2);
                                }

                                momentOfInertia = area * radius / 12;                                             //Moment of Inertia of a rectangle bending along the longer length
                            }
                        }
                        else
                        {
                            radius = Mathf.Min(KJRJointUtils.CalculateRadius(p, dir), KJRJointUtils.CalculateRadius(connectedPart, dir));
                            if (radius <= 0.001)
                            {
                                radius = node.size * 1.25f;
                            }
                            area            = Mathf.PI * radius * radius;                                          //Area of cylinder
                            momentOfInertia = area * radius * radius / 4;                                          //Moment of Inertia of cylinder
                        }
                    }
                    //Assume part is attached along its "up" cross section; use a cylinder to approximate properties
                    else if (p.attachMode == AttachModes.STACK)
                    {
                        radius = Mathf.Min(KJRJointUtils.CalculateRadius(p, Vector3.up), KJRJointUtils.CalculateRadius(connectedPart, Vector3.up));
                        if (radius <= 0.001)
                        {
                            radius = 1.25f;                             // FEHLER, komisch, wieso setzen wir dann nicht alles < 1.25f auf 1.25f? -> zudem hatten wir hier sowieso einen Bug, das ist also sowieso zu hinterfragen
                        }
                        area            = Mathf.PI * radius * radius;   //Area of cylinder
                        momentOfInertia = area * radius * radius / 4;   //Moment of Inertia of cylinder
                    }
                    else if (p.attachMode == AttachModes.SRF_ATTACH)
                    {
                        // x,z sides, y along main axis
                        Vector3 up1   = KJRJointUtils.GuessUpVector(p);
                        var     size1 = KJRJointUtils.CalculateExtents(p, up1);

                        Vector3 up2   = KJRJointUtils.GuessUpVector(connectedPart);
                        var     size2 = KJRJointUtils.CalculateExtents(connectedPart, up2);

                        // use average of the sides, since we don't know which one is used for attaching
                        float width1 = (size1.x + size1.z) / 2;
                        float width2 = (size2.x + size2.z) / 2;
                        if (size1.y * width1 > size2.y * width2)
                        {
                            area   = size1.y * width1;
                            radius = Mathf.Max(size1.y, width1);
                        }
                        else
                        {
                            area   = size2.y * width2;
                            radius = Mathf.Max(size2.y, width2);
                        }
                        momentOfInertia = area * radius / 12;                                     //Moment of Inertia of a rectangle bending along the longer length
                    }

                    if (KJRJointUtils.useVolumeNotArea)                                                 //If using volume, raise al stiffness-affecting parameters to the 1.5 power
                    {
                        area            = Mathf.Pow(area, 1.5f);
                        momentOfInertia = Mathf.Pow(momentOfInertia, 1.5f);
                    }


                    breakForce  = Mathf.Max(KJRJointUtils.breakStrengthPerArea * area, breakForce);
                    breakTorque = Mathf.Max(KJRJointUtils.breakTorquePerMOI * momentOfInertia, breakTorque);

                    JointDrive angDrive = j.angularXDrive;
                    angDrive.positionSpring = Mathf.Max(momentOfInertia * KJRJointUtils.angularDriveSpring, angDrive.positionSpring);
                    angDrive.positionDamper = Mathf.Max(momentOfInertia * KJRJointUtils.angularDriveDamper * 0.1f, angDrive.positionDamper);
                    angDrive.maximumForce   = breakTorque;

                    /*float moi_avg = p.rb.inertiaTensor.magnitude;
                     *
                     * moi_avg += (p.transform.localToWorldMatrix.MultiplyPoint(p.CoMOffset) - p.parent.transform.position).sqrMagnitude * p.rb.mass;
                     *
                     * if(moi_avg * 2f / drive.positionDamper < 0.08f)
                     * {
                     *      drive.positionDamper = moi_avg / (0.04f);
                     *
                     *      drive.positionSpring = drive.positionDamper * drive.positionDamper / moi_avg;
                     * }*/
                    j.angularXDrive = j.angularYZDrive = j.slerpDrive = angDrive;

                    JointDrive linDrive = j.xDrive;
                    linDrive.maximumForce = breakForce;
                    j.xDrive = j.yDrive = j.zDrive = linDrive;

                    j.linearLimit = j.angularYLimit = j.angularZLimit = j.lowAngularXLimit = j.highAngularXLimit
                                                                                                 = new SoftJointLimit {
                        limit = 0, bounciness = 0
                    };
                    j.linearLimitSpring = j.angularYZLimitSpring = j.angularXLimitSpring
                                                                       = new SoftJointLimitSpring {
                        spring = 0, damper = 0
                    };

                    j.targetAngularVelocity = Vector3.zero;
                    j.targetVelocity        = Vector3.zero;
                    j.targetRotation        = Quaternion.identity;
                    j.targetPosition        = Vector3.zero;

                    j.breakForce  = breakForce;
                    j.breakTorque = breakTorque;
                    p.attachJoint.SetBreakingForces(j.breakForce, j.breakTorque);

                    p.attachMethod = AttachNodeMethod.LOCKED_JOINT;

                    if (KJRJointUtils.debug)
                    {
                        debugString.AppendLine("Updated joint from " + p.partInfo.title + " to " + p.parent.partInfo.title);
                        debugString.AppendLine("  " + p.partInfo.name + " (" + p.flightID + ") -> " + p.parent.partInfo.name + " (" + p.parent.flightID + ")");
                        debugString.AppendLine("");
                        debugString.AppendLine(p.partInfo.title + " Inertia Tensor: " + p.rb.inertiaTensor + " " + p.parent.partInfo.name + " Inertia Tensor: " + connectedBody.inertiaTensor);
                        debugString.AppendLine("");


                        debugString.AppendLine("Std. Joint Parameters");
                        debugString.AppendLine("Connected Body: " + p.attachJoint.Joint.connectedBody);
                        debugString.AppendLine("Attach mode: " + p.attachMode + " (was " + jointType + ")");
                        if (attach != null)
                        {
                            debugString.AppendLine("Attach node: " + attach.id + " - " + attach.nodeType + " " + attach.size);
                        }
                        if (p_attach != null)
                        {
                            debugString.AppendLine("Parent node: " + p_attach.id + " - " + p_attach.nodeType + " " + p_attach.size);
                        }
                        debugString.AppendLine("Anchor: " + p.attachJoint.Joint.anchor);
                        debugString.AppendLine("Axis: " + p.attachJoint.Joint.axis);
                        debugString.AppendLine("Sec Axis: " + p.attachJoint.Joint.secondaryAxis);
                        debugString.AppendLine("Break Force: " + p.attachJoint.Joint.breakForce);
                        debugString.AppendLine("Break Torque: " + p.attachJoint.Joint.breakTorque);
                        debugString.AppendLine("");

                        debugString.AppendLine("Joint Motion Locked: " + Convert.ToString(p.attachJoint.Joint.xMotion == ConfigurableJointMotion.Locked));

                        debugString.AppendLine("Angular Drive");
                        debugString.AppendLine("Position Spring: " + angDrive.positionSpring);
                        debugString.AppendLine("Position Damper: " + angDrive.positionDamper);
                        debugString.AppendLine("Max Force: " + angDrive.maximumForce);
                        debugString.AppendLine("");

                        debugString.AppendLine("Cross Section Properties");
                        debugString.AppendLine("Radius: " + radius);
                        debugString.AppendLine("Area: " + area);
                        debugString.AppendLine("Moment of Inertia: " + momentOfInertia);
                    }
                }
            }

#if IncludeAnalyzer
            addAdditionalJointToParent &= WindowManager.Instance.BuildAdditionalJointToParent;
#endif

            if (addAdditionalJointToParent && p.parent.parent != null &&
                KJRJointUtils.IsJointAdjustmentAllowed(p.parent))          // verify that parent is not an excluded part -> we will skip this in our calculation, that's why we need to check it now
            {
                ConfigurableJoint j = p.attachJoint.Joint;                 // second steps uses the first/main joint as reference

                Part newConnectedPart = p.parent.parent;

                bool massRatioBelowThreshold = false;
                int  numPartsFurther         = 0;

                float       partMaxMass          = KJRJointUtils.MaximumPossiblePartMass(p);
                List <Part> partsCrossed         = new List <Part>();
                List <Part> possiblePartsCrossed = new List <Part>();

                partsCrossed.Add(p.parent);

                Part connectedRbPart = newConnectedPart;

                // search the first part with an acceptable mass/mass ration to this part (joints work better then)
                do
                {
                    float massRat1 = (partMaxMass < newConnectedPart.mass) ? (newConnectedPart.mass / partMaxMass) : (partMaxMass / newConnectedPart.mass);

                    if (massRat1 <= KJRJointUtils.stiffeningExtensionMassRatioThreshold)
                    {
                        massRatioBelowThreshold = true;
                    }
                    else
                    {
                        float maxMass  = KJRJointUtils.MaximumPossiblePartMass(newConnectedPart);
                        float massRat2 = (p.mass < maxMass) ? (maxMass / p.mass) : (p.mass / maxMass);

                        if (massRat2 <= KJRJointUtils.stiffeningExtensionMassRatioThreshold)
                        {
                            massRatioBelowThreshold = true;
                        }
                        else
                        {
                            if ((newConnectedPart.parent == null) ||
                                !KJRJointUtils.IsJointAdjustmentAllowed(newConnectedPart))
                            {
                                break;
                            }

                            newConnectedPart = newConnectedPart.parent;

                            if (newConnectedPart.rb == null)
                            {
                                possiblePartsCrossed.Add(newConnectedPart);
                            }
                            else
                            {
                                connectedRbPart = newConnectedPart;
                                partsCrossed.AddRange(possiblePartsCrossed);
                                partsCrossed.Add(newConnectedPart);
                                possiblePartsCrossed.Clear();
                            }

                            numPartsFurther++;
                        }
                    }
                } while(!massRatioBelowThreshold);                // && numPartsFurther < 5);

                if (newConnectedPart.rb != null && !multiJointManager.CheckDirectJointBetweenParts(p, newConnectedPart))
                {
                    ConfigurableJoint newJoint;

                    if ((p.mass >= newConnectedPart.mass) || (p.rb == null))
                    {
                        newJoint = p.gameObject.AddComponent <ConfigurableJoint>();
                        newJoint.connectedBody = newConnectedPart.rb;

                        newJoint.anchor = Vector3.zero;

                        if (!KJRJointUtils.useOldJointCreation)
                        {
                            newJoint.autoConfigureConnectedAnchor = false;
                            newJoint.connectedAnchor = Quaternion.Inverse(newConnectedPart.orgRot) * (p.orgPos - newConnectedPart.orgPos);

                            Quaternion must = newConnectedPart.transform.rotation * (Quaternion.Inverse(newConnectedPart.orgRot) * p.orgRot);
                            newJoint.SetTargetRotationLocal(Quaternion.Inverse(p.transform.rotation) * must, Quaternion.identity);
                            // FEHLER, direkter machen
                        }
                    }
                    else
                    {
                        newJoint = newConnectedPart.gameObject.AddComponent <ConfigurableJoint>();
                        newJoint.connectedBody = p.rb;

                        newJoint.anchor = Vector3.zero;

                        if (!KJRJointUtils.useOldJointCreation)
                        {
                            newJoint.autoConfigureConnectedAnchor = false;
                            newJoint.connectedAnchor = Quaternion.Inverse(p.orgRot) * (newConnectedPart.orgPos - p.orgPos);

                            Quaternion must = p.transform.rotation * (Quaternion.Inverse(p.orgRot) * newConnectedPart.orgRot);
                            newJoint.SetTargetRotationLocal(Quaternion.Inverse(newConnectedPart.transform.rotation) * must, Quaternion.identity);
                            // FEHLER, direkter machen
                        }
                    }

                    //			newJoint.linearLimit = newJoint.angularYLimit = newJoint.angularZLimit = newJoint.lowAngularXLimit = newJoint.highAngularXLimit
                    //				= new SoftJointLimit { limit = 0, bounciness = 0 }; // FEHLER, hab das mal rausgenommen -> evtl. später doch wieder Limited arbeiten??

                    newJoint.xMotion        = newJoint.yMotion = newJoint.zMotion = ConfigurableJointMotion.Free;
                    newJoint.angularYMotion = newJoint.angularZMotion = newJoint.angularXMotion = ConfigurableJointMotion.Free;

                    newJoint.xDrive        = j.xDrive; newJoint.yDrive = j.yDrive; newJoint.zDrive = j.zDrive;
                    newJoint.angularXDrive = newJoint.angularYZDrive = newJoint.slerpDrive = j.angularXDrive;

                    newJoint.breakForce  = j.breakForce;
                    newJoint.breakTorque = j.breakTorque;

                    // register joint
                    multiJointManager.RegisterMultiJoint(p, newJoint, true, KJRMultiJointManager.Reason.AdditionalJointToParent);
                    multiJointManager.RegisterMultiJoint(newConnectedPart, newJoint, true, KJRMultiJointManager.Reason.AdditionalJointToParent);

                    foreach (Part part in partsCrossed)
                    {
                        multiJointManager.RegisterMultiJoint(part, newJoint, false, KJRMultiJointManager.Reason.AdditionalJointToParent);
                    }
                }
            }

            if (KJRJointUtils.debug)
            {
                Debug.Log(debugString.ToString());
            }
        }
        public void MultiPartJointTreeChildren(Vessel v)
        {
            if (v.Parts.Count <= 1)
            {
                return;
            }

            Dictionary <Part, List <Part> > childPartsToConnectByRoot = new Dictionary <Part, List <Part> >();

            for (int i = 0; i < v.Parts.Count; ++i)
            {
                Part p = v.Parts[i];

                bool bEndPoint = (p.children.Count == 0);

                if (!bEndPoint && !KJRJointUtils.IsJointAdjustmentAllowed(p) && p.parent && (p.parent.vessel == v))
                {
                    p = p.parent;

                    bEndPoint = true;
                    for (int j = 0; j < p.children.Count; j++)
                    {
                        if (KJRJointUtils.IsJointAdjustmentAllowed(p.children[j]))
                        {
                            bEndPoint = false; break;
                        }
                    }
                }

                if (bEndPoint && !p.Modules.Contains("LaunchClamp") && KJRJointUtils.MaximumPossiblePartMass(p) > KJRJointUtils.massForAdjustment)
                {
                    if (p.rb == null && p.Rigidbody != null)
                    {
                        p = p.RigidBodyPart;
                    }

                    Part root = p;
                    while (root.parent && (root.parent.vessel == v) && KJRJointUtils.IsJointAdjustmentAllowed(root))
                    {
                        root = root.parent;
                    }

                    List <Part> childPartsToConnect;
                    if (!childPartsToConnectByRoot.TryGetValue(root, out childPartsToConnect))
                    {
                        childPartsToConnect = new List <Part>();
                        childPartsToConnectByRoot.Add(root, childPartsToConnect);
                    }

                    childPartsToConnect.Add(p);
                }
            }

            foreach (Part root in childPartsToConnectByRoot.Keys)
            {
                List <Part> childPartsToConnect = childPartsToConnectByRoot[root];

                for (int i = 0; i < childPartsToConnect.Count; ++i)
                {
                    Part p = childPartsToConnect[i];

                    if (!p.rb)
                    {
                        continue;
                    }

                    Part linkPart = childPartsToConnect[i + 1 >= childPartsToConnect.Count ? 0 : i + 1];

                    if (!linkPart.Rigidbody || p.rb == linkPart.Rigidbody)
                    {
                        continue;
                    }

#if IncludeAnalyzer
                    if (WindowManager.Instance.BuildMultiPartJointTreeChildren)
#endif
                    MultiPartJointBuildJoint(p, linkPart, KJRMultiJointManager.Reason.MultiPartJointTreeChildren);


                    int part2Index = i + childPartsToConnect.Count / 2;
                    if (part2Index >= childPartsToConnect.Count)
                    {
                        part2Index -= childPartsToConnect.Count;
                    }

                    Part linkPart2 = childPartsToConnect[part2Index];

                    if (!linkPart2.Rigidbody || p.rb == linkPart2.Rigidbody)
                    {
                        continue;
                    }

#if IncludeAnalyzer
                    if (WindowManager.Instance.BuildMultiPartJointTreeChildren)
#endif
                    MultiPartJointBuildJoint(p, linkPart2, KJRMultiJointManager.Reason.MultiPartJointTreeChildren);


                    if (!root.Rigidbody || p.rb == root.Rigidbody)
                    {
                        continue;
                    }

#if IncludeAnalyzer
                    if (WindowManager.Instance.BuildMultiPartJointTreeChildrenRoot)
#endif
                    MultiPartJointBuildJoint(p, root, KJRMultiJointManager.Reason.MultiPartJointTreeChildrenRoot);
                }
            }
        }
        private void RunVesselJointUpdateFunction(Vessel v)
        {
            if (KJRJointUtils.debug)
            {
                Debug.Log("KJR: Processing vessel " + v.id + " (" + v.GetName() + "); root " +
                          v.rootPart.partInfo.name + " (" + v.rootPart.flightID + ")");
            }

            bool bReinforced = false;

#if IncludeAnalyzer
            if (WindowManager.Instance.ReinforceExistingJoints)
            {
#endif

            foreach (Part p in v.Parts)
            {
                if (KJRJointUtils.reinforceAttachNodes)
                {
                    if ((p.parent != null) && (p.physicalSignificance == Part.PhysicalSignificance.FULL))
                    {
                        bReinforced = true;
                        ReinforceAttachJoints(p);
                    }
                }

                if (KJRJointUtils.reinforceDecouplersFurther)
                {
#if Compatible
                    if (p.parent && (p.children.Count > 0))
                    {
                        for (int i = 0; i < p.Modules.Count; i++)
                        {
                            if (KJRJointUtils.IsOfClass(p.Modules[i], ModuleDecoupleType))
                            {
                                if (!(bool)isDecoupledField.GetValue(p.Modules[i]))
                                {
                                    bReinforced = true;
                                    ReinforceDecouplers(p);
                                    goto continue_;
                                }
                            }
                        }
                    }
#endif

#if !Compatible
                    ModuleDecouplerBase d = p.GetComponent <ModuleDecouplerBase>();                    // FEHLER, wieso nicht auch ModuleDockingNode ??

                    if (p.parent && (p.children.Count > 0) && d && !d.isDecoupled)
                    {
                        bReinforced = true;
                        ReinforceDecouplers(p);
                        continue;
                    }
#endif
                }

                if (KJRJointUtils.reinforceLaunchClampsFurther)
                {
                    if (p.parent && p.GetComponent <LaunchClamp>())
                    {
                        ReinforceLaunchClamps(p);
                    }
                }
                continue_ :;
            }

#if IncludeAnalyzer
        }
#endif

            if (bReinforced && !updatedVessels.Contains(v))
            {
                updatedVessels.Add(v);
            }

            if (KJRJointUtils.reinforceAttachNodes && KJRJointUtils.multiPartAttachNodeReinforcement)
            {
                MultiPartJointTreeChildren(v);
            }
        }
Ejemplo n.º 23
0
        private void AddExtraJoints()
        {
            List <Part> childParts  = new List <Part>();
            List <Part> parentParts = new List <Part>();

            parentParts = KJRJointUtils.DecouplerPartStiffeningListParents(part.parent);

            foreach (Part p in part.children)
            {
                if (KJRJointUtils.IsJointAdjustmentAllowed(p))
                {
                    childParts.AddRange(KJRJointUtils.DecouplerPartStiffeningListChildren(p));
                    if (!childParts.Contains(p))
                    {
                        childParts.Add(p);
                    }
                }
            }

            neighbours.Clear();
            neighbours.AddRange(parentParts);
            neighbours.AddRange(childParts);
            neighbours.Remove(part);

            parentParts.Add(part);

            StringBuilder debugString = null;

            if (Log.debuglevel > 3)
            {
                debugString = new StringBuilder();
                debugString.AppendLine(parentParts.Count + " parts above decoupler to be connected to " + childParts.Count + " below decoupler.");
                debugString.AppendLine("The following joints added by " + part.partInfo.title + " to increase stiffness:");
            }

            foreach (Part p in parentParts)
            {
                if (p == null || p.rb == null || p.Modules.Contains("ProceduralFairingDecoupler"))
                {
                    continue;
                }

                foreach (Part q in childParts)
                {
                    if (q == null || q.rb == null || p == q || q.Modules.Contains("ProceduralFairingDecoupler"))
                    {
                        continue;
                    }

                    if (p.vessel != q.vessel)
                    {
                        continue;
                    }

                    joints.Add(KJRJointUtils.BuildJoint(p, q));

                    if (Log.debuglevel > 3)
                    {
                        debugString.AppendLine(p.partInfo.title + " connected to part " + q.partInfo.title);
                    }
                }
            }

            if (joints.Count > 0)
            {
                GameEvents.onVesselCreate.Add(OnVesselWasModified);
                GameEvents.onVesselWasModified.Add(OnVesselWasModified);
            }

            Log.dbg("{0}", debugString);
        }