Пример #1
0
 public AttachNodeBaseData(String nodeData)
 {
     String[] dataVals = nodeData.Split(new String[] { "," }, StringSplitOptions.None);
     position    = new Vector3(ROLUtils.safeParseFloat(dataVals[0].Trim()), ROLUtils.safeParseFloat(dataVals[1].Trim()), ROLUtils.safeParseFloat(dataVals[2].Trim()));
     orientation = new Vector3(ROLUtils.safeParseFloat(dataVals[3].Trim()), ROLUtils.safeParseFloat(dataVals[4].Trim()), ROLUtils.safeParseFloat(dataVals[5].Trim()));
     size        = dataVals.Length > 6 ? ROLUtils.safeParseInt(dataVals[6]) : 4;
 }
Пример #2
0
 private void Initialize()
 {
     //MonoBehaviour.print("NodeFairingInit: "+fairingCreated+ " :: " +fairingForceDisabled+ " :: "+fairingJettisoned + " :: " +fairingEnabled);
     if (rendersToRemove != null && rendersToRemove.Length > 0)
     {
         ROLUtils.removeTransforms(part, ROLUtils.parseCSV(rendersToRemove));
     }
     LoadFairingData(ROLConfigNodeUtils.parseConfigNode(configNodeData));
     if (externalUpdateData != null)
     {
         UpdateFromExternalData(externalUpdateData);
     }
     if (fairingCreated || (fairingEnabled && !fairingJettisoned && !fairingForceDisabled && string.IsNullOrEmpty(nodeName)))//previously existed, recreate it, or should exist by default values in the config
     {
         BuildFairing();
         UpdateFairingNodes();
         if (!string.IsNullOrEmpty(nodeName))
         {
             AttachNode n = part.FindAttachNode(nodeName);
             if (n != null && n.attachedPart != null)
             {
                 prevAttachedPart = n.attachedPart;
                 //MonoBehaviour.print("Setting initial attached part to: " + prevAttachedPart);
             }
         }
     }
     else if (!fairingJettisoned && !fairingForceDisabled && !string.IsNullOrEmpty(nodeName))//else could potentially be activated by a node...check for activation
     {
         needsStatusUpdate = true;
     }
     UpdateTextureSet(false);
     needsGuiUpdate = true;
     //MonoBehaviour.print("NodeFairingInit End: " + fairingCreated + " :: " + fairingForceDisabled + " :: " + fairingJettisoned + " :: " + fairingEnabled);
 }
Пример #3
0
 public void SetOpacity(float value)
 {
     opacity = value;
     if (rootObject != null)
     {
         ROLUtils.setOpacityRecursive(rootObject.transform, value);
     }
 }
Пример #4
0
 public void LoadPersistence(String data)
 {
     String[] csv = ROLUtils.parseCSV(data);
     topY         = ROLUtils.safeParseFloat(csv[0]);
     bottomY      = ROLUtils.safeParseFloat(csv[1]);
     topRadius    = ROLUtils.safeParseFloat(csv[2]);
     bottomRadius = ROLUtils.safeParseFloat(csv[3]);
     noseNode     = csv[4];
     mountNode    = csv[5];
 }
Пример #5
0
        public static bool[] ROLGetBoolValues(this ConfigNode node, String name)
        {
            String[] values = node.GetValues(name);
            int      len    = values.Length;

            bool[] vals = new bool[len];
            for (int i = 0; i < len; i++)
            {
                vals[i] = ROLUtils.safeParseBool(values[i]);
            }
            return(vals);
        }
Пример #6
0
        public static Vector3 ROLGetVector3(this ConfigNode node, String name, Vector3 defaultValue)
        {
            String value = node.GetValue(name);

            if (value == null)
            {
                return(defaultValue);
            }
            String[] vals = value.Split(',');
            if (vals.Length < 3)
            {
                ROLLog.error("ERROR parsing values for Vector3 from input: " + value + ". found less than 3 values, cannot create Vector3");
                return(defaultValue);
            }
            return(new Vector3((float)ROLUtils.safeParseDouble(vals[0]), (float)ROLUtils.safeParseDouble(vals[1]), (float)ROLUtils.safeParseDouble(vals[2])));
        }
Пример #7
0
        public static float[] ROLGetFloatValues(this ConfigNode node, String name, float[] defaults)
        {
            String baseVal = node.ROLGetStringValue(name);

            if (!String.IsNullOrEmpty(baseVal))
            {
                String[] split = baseVal.Split(new char[] { ',' });
                float[]  vals  = new float[split.Length];
                for (int i = 0; i < split.Length; i++)
                {
                    vals[i] = ROLUtils.safeParseFloat(split[i]);
                }
                return(vals);
            }
            return(defaults);
        }
Пример #8
0
        public static int[] ROLGetIntValues(this ConfigNode node, string name, int[] defaultValues = null)
        {
            int[]    values       = defaultValues;
            string[] stringValues = node.GetValues(name);
            if (stringValues == null || stringValues.Length == 0)
            {
                return(values);
            }
            int len = stringValues.Length;

            values = new int[len];
            for (int i = 0; i < len; i++)
            {
                values[i] = ROLUtils.safeParseInt(stringValues[i]);
            }
            return(values);
        }
Пример #9
0
        /// <summary>
        /// Initialization method.  Sets up model modules, loads their configs from the input config node.  Does all initial linking of part-modules.<para/>
        /// Does NOT set up their UI interaction -- that is all handled during OnStart()
        /// </summary>
        private void Initialize()
        {
            if (initialized)
            {
                return;
            }
            initialized = true;

            prevLength = panelLength;
            prevWidth  = panelWidth;
            prevScale  = panelScale;

            coreNodeNames = ROLUtils.parseCSV(coreManagedNodes);

            // Model-Module Setup / Initialization
            ConfigNode node = ROLConfigNodeUtils.parseConfigNode(configNodeData);

            // List of CORE model nodes from config
            // each one may contain multiple 'model=modelDefinitionName' entries
            // but must contain no more than a single 'variant' entry.
            // If no variant is specified, they are added to the 'Default' variant.
            ConfigNode[] coreDefNodes = node.GetNodes("CORE");

            List <ModelDefinitionLayoutOptions> coreDefList = new List <ModelDefinitionLayoutOptions>();

            foreach (ConfigNode cn in coreDefNodes)
            {
                string variantName = cn.ROLGetStringValue("variant", "Default");
                coreDefs = ROLModelData.getModelDefinitionLayouts(cn.ROLGetStringValues("model"));
                coreDefList.AddUniqueRange(coreDefs);
                ModelDefinitionVariantSet mdvs = GetVariantSet(variantName);
                mdvs.AddModels(coreDefs);
            }
            coreDefs = coreDefList.ToArray();

            coreModule      = new ROLModelModule <ModuleROSolar>(part, this, ROLUtils.GetRootTransform(part, "ModuleROSolar-CORE"), ModelOrientation.CENTRAL, nameof(currentCore), null, null, null);
            coreModule.name = "ModuleROSolar-Core";
            coreModule.getSymmetryModule = m => m.coreModule;
            coreModule.getValidOptions   = () => GetVariantSet(currentVariant).definitions;

            coreModule.setupModelList(coreDefs);
            coreModule.setupModel();

            UpdateModulePositions();
        }
Пример #10
0
        public GameObject[] generatePanels(Transform parent)
        {
            //each panelEdgeGroup should now contain the vertical edge loops for each vertical panel grouping
            //from here, need to generate meshes for panels depending upon splitPanels setting
            int len = panelGroups.Length;

            GameObject[] gos = new GameObject[panels];
            for (int i = 0; i < len; i++)
            {
                gos[i] = parent.ROLFindOrCreate("FairingPanel-" + i).gameObject;
                ROLUtils.destroyChildren(gos[i].transform);//remove any existing colliders
                MeshFilter mf = gos[i].GetComponent <MeshFilter>();
                if (mf == null)
                {
                    mf = gos[i].AddComponent <MeshFilter>();
                }
                mf.mesh = panelGroups[i].generatePanels(offset, outsideUV, insideUV, edgesUV);
                if (colliders)
                {
                    GameObject[] cols = panelGroups[i].generateColliders(offset, facesPerCollider);
                    for (int k = 0; k < cols.Length; k++)
                    {
                        cols[k].transform.NestToParent(gos[i].transform);
                    }
                }
                MeshRenderer mr = gos[i].GetComponent <MeshRenderer>();
                if (mr == null)
                {
                    mr = gos[i].AddComponent <MeshRenderer>();
                }
                gos[i].transform.parent        = parent;
                gos[i].transform.localPosition = Vector3.zero;
                gos[i].transform.rotation      = parent.rotation;
            }
            Transform[] trs;
            for (int i = len; i < 8; i++)//destroy extra unused panels
            {
                trs = parent.transform.ROLFindChildren("FairingPanel-" + i);
                for (int k = 0; k < trs.Length; k++)
                {
                    GameObject.DestroyImmediate(trs[k].gameObject);
                }
            }
            return(gos);
        }
Пример #11
0
        public static FloatCurve ROLGetFloatCurve(this ConfigNode node, String name, FloatCurve defaultValue = null)
        {
            FloatCurve curve = new FloatCurve();

            if (node.HasNode(name))
            {
                ConfigNode curveNode = node.GetNode(name);
                String[]   values    = curveNode.GetValues("key");
                int        len       = values.Length;
                String[]   splitValue;
                float      a, b, c, d;
                for (int i = 0; i < len; i++)
                {
                    splitValue = Regex.Replace(values[i], @"\s+", " ").Split(' ');
                    if (splitValue.Length > 2)
                    {
                        a = ROLUtils.safeParseFloat(splitValue[0]);
                        b = ROLUtils.safeParseFloat(splitValue[1]);
                        c = ROLUtils.safeParseFloat(splitValue[2]);
                        d = ROLUtils.safeParseFloat(splitValue[3]);
                        curve.Add(a, b, c, d);
                    }
                    else
                    {
                        a = ROLUtils.safeParseFloat(splitValue[0]);
                        b = ROLUtils.safeParseFloat(splitValue[1]);
                        curve.Add(a, b);
                    }
                }
            }
            else if (defaultValue != null)
            {
                foreach (Keyframe f in defaultValue.Curve.keys)
                {
                    curve.Add(f.time, f.value, f.inTangent, f.outTangent);
                }
            }
            else
            {
                curve.Add(0, 0);
                curve.Add(1, 1);
            }
            return(curve);
        }
Пример #12
0
        public static Material loadMaterial(String diffuse, String normal, String emissive, String shader)
        {
            Material material;
            Texture  diffuseTexture  = ROLUtils.findTexture(diffuse, false);
            Texture  normalTexture   = String.IsNullOrEmpty(normal) ? null : ROLUtils.findTexture(normal, true);
            Texture  emissiveTexture = String.IsNullOrEmpty(emissive) ? null : ROLUtils.findTexture(emissive, false);

            material = new Material(Shader.Find(shader));
            material.SetTexture("_MainTex", diffuseTexture);
            if (normalTexture != null)
            {
                material.SetTexture("_BumpMap", normalTexture);
            }
            if (emissiveTexture != null)
            {
                material.SetTexture("_Emissive", emissiveTexture);
            }
            return(material);
        }
Пример #13
0
        public void CreatePresets()
        {
            //ROLLog.debug("TankDimensionGUI: CreatePresets()");
            presetScroll = GUILayout.BeginScrollView(presetScroll);

            //ROLLog.debug("TankDimensionGUI: ForEach through Files.");
            foreach (string f in files)
            {
                file = f;
                //ROLLog.debug("TankDimensionGUI: Load ConfigNode");
                ConfigNode config = ConfigNode.Load(file);

                // If the player is deleting the files, append the names
                if (deleteEnabled)
                {
                    if (GUILayout.Button($"Delete {config.GetValue("name")} [{config.GetValue("diameter")}m]"))
                    {
                        deleteFile     = file;
                        deleteFileName = config.GetValue("name");
                        File.Delete(deleteFile);
                        UpdatePresetList();
                    }
                }
                else
                {
                    if (GUILayout.Button($"{config.GetValue("name")} [{config.GetValue("diameter")} m]"))
                    {
                        // Set currentDiameter of ROTank
                        diameter       = ROLUtils.safeParseFloat(config.GetValue("diameter"));
                        nameString     = config.GetValue("name");
                        diameterString = diameter.ToString("N3");
                        feet           = false;
                        SetCurrentDiameter(diameter);
                    }
                }
            }
            GUILayout.EndScrollView();
            //ROLLog.debug("TankDimensionGUI: Ending CreatePresets()");
        }
Пример #14
0
 public string[] getLayoutTitles()
 {
     return(ROLUtils.getNames(layouts, m => m.title));
 }
Пример #15
0
        //TODO clean this up to be easier to read/understand now that it is optimized for cylinder check only
        public static void findShieldedPartsCylinder(Part basePart, 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>();

            //do a basic sphere check vs the maximal size of the cylinder
            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);
                }
            }

            Vector3 otherPartCenterLocal;

            float partYPos;
            float partYPercent;
            float partYRadius;
            float radiusOffset = topRadius - bottomRadius;

            foreach (Part pt in partsFound)
            {
                Vector3 otherPartCenter = pt.partTransform.TransformPoint(PartGeometryUtil.FindBoundsCentroid(pt.GetRendererBounds(), pt.transform));
                //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 = ROLUtils.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);
                //print("Shielding part: " + pt);
            }
        }
Пример #16
0
        private void UpdateTankVolume(bool lw)
        {
            if (!lw)
            {
                float totalVol = noseModule.moduleVolume + coreModule.moduleVolume + mountModule.moduleVolume;
                SendVolumeChangedEvent(totalVol);
                return;
            }

            float horScale   = currentDiameter / coreModule.definition.diameter;
            float domeLength = currentDiameter / 2;

            noseEffectiveLength  = horScale * noseModule.definition.effectiveLength;
            mountEffectiveLength = horScale * mountModule.definition.effectiveLength;
            coreEffectiveLength  = currentLength - domeLength;
            effectiveLength      = noseEffectiveLength + mountEffectiveLength + coreEffectiveLength;

            /*
             * debug("================================================");
             * debug("<color=green>EFFECTIVE LENGTH INFORMATION</color>");
             * debug($"horScale: {horScale}, domeLength: {domeLength}");
             * debug($"noseEffectiveLength: {noseEffectiveLength}, mountEffectiveLength: {mountEffectiveLength}, coreEffectiveLength: {coreEffectiveLength}");
             * debug($"effectiveLength: {effectiveLength}");
             * debug("================================================");
             */

            // Set the minimum length based on domeLength
            minLength = Math.Max(0.1f, domeLength - (noseEffectiveLength + mountEffectiveLength));

            // Update the float controller to reset the proper minimum length
            this.ROLupdateUIFloatEditControl(nameof(currentLength), minLength, maxLength, diameterLargeStep, diameterSmallStep, diameterSlideStep, true, currentLength);

            // Set the tank length to be the same size as the minLength if it is currently smaller
            if (currentLength < minLength)
            {
                currentLength = minLength;
            }

            // Calculate the new volume
            // First, get the additional volume from the nose and mounts
            float noseDiameter = noseModule.definition.shouldInvert(noseModule.definition.orientation) ? noseModule.definition.upperDiameter : noseModule.definition.lowerDiameter;
            float noseScale    = currentDiameter / noseDiameter;

            noseScale = Mathf.Pow(noseScale, 3);

            float mountDiameter = mountModule.definition.shouldInvert(mountModule.definition.orientation) ? mountModule.definition.lowerDiameter : mountModule.definition.upperDiameter;
            float mountScale    = currentDiameter / mountDiameter;

            mountScale = Mathf.Pow(mountScale, 3);

            noseAdditionalVol  = noseScale * noseModule.definition.additionalVolume * 1000f;
            mountAdditionalVol = mountScale * mountModule.definition.additionalVolume * 1000f;

            // Calculate the volume of the main tank
            float r = currentDiameter / 2;

            effectiveVolume  = (ROLUtils.EllipsoidVolume(r, r, r / 2) + ROLUtils.CylinderVolume(r, effectiveLength)) * 1000f;
            effectiveVolume += noseAdditionalVol + mountAdditionalVol;

            /*
             * debug("================================================");
             * debug("<color=blue>EFFECTIVE VOLUME INFORMATION</color>");
             * debug($"noseScale: {noseScale}, mountScale: {mountScale}");
             * debug($"noseAdditionalOrig: {noseModule.definition.additionalVolume}, noseAdditionalVol: {noseAdditionalVol}, coreAdditionalOrig: {mountModule.definition.additionalVolume}, mountAdditionalVol: {mountAdditionalVol}");
             * debug($"origEffectiveVolume: {effectiveVolume - noseAdditionalVol - mountAdditionalVol}");
             * debug($"effectiveVolume: {effectiveVolume}");
             * debug("================================================");
             */

            ROLModInterop.RealFuelsVolumeUpdate(part, effectiveVolume);
        }
Пример #17
0
        /// <summary>
        /// Initialize the UI controls, including default values, and specifying delegates for their 'onClick' methods.<para/>
        /// All UI based interaction code will be defined/run through these delegates.
        /// </summary>
        public void InitializeUI()
        {
            // Set up the core variant UI control
            string[] variantNames = ROLUtils.getNames(variantSets.Values, m => m.variantName);
            this.ROLupdateUIChooseOptionControl(nameof(currentVariant), variantNames, variantNames, true, currentVariant);
            Fields[nameof(currentVariant)].guiActiveEditor = variantSets.Count > 1;
            Fields[nameof(currentVariant)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                // Query the index from that variant set
                ModelDefinitionVariantSet prevMdvs = GetVariantSet(coreModule.definition.name);
                // This is the index of the currently selected model within its variant set
                int previousIndex = prevMdvs.IndexOf(coreModule.layoutOptions);
                // Grab ref to the current/new variant set
                ModelDefinitionVariantSet mdvs = GetVariantSet(currentVariant);
                // And a reference to the model from same index out of the new set ([] call does validation internally for IAOOBE)
                ModelDefinitionLayoutOptions newCoreDef = mdvs[previousIndex];
                // Now, call model-selected on the core model to update for the changes, including symmetry counterpart updating.
                this.ROLactionWithSymmetry(m =>
                {
                    m.coreModule.modelSelected(newCoreDef.definition.name);
                    lengthWidth = coreModule.definition.lengthWidth;
                    Fields[nameof(panelLength)].guiActiveEditor = lengthWidth;
                    Fields[nameof(panelWidth)].guiActiveEditor  = lengthWidth;
                    Fields[nameof(panelScale)].guiActiveEditor  = !lengthWidth;
                    m.ResetModel();
                });
                ModelChangedHandlerWithSymmetry(true, true);
            };

            Fields[nameof(currentCore)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                coreModule.modelSelected(a, b);
                lengthWidth = coreModule.definition.lengthWidth;
                Fields[nameof(panelLength)].guiActiveEditor = lengthWidth;
                Fields[nameof(panelWidth)].guiActiveEditor  = lengthWidth;
                Fields[nameof(panelScale)].guiActiveEditor  = !lengthWidth;
                if (!lengthWidth)
                {
                    this.ROLupdateUIFloatEditControl(nameof(panelScale), 0.1f, 100f, largeStep, smallStep, slideStep, true, panelScale);
                }
                else
                {
                    this.ROLupdateUIFloatEditControl(nameof(panelLength), minLength, maxLength, largeStep, smallStep, slideStep, true, panelLength);
                    this.ROLupdateUIFloatEditControl(nameof(panelWidth), minWidth, maxWidth, largeStep, smallStep, slideStep, true, panelWidth);
                }
                ModelChangedHandlerWithSymmetry(true, true);
            };

            Fields[nameof(panelLength)].uiControlEditor.onFieldChanged             =
                Fields[nameof(panelLength)].uiControlEditor.onSymmetryFieldChanged = (a, b) =>
            {
                if ((float)a.GetValue(this) != prevLength)
                {
                    ModelChangedHandler(true);
                    prevLength = panelLength;
                }
            };

            Fields[nameof(panelWidth)].uiControlEditor.onFieldChanged             =
                Fields[nameof(panelWidth)].uiControlEditor.onSymmetryFieldChanged = (a, b) =>
            {
                if ((float)a.GetValue(this) != prevWidth)
                {
                    ModelChangedHandler(true);
                    prevWidth = panelWidth;
                }
            };

            Fields[nameof(panelScale)].uiControlEditor.onFieldChanged             =
                Fields[nameof(panelScale)].uiControlEditor.onSymmetryFieldChanged = (a, b) =>
            {
                if ((float)a.GetValue(this) != prevScale)
                {
                    ModelChangedHandler(true);
                    prevScale = panelScale;
                }
            };

            Fields[nameof(panelScale)].guiActiveEditor = !lengthWidth;
            if (!lengthWidth)
            {
                this.ROLupdateUIFloatEditControl(nameof(panelScale), 0.1f, 100f, largeStep, smallStep, slideStep, true, panelScale);
            }

            Fields[nameof(TechLevel)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                ModelChangedHandlerWithSymmetry(true, true);
            };

            if (maxLength == minLength || !lengthWidth)
            {
                Fields[nameof(panelLength)].guiActiveEditor = false;
            }
            else
            {
                this.ROLupdateUIFloatEditControl(nameof(panelLength), minLength, maxLength, largeStep, smallStep, slideStep, true, panelLength);
            }

            if (maxWidth == minWidth || !lengthWidth)
            {
                Fields[nameof(panelWidth)].guiActiveEditor = false;
            }
            else
            {
                this.ROLupdateUIFloatEditControl(nameof(panelWidth), minWidth, maxWidth, largeStep, smallStep, slideStep, true, panelWidth);
            }

            if (HighLogic.LoadedSceneIsEditor)
            {
                GameEvents.onEditorShipModified.Add(OnEditorVesselModified);
            }
        }
Пример #18
0
        /// <summary>
        /// Initialize the UI controls, including default values, and specifying delegates for their 'onClick' methods.<para/>
        /// All UI based interaction code will be defined/run through these delegates.
        /// </summary>
        public void InitializeUI()
        {
            //set up the core variant UI control
            string[] variantNames = ROLUtils.getNames(variantSets.Values, m => m.variantName);
            this.ROLupdateUIChooseOptionControl(nameof(currentVariant), variantNames, variantNames, true, currentVariant);
            Fields[nameof(currentVariant)].guiActiveEditor = variantSets.Count > 1;

            Fields[nameof(currentVariant)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                //TODO find variant set for the currently enabled core model
                //query the index from that variant set
                ModelDefinitionVariantSet prevMdvs = GetVariantSet(coreModule.definition.name);
                //this is the index of the currently selected model within its variant set
                int previousIndex = prevMdvs.IndexOf(coreModule.layoutOptions);
                //grab ref to the current/new variant set
                ModelDefinitionVariantSet mdvs = GetVariantSet(currentVariant);
                //and a reference to the model from same index out of the new set ([] call does validation internally for IAOOBE)
                ModelDefinitionLayoutOptions newCoreDef = mdvs[previousIndex];
                //now, call model-selected on the core model to update for the changes, including symmetry counterpart updating.
                this.ROLactionWithSymmetry(m =>
                {
                    if (lengthWidth)
                    {
                        m.SetModelFromDimensions();
                    }
                    else
                    {
                        m.coreModule.modelSelected(newCoreDef.definition.name);
                    }
                });
                ModelChangedHandlerWithSymmetry(true, true);
            };

            Fields[nameof(currentDiameter)].uiControlEditor.onFieldChanged             =
                Fields[nameof(currentDiameter)].uiControlEditor.onSymmetryFieldChanged = OnDiameterChanged;

            Fields[nameof(currentLength)].uiControlEditor.onFieldChanged             =
                Fields[nameof(currentLength)].uiControlEditor.onSymmetryFieldChanged = OnLengthChanged;

            Fields[nameof(currentVScale)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                ModelChangedHandlerWithSymmetry(true, true);
            };

            Fields[nameof(currentNose)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                noseModule.modelSelected(a, b);
                ModelChangedHandlerWithSymmetry(true, true);
            };

            Fields[nameof(currentCore)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                coreModule.modelSelected(a, b);
                ModelChangedHandlerWithSymmetry(true, true);
            };

            Fields[nameof(currentMount)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                mountModule.modelSelected(a, b);
                ModelChangedHandlerWithSymmetry(true, true);
            };

            //------------------MODEL DIAMETER / LENGTH SWITCH UI INIT---------------------//
            if (maxDiameter == minDiameter)
            {
                Fields[nameof(currentDiameter)].guiActiveEditor = false;
            }
            else
            {
                this.ROLupdateUIFloatEditControl(nameof(currentDiameter), minDiameter, maxDiameter, diameterLargeStep, diameterSmallStep, diameterSlideStep, true, currentDiameter);
            }

            if (maxLength == minLength || !lengthWidth)
            {
                Fields[nameof(currentLength)].guiActiveEditor = false;
            }
            else
            {
                this.ROLupdateUIFloatEditControl(nameof(currentLength), minLength, maxLength, diameterLargeStep, diameterSmallStep, diameterSlideStep, true, currentLength);
            }

            Fields[nameof(currentVScale)].guiActiveEditor = enableVScale && !lengthWidth;
            Events[nameof(ResetModel)].guiActiveEditor    = !lengthWidth;

            //------------------MODULE TEXTURE SWITCH UI INIT---------------------//
            Fields[nameof(currentNoseTexture)].uiControlEditor.onFieldChanged  = noseModule.textureSetSelected;
            Fields[nameof(currentCoreTexture)].uiControlEditor.onFieldChanged  = coreModule.textureSetSelected;
            Fields[nameof(currentMountTexture)].uiControlEditor.onFieldChanged = mountModule.textureSetSelected;

            if (HighLogic.LoadedSceneIsEditor)
            {
                GameEvents.onEditorShipModified.Add(new EventData <ShipConstruct> .OnEvent(OnEditorVesselModified));
            }
        }
Пример #19
0
        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 = ROLUtils.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);
            }
        }
Пример #20
0
 public void EnableColliders(bool val)
 {
     ROLUtils.enableColliderRecursive(rootObject.transform, val);
 }
Пример #21
0
        /// <summary>
        /// Initialization method.  Sets up model modules, loads their configs from the input config node.  Does all initial linking of part-modules.<para/>
        /// Does NOT set up their UI interaction -- that is all handled during OnStart()
        /// </summary>
        private void Initialize()
        {
            if (initialized)
            {
                return;
            }
            ROLLog.debug($"{modName}: Initialize Starting");
            initialized = true;

            prevLength = panelLength;
            prevWidth  = panelWidth;
            prevScale  = panelScale;

            ROLLog.debug($"{modName}: Initialize() parseCSV");
            coreNodeNames = ROLUtils.parseCSV(coreManagedNodes);

            ROLLog.debug($"{modName}: Initialize() Model-Module Initialization");
            // Model-Module Setup / Initialization
            ConfigNode node = ROLConfigNodeUtils.parseConfigNode(configNodeData);

            ROLLog.debug($"{modName}: Initialize() Core Model Nodes");
            // List of CORE model nodes from config
            // each one may contain multiple 'model=modelDefinitionName' entries
            // but must contain no more than a single 'variant' entry.
            // If no variant is specified, they are added to the 'Default' variant.
            ConfigNode[] coreDefNodes = node.GetNodes("CORE");

            ROLLog.debug($"{modName}: Initialize() MDLO");
            List <ModelDefinitionLayoutOptions> coreDefList = new List <ModelDefinitionLayoutOptions>();
            int coreDefLen = coreDefNodes.Length;

            for (int i = 0; i < coreDefLen; i++)
            {
                string variantName = coreDefNodes[i].ROLGetStringValue("variant", "Default");
                coreDefs = ROLModelData.getModelDefinitionLayouts(coreDefNodes[i].ROLGetStringValues("model"));
                coreDefList.AddUniqueRange(coreDefs);
                ModelDefinitionVariantSet mdvs = getVariantSet(variantName);
                mdvs.addModels(coreDefs);
            }
            coreDefs = coreDefList.ToArray();

            coreModule      = new ROLModelModule <ModuleROSolar>(part, this, getRootTransform("ModuleROSolar-CORE"), ModelOrientation.CENTRAL, nameof(currentCore), null, null, null);
            coreModule.name = "ModuleROSolar-Core";
            coreModule.getSymmetryModule = m => m.coreModule;
            coreModule.getValidOptions   = () => getVariantSet(currentVariant).definitions;

            coreModule.setupModelList(coreDefs);
            coreModule.setupModel();

            if (GameDatabase.Instance.GetConfigNode("ROSolar/TechLimits/ROSOLAR_CONFIG") is ConfigNode ROSconfig)
            {
                SolarTechLimit.Init(ROSconfig);
            }

            stl = SolarTechLimit.GetTechLevel(techLevel);

            UpdateModulePositions();
            UpdateAttachNodes(false);
            UpdateAvailableVariants();
            UpdateMassAndCost();
            RecalculateStats();
            ROLStockInterop.updatePartHighlighting(part);
        }
Пример #22
0
        /// <summary>
        /// Initialization method.  Sets up model modules, loads their configs from the input config node.  Does all initial linking of part-modules.<para/>
        /// Does NOT set up their UI interaction -- that is all handled during OnStart()
        /// </summary>
        private void initialize()
        {
            if (initialized)
            {
                return;
            }
            initialized = true;

            prevDiameter = currentDiameter;
            if (lengthWidth)
            {
                prevLength = currentLength;
            }

            noseNodeNames  = ROLUtils.parseCSV(noseManagedNodes);
            coreNodeNames  = ROLUtils.parseCSV(coreManagedNodes);
            mountNodeNames = ROLUtils.parseCSV(mountManagedNodes);

            //model-module setup/initialization
            ConfigNode node = ROLConfigNodeUtils.parseConfigNode(configNodeData);

            //list of CORE model nodes from config
            //each one may contain multiple 'model=modelDefinitionName' entries
            //but must contain no more than a single 'variant' entry.
            //if no variant is specified, they are added to the 'Default' variant.
            ConfigNode[] coreDefNodes = node.GetNodes("CORE");

            List <ModelDefinitionLayoutOptions> coreDefList = new List <ModelDefinitionLayoutOptions>();
            int coreDefLen = coreDefNodes.Length;

            for (int i = 0; i < coreDefLen; i++)
            {
                string variantName = coreDefNodes[i].ROLGetStringValue("variant", "Default");
                coreDefs = ROLModelData.getModelDefinitionLayouts(coreDefNodes[i].ROLGetStringValues("model"));
                coreDefList.AddUniqueRange(coreDefs);
                ModelDefinitionVariantSet mdvs = getVariantSet(variantName);
                mdvs.addModels(coreDefs);
            }
            coreDefs = coreDefList.ToArray();

            //model defs - brought here so we can capture the array rather than the config node+method call
            noseDefs  = ROLModelData.getModelDefinitions(node.GetNodes("NOSE"));
            mountDefs = ROLModelData.getModelDefinitions(node.GetNodes("MOUNT"));

            noseModule      = new ROLModelModule <ModuleROTank>(part, this, getRootTransform("ModularPart-NOSE"), ModelOrientation.TOP, nameof(currentNose), null, nameof(currentNoseTexture), nameof(noseModulePersistentData));
            noseModule.name = "ModuleROTank-Nose";
            noseModule.getSymmetryModule = m => m.noseModule;
            noseModule.getValidOptions   = () => noseDefs;

            coreModule      = new ROLModelModule <ModuleROTank>(part, this, getRootTransform("ModularPart-CORE"), ModelOrientation.CENTRAL, nameof(currentCore), null, nameof(currentCoreTexture), nameof(coreModulePersistentData));
            coreModule.name = "ModuleROTank-Core";
            coreModule.getSymmetryModule = m => m.coreModule;
            coreModule.getValidOptions   = () => getVariantSet(currentVariant).definitions;

            mountModule      = new ROLModelModule <ModuleROTank>(part, this, getRootTransform("ModularPart-MOUNT"), ModelOrientation.BOTTOM, nameof(currentMount), null, nameof(currentMountTexture), nameof(mountModulePersistentData));
            mountModule.name = "ModuleROTank-Mount";
            mountModule.getSymmetryModule = m => m.mountModule;
            mountModule.getValidOptions   = () => mountDefs;

            noseModule.volumeScalar  = volumeScalingPower;
            coreModule.volumeScalar  = volumeScalingPower;
            mountModule.volumeScalar = volumeScalingPower;

            //set up the model lists and load the currently selected model
            noseModule.setupModelList(noseDefs);
            coreModule.setupModelList(coreDefs);
            mountModule.setupModelList(mountDefs);
            coreModule.setupModel();
            noseModule.setupModel();
            mountModule.setupModel();

            updateModulePositions();
            updateDimensions();
            updateAttachNodes(false);
            updateAvailableVariants();
            if (scaleMass)
            {
                updateMass();
            }
            if (scaleCost)
            {
                updateCost();
            }
            ROLStockInterop.updatePartHighlighting(part);
            UpdateTankVolume(lengthWidth);
        }
Пример #23
0
        //creates/recreates FairingData instances from data from config node and any persistent node (if applicable)
        private void LoadFairingData(ConfigNode node)
        {
            recolorHandler = new RecoloringHandler(Fields[nameof(customColorData)]);

            ConfigNode[] fairingNodes = node.GetNodes("FAIRING");
            fairingParts = new ROLNodeFairingData[fairingNodes.Length];

            Transform modelBase = part.transform.FindRecursive("model");
            Transform parent;

            ModuleROLNodeFairing[] cs = part.GetComponents <ModuleROLNodeFairing>();
            int l           = Array.IndexOf(cs, this);
            int moduleIndex = l;

            for (int i = 0; i < fairingNodes.Length; i++)
            {
                parent          = modelBase.FindOrCreate(fairingName + "-" + moduleIndex + "-" + i);
                fairingParts[i] = new ROLNodeFairingData();
                fairingParts[i].load(fairingNodes[i], parent.gameObject);
                if (fairingParts[i].canAdjustTop)
                {
                    enableTopDiameterControls = true;
                    if (guiTopDiameter < 0)
                    {
                        guiTopDiameter = fairingParts[i].topRadius * 2f;
                    }
                    else
                    {
                        fairingParts[i].topRadius = guiTopDiameter * 0.5f;
                    }
                }
                if (fairingParts[i].canAdjustBottom)
                {
                    enableBottomDiameterControls = true;
                    if (guiBottomDiameter < 0)
                    {
                        guiBottomDiameter = fairingParts[i].bottomRadius * 2f;
                    }
                    else
                    {
                        fairingParts[i].bottomRadius = guiBottomDiameter * 0.5f;
                    }
                }
            }
            //reload fairing data from persistence;
            //it -should- already match the guiTopDiameter/guiBottomDiameter (or else was already corrupted/invalid when saved out).
            if (!String.IsNullOrEmpty(persistentDataString))
            {
                String[] datas  = ROLUtils.parseCSV(persistentDataString, ":");
                int      length = datas.Length;
                for (int i = 0; i < length; i++)
                {
                    fairingParts[i].LoadPersistence(datas[i]);
                }
            }
            string[]   names  = node.ROLGetStringValues("textureSet");
            string[]   titles = ROLUtils.getNames(TexturesUnlimitedLoader.getTextureSets(names), m => m.title);
            TextureSet t      = TexturesUnlimitedLoader.getTextureSet(currentTextureSet);

            if (t == null)
            {
                currentTextureSet = names[0];
                t = TexturesUnlimitedLoader.getTextureSet(currentTextureSet);
                initializedColors = false;
            }
            if (!initializedColors)
            {
                initializedColors = true;
                recolorHandler.setColorData(t.maskColors);
            }
            this.updateUIChooseOptionControl(nameof(currentTextureSet), names, titles, true, currentTextureSet);
        }
Пример #24
0
        /// <summary>
        /// Initialize the UI controls, including default values, and specifying delegates for their 'onClick' methods.<para/>
        /// All UI based interaction code will be defined/run through these delegates.
        /// </summary>
        public void initializeUI()
        {
            Action <ModuleROTank> modelChangedAction = (m) =>
            {
                m.updateModulePositions();
                m.updateDimensions();
                m.updateAttachNodes(true);
                m.updateAvailableVariants();
                m.updateDragCubes();
                if (scaleMass)
                {
                    m.updateMass();
                }
                if (scaleCost)
                {
                    m.updateCost();
                }
                //ROLModInterop.updateResourceVolume(m.part);
                m.UpdateTankVolume(lengthWidth);
            };

            //set up the core variant UI control
            string[] variantNames = ROLUtils.getNames(variantSets.Values, m => m.variantName);
            this.ROLupdateUIChooseOptionControl(nameof(currentVariant), variantNames, variantNames, true, currentVariant);
            Fields[nameof(currentVariant)].guiActiveEditor = variantSets.Count > 1;

            Fields[nameof(currentVariant)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                //TODO find variant set for the currently enabled core model
                //query the index from that variant set
                ModelDefinitionVariantSet prevMdvs = getVariantSet(coreModule.definition.name);
                //this is the index of the currently selected model within its variant set
                int previousIndex = prevMdvs.indexOf(coreModule.layoutOptions);
                //grab ref to the current/new variant set
                ModelDefinitionVariantSet mdvs = getVariantSet(currentVariant);
                //and a reference to the model from same index out of the new set ([] call does validation internally for IAOOBE)
                ModelDefinitionLayoutOptions newCoreDef = mdvs[previousIndex];
                //now, call model-selected on the core model to update for the changes, including symmetry counterpart updating.
                this.ROLactionWithSymmetry(m =>
                {
                    m.currentVariant = currentVariant;
                    if (lengthWidth)
                    {
                        m.SetModelFromDimensions();
                    }
                    else
                    {
                        m.coreModule.modelSelected(newCoreDef.definition.name);
                    }
                    modelChangedAction(m);
                });
            };

            Fields[nameof(currentDiameter)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                this.ROLactionWithSymmetry(m =>
                {
                    if (m != this)
                    {
                        m.currentDiameter = this.currentDiameter;
                    }
                    if (lengthWidth)
                    {
                        m.SetModelFromDimensions();
                    }
                    modelChangedAction(m);
                    m.prevDiameter = m.currentDiameter;
                });
                ROLStockInterop.fireEditorUpdate();
            };

            Fields[nameof(currentLength)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                this.ROLactionWithSymmetry(m =>
                {
                    if (m != this)
                    {
                        m.currentLength = this.currentLength;
                    }
                    m.SetModelFromDimensions();
                    modelChangedAction(m);
                    m.prevLength = m.currentLength;
                });
                ROLStockInterop.fireEditorUpdate();
            };

            Fields[nameof(currentVScale)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                this.ROLactionWithSymmetry(m =>
                {
                    if (m != this)
                    {
                        m.currentVScale = this.currentVScale;
                    }
                    modelChangedAction(m);
                });
                ROLStockInterop.fireEditorUpdate();
            };

            Fields[nameof(currentNose)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                noseModule.modelSelected(a, b);
                this.ROLactionWithSymmetry(modelChangedAction);
                ROLStockInterop.fireEditorUpdate();
            };

            Fields[nameof(currentCore)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                coreModule.modelSelected(a, b);
                this.ROLactionWithSymmetry(modelChangedAction);
                ROLStockInterop.fireEditorUpdate();
            };

            Fields[nameof(currentMount)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                mountModule.modelSelected(a, b);
                this.ROLactionWithSymmetry(modelChangedAction);
                ROLStockInterop.fireEditorUpdate();
            };

            //------------------MODEL DIAMETER / LENGTH SWITCH UI INIT---------------------//
            if (maxDiameter == minDiameter)
            {
                Fields[nameof(currentDiameter)].guiActiveEditor = false;
            }
            else
            {
                this.ROLupdateUIFloatEditControl(nameof(currentDiameter), minDiameter, maxDiameter, diameterLargeStep, diameterSmallStep, diameterSlideStep, true, currentDiameter);
            }

            if (maxLength == minLength || !lengthWidth)
            {
                Fields[nameof(currentLength)].guiActiveEditor = false;
            }
            else
            {
                this.ROLupdateUIFloatEditControl(nameof(currentLength), minLength, maxLength, diameterLargeStep, diameterSmallStep, diameterSlideStep, true, currentLength);
            }

            if (!lengthWidth)
            {
                Fields[nameof(currentVScale)].guiActiveEditor = enableVScale;
                Events[nameof(ResetModel)].guiActiveEditor    = true;
            }

            if (lengthWidth)
            {
                Fields[nameof(currentVScale)].guiActiveEditor = false;
                Events[nameof(ResetModel)].guiActiveEditor    = false;
            }

            //------------------MODULE TEXTURE SWITCH UI INIT---------------------//
            Fields[nameof(currentNoseTexture)].uiControlEditor.onFieldChanged  = noseModule.textureSetSelected;
            Fields[nameof(currentCoreTexture)].uiControlEditor.onFieldChanged  = coreModule.textureSetSelected;
            Fields[nameof(currentMountTexture)].uiControlEditor.onFieldChanged = mountModule.textureSetSelected;

            if (HighLogic.LoadedSceneIsEditor)
            {
                GameEvents.onEditorShipModified.Add(new EventData <ShipConstruct> .OnEvent(onEditorVesselModified));
            }
        }
Пример #25
0
 public static Vector3 ROLGetVector3(this ConfigNode node, string name, Vector3 defaultValue)
 {
     return(node.GetValue(name) is string value && value.Split(',') is string[] vals && vals.Length >= 3
         ? new Vector3((float)ROLUtils.safeParseDouble(vals[0]), (float)ROLUtils.safeParseDouble(vals[1]), (float)ROLUtils.safeParseDouble(vals[2]))
         : defaultValue);
 }
Пример #26
0
        /// <summary>
        /// Initialize the UI controls, including default values, and specifying delegates for their 'onClick' methods.<para/>
        /// All UI based interaction code will be defined/run through these delegates.
        /// </summary>
        public void InitializeUI()
        {
            ROLLog.debug($"ModuleDeployablePart.deployState: {this.deployState}");
            ROLLog.debug($"{modName}InitalizeUI() modelChangedAction");
            Action <ModuleROSolar> modelChangedAction = (m) =>
            {
                m.stl = SolarTechLimit.GetTechLevel(techLevel);
                m.UpdateModulePositions();
                m.UpdateAttachNodes(true);
                m.UpdateAvailableVariants();
                m.UpdateDragCubes();
                m.UpdateMassAndCost();
                m.RecalculateStats();
            };

            // Set up the core variant UI control
            string[] variantNames = ROLUtils.getNames(variantSets.Values, m => m.variantName);
            this.ROLupdateUIChooseOptionControl(nameof(currentVariant), variantNames, variantNames, true, currentVariant);
            Fields[nameof(currentVariant)].guiActiveEditor = variantSets.Count > 1;
            Fields[nameof(currentVariant)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                // Query the index from that variant set
                ModelDefinitionVariantSet prevMdvs = getVariantSet(coreModule.definition.name);
                // This is the index of the currently selected model within its variant set
                int previousIndex = prevMdvs.indexOf(coreModule.layoutOptions);
                // Grab ref to the current/new variant set
                ModelDefinitionVariantSet mdvs = getVariantSet(currentVariant);
                // And a reference to the model from same index out of the new set ([] call does validation internally for IAOOBE)
                ModelDefinitionLayoutOptions newCoreDef = mdvs[previousIndex];
                // Now, call model-selected on the core model to update for the changes, including symmetry counterpart updating.
                this.ROLactionWithSymmetry(m =>
                {
                    m.currentVariant = currentVariant;
                    m.coreModule.modelSelected(newCoreDef.definition.name);
                    lengthWidth = coreModule.definition.lengthWidth;
                    if (!lengthWidth)
                    {
                        Fields[nameof(panelLength)].guiActiveEditor = false;
                        Fields[nameof(panelWidth)].guiActiveEditor  = false;
                        Fields[nameof(panelScale)].guiActiveEditor  = true;
                        this.ROLupdateUIFloatEditControl(nameof(panelScale), 0.1f, 100f, largeStep, smallStep, slideStep, true, panelScale);
                    }
                    else
                    {
                        Fields[nameof(panelLength)].guiActiveEditor = true;
                        Fields[nameof(panelWidth)].guiActiveEditor  = true;
                        Fields[nameof(panelScale)].guiActiveEditor  = false;
                        this.ROLupdateUIFloatEditControl(nameof(panelLength), minLength, maxLength, largeStep, smallStep, slideStep, true, panelLength);
                        this.ROLupdateUIFloatEditControl(nameof(panelWidth), minWidth, maxWidth, largeStep, smallStep, slideStep, true, panelWidth);
                    }
                    m.ResetModel();
                    modelChangedAction(m);
                });
            };

            Fields[nameof(currentCore)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                coreModule.modelSelected(a, b);
                lengthWidth = coreModule.definition.lengthWidth;
                if (!lengthWidth)
                {
                    Fields[nameof(panelLength)].guiActiveEditor = false;
                    Fields[nameof(panelWidth)].guiActiveEditor  = false;
                    Fields[nameof(panelScale)].guiActiveEditor  = true;
                    this.ROLupdateUIFloatEditControl(nameof(panelScale), 0.1f, 100f, largeStep, smallStep, slideStep, true, panelScale);
                }
                else
                {
                    Fields[nameof(panelLength)].guiActiveEditor = true;
                    Fields[nameof(panelWidth)].guiActiveEditor  = true;
                    Fields[nameof(panelScale)].guiActiveEditor  = false;
                    this.ROLupdateUIFloatEditControl(nameof(panelLength), minLength, maxLength, largeStep, smallStep, slideStep, true, panelLength);
                    this.ROLupdateUIFloatEditControl(nameof(panelWidth), minWidth, maxWidth, largeStep, smallStep, slideStep, true, panelWidth);
                }
                this.ROLactionWithSymmetry(modelChangedAction);
                ROLStockInterop.fireEditorUpdate();
            };

            Fields[nameof(panelLength)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                this.ROLactionWithSymmetry(m =>
                {
                    if (m != this)
                    {
                        m.panelLength = this.panelLength;
                    }
                    modelChangedAction(m);
                    m.prevLength = m.panelLength;
                });
                ROLStockInterop.fireEditorUpdate();
            };

            Fields[nameof(panelWidth)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                this.ROLactionWithSymmetry(m =>
                {
                    if (m != this)
                    {
                        m.panelWidth = this.panelWidth;
                    }
                    modelChangedAction(m);
                    m.prevWidth = m.panelWidth;
                });
                ROLStockInterop.fireEditorUpdate();
            };

            Fields[nameof(panelScale)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                this.ROLactionWithSymmetry(m =>
                {
                    if (m != this)
                    {
                        m.panelScale = this.panelScale;
                    }
                    modelChangedAction(m);
                    m.prevScale = m.panelScale;
                });
                ROLStockInterop.fireEditorUpdate();
            };

            if (maxLength == minLength || !lengthWidth)
            {
                Fields[nameof(panelLength)].guiActiveEditor = false;
            }
            else
            {
                this.ROLupdateUIFloatEditControl(nameof(panelLength), minLength, maxLength, largeStep, smallStep, slideStep, true, panelLength);
            }

            if (maxWidth == minWidth || !lengthWidth)
            {
                Fields[nameof(panelWidth)].guiActiveEditor = false;
            }
            else
            {
                this.ROLupdateUIFloatEditControl(nameof(panelWidth), minWidth, maxWidth, largeStep, smallStep, slideStep, true, panelWidth);
            }

            if (lengthWidth)
            {
                Fields[nameof(panelScale)].guiActiveEditor = false;
            }
            else
            {
                Fields[nameof(panelScale)].guiActiveEditor = true;
                this.ROLupdateUIFloatEditControl(nameof(panelScale), 0.1f, 100f, largeStep, smallStep, slideStep, true, panelScale);
            }

            if (HighLogic.LoadedSceneIsEditor)
            {
                GameEvents.onEditorShipModified.Add(new EventData <ShipConstruct> .OnEvent(onEditorVesselModified));
            }

            Fields[nameof(TechLevel)].uiControlEditor.onFieldChanged = (a, b) =>
            {
                UpdateMassAndCost();
                RecalculateStats();
                this.ROLactionWithSymmetry(modelChangedAction);
                ROLStockInterop.fireEditorUpdate();
            };
        }
Пример #27
0
 /// <summary>
 /// Returns a string array of the UI-label titles for the texture sets for this model definition.<para/>
 /// Returned in the same order as getTextureSetNames(), so they can be used in with basic indexing to map one value to another.
 /// </summary>
 /// <returns></returns>
 public string[] GetTextureSetTitles() => ROLUtils.getNames(textureSets, m => m.title);