private void setupNodeCrossfeed()
 {
     AttachNode node = part.findAttachNode(nodeName);
     if(node!=null && node.attachedPart!=null)
     {
         Part ap = node.attachedPart;
         AttachNode an = null;
         if(ap.NoCrossFeedNodeKey==null || ap.NoCrossFeedNodeKey.Length==0)
         {
             foreach(AttachNode m in ap.attachNodes)
             {
                 if(m.attachedPart==part)
                 {
                     an = m;
                     break;
                 }
             }
             if(an!=null)
             {
                 ap.NoCrossFeedNodeKey = an.id;
                 otherNode = an;
             }
         }
     }
 }
Exemple #2
0
        public static void AssignAttachIcon(Part part, AttachNode node, Color iconColor, string name = null)
        {
            // Create NodeTransform if needed
            if (node.nodeTransform == null)
            {
                node.nodeTransform = new GameObject("KISNodeTransf").transform;
                node.nodeTransform.parent = part.transform;
                node.nodeTransform.localPosition = node.position;
                node.nodeTransform.localRotation = KIS_Shared.GetNodeRotation(node);
            }

            if (!node.icon)
            {
                node.icon = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                if (node.icon.collider) UnityEngine.Object.DestroyImmediate(node.icon.collider);
                if (node.icon.renderer)
                {
                    node.icon.renderer.material = new Material(Shader.Find("Transparent/Diffuse"));
                    iconColor.a = 0.5f;
                    node.icon.renderer.material.color = iconColor;
                }
                node.icon.transform.parent = part.transform;
                if (name != null) node.icon.name = name;
                double num;
                if (node.size == 0)
                {
                    num = (double)node.size + 0.5;
                }
                else num = (double)node.size;
                node.icon.transform.localScale = Vector3.one * node.radius * (float)num;
                node.icon.transform.parent = node.nodeTransform;
                node.icon.transform.localPosition = Vector3.zero;
                node.icon.transform.localRotation = Quaternion.identity;
            }
        }
Exemple #3
0
 public AnimatedNode(AttachNode node, Transform node_transform, Part part)
 {
     this.node = node;
     this.part = part;
     nT        = node_transform;
     pT        = part.partTransform;
 }
        public override void OnStart(PartModule.StartState state)
        {
            if (part != null)
            {
                if (MeshName != "")
                {
                    meshObject = part.FindModelTransform(MeshName).gameObject;

                }
                if (NodeName != "")
                {
                    foreach (AttachNode nodes in part.attachNodes)
                    {

                        if (nodes.id == NodeName)
                            node = nodes;
                    }
                }
                if (meshObject == null)
                {
                    Utils.LogError("Couldn't find gameObject " + MeshName);
                }
                else if (node == null)
                {
                    Utils.LogError("Couldn't find stack node " + NodeName);
                }
                else
                {
                    SetVisibility();
                }
            }
        }
        public static AttachNodeSim New(PartSim partSim, String newId, AttachNode.NodeType newNodeType)
        {
            AttachNodeSim nodeSim = pool.Borrow();

            nodeSim.attachedPartSim = partSim;
            nodeSim.nodeType = newNodeType;
            nodeSim.id = newId;

            return nodeSim;
        }
 private void CopyNodeSizeAndStrength()
 {
     if (bottomNode == null)
         bottomNode = part.findAttachNode(bottomNodeId);
     if (topNode == null)
         topNode = part.findAttachNode(topNodeId);
     bottomNode.size = topNode.size;
     bottomNode.breakingForce = topNode.breakingForce;
     bottomNode.breakingTorque = topNode.breakingTorque;
 }
 /// <summary>
 /// Destroys the input attach node and removes it from the part.
 /// </summary>
 /// <param name="part"></param>
 /// <param name="node"></param>
 public static void destroyAttachNode(Part part, AttachNode node)
 {
     if (node == null) { return; }
     part.attachNodes.Remove(node);
     node.owner = null;
     if (node.icon != null)
     {
         GameObject.Destroy(node.icon);
     }
 }
        public override void OnStart(PartModule.StartState state)
        {
            base.OnStart(state);

            node = part.findAttachNode(nodeName);
            if (node == null)
            {
                NE_Helper.logError("KEES PEC: AttachNode not found");
                node = part.attachNodes.First();
            }
        }
 /// <summary>
 /// Destroys the input attach node and removes it from the part.
 /// </summary>
 /// <param name="part"></param>
 /// <param name="node"></param>
 public static void destroyAttachNode(Part part, AttachNode node)
 {
     if (node == null) { return; }
     if (node.attachedPart != null) { MonoBehaviour.print("ERROR: Deleting attach node: " + node.id + " with attached part: " + node.attachedPart); }
     part.attachNodes.Remove(node);
     node.owner = null;
     if (node.icon != null)
     {
         GameObject.Destroy(node.icon);
     }
 }
 /// <summary>
 /// Creates a new attach node with the given paramaters and adds it to the input part.
 /// </summary>
 /// <param name="part"></param>
 /// <param name="id"></param>
 /// <param name="pos"></param>
 /// <param name="orient"></param>
 /// <param name="size"></param>
 /// <returns></returns>
 public static AttachNode createAttachNode(Part part, String id, Vector3 pos, Vector3 orient, int size)
 {
     AttachNode newNode = new AttachNode();
     newNode.id = id;
     newNode.owner = part;
     newNode.nodeType = AttachNode.NodeType.Stack;
     newNode.size = size;
     newNode.originalPosition = newNode.position = pos;
     newNode.originalOrientation = newNode.orientation = orient;
     part.attachNodes.Add(newNode);
     return newNode;
 }
Exemple #11
0
 public void UpdateNode()
 {
     //update node
     node.size = 0; //force node size to be zero; otherwise the Kraken comes when inflating
     node.position = pT.InverseTransformPoint(nT.position);
     node.originalPosition = node.position;
     //update attached parts
     attached_part = node.attachedPart;
     if(attached_part != null)
         attached_node = attached_part.findAttachNodeByPart(part);
     if(!UpdateJoint()) UpdatePartsPos();
 }
        public void ChangeAttachNodeSize(AttachNode node, float minDia, float area)
        {
            // ReSharper disable once CompareOfFloatsByEqualityOperator
            if (node.id != textureMessageName || maxImpulseDiameterRatio == 0)
                return;

            UI_FloatEdit ejectionImpulseEdit = (UI_FloatEdit)Fields["ejectionImpulse"].uiControlEditor;
            float oldRatio = ejectionImpulse / ejectionImpulseEdit.maxValue;

            maxImpulse = Mathf.Round(maxImpulseDiameterRatio * minDia);
            ejectionImpulseEdit.maxValue = maxImpulse;

            ejectionImpulse = Mathf.Round(maxImpulse * oldRatio / 0.1f) * 0.1f;
        }
Exemple #13
0
 public static void AddNodeTransform(Part p, AttachNode attachNode)
 {
     if (attachNode.nodeTransform == null)
     {
         Transform nodeTransform = new GameObject("KASNodeTransf").transform;
         nodeTransform.parent = p.transform;
         nodeTransform.localPosition = attachNode.position;
         nodeTransform.rotation = KAS_Shared.DirectionToQuaternion(p.transform, attachNode.orientation);
         attachNode.nodeTransform = nodeTransform;
     }
     else
     {
         attachNode.nodeTransform.localPosition = attachNode.position;
         attachNode.nodeTransform.rotation = KAS_Shared.DirectionToQuaternion(p.transform, attachNode.orientation);
         KAS_Shared.DebugLog("AddTransformToAttachNode - Node : " + attachNode.id + " already have a nodeTransform, only update");
     }
 }
Exemple #14
0
        public static void AddNodeTransform(Part p, AttachNode attachNode)
        {
            Quaternion rotation = Quaternion.LookRotation(attachNode.orientation, Vector3.up);

            if (attachNode.nodeType == AttachNode.NodeType.Surface) {
              rotation = Quaternion.Inverse(rotation);
            }

            if (attachNode.nodeTransform == null) {
              Transform nodeTransform = new GameObject("KASNodeTransf").transform;
              nodeTransform.parent = p.transform;
              nodeTransform.localPosition = attachNode.position;
              nodeTransform.localRotation = rotation;
              attachNode.nodeTransform = nodeTransform;
            } else {
              attachNode.nodeTransform.localPosition = attachNode.position;
              attachNode.nodeTransform.localRotation = rotation;
              KAS_Shared.DebugLog("AddTransformToAttachNode - Node : " + attachNode.id
                          + " already have a nodeTransform, only update");
            }
        }
        private void updatePartCrossflow()
        {
            print ("examining decoupler part crossfeed!");
            if(otherNode!=null){otherNode.ResourceXFeed=otherNodeDefaultFlow;}
            otherNode=null;
            AttachNode node = part.findAttachNode(nodeName);
            if(node!=null)
            {
                node.ResourceXFeed = !disableCrossflow;
                Part otherPart = node.attachedPart;
                AttachNode oNode = otherPart==null ? null : otherPart.findAttachNodeByPart(part);

                print ("set decoupler node crossflow to: "+node.ResourceXFeed+ " for node: "+node.id+" for part: "+part+ " attached part: "+otherPart+ " oNode: "+oNode);

                if(oNode!=null)
                {
                    otherNode = oNode;
                    otherNodeDefaultFlow = oNode.ResourceXFeed;
                    if(disableCrossflow){oNode.ResourceXFeed=false;}
                    print ("set other node crossflow to: "+oNode.ResourceXFeed);
                }
                else if(otherPart!=null)
                {
                    AttachNode on = SSTUUtils.findRemoteParentNode(otherPart, part);
                    if(on!=null)
                    {
                        print ("found remote node connection through: "+on+" :: "+on.id+" :: attached "+on.attachedPart);
                        otherNode = on;
                        otherNodeDefaultFlow = on.ResourceXFeed;
                        if(disableCrossflow){on.ResourceXFeed=false;}
                        print ("set remote connected node crosfeed to: "+on.ResourceXFeed);
                    }
                    else
                    {
                        print ("found part connected to node, but could not trace parantage through nodes");
                    }
                }
            }
        }
        public IntakeCrossSectionAdjuster(ModuleResourceIntake intake, Matrix4x4 worldToVesselMatrix)
        {
            this.part = intake.part;
            //ModuleResourceIntake intake = intake;

            intakeTrans = part.FindModelTransform(intake.intakeTransformName);
            vehicleBasisForwardVector = Vector3.forward;//intakeTrans.forward;

            foreach (AttachNode node in part.attachNodes)
            {
                if (node.nodeType == AttachNode.NodeType.Stack && Vector3.Dot(node.position, (part.transform.worldToLocalMatrix * intakeTrans.localToWorldMatrix).MultiplyVector(Vector3.forward)) > 0)
                {
                    frontNode = node;
                    break;
                }
            }

            thisToVesselMatrix = worldToVesselMatrix * intakeTrans.localToWorldMatrix;

            vehicleBasisForwardVector = thisToVesselMatrix.MultiplyVector(vehicleBasisForwardVector);

            intakeArea = INTAKE_AREA_SCALAR * intake.area;
        }
Exemple #17
0
        private AttachNode getLowestNode(Part p, out float fairingPos)
        {
            AttachNode node = null;
            AttachNode nodeTemp;
            float      pos = float.PositiveInfinity;
            Vector3    posTemp;
            int        len = p.attachNodes.Count;

            for (int i = 0; i < len; i++)
            {
                nodeTemp = p.attachNodes[i];
                posTemp  = nodeTemp.position;
                posTemp  = p.transform.TransformPoint(posTemp);
                posTemp  = part.transform.InverseTransformPoint(posTemp);
                if (posTemp.y < pos)
                {
                    node = nodeTemp;
                    pos  = posTemp.y;
                }
            }
            fairingPos = pos;
            return(node);
        }
Exemple #18
0
        /// <summary>
        /// Change the size of <paramref name="node"/> to reflect the new size of the part it's attached to.
        /// </summary>
        /// <param name="node">The node to resize.</param>
        /// <param name="baseNode">The same node, as found on the prefab part.</param>
        protected void ScaleAttachNode(AttachNode node, AttachNode baseNode)
        {
            Log.dbg("StandardPartScaler.ScaleAttachNode {0} {1}", node.id, baseNode.id);

            if (this.ts.isFreeScale || this.ScaleNodes == null || this.ScaleNodes.Length == 0)
            {
                float tmpBaseNodeSize = baseNode.size;
                if (tmpBaseNodeSize == 0)
                {
                    tmpBaseNodeSize = 0.5f;
                }
                node.size = (int)(tmpBaseNodeSize * this.ts.tweakScale / this.ts.defaultScale + 0.49);
            }
            else
            {
                node.size = baseNode.size + (1 * this.ScaleNodes[this.ts.tweakName]);
            }

            if (node.size < 0)
            {
                node.size = 0;
            }
        }
Exemple #19
0
        //Create the gameObject with the meshrenderer
        void createShroudGO()
        {
            if (!shroudEnabled)
            {
                return;
            }

            AttachNode topNode = part.FindAttachNode("top");

            generateShroud();

            if (shroudGO != null)
            {
                Destroy(shroudGO);
            }

            shroudGO = new GameObject("DecouplerShroud");
            shroudGO.transform.parent        = transform;
            shroudGO.transform.localPosition = topNode.position;
            shroudGO.transform.localRotation = Quaternion.identity;
            shroudGO.AddComponent <MeshFilter>().sharedMesh = shroudCylinders.multiCylinder.mesh;

            if (shroudMats != null)
            {
                foreach (Material mat in shroudMats)
                {
                    Destroy(mat);
                }
            }
            shroudGO.AddComponent <MeshRenderer>();

            //Setup materials
            CreateMaterials();
            updateTexture();

            generateDragCube();
        }
Exemple #20
0
        public static void FindResources_StackPri(Part part, HashSet <Part> visited, List <PartResource> resources, int resourceID)
        {
            // will never be called if we visited this part
            visited.Add(part);

            // check local first
            FindResources_Stack(part, visited, resources, resourceID);

            // Check self, else check parent.
            // weird logic, but this is what KSP does...
            PartResource resource = part.Resources.Get(resourceID);

            if (resource != null)
            {
                if (!resources.Contains(resource))
                {
                    resources.Add(resource);
                }
            }
            else
            {
                if (part.fuelCrossFeed && part.parent != null)
                {
                    AttachNode node = part.findAttachNodeByPart(part.parent);
                    if (node != null)
                    {
                        if (part.NoCrossFeedNodeKey == "" || !node.id.Contains(part.NoCrossFeedNodeKey))
                        {
                            if (!visited.Contains(part.parent))
                            {
                                FindResources_StackPri(part.parent, visited, resources, resourceID);
                            }
                        }
                    }
                }
            }
        }
Exemple #21
0
        private static Utils.Tuple <string, string> _nodeToString(AttachNode node, string id, bool stack = true)
        {
            const string delim = ", ";

            string retKey;

            if (stack)
            {
                retKey = "node_stack_" + id;
            }
            else
            {
                retKey = "node_attach";
            }

            var sb  = new StringBuilder();
            var pos = node.position;
            var or  = node.orientation;

            sb.Append(_formatNumberForOutput(pos.x));
            sb.Append(delim);
            sb.Append(_formatNumberForOutput(pos.y));
            sb.Append(delim);
            sb.Append(_formatNumberForOutput(pos.z));
            sb.Append(delim);
            sb.Append(_formatNumberForOutput(or.x));
            sb.Append(delim);
            sb.Append(_formatNumberForOutput(or.y));
            sb.Append(delim);
            sb.Append(_formatNumberForOutput(or.z));
            if (node.size >= 0)
            {
                sb.Append(delim);
                sb.Append(node.size);
            }
            return(new Utils.Tuple <string, string>(retKey, sb.ToString()));
        }
Exemple #22
0
        public static void CouplePart(Part srcPart, Part tgtPart, string srcAttachNodeID = null, AttachNode tgtAttachNode = null)
        {
            // Node links
            if (srcAttachNodeID != null)
            {
                if (srcAttachNodeID == "srfAttach")
                {
                    KIS_Shared.DebugLog("Attach type : " + srcPart.srfAttachNode.nodeType + " | ID : " + srcPart.srfAttachNode.id);
                    srcPart.attachMode = AttachModes.SRF_ATTACH;
                    srcPart.srfAttachNode.attachedPart = tgtPart;
                }
                else
                {
                    AttachNode srcAttachNode = srcPart.findAttachNode(srcAttachNodeID);
                    if (srcAttachNode != null)
                    {
                        KIS_Shared.DebugLog("Attach type : " + srcPart.srfAttachNode.nodeType + " | ID : " + srcAttachNode.id);
                        srcPart.attachMode         = AttachModes.STACK;
                        srcAttachNode.attachedPart = tgtPart;
                        if (tgtAttachNode != null)
                        {
                            tgtAttachNode.attachedPart = srcPart;
                        }
                    }
                    else
                    {
                        KIS_Shared.DebugError("Source attach node not found !");
                    }
                }
            }
            else
            {
                KIS_Shared.DebugWarning("Missing source attach node !");
            }

            srcPart.Couple(tgtPart);
        }
Exemple #23
0
        public void SetShipTransform(Transform shipTransform, Part rootPart)
        {
            // Don't assume shipTransform == rootPart.transform
            Transform  rootXform = rootPart.transform;
            AttachNode n         = FindNode(rootPart);
            var        rot       = Quaternion.identity;
            var        pos       = Vector3.zero;

            if (n != null)
            {
                Vector3 nodeAxis = rootXform.TransformDirection(n.orientation);
                Vector3 forward  = rootXform.forward;
                float   fwdDot   = Vector3.Dot(forward, nodeAxis);
                Debug.Log($"[EL] nodeAxis: {nodeAxis}");
                Debug.Log($"[EL] rotation: {rootXform.rotation} right:{rootXform.right} forward:{rootXform.forward} up:{rootXform.up}");
                if (Mathf.Abs(fwdDot) < 0.866f)
                {
                    rot = Quaternion.LookRotation(nodeAxis, forward);
                    rot = Quaternion.Inverse(rot);
                    Debug.Log($"[EL] {rot}");
                    rot = Quaternion.LookRotation(Vector3.up, -Vector3.forward) * rot;
                    Debug.Log($"[EL] {Quaternion.LookRotation (Vector3.up, -Vector3.forward)}");
                }
                else
                {
                    rot = Quaternion.LookRotation(nodeAxis, rootXform.right);
                    rot = Quaternion.Inverse(rot);
                    Debug.Log($"[EL] {rot}");
                    rot = new Quaternion(-0.5f, -0.5f, -0.5f, 0.5f) * rot;
                }
                pos = rootXform.TransformVector(n.position);
            }
            Debug.Log($"[EL] pos: {pos} rot: {rot}");
            shipTransform.position = rot * -pos;
            shipTransform.rotation = rot * shipTransform.rotation;
            Debug.Log($"[EL] position: {shipTransform.position} rotation: {shipTransform.rotation} right:{shipTransform.right} forward:{shipTransform.forward} up:{shipTransform.up}");
        }
Exemple #24
0
        public static void updateAttachedPartPos(AttachNode node, Part part)
        {
            if (node == null || part == null)
            {
                return;
            }

            var ap = node.attachedPart;

            if (!ap)
            {
                return;
            }

            var an = ap.FindAttachNodeByPart(part);

            if (an == null)
            {
                return;
            }

            var dp = part.transform.TransformPoint(node.position) - ap.transform.TransformPoint(an.position);

            if (ap == part.parent)
            {
                while (ap.parent)
                {
                    ap = ap.parent;
                }
                ap.transform.position   += dp;
                part.transform.position -= dp;
            }
            else
            {
                ap.transform.position += dp;
            }
        }
Exemple #25
0
        public static void CouplePart(Part srcPart, Part tgtPart, string srcAttachNodeID = null, AttachNode tgtAttachNode = null)
        {
            // Node links
            if (srcAttachNodeID != null)
            {
                if (srcAttachNodeID == "srfAttach")
                {
                    KIS_Shared.DebugLog("Attach type : " + srcPart.srfAttachNode.nodeType + " | ID : " + srcPart.srfAttachNode.id);
                    srcPart.attachMode = AttachModes.SRF_ATTACH;
                    srcPart.srfAttachNode.attachedPart = tgtPart;
                }
                else
                {
                    AttachNode srcAttachNode = srcPart.findAttachNode(srcAttachNodeID);
                    if (srcAttachNode != null)
                    {
                        KIS_Shared.DebugLog("Attach type : " + srcPart.srfAttachNode.nodeType + " | ID : " + srcAttachNode.id);
                        srcPart.attachMode = AttachModes.STACK;
                        srcAttachNode.attachedPart = tgtPart;
                        if (tgtAttachNode != null)
                        {
                            tgtAttachNode.attachedPart = srcPart;
                        }
                    }
                    else
                    {
                        KIS_Shared.DebugError("Source attach node not found !");
                    }
                }
            }
            else
            {
                KIS_Shared.DebugWarning("Missing source attach node !");
            }

            srcPart.Couple(tgtPart);
        }
        // tries to work out if the docking port is attached to another docking port (ie in the VAB) and therefore can be treated as if it is docked (for example by not requiring the hatch to be closed)
        private bool isAttachedToDockingPort()
        {
            // First - this is only possible if we have an reference attachmentNode
            if (!string.IsNullOrEmpty(docNodeAttachmentNodeName))
            {
                AttachNode thisNode = part.attachNodes.Find(x => x.id == docNodeAttachmentNodeName);
                if (null != thisNode)
                {
                    Part attachedPart = thisNode.attachedPart;
                    if (null != attachedPart)
                    {
                        // What is the attachNode in the attachedPart that links back to us?
                        AttachNode reverseNode = attachedPart.FindAttachNodeByPart(part);
                        if (null != reverseNode)
                        {
                            // Now the big question - is the attached part a docking node that is centred on the reverseNode?
                            IEnumerator <ModuleDockingNode> eNodes = attachedPart.Modules.OfType <ModuleDockingNode>().GetEnumerator();
                            while (eNodes.MoveNext())
                            {
                                if (eNodes.Current == null)
                                {
                                    continue;
                                }
                                if (eNodes.Current.referenceNode.id == reverseNode.id)
                                {
                                    // The part has a docking node that references the attachnode that connects back to our part - this is what we have been looking for!
                                    return(true);
                                }
                            }
                        }
                    }
                }
            }

            return(false);
        }
        //TODO: extract this method somewhere to use both here and in VesselKit
        AttachNode find_closest_free_node(IEnumerable <Part> parts,
                                          Vector3 world_pos, Vector3 world_fwd,
                                          out Vector3 world_delta)
        {
            world_delta = Vector3.zero;
            var        best_dist = float.MaxValue;
            Part       best_part = null;
            AttachNode best_node = null;

            foreach (var p in parts)
            {
                foreach (var n in p.attachNodes)
                {
                    var orientation = p.partTransform.TransformDirection(n.orientation).normalized;
                    if (Vector3.Dot(world_fwd, orientation) > GLB.MaxDockingCos)
                    {
                        var delta = p.partTransform.TransformPoint(n.position) - world_pos;
                        var dist  = delta.sqrMagnitude;
                        if (best_node == null || dist < best_dist)
                        {
                            best_part   = p;
                            best_node   = n;
                            best_dist   = dist;
                            world_delta = delta;
                        }
                    }
                }
            }
            if (best_node != null &&
                best_node.attachedPart != null &&
                best_node.attachedPart != part)
            {
                best_node = null;
            }
            return(best_node);
        }
Exemple #28
0
        public static void UpdateAttachedPartPos(this Part p, AttachNode node)
        {
            if (node == null)
            {
                return;
            }
            var ap = node.attachedPart;

            if (ap == null)
            {
                return;
            }
            var an = ap.FindAttachNodeByPart(p);

            if (an == null)
            {
                return;
            }
            var dp =
                p.transform.TransformPoint(node.position) -
                ap.transform.TransformPoint(an.position);

            if (ap == p.parent)
            {
                while (ap.parent)
                {
                    ap = ap.parent;
                }
                ap.transform.position += dp;
                p.transform.position  -= dp;
            }
            else
            {
                ap.transform.position += dp;
            }
        }
Exemple #29
0
        public static void AddNodeTransform(Part p, AttachNode attachNode)
        {
            Quaternion rotation = Quaternion.LookRotation(attachNode.orientation, Vector3.up);

            if (attachNode.nodeType == AttachNode.NodeType.Surface)
            {
                rotation = Quaternion.Inverse(rotation);
            }

            if (attachNode.nodeTransform == null)
            {
                Transform nodeTransform = new GameObject("KASNodeTransf").transform;
                nodeTransform.parent        = p.transform;
                nodeTransform.localPosition = attachNode.position;
                nodeTransform.localRotation = rotation;
                attachNode.nodeTransform    = nodeTransform;
            }
            else
            {
                attachNode.nodeTransform.localPosition = attachNode.position;
                attachNode.nodeTransform.localRotation = rotation;
                KAS_Shared.DebugLog("AddTransformToAttachNode - Node : " + attachNode.id + " already have a nodeTransform, only update");
            }
        }
Exemple #30
0
        public AttachNodeMover CreateAttachNodeModifier(Part part, ILinearScaleProvider linearScaleProvider, Action <string> onError)
        {
            if (position == null)
            {
                return(null);
            }
            AttachNode node = part.attachNodes.FirstOrDefault(n => (n.nodeType == AttachNode.NodeType.Stack || n.nodeType == AttachNode.NodeType.Dock) && n.id == nodeID);

            if (node == null)
            {
                onError($"Attach node with id '{nodeID}' not found for attach node modifier");
                return(null);
            }

            // Explanation
            // Config has scale and rescaleFactor which both multiply node positions, but doesn't store scale directly
            // Instead it stores scaleFactor which is scale / rescaleFactor
            // So we have to multiply by rescaleFactor again to get it back
            // Use the prefab since TweakScale modifies rescaleFactor
            Part  maybePrefab = part.partInfo?.partPrefab ?? part;
            float fixedScale  = maybePrefab.scaleFactor * maybePrefab.rescaleFactor * maybePrefab.rescaleFactor;

            return(new AttachNodeMover(node, position.Value * fixedScale, linearScaleProvider));
        }
Exemple #31
0
        /// <summary>
        /// Moves <paramref name="node"/> to reflect the new scale. If <paramref name="movePart"/> is true, also moves attached parts.
        /// </summary>
        /// <param name="node">The node to move.</param>
        /// <param name="baseNode">The same node, as found on the prefab part.</param>
        /// <param name="movePart">Whether or not to move attached parts.</param>
        /// <param name="absolute">Whether to use absolute or relative scaling.</param>
        private void MoveNode(AttachNode node, AttachNode baseNode, bool movePart, bool absolute)
        {
            if (baseNode == null)
            {
                baseNode = node;
                absolute = false;
            }

            var oldPosition = node.position;

            if (absolute)
            {
                node.position = baseNode.position * ScalingFactor.absolute.linear;
            }
            else
            {
                node.position = node.position * ScalingFactor.relative.linear;
            }

            var deltaPos = node.position - oldPosition;

            if (movePart && node.attachedPart != null)
            {
                if (node.attachedPart == part.parent)
                {
                    part.transform.Translate(-deltaPos, part.transform);
                }
                else
                {
                    var offset = node.attachedPart.attPos * (ScalingFactor.relative.linear - 1);
                    node.attachedPart.transform.Translate(deltaPos + offset, part.transform);
                    node.attachedPart.attPos *= ScalingFactor.relative.linear;
                }
            }
            RescaleNode(node, baseNode);
        }
Exemple #32
0
 private void parseAttachNodes(AttachNode parentNode, List <AttachNode> childNodes, Vessel vessel = null)
 {
     if (vessel == null)
     {
         vessel = parentNode.owner.vessel;
     }
     for (int i = 0; i < childNodes.Count; i++)
     {
         FlightJointTracker existingTracker = allJoints.FirstOrDefault((FlightJointTracker jt) => jt.nodes.Contains(parentNode) && jt.nodes.Contains(childNodes[i]));
         if (existingTracker == null)
         {
             trackedJoints[vessel].Add(new FlightJointTracker(parentNode, childNodes[i]));
         }
         else if (!trackedJoints[vessel].Contains(existingTracker))
         {
             trackedJoints[vessel].Add(existingTracker);
             Vessel currentListing = findDictEntry(existingTracker);
             if (currentListing != null)
             {
                 trackedJoints[currentListing].Remove(existingTracker);
             }
         }
     }
 }
        public void OnPartAttachNodeSizeChanged(BaseEventData data)
        {
            if (!HighLogic.LoadedSceneIsEditor)
            {
                return;
            }

            AttachNode node   = data.Get <AttachNode>("node");
            float      minDia = data.Get <float>("minDia");

            // ReSharper disable once CompareOfFloatsByEqualityOperator
            if (node.id != textureMessageName || maxImpulseDiameterRatio == 0)
            {
                return;
            }

            UI_FloatEdit ejectionImpulseEdit = (UI_FloatEdit)Fields["ejectionImpulse"].uiControlEditor;
            float        oldRatio            = ejectionImpulse / ejectionImpulseEdit.maxValue;

            maxImpulse = Mathf.Round(maxImpulseDiameterRatio * minDia);
            ejectionImpulseEdit.maxValue = maxImpulse;

            ejectionImpulse = Mathf.Round(maxImpulse * oldRatio / 0.1f) * 0.1f;
        }
Exemple #34
0
        public override void OnStart(StartState state)
        {
            base.OnStart(state);
            if (state == StartState.Editor || state == StartState.None)
            {
                return;
            }
            KAS_Shared.createFXSound(this.part, fxSndGrab, grabSndPath, false);
            KAS_Shared.createFXSound(this.part, fxSndAttachPart, attachPartSndPath, false);
            KAS_Shared.createFXSound(this.part, fxSndDetach, detachSndPath, false);
            KAS_Shared.createFXSound(this.part, fxSndAttachStatic, attachStaticSndPath, false);
            RefreshContextMenu();

            //Get attach node
            if (attachNodeName == null || attachNodeName == "")
            {
                if (this.part.srfAttachNode == null)
                {
                    KAS_Shared.DebugError("Grab - surface attach node cannot be found on the part !");
                    return;
                }
                KAS_Shared.AddNodeTransform(this.part, this.part.srfAttachNode);
                partNode = this.part.srfAttachNode;
            }
            else
            {
                AttachNode an = this.part.findAttachNode(attachNodeName);
                if (an == null)
                {
                    KAS_Shared.DebugError("Grab - " + attachNodeName + " node cannot be found on the part !");
                    return;
                }
                KAS_Shared.AddNodeTransform(this.part, an);
                partNode = an;
            }
        }
Exemple #35
0
 static void OnMouseExitNode(AttachNode hoverNode)
 {
     SendPointerState(pointerTarget, PointerState.OnMouseExitNode, hoverNode.owner, hoverNode);
 }
Exemple #36
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());
            }
        }
        public static void CrossfeedRecurseParts(HashSet <Part> set, Part p, Vessel v)
        {
            if (set.Contains(p))
            {
                return;
            }

            set.Add(p);

            // check fuel lines
            Part otherPart;
            int  fCount = p.fuelLookupTargets.Count;

            if (fCount > 0)
            {
                for (int i = fCount; i-- > 0;)
                {
                    otherPart = p.fuelLookupTargets[i];
                    if (otherPart != null && (otherPart.vessel == v || HighLogic.LoadedSceneIsEditor))
                    {
                        if ((otherPart == p.parent && p.isAttached) ||
                            (otherPart != p.parent && otherPart.isAttached))
                        {
                            CrossfeedRecurseParts(set, otherPart, v);
                        }
                    }
                }
            }

            // if not, we only continue if the part has fuelCrossFeed enabled or if this same part is the one generating the request
            if (!p.fuelCrossFeed)
            {
                return;
            }

            // check surface attachments (i.e. our children)
            for (int i = p.children.Count; i-- > 0;)
            {
                otherPart = p.children[i];
                if (otherPart.srfAttachNode.attachedPart == p && otherPart.fuelCrossFeed)
                {
                    CrossfeedRecurseParts(set, otherPart, v);
                }
            }

            // check any neighbour nodes that are attached
            AttachNode node;

            for (int anI = p.attachNodes.Count; anI-- > 0;)
            {
                node = p.attachNodes[anI];

                if (!string.IsNullOrEmpty(p.NoCrossFeedNodeKey) && node.id.Contains(p.NoCrossFeedNodeKey))
                {
                    continue;
                }

                otherPart = node.attachedPart;

                if (!node.ResourceXFeed)
                {
                    continue;
                }

                if (otherPart == null)
                {
                    continue;
                }

                CrossfeedRecurseParts(set, otherPart, v);
            }

            // lastly check parent, if we haven't yet.
            if (p.parent != null)
            {
                AttachNode parentNode = p.FindAttachNodeByPart(p.parent);

                if (parentNode != null)
                {
                    if (string.IsNullOrEmpty(p.NoCrossFeedNodeKey) || !parentNode.id.Contains(p.NoCrossFeedNodeKey))
                    {
                        CrossfeedRecurseParts(set, p.parent, v);
                    }
                }
            }
        }
Exemple #38
0
 public bool NodeManaged(AttachNode node) => nodes.Contains(node);
Exemple #39
0
 public void ClearAttachNode()
 {
     attachNode = null;
 }
Exemple #40
0
 //Checks if th given AttachNode has the parent part
 private bool CheckParentNode(AttachNode node)
 {
     return(node.attachedPart != null && this.part.parent != null && node.attachedPart == this.part.parent);
 }
        protected void WindowGui(int windowID)
        {
            if (this._axisLockCounter > 0)
            {
                this._axisLockCounter--;
            }
            var textFieldWidth = GUILayout.Width(90);
            const int spacing = 3;
            const int bigSpacing = spacing*2;
            var expandWidth = GUILayout.ExpandWidth(true);
            GUILayout.BeginVertical("box");
            if (this._selectedPart == null)
            {
                GUILayout.Label("Please select (right-click) a part.", expandWidth);
                GUILayout.EndVertical();
                GUI.DragWindow();
                return;
            }
            foreach (var node in this._nodeMapping.Keys)
            {
                var isSel = this._selectedNode != null && this._selectedNode == node;
                if (GUILayout.Toggle(isSel, this._getNodeName(node), "Button", expandWidth))
                {
                    this._selectedNode = node;
                }
            }
            if (this._nodeMapping.Keys.Count > 0)
            {
                GUILayout.Space(spacing);
            }
            if (GUILayout.Button("Clear Selection", expandWidth))
            {
                this._selectedNode = null;
            }
            GUILayout.EndVertical();
            if (this._selectedNode != null)
            {
                GUILayout.Space(bigSpacing);
                GUILayout.BeginVertical("box");
                GUILayout.Label("Stepwidth:", textFieldWidth);
                GUILayout.BeginHorizontal();
                this._stepWidthString = GUILayout.TextField(this._stepWidthString, textFieldWidth);
                GUILayout.Space(spacing);
                if (GUILayout.Button("Set"))
                {
                    this._parseStepWidth();
                }
                GUILayout.EndHorizontal();
                GUILayout.Space(spacing);
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("X+"))
                {
                    this._moveNode(MoveDirs.X, true);
                }
                if (GUILayout.Button("Y+"))
                {
                    this._moveNode(MoveDirs.Y, true);
                }
                if (GUILayout.Button("Z+"))
                {
                    this._moveNode(MoveDirs.Z, true);
                }
                GUILayout.EndHorizontal();
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("X-"))
                {
                    this._moveNode(MoveDirs.X, false);
                }
                if (GUILayout.Button("Y-"))
                {
                    this._moveNode(MoveDirs.Y, false);
                }
                if (GUILayout.Button("Z-"))
                {
                    this._moveNode(MoveDirs.Z, false);
                }
                GUILayout.EndHorizontal();
                GUILayout.Space(spacing);
                GUILayout.BeginVertical();
                var cPos = this._selectedNode.position;
                var posText = string.Format("{0},{1},{2}", _formatNumberForOutput(cPos.x), _formatNumberForOutput(cPos.y), _formatNumberForOutput(cPos.z));
                GUILayout.Label("Current Position:", expandWidth);
                GUILayout.BeginHorizontal();
                GUILayout.Label("(" + posText + ")", expandWidth);
                GUILayout.EndHorizontal();
                if (GUILayout.Button("copy to set pos.", expandWidth))
                {
                    this._targetPos = posText;
                }
                GUILayout.EndVertical();
                GUILayout.Space(spacing);
                GUILayout.BeginHorizontal();
                this._targetPos = GUILayout.TextField(this._targetPos, textFieldWidth);
                GUILayout.Space(spacing);
                if (GUILayout.Button("Set to pos", expandWidth))
                {
                    this._setToPos();
                }
                GUILayout.EndHorizontal();
                GUILayout.BeginVertical();
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Reset node", expandWidth))
                {
                    this._resetCurrNode();
                }
                GUILayout.EndHorizontal();
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Update Reset position", expandWidth))
                {
                    this._updateResetPosCurrNode();
                }
                GUILayout.EndHorizontal();
                GUILayout.EndVertical();
                GUILayout.Space(spacing);

                GUILayout.BeginVertical();
                GUILayout.Label("curr. node size: " + this._selectedNode.size, expandWidth);
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("reduce size", expandWidth))
                {
                    if (this._selectedNode.size > 0)
                    {
                        this._selectedNode.size -= 1;
                    }
                }
                GUILayout.Space(spacing);
                if (GUILayout.Button("increase size", expandWidth))
                {
                    if (this._selectedNode.size < int.MaxValue - 1)
                    {
                        this._selectedNode.size += 1;
                    }
                }
                GUILayout.EndHorizontal();
                GUILayout.EndVertical();
                GUILayout.Space(spacing);
                GUILayout.BeginVertical();
                var or = this._selectedNode.orientation;
                var orientationString = _formatNumberForOutput(or.x) + "," + _formatNumberForOutput(or.y) + "," + _formatNumberForOutput(or.z);
                GUILayout.Label("curr. node orientation: " + orientationString, expandWidth);
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("X", expandWidth))
                {
                    this._selectedNode.orientation = new Vector3(1f, 0f, 0f);
                }
                if (GUILayout.Button("Y", expandWidth))
                {
                    this._selectedNode.orientation = new Vector3(0f, 1f, 0f);
                }
                if (GUILayout.Button("Z", expandWidth))
                {
                    this._selectedNode.orientation = new Vector3(0f, 0f, 1f);
                }
                this._nodeOrientationCust = GUILayout.TextField(this._nodeOrientationCust, expandWidth);
                GUILayout.EndHorizontal();
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("p. up", expandWidth))
                {
                    this._selectedNode.orientation = this._selectedPart.transform.up;
                }
                if (GUILayout.Button("p. forward", expandWidth))
                {
                    this._selectedNode.orientation = this._selectedPart.transform.forward;
                }
                if (GUILayout.Button("p. right", expandWidth))
                {
                    this._selectedNode.orientation = this._selectedPart.transform.right;
                }
                if (GUILayout.Button("cust.", expandWidth))
                {
                    this._orientNodeToCust();
                }
                GUILayout.EndHorizontal();
                this._showOrientationPointer = GUILayout.Toggle(this._showOrientationPointer, "Show Orientation Pointer", "Button", expandWidth);
                GUILayout.EndVertical();
                GUILayout.Space(bigSpacing);
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Delete node", expandWidth))
                {
                    this._deleteCurrNode();
                }
                GUILayout.EndHorizontal();
                GUILayout.EndVertical();
                GUILayout.Space(bigSpacing);
            }
            else
            {
                GUILayout.Space(bigSpacing);
                GUILayout.BeginVertical("box");
                GUILayout.Label("Part Attach Rules: " + this._getSelPartAttRulesString());
                var tempArr = new bool[5];
                Array.Copy(this._selectedPartRules, tempArr, 5);
                GUILayout.BeginHorizontal();
                tempArr[0] = GUILayout.Toggle(tempArr[0], "stack", "Button", expandWidth);
                tempArr[1] = GUILayout.Toggle(tempArr[1], "srfAttach", "Button", expandWidth);
                tempArr[2] = GUILayout.Toggle(tempArr[2], "allowStack", "Button", expandWidth);
                GUILayout.EndHorizontal();
                GUILayout.BeginHorizontal();
                tempArr[3] = GUILayout.Toggle(tempArr[3], "allowSrfAttch", "Button", expandWidth);
                tempArr[4] = GUILayout.Toggle(tempArr[4], "allowCollision", "Button", expandWidth);
                GUILayout.EndHorizontal();
                this._processAttachRules(tempArr);
                GUILayout.EndVertical();
                GUILayout.Space(bigSpacing);
                if (!this._showCreateMenu)
                {
                    GUILayout.BeginVertical("box");
                    if (GUILayout.Button("Show Node Creation"))
                    {
                        this._showCreateMenu = true;
                    }
                    GUILayout.EndVertical();
                }
                else
                {
                    GUILayout.BeginVertical("box");
                    if (GUILayout.Button("Hide Node Creation"))
                    {
                        this._showCreateMenu = false;
                    }
                    GUILayout.Label("Warning: When adding new nodes and attaching parts to them the vessel can't be launched any more!", GUILayout.ExpandWidth(false));
                    GUILayout.Space(spacing);
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Add a node", expandWidth);
                    GUILayout.Space(spacing);
                    if (GUILayout.Button("Create"))
                    {
                        this._createNewNode();
                    }
                    GUILayout.EndHorizontal();
                    GUILayout.Space(spacing);
                    GUILayout.Label("Node name:", expandWidth);
                    this._newNodeName = GUILayout.TextField(this._newNodeName, textFieldWidth);
                    GUILayout.Label("Node pos. rel. to trans.:", expandWidth);
                    this._newNodePos = GUILayout.TextField(this._newNodePos, textFieldWidth);
                    GUILayout.EndVertical();
                    GUILayout.Space(bigSpacing);
                }
            }
            GUILayout.BeginVertical("box");
            GUILayout.Label("Normal planes:", expandWidth);
            GUILayout.BeginHorizontal();
            this._showPlanes[0] = GUILayout.Toggle(this._showPlanes[0], "X", "Button");
            this._showPlanes[1] = GUILayout.Toggle(this._showPlanes[1], "Y", "Button");
            this._showPlanes[2] = GUILayout.Toggle(this._showPlanes[2], "Z", "Button");
            GUILayout.EndHorizontal();
            GUILayout.Label("Plane radius:");
            GUILayout.BeginHorizontal();
            this._planeRadiusString = GUILayout.TextField(this._planeRadiusString, textFieldWidth);
            GUILayout.Space(spacing);
            if (GUILayout.Button("Set"))
            {
                this._parsePlaneRadius();
            }
            GUILayout.EndHorizontal();
            GUILayout.EndVertical();
            GUILayout.Space(bigSpacing);
            GUILayout.BeginVertical("box");
            GUILayout.Label("Write new config:", expandWidth);
            if (GUILayout.Button("Write node data"))
            {
                if (this._selectedPart != null && !this._printingActive)
                {
                    this._printingActive = true;
                    this._printNodeConfigForPart(!PrintAdvancedConfig);
                }
            }
            GUILayout.EndVertical();
            GUI.DragWindow();
        }
Exemple #42
0
 protected override void on_vessel_launched(Vessel vsl)
 {
     base.on_vessel_launched(vsl);
     if (recipient_node != null)
     {
         var construction_node_pos =
             part.partTransform.TransformPoint(construction_node.position);
         var construction_part = recipient_node.owner;
         var docking_node      = kit.GetDockingNode(vsl, ConstructDockingNode);
         if (docking_node == null)
         {
             Utils.Message(
                 "No suitable attachment node found in \"{0}\" to dock it to the {1}",
                 vsl.GetDisplayName(),
                 construction_part.Title());
             return;
         }
         var docking_offset =
             docking_node.owner.partTransform.TransformPoint(docking_node.position)
             - construction_node_pos;
         FXMonger.Explode(part, construction_node_pos, 0);
         var docking_part = docking_node.owner;
         this.Log("Docking {} to {}", docking_part.GetID(), construction_part.GetID());
         // vessels' position and rotation
         construction_part.vessel.SetPosition(construction_part.vessel.transform.position,
                                              true);
         construction_part.vessel.SetRotation(construction_part.vessel.transform.rotation);
         docking_part.vessel.SetPosition(
             docking_part.vessel.transform.position - docking_offset,
             true);
         docking_part.vessel.SetRotation(docking_part.vessel.transform.rotation);
         construction_part.vessel.IgnoreGForces(10);
         docking_part.vessel.IgnoreGForces(10);
         if (construction_part == part.parent)
         {
             part.decouple();
         }
         else
         {
             construction_part.decouple();
         }
         recipient_node.attachedPart   = docking_part;
         recipient_node.attachedPartId = docking_part.flightID;
         docking_node.attachedPart     = construction_part;
         docking_node.attachedPartId   = construction_part.flightID;
         docking_part.Couple(construction_part);
         // manage docking ports, if any
         foreach (var port in construction_part.FindModulesImplementing <ModuleDockingNode>())
         {
             if (port.referenceNode == recipient_node)
             {
                 port.dockedPartUId = docking_part.persistentId;
                 port.fsm.StartFSM(port.st_preattached);
                 break;
             }
         }
         foreach (var port in docking_part.FindModulesImplementing <ModuleDockingNode>())
         {
             if (port.referenceNode == docking_node)
             {
                 port.dockedPartUId = construction_part.persistentId;
                 port.fsm.StartFSM(port.st_preattached);
                 break;
             }
         }
         // add fuel lookups
         construction_part.fuelLookupTargets.Add(docking_part);
         docking_part.fuelLookupTargets.Add(construction_part);
         GameEvents.onPartFuelLookupStateChange.Fire(
             new GameEvents.HostedFromToAction <bool, Part>(true,
                                                            docking_part,
                                                            construction_part));
         FlightGlobals.ForceSetActiveVessel(construction_part.vessel);
         FlightInputHandler.SetNeutralControls();
         GameEvents.onVesselWasModified.Fire(construction_part.vessel);
         recipient_node = null;
         this.Log("Docked {} to {}, new vessel {}",
                  docking_part,
                  construction_part,
                  construction_part.vessel.GetID());
     }
 }
        public override void OnStart(PartModule.StartState state)
        {
            base.OnStart (state);
            upperNode = part.findAttachNode(topNodeName);
            lowerNode = part.findAttachNode(bottomNodeName);
            innerNode = part.findAttachNode(internalNodeName);

            modelBase = part.FindModelTransform(modelMeshName);
            SSTUUtils.enableRenderRecursive(modelBase, false);
            SSTUUtils.enableColliderRecursive(modelBase, false);

            if(boundsCollider!=null)
            {
                Component.Destroy(boundsCollider);
                boundsCollider = null;
            }

            restoreEditorFields();
            updateModelParameters();

            updateFairingHeight(currentHeight);//set nodes to current height, will not change any positions parts with a zero delta, but will still set nodes to proper height

            if(HighLogic.LoadedSceneIsFlight)//if in flight, selectively enable/disable the actions/gui events
            {
                Events ["deployEvent"].active = !deployed && !decoupled;//only available if not previously deployed or decoupled
                Events ["decoupleEvent"].active = deployed && !decoupled;//only available if deployed but not decoupled
                Actions ["deployAction"].active = !deployed && !decoupled;//only available if not previously deployed or decoupled
                Actions ["decoupleAction"].active = deployed && !decoupled;//only available if deployed but not decoupled
                enableEditorColliders(false);
            }

            //register for game events, used to notify when to update shielded parts
            GameEvents.onEditorShipModified.Add(new EventData<ShipConstruct>.OnEvent(onEditorVesselModified));
            GameEvents.onVesselWasModified.Add(new EventData<Vessel>.OnEvent(onVesselModified));
            GameEvents.onVesselGoOffRails.Add(new EventData<Vessel>.OnEvent(onVesselUnpack));
            GameEvents.onVesselGoOnRails.Add(new EventData<Vessel>.OnEvent(onVesselPack));
            GameEvents.onPartDie.Add(new EventData<Part>.OnEvent(onPartDestroyed));
        }
 private void _createNewNode()
 {
     try
     {
         if (string.IsNullOrEmpty(this._newNodeName))
         {
             OSD.PostMessageUpperCenter("[NH] name for new node emtpy");
             return;
         }
         var pos = KSPUtil.ParseVector3(this._newNodePos);
         var an = new AttachNode
                  {
                      owner = this._selectedPart,
                      position = pos,
                      nodeType = AttachNode.NodeType.Stack,
                      size = 1,
                      id = this._findUniqueId(this._newNodeName),
                      attachMethod = AttachNodeMethod.FIXED_JOINT,
                      nodeTransform = this._selectedPart.transform,
                      orientation = this._selectedPart.transform.up
                  };
         this._selectedPart.attachNodes.Add(an);
         this._clearMapping(false);
         OSD.PostMessageUpperCenter("[NH] new node created");
     }
     catch (Exception e)
     {
         Debug.Log("[NH] creating new node threw exception: " + e.Message);
         OSD.PostMessageUpperCenter("[NH] unable to create node, please check vector format");
     }
 }
 private string _getNodeName(AttachNode node)
 {
     if (this._nodeNameMapping.ContainsKey(node))
     {
         return this._nodeNameMapping[node];
     }
     return "n.a.";
 }
 private void _clearMapping(bool deselect = true)
 {
     if (!this._initialized)
     {
         return;
     }
     this._orientationPointer.SetActive(false);
     foreach (var kv in this._nodeMapping)
     {
         Destroy(kv.Value);
     }
     this._nodeMapping.Clear();
     this._nodeNameMapping.Clear();
     //this._nodePosBackup.Clear();
     for (var i = 0; i < 3; i++)
     {
         this._showPlanes[i] = false;
         this._planes[i].SetActive(false);
     }
     if (deselect)
     {
         this._selectedPart = null;
         this._selectedNode = null;
         this._selectedPartRules = new bool[5];
     }
 }
        private static CIT_Util.Types.Tuple<string, string> _nodeToString(AttachNode node, string id, bool stack = true)
        {
            const string delim = ", ";

            string retKey;
            if (stack)
            {
                retKey = "node_stack_" + id;
            }
            else
            {
                retKey = "node_attach";
            }
            var sb = new StringBuilder();
            var pos = node.position;
            var or = node.orientation;
            sb.Append(_formatNumberForOutput(pos.x));
            sb.Append(delim);
            sb.Append(_formatNumberForOutput(pos.y));
            sb.Append(delim);
            sb.Append(_formatNumberForOutput(pos.z));
            sb.Append(delim);
            sb.Append(_formatNumberForOutput(or.x));
            sb.Append(delim);
            sb.Append(_formatNumberForOutput(or.y));
            sb.Append(delim);
            sb.Append(_formatNumberForOutput(or.z));
            if (node.size >= 0)
            {
                sb.Append(delim);
                sb.Append(node.size);
            }
            return new CIT_Util.Types.Tuple<string, string>(retKey, sb.ToString());
        }
 private static Vector3 GetGoScaleForNode(AttachNode attachNode)
 {
     return ((Vector3.one*attachNode.radius)*(attachNode.size != 0 ? attachNode.size : 0.5f));
 }
Exemple #49
0
        //the part that is enabled and disabled
        public override void OnStart(StartState state)
        {
            base.OnStart(state);

            if (HighLogic.LoadedSceneIsEditor)
            {
                if (!editorChangeRegistered)
                {
                    GameEvents.onEditorShipModified.Add(shipModified);
                    editorChangeRegistered = false;
                }
                if (flightChangeRegistered)
                {
                    GameEvents.onVesselWasModified.Remove(vesselModified);
                    flightChangeRegistered = false;
                }
            }
            if (HighLogic.LoadedSceneIsFlight)
            {
                if (!flightChangeRegistered)
                {
                    GameEvents.onVesselWasModified.Add(vesselModified);
                    flightChangeRegistered = true;
                }
                if (flightChangeRegistered)
                {
                    GameEvents.onEditorShipModified.Remove(shipModified);
                    editorChangeRegistered = false;
                }
            }

            string[] nodenames           = nodeNames.Split(',');
            string[] transformGroupNames = transormNames.Split(',');

            List <string[]> transformnames = new List <string[]>();

            //when the lengths are not equal
            if (transformGroupNames.Length != nodenames.Length)
            {
                return;
            }

            //----------------------------------------------------------
            //create the list of transforms to be made visible on attach
            //----------------------------------------------------------

            //remove the whitespaces
            for (int i = 0; i < nodenames.Length; i++)
            {
                nodenames[i] = nodenames[i].Trim();

                //split up the names for the nodes
                string[] transformGroup = transformGroupNames[i].Split('|');

                for (int j = 0; j < transformGroup.Length; j++)
                {
                    transformGroup[j] = transformGroup[j].Trim();
                }
                transformnames.Add(transformGroup);
            }

            int num = 0;

            for (int i = 0; i < nodenames.Length; i++)
            {
                AttachNode       node       = part.FindAttachNode(nodenames[i]);
                List <Transform> transforms = new List <Transform>();
                for (int k = 0; k < transformnames[num].Length; k++)
                {
                    transforms.AddRange(part.FindModelTransforms(transformnames[num][k]));
                }

                //when nodes and transforms are valid and found
                if ((node != null) && (transforms.Count > 0))
                {
                    //create the new corridor data
                    CorridorPart corridor = new CorridorPart();
                    corridor.node       = node;
                    corridor.transforms = transforms;

                    if ((allowSurfaceAttach) && (surfaceAttachNode == nodenames[i]) && (part.srfAttachNode != null))
                    {
                        corridor.isSurfaceAttachPoint = true;
                    }
                    else
                    {
                        corridor.isSurfaceAttachPoint = false;
                    }

                    corridor.lastAttached = true;
                    corridors.Add(corridor);
                }
                num++;
            }

            //------------------------------------------------------------
            //create the list of transforms to be made invisible on attach
            //------------------------------------------------------------
            string[]        replaceTransformGroupNames = null;
            string[]        replaceNodeGroupNames      = null;
            List <string[]> replacetransformnames      = new List <string[]>();
            List <string[]> replacenodenames           = new List <string[]>();

            if ((replaceTransformNames != string.Empty) && (replaceNodeNames != string.Empty))
            {
                replaceTransformGroupNames = replaceTransformNames.Split(',');
                replaceNodeGroupNames      = replaceNodeNames.Split(',');

                if (replaceNodeGroupNames.Length == replaceTransformGroupNames.Length)
                {
                    //split up all the name for the groups
                    for (int i = 0; i < replaceNodeGroupNames.Length; i++)
                    {
                        //split up the names for the nodes
                        string[] transformGroup = replaceTransformGroupNames[i].Split('|');
                        for (int j = 0; j < transformGroup.Length; j++)
                        {
                            transformGroup[j] = transformGroup[j].Trim();
                        }
                        replacetransformnames.Add(transformGroup);

                        string[] nodeGroup = replaceNodeGroupNames[i].Split('|');
                        for (int j = 0; j < nodeGroup.Length; j++)
                        {
                            nodeGroup[j] = nodeGroup[j].Trim();
                        }
                        replacenodenames.Add(nodeGroup);
                    }


                    //for all transform groups
                    num = 0;
                    for (int i = 0; i < replacetransformnames.Count; i++)
                    {
                        List <Transform>  rTransforms  = new List <Transform>();
                        List <AttachNode> rAttachnodes = new List <AttachNode>();

                        for (int j = 0; j < replacetransformnames[i].Length; j++)
                        {
                            //Debug.Log("[KPBS] Replace Tranform Name: " + replacetransformnames[i][j]);
                            rTransforms.AddRange(part.FindModelTransforms(replacetransformnames[i][j]));
                        }

                        for (int j = 0; j < replacenodenames[num].Length; j++)
                        {
                            //Debug.Log("[KPBS] Replace Node Name: " + replacenodenames[num][j]);
                            rAttachnodes.Add(part.FindAttachNode(replacenodenames[num][j]));
                        }

                        if ((rTransforms.Count > 0) && (rAttachnodes.Count > 0))
                        {
                            ReplacedPart rp = new ReplacedPart();
                            rp.nodes      = rAttachnodes;
                            rp.transforms = rTransforms;
                            replaceParts.Add(rp);
                        }
                        num++;
                    }
                }
            }
            //check the visibility of all the parts
            updateAllCorridors();
        }
 private void decoupleNode(AttachNode node)
 {
     Part attachedPart = node.attachedPart;
     if(attachedPart==null){return;}
     if (attachedPart == part.parent)
     {
         part.decouple (0f);
     }
     else
     {
         attachedPart.decouple (0f);
     }
 }
Exemple #51
0
        public static Part CreatePart(ConfigNode partConfig, Vector3 position, Quaternion rotation, Part fromPart, Part coupleToPart = null, string srcAttachNodeID = null, AttachNode tgtAttachNode = null, OnPartCoupled onPartCoupled = null)
        {
            ConfigNode node_copy = new ConfigNode();
            partConfig.CopyTo(node_copy);
            ProtoPartSnapshot snapshot = new ProtoPartSnapshot(node_copy, null, HighLogic.CurrentGame);

            if (HighLogic.CurrentGame.flightState.ContainsFlightID(snapshot.flightID) || snapshot.flightID == 0)
            {
                snapshot.flightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState);
            }
            snapshot.parentIdx = 0;
            snapshot.position = position;
            snapshot.rotation = rotation;
            snapshot.stageIndex = 0;
            snapshot.defaultInverseStage = 0;
            snapshot.seqOverride = -1;
            snapshot.inStageIndex = -1;
            snapshot.attachMode = (int)AttachModes.SRF_ATTACH;
            snapshot.attached = true;
            snapshot.connected = true;
            snapshot.flagURL = fromPart.flagURL;

            Part newPart = snapshot.Load(fromPart.vessel, false);

            newPart.transform.position = position;
            newPart.transform.rotation = rotation;
            newPart.missionID = fromPart.missionID;

            fromPart.vessel.Parts.Add(newPart);

            newPart.physicalSignificance = Part.PhysicalSignificance.NONE;
            newPart.PromoteToPhysicalPart();
            newPart.Unpack();
            newPart.InitializeModules();

            if (coupleToPart)
            {
                newPart.rigidbody.velocity = coupleToPart.rigidbody.velocity;
                newPart.rigidbody.angularVelocity = coupleToPart.rigidbody.angularVelocity;
            }
            else
            {
                if (fromPart.rigidbody)
                {
                    newPart.rigidbody.velocity = fromPart.rigidbody.velocity;
                    newPart.rigidbody.angularVelocity = fromPart.rigidbody.angularVelocity;
                }
                else
                {
                    // If fromPart is a carried container
                    newPart.rigidbody.velocity = fromPart.vessel.rootPart.rigidbody.velocity;
                    newPart.rigidbody.angularVelocity = fromPart.vessel.rootPart.rigidbody.angularVelocity;
                }
            }

            newPart.decouple();

            if (coupleToPart)
            {
                newPart.StartCoroutine(WaitAndCouple(newPart, coupleToPart, srcAttachNodeID, tgtAttachNode, onPartCoupled));
            }
            else
            {
                newPart.vessel.vesselType = VesselType.Unknown;
                //name container
                ModuleKISInventory inv = newPart.GetComponent<ModuleKISInventory>();
                if (inv)
                {
                    if (inv.invName != "")
                    {
                        newPart.vessel.vesselName = inv.part.partInfo.title + " | " + inv.invName;
                    }
                    else
                    {
                        newPart.vessel.vesselName = inv.part.partInfo.title;
                    }
                }
            }
            return newPart;
        }
Exemple #52
0
        /// <summary>
        /// Updates the attach nodes on the part for the input list of attach nodes and the current specified nodes for this model.
        /// Any 'extra' attach nodes from the part will be disabled.
        /// </summary>
        /// <param name="part"></param>
        /// <param name="nodeNames"></param>
        /// <param name="userInput"></param>
        /// <param name="orientation"></param>
        public void updateAttachNodes(Part part, String[] nodeNames, bool userInput, ModelOrientation orientation)
        {
            if (nodeNames.Length == 1 && (nodeNames[0] == "NONE" || nodeNames[0] == "none"))
            {
                return;
            }
            float currentVerticalPosition = this.currentVerticalPosition;
            float offset = getVerticalOffset();

            if (orientation == ModelOrientation.BOTTOM)
            {
                offset = -offset;
            }
            currentVerticalPosition -= offset;

            AttachNode         node = null;
            AttachNodeBaseData data;

            int nodeCount = modelDefinition.attachNodeData.Length;
            int len       = nodeNames.Length;

            Vector3 pos    = Vector3.zero;
            Vector3 orient = Vector3.up;
            int     size   = 2;

            bool invert = (orientation == ModelOrientation.BOTTOM && modelDefinition.invertForBottom) || (orientation == ModelOrientation.TOP && modelDefinition.invertForTop);

            for (int i = 0; i < len; i++)
            {
                node = part.FindAttachNode(nodeNames[i]);
                if (i < nodeCount)
                {
                    data = modelDefinition.attachNodeData[i];
                    size = data.size;
                    pos  = data.position * currentHeightScale;
                    if (invert)
                    {
                        pos.y = -pos.y;
                        pos.x = -pos.x;
                    }
                    pos.y += currentVerticalPosition;
                    orient = data.orientation;
                    if (invert)
                    {
                        orient = -orient; orient.z = -orient.z;
                    }
                    if (node == null)//create it
                    {
                        SSTUAttachNodeUtils.createAttachNode(part, nodeNames[i], pos, orient, size);
                    }
                    else//update its position
                    {
                        SSTUAttachNodeUtils.updateAttachNodePosition(part, node, pos, orient, userInput);
                    }
                }
                else//extra node, destroy
                {
                    if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight)
                    {
                        SSTUAttachNodeUtils.destroyAttachNode(part, node);
                    }
                }
            }
        }
Exemple #53
0
        public Part getBottomPart()
        {
            AttachNode attachNode = part.FindAttachNode("bottom");

            return((attachNode == null) ? null : attachNode.attachedPart);
        }
        public void Start()
        {
            ConfigNode settings = GameDatabase.Instance.GetConfigNodes("NodeHelper").FirstOrDefault();
            bool stockToolbar;
            bool blizzyToolbar;
            if (settings != null)
            {
                if (!bool.TryParse(settings.GetValue("StockToolbar"), out stockToolbar))
                    stockToolbar = true;
                if (!bool.TryParse(settings.GetValue("BlizzyToolbar"), out blizzyToolbar))
                    blizzyToolbar = true;
            }
            else
            {
                stockToolbar = true;
                blizzyToolbar = true;
            }
            if (stockToolbar)
                btnLauncher = ApplicationLauncher.Instance.AddModApplication(() => _show = !_show, () => _show = !_show, null, null, null, null, ApplicationLauncher.AppScenes.VAB | ApplicationLauncher.AppScenes.SPH, GameDatabase.Instance.GetTexture("CIT/NodeHelper/Textures/button_icon", false));

            GameEvents.onPartActionUICreate.Add(this.HandleActionMenuOpened);
            GameEvents.onPartActionUIDismiss.Add(this.HandleActionMenuClosed);
            this._selectedPart = null;
            this._selectedNode = null;
            this._show = false;
            this._nodeMapping = new Dictionary<AttachNode, GameObject>();
            this._nodeNameMapping = new Dictionary<AttachNode, string>();
            this._nodePosBackup = new Dictionary<AttachNode, Vector3>();
            this._affectedParts = new HashSet<Part>();
            this._selectedPartRules = new bool[5];
            this._showPlanes = new bool[3];
            this._planes = new GameObject[3];
            this._createPlanes();

            _orientationPointer = Utilities.CreatePrimitive(PrimitiveType.Cylinder, _planeColor, new Vector3(0.0625f, 0.25f, 0.0625f), false, false, false, name: "node orientation helper", shader: TransShader);
            var vesselOverlays = (EditorVesselOverlays) FindObjectOfType(typeof(EditorVesselOverlays));
            this._nodeMaterial = vesselOverlays.CoMmarker.gameObject.renderer.material;
            this._nodeMaterial.shader = Shader.Find(TransShader);
            this._initialized = true;
            if (ToolbarManager.Instance == null || !blizzyToolbar)
            {
                return;
            }
            this._nodeHelperButton = ToolbarManager.Instance.add("CIT_NodeHelper", "NodeHelperButton");
            this._nodeHelperButton.TexturePath = "CIT/NodeHelper/Textures/button_icon";
            this._nodeHelperButton.ToolTip = "NodeHelper";
            this._nodeHelperButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR);
            this._nodeHelperButton.OnClick += e => this._show = !this._show;
        }
 private void removeNodeInternal(AttachNode node)
 {
     part.attachNodes.Remove(node);
     if(node.icon!=null){node.icon.SetActive(false);}
 }
Exemple #56
0
 public static Quaternion GetNodeRotation(AttachNode attachNode)
 {
     Quaternion rotation;
     rotation = Quaternion.LookRotation(attachNode.orientation);
     return rotation;
 }
Exemple #57
0
        /// <summary>Handles everything realted to the pointer.</summary>
        public static void UpdateHoverDetect()
        {
            if (isRunning)
            {
                //Cast ray
                Ray ray         = FlightCamera.fetch.mainCamera.ScreenPointToRay(Input.mousePosition);
                var colliderHit = Physics.Raycast(
                    ray, out hit, maxDistance: 500,
                    layerMask: (int)(KspLayerMask.Part | KspLayerMask.Kerbal | KspLayerMask.SurfaceCollider),
                    queryTriggerInteraction: QueryTriggerInteraction.Ignore);
                if (!colliderHit)
                {
                    pointerTarget = PointerTarget.Nothing;
                    ResetMouseOver();
                    return;
                }

                // Check target type
                var        tgtPart       = Mouse.HoveredPart;
                KerbalEVA  tgtKerbalEva  = null;
                AttachNode tgtAttachNode = null;

                if (!tgtPart)
                {
                    // check linked part
                    KIS_LinkedPart linkedObject = hit.collider.gameObject.GetComponent <KIS_LinkedPart>();
                    if (linkedObject)
                    {
                        tgtPart = linkedObject.part;
                    }
                }
                if (tgtPart)
                {
                    tgtKerbalEva = tgtPart.GetComponent <KerbalEVA>();
                }

                // If rigidbody
                if (hit.rigidbody && !tgtPart && !tgtKerbalEva)
                {
                    pointerTarget = PointerTarget.StaticRb;
                }

                // If kerbal
                if (tgtKerbalEva)
                {
                    pointerTarget = PointerTarget.KerbalEva;
                }

                // If part
                if (tgtPart && !tgtKerbalEva)
                {
                    float currentDist = Mathf.Infinity;
                    foreach (AttachNode an in tgtPart.attachNodes)
                    {
                        if (an.icon)
                        {
                            float dist;
                            var   cameraToMouseRay =
                                FlightCamera.fetch.mainCamera.ScreenPointToRay(Input.mousePosition);
                            var iconRenderer = an.icon.GetComponent <Renderer>();
                            if (iconRenderer.bounds.IntersectRay(cameraToMouseRay, out dist))
                            {
                                if (dist < currentDist)
                                {
                                    tgtAttachNode = an;
                                    currentDist   = dist;
                                }
                            }
                        }
                    }
                    if (tgtAttachNode != null)
                    {
                        if (tgtAttachNode.icon.name == "KISMount")
                        {
                            pointerTarget = PointerTarget.PartMount;
                        }
                        else
                        {
                            pointerTarget = PointerTarget.PartNode;
                        }
                    }
                    else
                    {
                        pointerTarget = PointerTarget.Part;
                    }
                }

                //if nothing
                if (!hit.rigidbody && !tgtPart && !tgtKerbalEva)
                {
                    pointerTarget = PointerTarget.Static;
                }

                if (tgtPart)
                {
                    if (tgtAttachNode != null)
                    {
                        // OnMouseEnter node
                        if (tgtAttachNode != hoveredNode)
                        {
                            if (hoveredNode != null)
                            {
                                OnMouseExitNode(hoveredNode);
                            }
                            OnMouseEnterNode(tgtAttachNode);
                            hoveredNode = tgtAttachNode;
                        }
                    }
                    else
                    {
                        // OnMouseExit node
                        if (tgtAttachNode != hoveredNode)
                        {
                            OnMouseExitNode(hoveredNode);
                            hoveredNode = null;
                        }
                    }

                    // OnMouseEnter part
                    if (tgtPart != hoveredPart)
                    {
                        if (hoveredPart)
                        {
                            OnMouseExitPart(hoveredPart);
                        }
                        OnMouseEnterPart(tgtPart);
                        hoveredPart = tgtPart;
                    }
                }
                else
                {
                    // OnMouseExit part
                    if (tgtPart != hoveredPart)
                    {
                        OnMouseExitPart(hoveredPart);
                        hoveredPart = null;
                    }
                }
            }
        }
Exemple #58
0
 public static void SendKISMessage(Part destPart, MessageAction action, Part tgtPart = null, AttachNode tgtNode = null)
 {
     BaseEventData bEventData = new BaseEventData(BaseEventData.Sender.AUTO);
     bEventData.Set("action", action.ToString());
     bEventData.Set("targetPart", tgtPart);
     bEventData.Set("targetNode", tgtNode);
     destPart.SendMessage("OnKISAction", bEventData, SendMessageOptions.DontRequireReceiver);
 }
Exemple #59
0
        /// <summary>
        /// Updates properties that change linearly with scale.
        /// </summary>
        /// <param name="moveParts">Whether or not to move attached parts.</param>
        /// <param name="absolute">Whether to use absolute or relative scaling.</param>
        private void ScalePart(bool moveParts, bool absolute)
        {
            ScalePartTransform();

            int len = part.attachNodes.Count;

            for (int i = 0; i < len; i++)
            {
                AttachNode   node            = part.attachNodes[i];
                AttachNode[] nodesWithSameId = part.attachNodes
                                               .Where(a => a.id == node.id)
                                               .ToArray();
                int          idIdx = Array.FindIndex(nodesWithSameId, a => a == node);
                AttachNode[] baseNodesWithSameId = _prefabPart.attachNodes
                                                   .Where(a => a.id == node.id)
                                                   .ToArray();
                if (idIdx < baseNodesWithSameId.Length)
                {
                    AttachNode baseNode = baseNodesWithSameId[idIdx];

                    MoveNode(node, baseNode, moveParts, absolute);
                }
                else
                {
                    Log.warn("Error scaling part. Node {0} does not have counterpart in base part.", node.id);
                }
            }

            try
            {
                // support for ModulePartVariants (the stock texture switch module)
                if (_prefabPart.Modules.Contains("ModulePartVariants"))
                {
                    ModulePartVariants pm = _prefabPart.Modules["ModulePartVariants"] as ModulePartVariants;
                    ModulePartVariants m  = part.Modules["ModulePartVariants"] as ModulePartVariants;

                    int n = pm.variantList.Count;
                    for (int i = 0; i < n; i++)
                    {
                        PartVariant v  = m.variantList[i];
                        PartVariant pv = pm.variantList[i];
                        for (int j = 0; j < v.AttachNodes.Count; j++)
                        {
                            // the module contains attachNodes, so we need to scale those
                            MoveNode(v.AttachNodes[j], pv.AttachNodes[j], false, true);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log.warn("Exception during ModulePartVariants interaction" + e.ToString());
            }


            if (part.srfAttachNode != null)
            {
                MoveNode(part.srfAttachNode, _prefabPart.srfAttachNode, moveParts, absolute);
            }
            if (moveParts)
            {
                int numChilds = part.children.Count;
                for (int i = 0; i < numChilds; i++)
                {
                    Part child = part.children[i];
                    if (child.srfAttachNode == null || child.srfAttachNode.attachedPart != part)
                    {
                        continue;
                    }

                    Vector3 attachedPosition = child.transform.localPosition + child.transform.localRotation * child.srfAttachNode.position;
                    Vector3 targetPosition   = attachedPosition * ScalingFactor.relative.linear;
                    child.transform.Translate(targetPosition - attachedPosition, part.transform);
                }
            }
        }
Exemple #60
0
        private static IEnumerator WaitAndCouple(Part newPart, Part tgtPart = null, string srcAttachNodeID = null, AttachNode tgtAttachNode = null, OnPartCoupled onPartCoupled = null)
        {
            // Get relative position & rotation
            Vector3 toPartLocalPos = Vector3.zero;
            Quaternion toPartLocalRot = Quaternion.identity;
            if (tgtPart)
            {
                if (tgtAttachNode == null)
                {
                    // Local position & rotation from part
                    toPartLocalPos = tgtPart.transform.InverseTransformPoint(newPart.transform.position);
                    toPartLocalRot = Quaternion.Inverse(tgtPart.transform.rotation) * newPart.transform.rotation;
                }
                else
                {
                    // Local position & rotation from node (KAS winch connector)
                    toPartLocalPos = tgtAttachNode.nodeTransform.InverseTransformPoint(newPart.transform.position);
                    toPartLocalRot = Quaternion.Inverse(tgtAttachNode.nodeTransform.rotation) * newPart.transform.rotation;
                }
            }

            // Wait part to initialize
            while (!newPart.started && newPart.State != PartStates.DEAD)
            {
                KIS_Shared.DebugLog("CreatePart - Waiting initialization of the part...");
                if (tgtPart)
                {
                    // Part stay in position
                    if (tgtAttachNode == null)
                    {
                        newPart.transform.position = tgtPart.transform.TransformPoint(toPartLocalPos);
                        newPart.transform.rotation = tgtPart.transform.rotation * toPartLocalRot;
                    }
                    else
                    {
                        newPart.transform.position = tgtAttachNode.nodeTransform.TransformPoint(toPartLocalPos);
                        newPart.transform.rotation = tgtAttachNode.nodeTransform.rotation * toPartLocalRot;
                    }
                }
                yield return null;
            }
            // Part stay in position
            if (tgtAttachNode == null)
            {
                newPart.transform.position = tgtPart.transform.TransformPoint(toPartLocalPos);
                newPart.transform.rotation = tgtPart.transform.rotation * toPartLocalRot;
            }
            else
            {
                newPart.transform.position = tgtAttachNode.nodeTransform.TransformPoint(toPartLocalPos);
                newPart.transform.rotation = tgtAttachNode.nodeTransform.rotation * toPartLocalRot;
            }
            KIS_Shared.DebugLog("CreatePart - Coupling part...");
            CouplePart(newPart, tgtPart, srcAttachNodeID, tgtAttachNode);

            if (onPartCoupled != null)
            {
                onPartCoupled(newPart, tgtPart, tgtAttachNode);
            }
        }