public void ResetModel() { if (lengthWidth) { return; } currentDiameter = coreModule.definition.diameter; currentVScale = 0; this.ROLupdateUIFloatEditControl(nameof(currentDiameter), minDiameter, maxDiameter, diameterLargeStep, diameterSmallStep, diameterSlideStep, true, currentDiameter); this.ROLupdateUIFloatEditControl(nameof(currentVScale), -1, 1, 0.25f, 0.05f, 0.001f, true, currentVScale); updateModulePositions(); updateAttachNodes(true); updateAvailableVariants(); updateDragCubes(); if (scaleMass) { updateMass(); } if (scaleCost) { updateCost(); } ROLStockInterop.updatePartHighlighting(part); UpdateTankVolume(lengthWidth); }
/// <summary> /// Updates part highlight renderer list, sends message to ModuleROTFlagDecal to update its renderer, /// sends message to FAR to update voxels, or if createDefaultCube==true will re-render the 'default' stock drag cube for the part<para/> /// Should be called anytime the model geometry in a part is changed -- either models added/deleted, procedural meshes updated. Other methods exist for pure drag-cube updating in ROLStockInterop. /// </summary> /// <param name="part"></param> /// <param name="createDefaultCube"></param> public static void onPartGeometryUpdate(Part part, bool createDefaultCube) { if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) { return; } //noop on prefabs //MonoBehaviour.print(System.Environment.StackTrace); ROLStockInterop.updatePartHighlighting(part); part.airlock = locateAirlock(part); partGeometryUpdate(part); if (isFARInstalled()) { ROLStockInterop.addFarUpdatePart(part); //FARdebug(part); //part.SendMessage("GeometryPartModuleRebuildMeshData"); } else if (createDefaultCube && (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight)) { ROLStockInterop.addDragUpdatePart(part); } if (HighLogic.LoadedSceneIsEditor && part.parent == null && part != EditorLogic.RootPart) //likely the part under the cursor; this fixes problems with modular parts not wanting to attach to stuff { part.gameObject.SetLayerRecursive(1, 2097152); //1<<21 = Part Triggers get skipped by the relayering (hatches, ladders, ??) } }
public void LateUpdate() { //MonoBehaviour.print("Checking late update1: " + needsStatusUpdate + " :: " + needsRebuilt); if (externalUpdateData != null) { UpdateFromExternalData(externalUpdateData); } //MonoBehaviour.print("Checking late update2: " + needsStatusUpdate + " :: " + needsRebuilt); if (needsStatusUpdate) { UpdateFairingStatus(); } //MonoBehaviour.print("Checking late update3: " + needsStatusUpdate + " :: " + needsRebuilt); if (needsRebuilt) { RebuildFairing(); UpdatePersistentDataString(); ROLStockInterop.fireEditorUpdate(); needsGuiUpdate = true; needsRebuilt = false; } if (needsGuiUpdate) { UpdateGuiState(); needsGuiUpdate = false; } if (HighLogic.LoadedSceneIsEditor && fairingParts != null) { UpdateOpacity(); } }
public void Start() { INSTANCE = this; KSPShaderTools.TexturesUnlimitedLoader.addPostLoadCallback(KSPShaderToolsPostLoad); GameObject.DontDestroyOnLoad(this); MonoBehaviour.print("ROTStockInterop Start"); }
internal void ModelChangedHandler(bool pushNodes) { if (validateNose || validateMount) { ValidateModules(); } ValidateLength(); UpdateModulePositions(); UpdateTankVolume(lengthWidth); UpdateDimensions(); UpdateModelMeshes(); UpdateAttachNodes(pushNodes); UpdateAvailableVariants(); //UpdateFairing(true); UpdateDragCubes(); if (scaleMass) { UpdateMass(); } if (scaleCost) { UpdateCost(); } ROLStockInterop.UpdatePartHighlighting(part); if (HighLogic.LoadedSceneIsEditor) { GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship); } }
/// <summary> /// Internal method to update the persistent data state(s) from the current animation state. /// </summary> /// <param name="newState"></param> protected void onAnimationStateChange(ROLAnimState newState, bool updateExternal = false) { animationState = newState; persistentData = newState.ToString(); if (updateDragCube) { ROLStockInterop.addDragUpdatePart(part); } if (updateExternal && onAnimStateChangeCallback != null) { onAnimStateChangeCallback(newState); } }
internal void ModelChangedHandler(bool pushNodes) { stl = SolarTechLimit.GetTechLevel(techLevel); retractable = stl.retractable && solarPanelType != "static"; UpdateModulePositions(); startFSM(); UpdateAttachNodes(pushNodes); UpdateAvailableVariants(); UpdateDragCubes(); UpdateMassAndCost(); RecalculateStats(); ROLStockInterop.UpdatePartHighlighting(part); if (HighLogic.LoadedSceneIsEditor) { ROLStockInterop.FireEditorUpdate(); } }
/// <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(); }; }
/// <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); }
private void SetModelFromDimensions() { currentVScale = 0.0f; if (!lengthWidth) { return; } Action <ModuleROTank> modelChangedAction = (m) => { m.updateModulePositions(); m.updateDimensions(); m.updateAttachNodes(true); m.updateAvailableVariants(); m.updateDragCubes(); if (scaleMass) { m.updateMass(); } if (scaleCost) { m.updateCost(); } m.UpdateTankVolume(lengthWidth); }; float dimRatio, modelRatio = 0.0f; string s = "1.0x-Kerolox"; dimRatio = currentLength / currentDiameter; if (dimRatio < 0.625) { modelRatio = 0.5f; } else if (dimRatio < 1.25) { modelRatio = 1.0f; } else if (dimRatio < 1.75) { modelRatio = 1.5f; } else if (dimRatio < 2.25) { modelRatio = 2.0f; } else if (dimRatio < 2.75) { modelRatio = 2.5f; } else if (dimRatio < 3.25) { modelRatio = 3.0f; } else if (dimRatio < 3.75) { modelRatio = 3.5f; } else if (dimRatio < 4.25) { modelRatio = 4.0f; } else if (dimRatio < 4.75) { modelRatio = 4.5f; } else if (dimRatio < 5.25) { modelRatio = 5.0f; } else if (dimRatio < 5.75) { modelRatio = 5.5f; } else if (dimRatio < 6.25) { modelRatio = 6.0f; } else if (dimRatio < 6.75) { modelRatio = 6.5f; } else if (dimRatio < 7.25) { modelRatio = 7.0f; } else if (dimRatio < 7.75) { modelRatio = 7.5f; } else { modelRatio = 8.0f; } string ratioName = string.Format("{0:0.0}", modelRatio); s = $"{ratioName}x-{currentVariant}"; ROLLog.debug($"dimRatio: {dimRatio}, modelRatio: {modelRatio}, string: {s}"); currentVScale = (dimRatio / modelRatio) - 1; coreModule.modelSelected(s); this.ROLactionWithSymmetry(modelChangedAction); ROLStockInterop.fireEditorUpdate(); }
/// <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)); } }
/// <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); }
private void UpdateTankVolume(bool lw) { if (!lw) { float totalVol = noseModule.moduleVolume + coreModule.moduleVolume + mountModule.moduleVolume; SendVolumeChangedEvent(totalVol); return; } Action <ModuleROTank> modelChangedAction = (m) => { m.updateModulePositions(); m.updateDimensions(); m.updateAttachNodes(true); m.updateDragCubes(); if (scaleMass) { m.updateMass(); } if (scaleCost) { m.updateCost(); } ROLModInterop.realFuelsVolumeUpdate(m.part, m.effectiveVolume); }; 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 = (EllipsoidVolume(r, r, r / 2) + 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("================================================"); */ this.ROLactionWithSymmetry(modelChangedAction); ROLStockInterop.fireEditorUpdate(); }