public static Vector3 GetSize(Vessel v) { Bounds bounds = default(Bounds); Vector3 orgPos = v.parts[0].orgPos; bounds.center = orgPos; List <Bounds> list = new List <Bounds>(); foreach (Part current in v.parts) { MPLog.Writelog("[Maritime Pack] part: " + current.name + " WCoM" + current.WCoM); MPLog.Writelog("[Maritime Pack] part: " + current.name + " CoB" + current.CenterOfBuoyancy); MPLog.Writelog("[Maritime Pack] part: " + current.name + " CoD" + current.CenterOfDisplacement); Bounds[] partRendererBounds = PartGeometryUtil.GetPartRendererBounds(current); Bounds[] array = partRendererBounds; for (int i = 0; i < array.Length; i++) { Bounds bounds2 = array[i]; Bounds bounds3 = bounds2; bounds3.size *= current.boundsMultiplier; Vector3 size = bounds3.size; bounds3.Expand(current.GetModuleSize(size)); list.Add(bounds2); } } return(PartGeometryUtil.MergeBounds(list.ToArray(), v.parts[0].transform.root).size); }
private static float EstimatePartVolume(Part part) { var boundsSize = PartGeometryUtil.MergeBounds(part.GetRendererBounds(), part.transform).size; var volume = boundsSize.x * boundsSize.y * boundsSize.z * 1000f; return(volume); }
public static float GetPartVolume(Part partPrefab) { Bounds[] rendererBounds = PartGeometryUtil.GetRendererBounds(partPrefab); Vector3 boundsSize = PartGeometryUtil.MergeBounds(rendererBounds, partPrefab.transform).size; float volume = boundsSize.x * boundsSize.y * boundsSize.z; return(volume * 1000); }
public static float GetArea(this Part part) { var boundsSize = PartGeometryUtil.MergeBounds(part.GetRendererBounds(), part.transform).size; float sfcAreaCalc = 2f * (boundsSize.x * boundsSize.y) + 2f * (boundsSize.y * boundsSize.z) + 2f * (boundsSize.x * boundsSize.z); //Debug.Log("[BDArmory]: Surface Area1: " + part.surfaceAreas.magnitude); //Debug.Log("[BDArmory]: Surface Area2: " + sfcAreaCalc); return(sfcAreaCalc); }
public static float GetVolume(Vessel v) { float volume = 0.0f; foreach (Part mypart in v.parts) { var boundsSize = PartGeometryUtil.MergeBounds(mypart.GetRendererBounds(), mypart.transform).size; volume = boundsSize.x * boundsSize.y * boundsSize.z * 1000f; } return(volume); }
//This will provide a list of lines that make up the part's geometry, oriented so that they are in part-oriented space private static List <Line> GenerateLinesFromPart(Part p) { Transform partTransform = p.transform; Bounds colliderBounds, meshBounds; colliderBounds = PartGeometryUtil.MergeBounds(p.GetColliderBounds(), partTransform); meshBounds = PartGeometryUtil.MergeBounds(p.GetRendererBounds(), partTransform); List <Vector3> vertexList; List <int> triangleIndices; //If the mesh shape is much larger than the colliders, then unfortunately, we have to use the raw mesh //Otherwise, use the collider because it has fewer verts and tris to work with //if (UseMeshBounds(colliderBounds, meshBounds, 0.05f)) //{ Transform[] meshTransforms = FARGeoUtil.PartModelTransformArray(p); Mesh[] meshes = new Mesh[meshTransforms.Length]; for (int i = 0; i < meshTransforms.Length; i++) { MeshFilter mf = meshTransforms[i].GetComponent <MeshFilter>(); if (mf == null) { continue; } meshes[i] = mf.sharedMesh; } vertexList = GetVertexList(meshes, meshTransforms, partTransform); triangleIndices = GetTriangleVerts(meshes); /*} * else * { * MeshCollider[] meshColliders = p.GetComponents<MeshCollider>(); * Transform[] meshTransforms = new Transform[meshColliders.Length]; * Mesh[] meshes = new Mesh[meshColliders.Length]; * * for (int i = 0; i < meshColliders.Length; i++) * { * MeshCollider mc = meshColliders[i]; * meshTransforms[i] = mc.transform; * meshes[i] = mc.sharedMesh; * } * vertexList = GetVertexList(meshes, meshTransforms, partTransform); * triangleIndices = GetTriangleVerts(meshes); * }*/ return(GenerateLinesFromVertsAndTris(vertexList, triangleIndices)); }
/// <summary>Returns part's volume basing on its geometrics.</summary> /// <remarks>Geometry of a part depends on the state (e.g. solar panel can be deployed and take /// more space). It's not possible (nor practical) for KIS to figure out which state of the part /// is the most compact one. So, when calculating part's volume the initial state of the mesh /// renderers in the prefab is considered the right ones. If parts's initial state is deployed /// (e.g. Drill-O-Matic) then it will take more space than it could have.</remarks> /// <param name="partInfo">A part to get volume for.</param> /// <returns>Volume in liters.</returns> public static float GetPartVolume(AvailablePart partInfo) { var p = partInfo.partPrefab; float volume; // If there is a KIS item volume then use it but still apply scale tweaks. var kisItem = p.GetComponent <ModuleKISItem>(); if (kisItem && kisItem.volumeOverride > 0) { volume = kisItem.volumeOverride; } else { var boundsSize = PartGeometryUtil.MergeBounds(p.GetRendererBounds(), p.transform).size; volume = boundsSize.x * boundsSize.y * boundsSize.z * 1000f; } // Apply cube of the scale modifier since volume involves all 3 axis. return((float)(volume * Math.Pow(GetPartExternalScaleModifier(partInfo), 3))); }
public static Vector3 GetBoundsSize(Part part) { return(PartGeometryUtil.MergeBounds(part.GetRendererBounds(), part.transform).size); }
void GetPartData(AvailablePart part) { bool started = false; Vector3 pg = new Vector3(); StartLine(part.name); started = true; if (partAttrs[(int)PartAttrEnum.DimensionsInfo - 1] != null && partAttrs[(int)PartAttrEnum.DimensionsInfo - 1].enabled) { // // Now get the part dimensions: x,y,z // List <Bounds> list = new List <Bounds>(); if (!(part.partPrefab.Modules.GetModule <LaunchClamp>(0) != null)) { Bounds[] partRendererBounds = PartGeometryUtil.GetPartRendererBounds(part.partPrefab); int num = partRendererBounds.Length; for (int j = 0; j < num; j++) { Bounds bounds2 = partRendererBounds[j]; Bounds bounds3 = bounds2; bounds3.size *= part.partPrefab.boundsMultiplier; Vector3 size = bounds3.size; bounds3.Expand(part.partPrefab.GetModuleSize(size, ModifierStagingSituation.CURRENT)); list.Add(bounds2); } } pg = PartGeometryUtil.MergeBounds(list.ToArray(), part.partPrefab.transform.root).size; #if false if (!started) { StartLine(pg.x.ToString("F3")); } else { AppendLine(pg.x.ToString("F3")); } AppendLine(pg.y.ToString("F3")); AppendLine(pg.z.ToString("F3")); started = true; #endif #if false string resources = ""; foreach (AvailablePart.ResourceInfo r in part.resourceInfos) { if (r.resourceName != "ElectricCharge" && r.resourceName != "Ablator") { resources += r.resourceName + ","; } } if (resources != "") { Log.Info("part: " + part.name + ", part.title: " + part.title + ", descr: " + part.description.Replace(",", ".") + ", mass: " + part.partPrefab.mass + ", techRequired: " + part.TechRequired + ", height x,y,z: " + pg.x.ToString() + ", " + pg.y.ToString() + ", " + pg.z.ToString() + "," + resources); } #endif } DataDump.activeMod = "PART"; var a = part.GetType(); bool b = false; Module partmod = new Module("PART", "PART", a); // ConfigNode partNode = part.partConfig.GetNode("PART"); //Log.Info("partConfig: " + part.partConfig); if (ActiveLists.activePropertyList.TryGetValue(Property.GetKey(partmod.modName, partmod.moduleName), out Property p)) { foreach (FldInfo s in p.fields) //FromReflection) { if (!b) { //string value = part.partConfig.GetValue(s.Name); b = true; for (var partAttr = PartAttrEnum.first + 1; partAttr < PartAttrEnum.last; partAttr++) { if (DataDump.partAttrs[(int)partAttr - 1] != null && DataDump.partAttrs[(int)partAttr - 1].enabled) { switch (partAttr) { case PartAttrEnum.DimensionsInfo: AppendLine(pg.x.ToString("F3")); AppendLine(pg.y.ToString("F3")); AppendLine(pg.z.ToString("F3")); break; case PartAttrEnum.Resources: var nodes = part.partConfig.GetNodes("RESOURCE").ToList().OrderBy(r => r.GetValue("name")); int cnt = 0; foreach (var n in nodes) { string name = n.GetValue("name"); string maxAmount = n.GetValue("maxAmount"); if (cnt < maxResources) { AppendLine(name + ":" + maxAmount); } cnt++; if (cnt >= maxResources) { break; } } break; case PartAttrEnum.TechRequired: AppendLine(part.TechRequired); break; case PartAttrEnum.entryCost: AppendLine(part.entryCost); break; case PartAttrEnum.cost: AppendLine(part.cost); break; case PartAttrEnum.category: AppendLine(part.category.ToString()); break; default: string str = "n/a"; str = ""; if (!part.partConfig.TryGetValue(partAttr.ToString(), ref str)) { if (useDefaultValues) { Part p1 = new Part(); switch (partAttr) { case PartAttrEnum.breakingForce: str = p1.breakingForce.ToString(); break; case PartAttrEnum.breakingtorque: str = p1.breakingTorque.ToString(); break; case PartAttrEnum.minimum_drag: str = p1.minimum_drag.ToString(); break; case PartAttrEnum.maximum_drag: str = p1.maximum_drag.ToString(); break; case PartAttrEnum.angularDrag: str = p1.angularDrag.ToString(); break; case PartAttrEnum.crashTolerance: str = p1.crashTolerance.ToString(); break; case PartAttrEnum.maxTemp: str = p1.maxTemp.ToString(); break; case PartAttrEnum.mass: AppendLine("Default: " + p1.mass); break; } } else { Log.Error("data not found"); } } //str = part.partConfig.GetValue(partAttr.ToString()); AppendLine(str); break; } } } } Field field = new Field(partmod.modName, partmod.moduleName, s.Name); if (s.Name == "entryCost") { s.Name = "_entryCost"; } if (ActiveLists.activeFieldsList.TryGetValue(field.ActiveKey, out field)) { if (field != null && field.enabled) { string value = part.partConfig.GetValue(s.Name); if (value == null || value == "") { Type fieldsType = typeof(AvailablePart); // Get an array of FieldInfo objects. FieldInfo[] fields = fieldsType.GetFields(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); foreach (var f in fields) { string v = ""; var fieldtype = s.FieldType.ToString(); string t = "System.Collections.Generic"; if (fieldtype.StartsWith(t)) { fieldtype = fieldtype.Substring(t.Length + 1); } if (f.Name == s.Name) { switch (fieldtype) { case "System.Single": v = "float"; value = ((float)f.GetValue(part)).ToString(); break; case "System.Double": v = "double"; value = ((double)f.GetValue(part)).ToString(); break; case "System.Int32": v = "int"; value = ((int)f.GetValue(part)).ToString(); break; case "System.UInt32": v = "uint"; value = ((uint)f.GetValue(part)).ToString(); break; case "System.String": v = "string"; value = (string)f.GetValue(part); if (s.Name == "description") { value = StripHtml(value); if (value.Length > maxLen && s.Name == "description") { value = value.Substring(0, maxLen); } value = value.Replace("\n", " ").Replace("\r", " "); } break; case "System.Boolean": v = "boolean"; value = ((bool)f.GetValue(part)).ToString(); break; case "UnityEngine.Vector3": v = "Vector3"; value = ((Vector3)f.GetValue(part)).ToString(); break; } break; } Log.Info("v: " + v); } } if (!started) { } else { AppendLine(value); } } } else { #if false if (field == null) { Log.Error("GetPartData, field is null"); } else if (field.ActiveKey == null) { Log.Error("GetPartData, field.ActiveKey is null"); } else { Log.Error("GetPartData, not found: " + field.ActiveKey); } #endif } } } }
public static float GetVolume(this Part part) { var boundsSize = PartGeometryUtil.MergeBounds(part.GetRendererBounds(), part.transform).size; return(boundsSize.x * boundsSize.y * boundsSize.z); }
public static float GetAverageBoundSize(this Part part) { var boundsSize = PartGeometryUtil.MergeBounds(part.GetRendererBounds(), part.transform).size; return((boundsSize.x + boundsSize.y + boundsSize.z) / 3f); }
public static void findShieldedPartsCylinder(Part basePart, Bounds fairingRenderBounds, List <Part> shieldedParts, float topY, float bottomY, float topRadius, float bottomRadius) { float height = topY - bottomY; float largestRadius = topRadius > bottomRadius ? topRadius : bottomRadius; Vector3 lookupCenterLocal = new Vector3(0, bottomY + (height * 0.5f), 0); Vector3 lookupTopLocal = new Vector3(0, topY, 0); Vector3 lookupBottomLocal = new Vector3(0, bottomY, 0); Vector3 lookupCenterGlobal = basePart.transform.TransformPoint(lookupCenterLocal); Ray lookupRay = new Ray(lookupBottomLocal, new Vector3(0, 1, 0)); List <Part> partsFound = new List <Part>(); Collider[] foundColliders = Physics.OverlapSphere(lookupCenterGlobal, height * 1.5f, 1); foreach (Collider col in foundColliders) { Part pt = col.gameObject.GetComponentUpwards <Part>(); if (pt != null && pt != basePart && pt.vessel == basePart.vessel && !partsFound.Contains(pt)) { partsFound.Add(pt); } } Bounds[] otherPartBounds; Vector3 otherPartCenterLocal; float partYPos; float partYPercent; float partYRadius; float radiusOffset = topRadius - bottomRadius; foreach (Part pt in partsFound) { //check basic render bounds for containment //TODO this check misses the case where the fairing is long/tall, containing a wide part; it will report that the wide part can fit inside //of the fairing, due to the relative size of their colliders otherPartBounds = pt.GetRendererBounds(); if (PartGeometryUtil.MergeBounds(otherPartBounds, pt.transform).size.sqrMagnitude > fairingRenderBounds.size.sqrMagnitude) { continue; } Vector3 otherPartCenter = pt.partTransform.TransformPoint(PartGeometryUtil.FindBoundsCentroid(otherPartBounds, pt.transform)); if (!fairingRenderBounds.Contains(otherPartCenter)) { continue; } //check part bounds center point against conic projection of the fairing otherPartCenterLocal = basePart.transform.InverseTransformPoint(otherPartCenter); //check vs top and bottom of the shielded area if (otherPartCenterLocal.y > lookupTopLocal.y || otherPartCenterLocal.y < lookupBottomLocal.y) { continue; } //quick check vs cylinder radius float distFromLine = SSTUUtils.distanceFromLine(lookupRay, otherPartCenterLocal); if (distFromLine > largestRadius) { continue; } //more precise check vs radius of the cone at that Y position partYPos = otherPartCenterLocal.y - lookupBottomLocal.y; partYPercent = partYPos / height; partYRadius = partYPercent * radiusOffset; if (distFromLine > (partYRadius + bottomRadius)) { continue; } shieldedParts.Add(pt); } }
void enableShielding() { disableShielding(); var attached = getFairingParams(); if (!sideFairing) { return; } // Get all parts in range. var parts = new List <Part>(); var colliders = Physics.OverlapSphere(part.transform.TransformPoint(lookupCenter), lookupRad, 1); for (int i = colliders.Length - 1; i >= 0; --i) { var p = colliders [i].gameObject.GetComponentUpwards <Part>(); if (p != null) { parts.AddUnique(p); } } // Filter parts. float sizeSqr = lookupRad * lookupRad * 4; float boundCylRadSq = boundCylRad * boundCylRad; bool isInline = (sideFairing.inlineHeight > 0); bool topClosed = false; Matrix4x4 w2l = Matrix4x4.identity, w2lb = Matrix4x4.identity; Bounds topBounds = default(Bounds); if (isInline) { w2l = part.transform.worldToLocalMatrix; w2lb = w2l; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { w2lb [i, j] = Mathf.Abs(w2lb [i, j]); } } topBounds = new Bounds(new Vector3(0, boundCylY1, 0), new Vector3(sideFairing.topRad * 2, sideFairing.sideThickness, sideFairing.topRad * 2)); } for (int pi = 0; pi < parts.Count; ++pi) { var pt = parts [pi]; // Check special cases. if (pt == part) { shieldedParts.Add(pt); continue; } bool isSide = false; for (int i = 0; i < attached.Length; ++i) { if (attached [i].attachedPart == pt) { isSide = true; break; } } if (isSide) { continue; } // Check if the top is closed in the inline case. var bounds = pt.GetRendererBounds(); var box = PartGeometryUtil.MergeBounds(bounds, pt.transform); if (isInline && !topClosed && pt.vessel == vessel) { var wb = box; wb.Expand(sideFairing.sideThickness * 4); var b = new Bounds(w2l.MultiplyPoint3x4(wb.center), w2lb.MultiplyVector(wb.size)); if (b.Contains(topBounds.min) && b.Contains(topBounds.max)) { topClosed = true; } } // Check if the centroid is within the fairing bounds. var c = part.transform.InverseTransformPoint(PartGeometryUtil.FindBoundsCentroid(bounds, null)); float y = c.y; if (y < boundCylY0 || y > boundCylY1) { continue; } float xsq = new Vector2(c.x, c.z).sqrMagnitude; if (xsq > boundCylRadSq) { continue; } // Accurate centroid check. float x = Mathf.Sqrt(xsq); bool inside = false; for (int i = 1; i < shape.Length; ++i) { var p0 = shape [i - 1]; var p1 = shape [i]; if (p0.y > p1.y) { var p = p0; p0 = p1; p1 = p; } if (y < p0.y || y > p1.y) { continue; } float dy = p1.y - p0.y, r; if (dy <= 1e-6f) { r = (p0.x + p1.x) * 0.5f; } else { r = (p1.x - p0.x) * (y - p0.y) / dy + p0.x; } if (x > r) { continue; } inside = true; break; } if (!inside) { continue; } shieldedParts.Add(pt); } if (isInline && !topClosed) { disableShielding(); return; } // Add shielding. for (int i = 0; i < shieldedParts.Count; ++i) { shieldedParts [i].AddShield(this); } numShieldedDisplay = shieldedParts.Count; var fbase = part.GetComponent <ProceduralFairingBase>(); if (fbase != null) { fbase.onShieldingEnabled(shieldedParts); } }
public void Start() { Settings.LoadConfig(); if (CheckForKIFA()) { return; } Start2(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); List <AvailablePart> loadedParts = PartLoader.LoadedPartsList; // PartLoader.Instance.loadedParts; StringBuilder stringBuilder; bool fileExists = File.Exists(VOL_CFG_FILE); Log.Info("Finding Parts Volume...."); using (List <AvailablePart> .Enumerator partEnumerator = loadedParts.GetEnumerator()) { while (partEnumerator.MoveNext()) { AvailablePart current = partEnumerator.Current; string[] urlParts = current.partUrl.Split('/'); string urlName = urlParts[urlParts.Length - 1]; // // urlName more precisely correspond to part name in the config than current.name, // but KerbalEVA and flag have empty urlname and need to be filtered, so: // string partName = urlParts[urlParts.Length - 1]; if (partName == "") { partName = current.name; } if (partBlacklist.Contains(partName) || Regex.IsMatch(partName, blacklistRegexPattern)) { Log.Info(String.Format("partName: {0, -40} found in the blacklist and ignored.", partName + ",")); continue; } bool contains_ModuleCargoPart = false; bool contains_ModuleInventoryPart = false; bool contains_KSPPartVolumeModule = false; bool containsCrew = false; bool isTank = false; bool isTankNotIgnoreable = false; bool sizeTooBig = false; bool isStock = false; bool isRcsPart = false; bool isEnginePart = false; ConfigNode currentCargoPart = null; if (!Settings.doStock) { if (urlParts[0] == "Squad" || urlParts[0] == "SquadExpansion") { if (!partWhitelist.Contains(partName)) { isStock = true; } } } var moduleNodes = current.partConfig.GetNodes("MODULE"); for (int i = 0; i < moduleNodes.Length; i++) { var name = moduleNodes[i].GetValue("name"); if (name == "ModuleCargoPart") { contains_ModuleCargoPart = true; currentCargoPart = moduleNodes[i]; } if (name == "ModuleInventoryPart") { contains_ModuleInventoryPart = true; } if (name == "KSPPartVolumeModule") { contains_KSPPartVolumeModule = true; } if (name == "ModuleRCS" || name == "ModuleRCSFX") { isRcsPart = true; } if (name == "ModuleEngines" || name == "ModuleEnginesFX") { isEnginePart = true; } // Check for manned if (!Settings.manned) { int CrewCapacity = 0; if (current.partConfig.TryGetValue("CrewCapacity", ref CrewCapacity)) { if (CrewCapacity > 0) { containsCrew = true; } } } } if (contains_KSPPartVolumeModule) { contains_ModuleCargoPart = false; } var resNodes = current.partConfig.GetNodes("RESOURCE"); float mass = 0; current.partConfig.TryGetValue("mass", ref mass); float totalResMass = 0; //if (!Settings.doTanks) { foreach (var resNode in resNodes) { var name = resNode.GetValue("name"); if (resourceBlackList.Contains(name)) { continue; } float maxAmount = 0; resNode.TryGetValue("maxAmount", ref maxAmount); var definition = PartResourceLibrary.Instance.GetDefinition(name); if (definition != null) { var density = definition.density; float resMass = maxAmount * density; totalResMass += resMass; } } if (totalResMass > mass) { isTankNotIgnoreable = true; isTank = !Settings.doTanks; } } stringBuilder = new StringBuilder(); Bounds bounds = default(Bounds); foreach (Bounds rendererBound in PartGeometryUtil.GetRendererBounds((Part)current.partPrefab)) { bounds.Encapsulate(rendererBound); } #if false Bounds colliderBounds = default(Bounds); foreach (Bounds rendererBound in PartGeometryUtil.GetPartColliderBounds((Part)current.partPrefab)) { colliderBounds.Encapsulate(rendererBound); } Bounds allBounds = default(Bounds); var a = PartGeometryUtil.GetPartColliderBounds(current.partPrefab); allBounds = PartGeometryUtil.MergeBounds(a, current.iconPrefab.transform.root); #endif float vol = (float)(bounds.size.x * bounds.size.y * bounds.size.z) * 1000f; if (vol > Settings.largestAllowablePart && Settings.limitSize) { sizeTooBig = true; } var maxLen = Math.Max(bounds.size.x, Math.Max(bounds.size.y, bounds.size.z)); var minLen = Math.Min(bounds.size.x, Math.Min(bounds.size.y, bounds.size.z)); var tankVol = Math.Pow(minLen * 0.5, 2) * maxLen * Math.PI * 1000; var adjVol = AdjustedVolume(current, vol, isEnginePart, isRcsPart, out float adj); int stackableQuantity = Math.Min((int)Settings.maxCommonStackVolume / (int)adjVol, Settings.maxPartsInStack); bool isManipulableOnly = false; bool isKSP_PartVolumeModule = false; string currentCargoPartPackedVolume = ""; if (currentCargoPart != null) { Log.Info("currentCargoPart: " + current.name); if (currentCargoPart.HasValue("packedVolume")) { currentCargoPartPackedVolume = currentCargoPart.GetValue("packedVolume"); currentCargoPart.SetValue("packedVolume", adjVol.ToString("F0")); Log.Info(String.Format("partName: {0, -40} packedVolume: {1,7}, calcPackedVolume: {2,7:F0}", partName + ",", currentCargoPartPackedVolume, adjVol)); var v = float.Parse(currentCargoPartPackedVolume); if (v <= 0) { isManipulableOnly = true; } isKSP_PartVolumeModule = currentCargoPart.HasValue("KSP_PartVolume"); } else { Log.Error(String.Format("partName: {0, -40} packedVolume not found", partName + ",")); } } if (contains_ModuleInventoryPart) { adjVol = -1; } StringBuilder tmp = new StringBuilder(); tmp.AppendLine("// " + current.partUrl); tmp.AppendLine("// Dimensions: x: " + bounds.size.x.ToString("F2") + ", y: " + bounds.size.y.ToString("F2") + ", z: " + bounds.size.z.ToString("F2")); tmp.AppendLine(string.Format("// Bounding Box Size: {0} liters", vol)); tmp.AppendLine("// Volume adjustment: " + (adj * 100).ToString("F0") + "%"); if (isRcsPart) { tmp.AppendLine("// RCS module detected"); } if (isEnginePart) { tmp.AppendLine("// Engine module detected"); } Part part = UnityEngine.Object.Instantiate(current.partPrefab); part.gameObject.SetActive(value: false); if (isTankNotIgnoreable) { var volume = DetermineVolume(part) * 1000; stringBuilder.AppendLine("// Calculated tank volume: " + volume.ToString("F1")); stringBuilder.AppendLine("// Calculated tankVol (max x min) volume: " + tankVol.ToString("F1")); } tmp.AppendLine("//"); if (!containsCrew && !isTank && !sizeTooBig && !isStock && !contains_ModuleInventoryPart && (!contains_ModuleCargoPart || (contains_ModuleCargoPart && Settings.processManipulableOnly && isManipulableOnly) || (!isKSP_PartVolumeModule && partWhitelist.Contains(partName)) )) { stringBuilder.Append(tmp); string adjName = partName.Replace(' ', '?').Replace('(', '?').Replace(')', '?'); if (contains_ModuleCargoPart) { stringBuilder.AppendLine("@PART[" + adjName + "]:HAS[@MODULE[ModuleCargoPart]]:Final"); stringBuilder.AppendLine("{"); stringBuilder.AppendLine(" @MODULE[ModuleCargoPart]"); stringBuilder.AppendLine(" {"); stringBuilder.AppendLine(" %packedVolume = " + adjVol.ToString("F0")); } else { stringBuilder.AppendLine("@PART[" + adjName + "]:HAS[!MODULE[ModuleCargoPart]]:Final"); stringBuilder.AppendLine("{"); stringBuilder.AppendLine(" MODULE"); stringBuilder.AppendLine(" {"); stringBuilder.AppendLine(" name = ModuleCargoPart"); stringBuilder.AppendLine(" packedVolume = " + adjVol.ToString("F0")); } if (Settings.stackParts && stackableQuantity > 1) { stringBuilder.AppendLine(" %stackableQuantity = " + stackableQuantity); } { stringBuilder.AppendLine(" %KSP_PartVolume = true"); stringBuilder.AppendLine(" }"); stringBuilder.AppendLine("}"); } RestartWindowVisible = true; newPartsDetected = true; part = UnityEngine.Object.Instantiate(current.partPrefab); part.gameObject.SetActive(value: false); foreach (PartModule m in part.Modules) { if (m.moduleName == "ModuleCargoPart") { var mcp = m as ModuleCargoPart; mcp.part = part; mcp.packedVolume = adjVol; if (stackableQuantity > 1) { mcp.stackableQuantity = stackableQuantity; } for (int i = current.moduleInfos.Count - 1; i >= 0; --i) { AvailablePart.ModuleInfo info = current.moduleInfos[i]; if (info.moduleName == Localizer.Format("#autoLOC_8002221")) // Cargo Part { try { info.info = mcp.GetInfo(); } catch (Exception ex) { Log.Error("PartInfo.Start, Part: " + current.partUrl + ", Exception caught in ModuleCargoPart.GetInfo, exception: " + ex.Message + "\n" + ex.StackTrace); info.info = "KSP_PartVolume error"; } break; } } } } } else { if (!fileExists) { stringBuilder.Append(tmp); stringBuilder.AppendLine("// Bypass reasons:"); if (containsCrew) { stringBuilder.AppendLine("// contains crew "); } if (isTank) { stringBuilder.AppendLine("// is tank"); } if (sizeTooBig) { stringBuilder.AppendLine("// size exceeds largestAllowablePart: " + Settings.largestAllowablePart); } if (isStock) { stringBuilder.AppendLine("// is stock"); } if (contains_ModuleCargoPart && !Settings.processManipulableOnly || contains_ModuleCargoPart && !isManipulableOnly) { stringBuilder.AppendLine("// contains ModuleCargoPart (packedVolume = " + currentCargoPartPackedVolume + ")"); } if (contains_ModuleInventoryPart) { stringBuilder.AppendLine("// contains ModuleInventoryPart"); } stringBuilder.AppendLine("//"); adjVol = -999; #if true current.partConfig.RemoveNode(currentCargoPart); //Part part = UnityEngine.Object.Instantiate(current.partPrefab); //part.gameObject.SetActive(value: false); Statics.Check4DelModCargoPart(part); //Destroy(part); #endif } } Destroy(part); if (!Statics.modifiedParts.ContainsKey(current.partUrl)) { Statics.modifiedParts.Add(current.partUrl, new PartModification(stringBuilder, adjVol, adjVol == -999)); } else { Log.Error("modifiedParts already contains: " + current.partUrl); } if (!fileExists) { stringBuilder.AppendLine("// ----------------------------------------------------------------------"); } } } stringBuilder = new StringBuilder(); if (Statics.modifiedParts.Count > 0) { foreach (var d in Statics.modifiedParts) { stringBuilder.Append(d.Value.cfg.ToString()); } File.AppendAllText(VOL_CFG_FILE, stringBuilder.ToString()); } stopwatch.Stop(); Log.Info("File written to " + VOL_CFG_FILE); Log.Info(string.Format("Run in {0}ms", (object)stopwatch.ElapsedMilliseconds)); //if (numCargoPartsAdded > 0) // ShowWarning(numCargoPartsAdded); }
public Dictionary <string, blackListPart> loadData(string fname) { Dictionary <string, blackListPart> blpList = new Dictionary <string, blackListPart>(); List <AvailablePart> loadedParts = new List <AvailablePart>(); if (PartLoader.Instance != null) { loadedParts.AddRange(PartLoader.LoadedPartsList); } #if false // This code is used to export various information about parts and their resources // used to rebalance fuel tanks foreach (AvailablePart part in loadedParts) { List <Bounds> list = new List <Bounds>(); if (!(part.partPrefab.Modules.GetModule <LaunchClamp>(0) != null)) { Bounds[] partRendererBounds = PartGeometryUtil.GetPartRendererBounds(part.partPrefab); int num = partRendererBounds.Length; for (int j = 0; j < num; j++) { Bounds bounds2 = partRendererBounds[j]; Bounds bounds3 = bounds2; bounds3.size *= part.partPrefab.boundsMultiplier; Vector3 size = bounds3.size; bounds3.Expand(part.partPrefab.GetModuleSize(size, ModifierStagingSituation.CURRENT)); list.Add(bounds2); } } var pg = PartGeometryUtil.MergeBounds(list.ToArray(), part.partPrefab.transform.root).size; string resources = ""; foreach (AvailablePart.ResourceInfo r in part.resourceInfos) { if (r.resourceName != "ElectricCharge" && r.resourceName != "Ablator") { resources += r.resourceName + ","; } } if (resources != "") { Log.Info("part: " + part.name + ", part.title: " + part.title + ", descr: " + part.description.Replace(",", ".") + ", mass: " + part.partPrefab.mass + ", techRequired: " + part.TechRequired + ", height x,y,z: " + pg.x.ToString() + ", " + pg.y.ToString() + ", " + pg.z.ToString() + "," + resources); } } #endif Log.Info("loadData, fname: " + fname); if (fname != "" && File.Exists(fname)) { using (StreamReader f = File.OpenText(fname)) { string l = ""; while ((l = f.ReadLine()) != null) { string[] s = l.Split(','); if (s.Length >= 2) { blackListPart blp = new blackListPart(); blp.modName = s[0]; if (s[1] == "ALL") { blp.where = blackListType.ALL; } if (s[1] == "SPH") { blp.where = blackListType.SPH; } if (s[1] == "VAB") { blp.where = blackListType.VAB; } AvailablePart p = loadedParts.Find(part => part.name == blp.modName); if (p != null) { blp.title = p.title; Log.Info("Blacklist mod: " + blp.modName); Log.Info("partTitle: " + blp.title); blp.permapruned = false; blpList.Add(blp.modName, blp); } } } } return(blpList); } else { return(blpList); } }