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; } } } }
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; } }
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; }
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; }
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"); } }
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; }
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); }
/// <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; } }
//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(); }
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); } } } } } }
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())); }
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); }
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}"); }
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; } }
// 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); }
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; } }
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)); }
/// <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); }
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; }
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; } }
static void OnMouseExitNode(AttachNode hoverNode) { SendPointerState(pointerTarget, PointerState.OnMouseExitNode, hoverNode.owner, hoverNode); }
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); } } } }
public bool NodeManaged(AttachNode node) => nodes.Contains(node);
public void ClearAttachNode() { attachNode = null; }
//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(); }
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)); }
//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); } }
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; }
/// <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); } } } }
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);} }
public static Quaternion GetNodeRotation(AttachNode attachNode) { Quaternion rotation; rotation = Quaternion.LookRotation(attachNode.orientation); return rotation; }
/// <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; } } } }
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); }
/// <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); } } }
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); } }