public ModelLayoutData getLayout(string name) { ModelLayoutData mld = layouts.ROLFind(m => m.name == name); if (mld == null) { ROLLog.error("ERROR: Could not locate layout for name: " + name); } return(mld); }
public readonly float gimbalFlightRange; //how far the gimbal may be actuated while in flight from the adjusted reference angle public ModelEngineTransformData(ConfigNode node) { thrustTransformName = node.ROLGetStringValue("thrustTransform"); if (string.IsNullOrEmpty(thrustTransformName)) { ROLLog.error("ERROR: THrust transform name was null for model def engine transform data"); } gimbalTransformName = node.ROLGetStringValue("gimbalTransform"); gimbalAdjustmentRange = node.ROLGetFloatValue("gimbalAdjustRange", 0); gimbalFlightRange = node.ROLGetFloatValue("gimbalFlightRange", 0); }
public ModelDefinitionLayoutOptions(ROLModelDefinition def, ModelLayoutData[] layouts) { this.definition = def; if (definition == null) { ROLLog.error("Model definition was null when creating model layout options!"); } this.layouts = layouts; if (this.layouts == null || this.layouts.Length < 1) { throw new InvalidOperationException("ERROR: No valid layout data specified."); } }
public ModelDefinitionLayoutOptions(ROLModelDefinition def) { definition = def; if (definition == null) { ROLLog.error("Model definition was null when creating model layout options!"); } layouts = ROLModelLayout.findLayouts(new string[] { "default" }); if (this.layouts == null || this.layouts.Length < 1) { throw new InvalidOperationException("ERROR: No valid layout data specified."); } }
/// <summary> /// Create a group of model definition layout sets. Loads the model definitions + their supported layout configurations. /// </summary> /// <param name="nodes"></param> /// <returns></returns> public static ModelDefinitionLayoutOptions[] getModelDefinitions(ConfigNode[] nodes) { int len = nodes.Length; List <ModelDefinitionLayoutOptions> options = new List <ModelDefinitionLayoutOptions>(); List <ModelLayoutData> layoutDataList = new List <ModelLayoutData>(); ROLModelDefinition def; string[] groupedNames; string[] groupedLayouts; int len2; for (int i = 0; i < len; i++) { //because configNode.ToString() reverses the order of values, and model def layouts are always loaded from string-cached config nodes //we need to reverse the order of the model and layout names during parsing groupedNames = nodes[i].ROLGetStringValues("model"); groupedLayouts = nodes[i].ROLGetStringValues("layout", new string[] { "default" }); len2 = groupedNames.Length; for (int k = 0; k < len2; k++) { def = ROLModelData.getModelDefinition(groupedNames[k]); layoutDataList.AddRange(ROLModelLayout.findLayouts(groupedLayouts)); if (nodes[i].HasValue("position") || nodes[i].HasValue("rotation") || nodes[i].HasValue("scale")) { Vector3 pos = nodes[i].ROLGetVector3("position", Vector3.zero); Vector3 scale = nodes[i].ROLGetVector3("scale", Vector3.one); Vector3 rot = nodes[i].ROLGetVector3("rotation", Vector3.zero); ModelPositionData mpd = new ModelPositionData(pos, scale, rot); ModelLayoutData custom = new ModelLayoutData("default", new ModelPositionData[] { mpd }); if (layoutDataList.Exists(m => m.name == "default")) { ModelLayoutData del = layoutDataList.Find(m => m.name == "default"); layoutDataList.Remove(del); } layoutDataList.Add(custom); } if (def == null) { ROLLog.error("Model definition was null for name: " + groupedNames[k] + ". Skipping definition during loading of part"); } else { options.Add(new ModelDefinitionLayoutOptions(def, layoutDataList.ToArray())); } layoutDataList.Clear(); } } return(options.ToArray()); }
public static ModelLayoutData findLayout(string name) { if (!loaded) { load(); } ModelLayoutData mld; if (!layouts.TryGetValue(name, out mld)) { ROLLog.error("Could not find layout by name: " + name); } return(mld); }
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]))); }
public override void OnStart(StartState state) { base.OnStart(state); if (!FindDecoupler()) { ROLLog.error("Unable to find any Decoupler modules"); isEnabled = enabled = false; return; } if (HighLogic.LoadedSceneIsFlight) { decouple.isOmniDecoupler = isOmniDecoupler; } }
public static T ROLFind <T>(this T[] array, Func <T, bool> predicate) { int len = array.Length; for (int i = 0; i < len; i++) { if (array[i] == null) { ROLLog.error("ERROR: Null value in array in Find method, at index: " + i); } if (predicate(array[i])) { return(array[i]); } } //return default in order to properly handle value types (structs) //should return either null for reference types or default value for structs return(default(T)); }
public override void OnStartFinished(StartState state) { base.OnStartFinished(state); ROLLog.debug("OnStartFinished()..."); if (!FindModularPart()) { ROLLog.error("Unable to find any Modular Part modules"); isEnabled = enabled = false; return; } SetupUICallbacks(); if (HighLogic.LoadedSceneIsEditor) { UpdateImpulseValues(); } }
/// <summary> /// Create a group of model definition layout options by model definition name, with default (single position) layouts. /// </summary> /// <param name="names"></param> /// <returns></returns> public static ModelDefinitionLayoutOptions[] getModelDefinitionLayouts(string[] names) { List <ModelDefinitionLayoutOptions> defs = new List <ModelDefinitionLayoutOptions>(); int len = names.Length; for (int i = 0; i < len; i++) { ROLModelDefinition def = getModelDefinition(names[i]); if (def != null) { defs.Add(new ModelDefinitionLayoutOptions(def)); } else { ROLLog.error("Could not locate model defintion for name: " + names[i]); } } return(defs.ToArray()); }
public void SetupSubmodel(GameObject modelRoot) { if (modelMeshes.Length > 0) { List <Transform> toKeep = new List <Transform>(); List <Transform> toCheck = new List <Transform>(); foreach (Transform tr in modelRoot.transform.ROLGetAllChildren()) { if (tr is Transform) { if (IsActiveMesh(tr.name)) { toKeep.Add(tr); } else { toCheck.Add(tr); } } } foreach (Transform tr in toCheck.Where(x => !IsParent(x, toKeep))) { GameObject.DestroyImmediate(tr.gameObject); } } foreach (string renameMesh in renameMeshes) { string[] split = renameMesh.Split(','); if (split.Length < 2) { ROLLog.error("ERROR: Mesh rename format invalid, must specify <oldName>,<newName>"); continue; } string oldName = split[0].Trim(); string newName = split[1].Trim(); foreach (Transform tr in modelRoot.transform.ROLFindChildren(oldName)) { tr.name = newName; } } }
public override void OnStartFinished(StartState state) { base.OnStartFinished(state); decouple = part.FindModuleImplementing <ModuleDecouple>(); modularPart = part.FindModuleImplementing <ModuleROTank>(); if (!(decouple is ModuleDecouple && modularPart is ModuleROTank)) { ROLLog.error($"{part} Unable to find ModuleDecouple or ModuleROTank modules"); isEnabled = enabled = false; return; } else { decouple.isOmniDecoupler = isOmniDecoupler; if (modularPart is ModuleROTank) { modularPart.Fields[nameof(modularPart.currentDiameter)].uiControlEditor.onFieldChanged += OnDiameterChange; } UpdateImpulseValues(); } }
private static void loadDefs() { if (defsLoaded) { return; } defsLoaded = true; ConfigNode[] modelDatas = GameDatabase.Instance.GetConfigNodes("ROL_MODEL"); ROLModelDefinition data; foreach (ConfigNode node in modelDatas) { data = new ROLModelDefinition(node); ROLLog.log("Loading model definition data for name: " + data.name + " with model URL: " + data.modelName); if (baseModelData.ContainsKey(data.name)) { ROLLog.error("Model defs already contains def for name: " + data.name + ". Please check your configs as this is an error. The duplicate entry was found in the config node of:\n" + node); continue; } baseModelData.Add(data.name, data); } }
public static bool RealFuelsVolumeUpdate(Part part, float liters) { if (!IsRFInstalled() && !IsMFTInstalled()) { ROLLog.error($"Config for {part} is set to use RF/MFT, but neither RF nor MFT is installed, cannot update part volumes through them. Please check your configs and/or patches for errors."); return(false); } if (MFTChangeTotalVolumeMI is MethodInfo && MFTCalculateMassMI is MethodInfo && GetModuleFuelTanks(part) is PartModule pm) { double volumeLiters = liters; MFTChangeTotalVolumeMI.Invoke(pm, new object[] { volumeLiters, false }); MFTCalculateMassMI.Invoke(pm, new object[] { }); UpdatePartResourceDisplay(part); ROLLog.debug($"ROTModInterop - Set RF/MFT total tank volume to: {volumeLiters} Liters for part: {part.name}"); return(true); } else { ROLLog.error($"Could not find ModuleFuelTank in part {part} for RealFuels/MFT!"); return(false); } }
/// <summary> /// Construct the model definition from the data in the input ConfigNode.<para/> /// All data constructs MUST conform to the expected format (see documentation), or things will not load properly and the model will likely not work as expected. /// </summary> /// <param name="node"></param> public ROLModelDefinition(ConfigNode node) { //load basic model definition values -- data that pertains to every model definition regardless of end-use. configNode = node; name = node.ROLGetStringValue("name", String.Empty); if (string.IsNullOrEmpty(name)) { ROLLog.error("ERROR: Cannot load ROLModelDefinition with null or empty name. Full config:\n" + node.ToString()); } title = node.ROLGetStringValue("title", name); description = node.ROLGetStringValue("description", title); modelName = node.ROLGetStringValue("modelName", string.Empty); upgradeUnlock = node.ROLGetStringValue("upgradeUnlock", upgradeUnlock); height = node.ROLGetFloatValue("height", height); actualHeight = node.ROLGetFloatValue("actualHeight", actualHeight); volume = node.ROLGetFloatValue("volume", volume); mass = node.ROLGetFloatValue("mass", mass); cost = node.ROLGetFloatValue("cost", cost); diameter = node.ROLGetFloatValue("diameter", diameter); minVerticalScale = node.ROLGetFloatValue("minVerticalScale", minVerticalScale); maxVerticalScale = node.ROLGetFloatValue("maxVerticalScale", maxVerticalScale); upperDiameter = node.ROLGetFloatValue("upperDiameter", diameter); lowerDiameter = node.ROLGetFloatValue("lowerDiameter", diameter); panelLength = node.ROLGetFloatValue("panelLength", panelLength); panelWidth = node.ROLGetFloatValue("panelWidth", panelWidth); panelArea = node.ROLGetFloatValue("panelArea", panelArea); panelScale = node.ROLGetFloatValue("panelScale", panelScale); secondaryTransformName = node.ROLGetStringValue("secondaryTransformName", secondaryTransformName); pivotName = node.ROLGetStringValue("pivotName", pivotName); animationName = node.ROLGetStringValue("animationName", animationName); lengthWidth = node.ROLGetBoolValue("lengthWidth", lengthWidth); isTracking = node.ROLGetBoolValue("isTracking", isTracking); effectiveLength = node.ROLGetFloatValue("effectiveLength", effectiveLength); additionalVolume = node.ROLGetFloatValue("additionalVolume", additionalVolume); if (node.HasValue("verticalOffset")) { positionOffset = new Vector3(0, node.ROLGetFloatValue("verticalOffset"), 0); } else { positionOffset = node.ROLGetVector3("positionOffset", Vector3.zero); } rotationOffset = node.ROLGetVector3("rotationOffset", rotationOffset); scaleOffset = node.ROLGetVector3("scaleOffset", Vector3.one); orientation = (ModelOrientation)Enum.Parse(typeof(ModelOrientation), node.ROLGetStringValue("orientation", ModelOrientation.TOP.ToString())); invertAxis = node.ROLGetVector3("invertAxis", invertAxis); //load sub-model definitions ConfigNode[] subModelNodes = node.GetNodes("SUBMODEL"); int len = subModelNodes.Length; if (len == 0)//no defined submodel data, check for regular single model definition, if present, build a submodel definition for it. { if (!string.IsNullOrEmpty(modelName)) { SubModelData smd = new SubModelData(modelName, new string[0], string.Empty, positionOffset, rotationOffset, scaleOffset); subModelData = new SubModelData[] { smd }; } else//is an empty proxy model with no meshes { subModelData = new SubModelData[0]; } } else { subModelData = new SubModelData[len]; for (int i = 0; i < len; i++) { subModelData[i] = new SubModelData(subModelNodes[i]); } } if (node.HasNode("MERGEDMODELS")) { ConfigNode[] mergeNodes = node.GetNodes("MERGEDMODELS"); len = mergeNodes.Length; mergeData = new MeshMergeData[len]; for (int i = 0; i < len; i++) { mergeData[i] = new MeshMergeData(mergeNodes[i]); } } else { mergeData = new MeshMergeData[0]; } //Load texture set definitions. List <TextureSet> textureSetList = new List <TextureSet>(); foreach (string tsName in node.ROLGetStringValues("textureSet")) { if (TexturesUnlimitedLoader.getTextureSet(tsName) is TextureSet ts) { textureSetList.Add(ts); } } //then load any of the model-specific sets foreach (ConfigNode tsNode in node.GetNodes("KSP_TEXTURE_SET")) { textureSetList.Add(new TextureSet(tsNode)); } textureSets = textureSetList.ToArray(); //Load the default texture set specification defaultTextureSet = node.ROLGetStringValue("defaultTextureSet"); //if none is defined in the model def, but texture sets are present, set it to the name of the first defined texture set if (string.IsNullOrEmpty(defaultTextureSet) && textureSets.Length > 0) { defaultTextureSet = textureSets[0].name; } if (node.HasValue("topNode")) { topNodeData = new AttachNodeBaseData(node.ROLGetStringValue("topNode")); } else { float y = height; if (orientation == ModelOrientation.CENTRAL) { y *= 0.5f; } else if (orientation == ModelOrientation.BOTTOM) { y = 0; } topNodeData = new AttachNodeBaseData(0, y, 0, 0, 1, 0, diameter / 1.25f); } if (node.HasValue("bottomNode")) { bottomNodeData = new AttachNodeBaseData(node.ROLGetStringValue("bottomNode")); } else { float y = -height; if (orientation == ModelOrientation.CENTRAL) { y *= 0.5f; } else if (orientation == ModelOrientation.TOP) { y = 0; } bottomNodeData = new AttachNodeBaseData(0, y, 0, 0, -1, 0, diameter / 1.25f); } if (node.HasValue("bodyNode")) { string[] nodeData = node.ROLGetStringValues("bodyNode"); len = nodeData.Length; bodyNodeData = new AttachNodeBaseData[len]; for (int i = 0; i < len; i++) { bodyNodeData[i] = new AttachNodeBaseData(nodeData[i]); } } //load the surface attach node specifications, or create default if none are defined. if (node.HasValue("surface")) { surfaceNode = new AttachNodeBaseData(node.ROLGetStringValue("surface")); } else { surfaceNode = new AttachNodeBaseData($"{diameter / 2},0,0,1,0,0,2"); } if (node.HasNode("COMPOUNDMODEL")) { compoundModelData = new CompoundModelData(node.GetNode("COMPOUNDMODEL")); } if (node.HasNode("CONSTRAINT")) { constraintData = new ModelConstraintData(node.GetNode("CONSTRAINT")); } if (node.HasNode("RCSDATA")) { rcsModuleData = new ModelRCSModuleData(node.GetNode("RCSDATA")); } if (node.HasNode("RCSPOSITION")) { ConfigNode[] pns = node.GetNodes("RCSPOSITION"); len = pns.Length; rcsPositionData = new ModelAttachablePositionData[len]; for (int i = 0; i < len; i++) { rcsPositionData[i] = new ModelAttachablePositionData(pns[i]); } } if (node.HasNode("ENGINE_THRUST")) { engineThrustData = new ModelEngineThrustData(node.GetNode("ENGINE_THRUST")); } if (node.HasNode("ENGINE_TRANSFORM")) { engineTransformData = new ModelEngineTransformData(node.GetNode("ENGINE_TRANSFORM")); } }