private void drawLineBetweenBadParts() { float dist = ASPFuelLine.distanceBetweenParts(badStartTank, badDestTank); line.SetPosition(1, Vector3.forward * dist); line.transform.parent = badStartTank.transform; line.transform.localPosition = Vector3.zero; line.transform.localEulerAngles = Vector3.zero; //line.SetPosition(1, line.transform.InverseTransformPoint(badDestTank.transform.position).normalized); line.transform.localRotation = Quaternion.LookRotation(line.transform.InverseTransformPoint(badDestTank.transform.position).normalized); lineObj.layer = lineLayer; line.enabled = true; }
/*public static class PartIconGenerator * { * private const string IconHiddenTag = "Icon_Hidden"; * private const string KerbalEvaSubstring = "kerbal"; * * private static readonly int GameObjectLayer = LayerMask.NameToLayer ("PartsList_Icons"); * // note to future: if creating icons inside editor, you might want to choose a different layer or translate the camera and object out of frame * * private static Camera CreateCamera (int pixelWidth, int pixelHeight, Color backgroundColor) * { * //var camGo = new GameObject ("PartIconGenerator.Camera", typeof(Camera)); * //var cam = camGo.camera; * Camera cam = new Camera(); * * cam.enabled = false; * cam.cullingMask = (1 << GameObjectLayer); * cam.clearFlags = ~CameraClearFlags.Nothing; * cam.nearClipPlane = 0.1f; * cam.farClipPlane = 10f; * cam.orthographic = true; * cam.backgroundColor = backgroundColor; * cam.aspect = pixelWidth / (float)pixelHeight; * * // Camera Size = x / ((( x / y ) * 2 ) * s ) * cam.orthographicSize = pixelWidth / (((pixelWidth / (float)pixelHeight) * 2f) * pixelHeight); * cam.pixelRect = new Rect (0f, 0f, pixelWidth, pixelHeight); * * return cam; * } * * private static Light CreateLight () * { * var light = new GameObject ("PartIconGenerator.Light").AddComponent<Light> (); * * light.type = LightType.Directional; * light.color = XKCDColors.OffWhite; * light.cullingMask = 1 << GameObjectLayer; * light.intensity = 0.1f; * * return light; * } * * private static GameObject CreateIcon (AvailablePart part) * { * // kerbalEVA doesn't seem to init at origin if we aren't explicit * var go = UnityEngine.Object.Instantiate (part.iconPrefab, Vector3.zero, Quaternion.identity) as GameObject; * * // The kerbals are initially facing along positive Z so we'll be looking at their backs if we don't * // rotate them around * if (part.name.StartsWith (KerbalEvaSubstring)) * go.transform.rotation = Quaternion.AngleAxis (180f, Vector3.up); * * go.SetLayerRecursive (GameObjectLayer); * go.SetActive (true); * return go; * } * * private static void AdjustScaleAndCameraPosition (GameObject icon, Camera camera) * { * // get size of prefab * var bounds = CalculateBounds (icon); * float sphereDiameter = Mathf.Max (bounds.size.x, bounds.size.y, bounds.size.z); * * // rescale to size 1 unit so that object will take up as much viewspace as possible in ortho cam (with ortho size = 0.5) * var currentScale = icon.transform.localScale; * float scaleFactor = 1f / sphereDiameter; * icon.transform.localScale = currentScale * scaleFactor; * * icon.transform.position = -bounds.center * scaleFactor; * * camera.transform.position = Vector3.zero; * * // back out, else we'll be inside the model (which is scaled at 1 unit so this should be plenty) * camera.transform.Translate (new Vector3 (0f, 0f, -5f), Space.Self); * camera.transform.LookAt (Vector3.zero, Vector3.up); * } * * * public static Texture2D Create2D (AvailablePart part, int width, int height, Quaternion orientation, Color backgroundColor) * { * var cam = CreateCamera (width, height, backgroundColor); * var icon = CreateIcon (part); * var light = CreateLight (); * * var texture = new Texture2D (width, height, TextureFormat.ARGB32, false); * var rt = RenderTexture.GetTemporary (width, height, 24); * var prevRt = RenderTexture.active; * * RenderTexture.active = rt; * * icon.transform.rotation = orientation * icon.transform.rotation; * * AdjustScaleAndCameraPosition (icon, cam); * * cam.targetTexture = rt; * cam.pixelRect = new Rect (0f, 0f, width, height); // doc says this should be ignored but doesn't seem to be (?) -- rendered area very small once targetTexture is set * cam.Render (); * * texture.ReadPixels (new Rect (0f, 0f, width, height), 0, 0, false); * texture.Apply (); * * RenderTexture.active = prevRt; * RenderTexture.ReleaseTemporary (rt); * UnityEngine.Object.DestroyImmediate (light); * UnityEngine.Object.DestroyImmediate (cam); * UnityEngine.Object.DestroyImmediate (icon); * * return texture; * } * * private static Bounds CalculateBounds (GameObject go) * { * var renderers = go.GetComponentsInChildren<Renderer> (true).ToList (); * * if (renderers.Count == 0) * return default(Bounds); * * var boundsList = new List<Bounds> (); * * renderers.ForEach (r => { * if (r.tag == IconHiddenTag) * return; * * if (r is SkinnedMeshRenderer) { * var smr = r as SkinnedMeshRenderer; * * // the localBounds of the SkinnedMeshRenderer are initially large enough * // to accomodate all animation frames; they're likely to be far off for * // parts that do a lot of animation-related movement (like solar panels expanding) * // * // We can get correct mesh bounds by baking the current animation into a mesh * // note: vertex positions in baked mesh are relative to smr.transform; any scaling * // is already baked in * var mesh = new Mesh (); * smr.BakeMesh (mesh); * * // while the mesh bounds will now be correct, they don't consider orientation at all. * // If a long part is oriented along the wrong axis in world space, the bounds we'd get * // here could be very wrong. We need to come up with essentially the renderer bounds: * // a bounding box in world space that encompasses the mesh * var m = Matrix4x4.TRS (smr.transform.position, smr.transform.rotation, Vector3.one * // remember scale already factored in! * ); * var vertices = mesh.vertices; * * var smrBounds = new Bounds (m.MultiplyPoint3x4 (vertices [0]), Vector3.zero); * * for (int i = 1; i < vertices.Length; ++i) * smrBounds.Encapsulate (m.MultiplyPoint3x4 (vertices [i])); * * UnityEngine.Object.Destroy (mesh); * * boundsList.Add (smrBounds); * } else if (r is MeshRenderer) { // note: there are ParticleRenderers, LineRenderers, and TrailRenderers * r.gameObject.GetComponent<MeshFilter> ().sharedMesh.RecalculateBounds (); * boundsList.Add (r.bounds); * } * }); * * Bounds bounds = boundsList [0]; * * boundsList.Skip (1).ToList ().ForEach (b => bounds.Encapsulate (b)); * * return bounds; * } * }*/ private void OnGUI() { if (tooltipstyle == null) { setStyles(); } if (osdtime > Time.time) { float osdheight = osdstyle.CalcSize(new GUIContent(osdmessage)).y; GUILayout.BeginArea(new Rect(0, Screen.height * 0.1f, Screen.width, osdheight), osdstyle); GUILayout.Label(osdmessage, osdstyle); GUILayout.EndArea(); } if (visible) { if (refreshwait > 0) { refreshwait = refreshwait - 1; } else { switch (mystate) { case ASPState.IDLE: EditorLogic editor = EditorLogic.fetch; ShipConstruct ship = editor.ship; if (ship != null) { List <Part> parts = ship.parts; if ((parts != null) && (parts.Count > 0) && (parts [0] != null)) { parts [0].SetHighlight(false, true); if (tanks == null) { tanks = ASPStaging.findFuelTanks(parts); } else { if (vizualize) { if ((badDestTank != null) && (badStartTank != null)) { drawLineBetweenBadParts(); } foreach (Part p in parts) { if (p != null) { if ((badStartTank != null) && (p == badStartTank)) { Vector3 position = Camera.main.WorldToScreenPoint(p.transform.position); GUI.Label(new Rect(position.x, Screen.height - position.y, 200, 30), "Start tank"); badStartTank.SetHighlightColor(Color.blue); badStartTank.SetHighlight(true, false); badStartTank.highlightType = Part.HighlightType.AlwaysOn; } else if ((badDestTank != null) && (p == badDestTank)) { Vector3 position = Camera.main.WorldToScreenPoint(p.transform.position); GUI.Label(new Rect(position.x, Screen.height - position.y, 200, 30), "Destination tank"); badDestTank.SetHighlightColor(Color.blue); badDestTank.SetHighlight(true, false); badDestTank.highlightType = Part.HighlightType.AlwaysOn; } else if (blockingTanks.Contains(p)) { Vector3 position = Camera.main.WorldToScreenPoint(p.transform.position); GUI.Label(new Rect(position.x, Screen.height - position.y, 200, 30), "X"); p.SetHighlightColor(Color.red); p.SetHighlight(true, false); p.highlightType = Part.HighlightType.AlwaysOn; } else if (tanks.Contains(p)) { // draw labels on the tanks Vector3 position = Camera.main.WorldToScreenPoint(p.transform.position); string label = "L" + ASPFuelLine.countDecouplersToRoot(p).ToString(); #if DEBUG //label = label+": "+ASPConsoleStuff.getFriendlyName (p.craftID.ToString ()); #endif GUI.Label(new Rect(position.x, Screen.height - position.y, 200, 30), label); if ((p != badStartTank) && (p != badDestTank) && (!blockingTanks.Contains(p))) { p.SetHighlightColor(Color.green); p.SetHighlight(true, false); p.highlightType = Part.HighlightType.AlwaysOn; } } else if (ASPStaging.isDecoupler(p)) { p.SetHighlightColor(Color.magenta); p.SetHighlight(true, false); p.highlightType = Part.HighlightType.AlwaysOn; } else { p.SetHighlight(false, false); } } } } } } windowRect = ClickThruBlocker.GUILayoutWindow(windowID, clampToScreen(windowRect), OnWindow, "AutoAsparagus " + versionString); mousepos = new Vector2(Input.mousePosition.x, Input.mousePosition.y); if ((tooltip != null) && (tooltip.Length > 0)) { GUI.depth = 0; Vector2 size = tooltipstyle.CalcSize(new GUIContent(tooltip)); Rect rect = new Rect(Input.mousePosition.x + 20, (Screen.height - Input.mousePosition.y) + 20, size.x, size.y); rect = clampToScreen(rect); GUILayout.BeginArea(rect); GUILayout.Label(tooltip, tooltipstyle); GUILayout.EndArea(); } } break; case ASPState.ERROR: vizualize = true; mystate = ASPState.IDLE; break; case ASPState.ADDASP: ASPConsoleStuff.ListTheShip(); mystate = ASPState.CONNECT; ASPFuelLine.AddAsparagusFuelLines(partsWeCanUse [partToUseIndex], textureIndex, partTexturePaths [partToUseIndex], partTextureNames [partToUseIndex], rainbow); if (mystate == ASPState.CONNECT) { osd("Connecting parts..."); } refreshwait = 100; break; case ASPState.ADDONION: ASPConsoleStuff.ListTheShip(); mystate = ASPState.CONNECT; ASPFuelLine.AddOnionFuelLines(partsWeCanUse [partToUseIndex], textureIndex, partTexturePaths [partToUseIndex], partTextureNames [partToUseIndex], rainbow); if (mystate == ASPState.CONNECT) { osd("Connecting parts..."); } refreshwait = 100; break; case ASPState.CONNECT: ASPFuelLine.connectFuelLines(); refreshwait = 100; osd("Refreshing ship..."); mystate = ASPState.AFTERCONNECT; break; case ASPState.AFTERCONNECT: newReloadShip(); refreshwait = 100; if (useSmartStage) { mystate = ASPState.SMARTSTAGE; osd("Calling SmartStage..."); ASPConsoleStuff.AAprint("Calling SmartStage"); } else { mystate = ASPState.ADDSTAGES; osd("Adding empty stages..."); } break; case ASPState.ADDSTAGES: ASPStaging.AddEmptyStages(); mystate = ASPState.STAGE; osd("Staging decouplers..."); refreshwait = 10; break; case ASPState.STAGE: ASPStaging.AsaparagusTheShip(partsWeCanUse [partToUseIndex].name); mystate = ASPState.AFTERSTAGE; osd("Decoupler staging done, refreshing..."); refreshwait = 10; break; case ASPState.CLAMPS: if (stageLaunchClamps) { ASPStaging.StageLaunchClamps(launchClampsStage); } mystate = ASPState.FINALREFRESH; osd("Done!"); refreshwait = 10; break; case ASPState.DELETEFUEL: ASPConsoleStuff.ListTheShip(); int count = ASPFuelLine.DeleteAllFuelLines(partsWeCanUse [partToUseIndex].name); newReloadShip(); osd(count.ToString() + " parts deleted."); mystate = ASPState.IDLE; break; case ASPState.FINALREFRESH: newReloadShip(); mystate = ASPState.IDLE; osd("Done!"); #if DEBUG tanks = ASPStaging.findFuelTanks(EditorLogic.fetch.ship.Parts); #endif break; case ASPState.AFTERSTAGE: newReloadShip(); if (stageLaunchClamps) { osd("Staging launch clamps..."); mystate = ASPState.CLAMPS; refreshwait = 10; } else { osd("Done!"); mystate = ASPState.IDLE; } break; case ASPState.SMARTSTAGE: mystate = ASPState.FINALREFRESH; try { computeStagesMethod.Invoke(null, new object[] { }); } catch (Exception e) { UnityEngine.Debug.LogError("Error invoking method\n" + e.StackTrace); } osd("Done!"); break; } } } }
static public void AsaparagusTheShip(string partName) { var editor = EditorLogic.fetch; // Get all the parts of the ship var parts = editor.ship.parts; ASPConsoleStuff.printPartList("All parts of ship", "Part", parts); // Find the symmetrical fuel tanks List <Part> tanks = findFuelTanks(parts); ASPConsoleStuff.AAprint("=== Tanks ==="); // print out a list of tanks, partners, and children foreach (Part p in tanks) { ASPConsoleStuff.printPart("Tank", p); foreach (Part partner in p.symmetryCounterparts) { ASPConsoleStuff.printPart("partner", partner); } foreach (Part child in p.children) { ASPConsoleStuff.printPart("child", child); } } // Make chains by following fuel lines List <Part> tanksToStage = new List <Part>(); foreach (Part p in tanks) { if (ASPFuelLine.countDecouplersToRoot(p) > 0) { tanksToStage.Add(p); } } int safetyfactor = 10000; while (tanksToStage.Count > 0) { safetyfactor = safetyfactor - 1; if (safetyfactor == 0) { AutoAsparagus.osd("Infinite loop in AsaparagusTheShip:tanksToStage.Count, aborting :("); AutoAsparagus.mystate = AutoAsparagus.ASPState.IDLE; return; } // start a new chain with the first tank Part p = tanksToStage [0]; List <Part> chain = new List <Part> (); ASPConsoleStuff.printPart("*** Starting new chain with", p); // First, follow the fuel lines while (p != null) { safetyfactor = safetyfactor - 1; if (safetyfactor == 0) { AutoAsparagus.osd("Infinite loop in AsaparagusTheShip:tanksToStage.Count:p!=null, aborting :("); AutoAsparagus.mystate = AutoAsparagus.ASPState.IDLE; return; } ASPConsoleStuff.printPart("Adding to chain at position " + chain.Count, p); chain.Add(p); // don't try to put that tank in another chain tanksToStage.Remove(p); ASPConsoleStuff.printPart("Following fuel line from", p); Part r = p; p = null; foreach (Part target in ASPFuelLine.getFuelLineTargets(r, partName)) { if (tanks.Contains(target)) // we're only following fuel lines in the asparagus { ASPConsoleStuff.printPart("..followed fuel line to", target); p = target; } } } // Next, look for fuel lines that lead to the start of our chain int x = tanksToStage.Count; while (x > 0) { p = tanksToStage [x - 1]; // get last tank ASPConsoleStuff.printPart("Checking tank " + x.ToString() + " of " + tanksToStage.Count + " to insert in chain", p); x = x - 1; foreach (Part target in ASPFuelLine.getFuelLineTargets(p, partName)) { if (chain [0] == target) { ASPConsoleStuff.printPart("..prepending to chain", target); chain.Insert(0, p); tanksToStage.Remove(p); x = tanksToStage.Count; // reset the countdown } } } ASPConsoleStuff.printPartList("*** Completed chain", "chain part", chain); stageChain(chain); } // Update staging display //StageManager.Instance.DeleteEmptyStages (); //StageManager.GenerateStagingSequence (parts [0]); //StageManager.Instance.SortIcons (true); //StageManager.Instance.UpdateStageGroups (false); //foreach (KSP.UI.Screens.StageGroup s in StageManager.Instance.Stages) { //} }