private static SmarterButton AttachBehaviour(InternalProp thatProp, InternalModel thatModel, string buttonName) { string[] tokens = buttonName.Split('|'); if (thatModel == null || tokens.Length == 2) { if (tokens.Length == 2) { // First token is the button name, second is the prop ID. int propID; if (int.TryParse(tokens[1], out propID)) { if (propID < thatProp.internalModel.props.Count) { if (propID < 0) { thatModel = thatProp.internalModel; } else { thatProp = thatProp.internalModel.props[propID]; thatModel = null; } buttonName = tokens[0].Trim(); } else { Debug.LogError(string.Format("Could not find a prop with ID {0}", propID)); } } } else { buttonName = buttonName.Trim(); } } try { GameObject buttonObject; buttonObject = thatModel == null?thatProp.FindModelTransform(buttonName).gameObject : thatModel.FindModelTransform(buttonName).gameObject; SmarterButton thatComponent = buttonObject.GetComponent <SmarterButton>() ?? buttonObject.AddComponent <SmarterButton>(); return(thatComponent); } catch { Debug.LogError(string.Format( "Could not register a button on transform named '{0}' in {2} named '{1}'. Check your configuration.", buttonName, thatModel == null ? thatProp.propName : thatModel.name, thatModel == null ? "prop" : "internal model")); } return(null); }
public void Start() { comp = RasterPropMonitorComputer.Instantiate(internalProp); textObjTransform = internalProp.FindModelTransform(labelTransform); textObj = InternalComponents.Instance.CreateText(fontName, fontSize, textObjTransform, string.Empty); activeLabel = 0; SmarterButton.CreateButton(internalProp, switchTransform, Click); ConfigNode moduleConfig = null; foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { if (node.GetValue("name") == internalProp.propName) { moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] variableNodes = moduleConfig.GetNodes("VARIABLESET"); for (int i = 0; i < variableNodes.Length; i++) { try { labelsEx.Add(new VariableLabelSet(variableNodes[i])); } catch (ArgumentException e) { JUtil.LogMessage(this, "Error in building prop number {1} - {0}", e.Message, internalProp.propID); } } break; } } // Fallback: If there are no VARIABLESET blocks, we treat the module configuration itself as a variableset block. if (labelsEx.Count < 1 && moduleConfig != null) { try { labelsEx.Add(new VariableLabelSet(moduleConfig)); } catch (ArgumentException e) { JUtil.LogMessage(this, "Error in building prop number {1} - {0}", e.Message, internalProp.propID); } } colorShiftRenderer = internalProp.FindModelComponent <Renderer>(coloredObject); if (labelsEx[activeLabel].hasColor) { colorShiftRenderer.material.SetColor(colorName, labelsEx[activeLabel].color); } textObj.text.Text = StringProcessor.ProcessString(labelsEx[activeLabel].labelText, comp); audioOutput = JUtil.SetupIVASound(internalProp, switchSound, switchSoundVolume, false); JUtil.LogMessage(this, "Configuration complete in prop {1}, supporting {0} variable indicators.", labelsEx.Count, internalProp.propID); }
public void Start() { // If we're not in the correct location, there's no point doing anything. if (!InstallationPathWarning.Warn()) { return; } if (HighLogic.LoadedSceneIsEditor) { return; } try { // Install the calculator module. RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); comp.UpdateDataRefreshRate(refreshDataRate); persistence = new PersistenceAccessor(internalProp); // Loading the font... List <Texture2D> fontTexture = new List <Texture2D>(); fontTexture.Add(LoadFont(this, internalProp, fontTransform)); // Damn KSP's config parser!!! if (!string.IsNullOrEmpty(emptyColor)) { emptyColorValue = ConfigNode.ParseColor32(emptyColor); } if (!string.IsNullOrEmpty(defaultFontTint)) { defaultFontTintValue = ConfigNode.ParseColor32(defaultFontTint); } if (!string.IsNullOrEmpty(fontDefinition)) { JUtil.LogMessage(this, "Loading font definition from {0}", fontDefinition); fontDefinitionString = File.ReadAllLines(KSPUtil.ApplicationRootPath + "GameData/" + fontDefinition.EnforceSlashes(), Encoding.UTF8)[0]; } // Now that is done, proceed to setting up the screen. screenTexture = new RenderTexture(screenPixelWidth, screenPixelHeight, 24, RenderTextureFormat.ARGB32); screenMat = internalProp.FindModelTransform(screenTransform).renderer.material; foreach (string layerID in textureLayerID.Split()) { screenMat.SetTexture(layerID.Trim(), screenTexture); } if (GameDatabase.Instance.ExistsTexture(noSignalTextureURL.EnforceSlashes())) { noSignalTexture = GameDatabase.Instance.GetTexture(noSignalTextureURL.EnforceSlashes(), false); } // Create camera instance... cameraStructure = new FlyingCamera(part, screenTexture, cameraAspect); // The neat trick. IConfigNode doesn't work. No amount of kicking got it to work. // Well, we don't need it. GameDatabase, gimme config nodes for all props! foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { // Now, we know our own prop name. if (node.GetValue("name") == internalProp.propName) { // So this is the configuration of our prop in memory. Nice place. // We know it contains at least one MODULE node, us. // And we know our moduleID, which is the number in order of being listed in the prop. // Therefore the module by that number is our module's own config node. ConfigNode moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] pageNodes = moduleConfig.GetNodes("PAGE"); // Which we can now parse for page definitions. for (int i = 0; i < pageNodes.Length; i++) { // Mwahahaha. try { var newPage = new MonitorPage(i, pageNodes[i], this); activePage = activePage ?? newPage; if (newPage.isDefault) { activePage = newPage; } pages.Add(newPage); } catch (ArgumentException e) { JUtil.LogMessage(this, "Warning - {0}", e); } } // Now that all pages are loaded, we can use the moment in the loop to suck in all the extra fonts. foreach (string value in moduleConfig.GetValues("extraFont")) { fontTexture.Add(LoadFont(this, internalProp, value)); } break; } } JUtil.LogMessage(this, "Done setting up pages, {0} pages ready.", pages.Count); textRenderer = new TextRenderer(fontTexture, new Vector2((float)fontLetterWidth, (float)fontLetterHeight), fontDefinitionString, 17, screenPixelWidth, screenPixelHeight); // Load our state from storage... persistentVarName = "activePage" + internalProp.propID; int activePageID = persistence.GetVar(persistentVarName, pages.Count); if (activePageID < pages.Count) { activePage = pages[activePageID]; } activePage.Active(true); // If we have global buttons, set them up. if (!string.IsNullOrEmpty(globalButtons)) { string[] tokens = globalButtons.Split(','); for (int i = 0; i < tokens.Length; i++) { string buttonName = tokens[i].Trim(); // Notice that holes in the global button list ARE legal. if (!string.IsNullOrEmpty(buttonName)) { SmarterButton.CreateButton(internalProp, buttonName, i, GlobalButtonClick, GlobalButtonRelease); } } } audioOutput = JUtil.SetupIVASound(internalProp, buttonClickSound, buttonClickVolume, false); // One last thing to make sure of: If our pod is transparent, we're always active. ourPodIsTransparent = JUtil.IsPodTransparent(part); // And if the try block never completed, startupComplete will never be true. startupComplete = true; } catch { JUtil.AnnoyUser(this); startupFailed = true; // We can also disable ourselves, that should help. enabled = false; // And now that we notified the user that config is borked, we rethrow the exception so that // it gets logged and we can debug. throw; } }
public void Start() { if (HighLogic.LoadedSceneIsEditor) { return; } try { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); if (!groupList.ContainsKey(actionName) && !customGroupList.ContainsKey(actionName)) { JUtil.LogErrorMessage(this, "Action \"{0}\" is not supported.", actionName); return; } // Parse the needs-electric-charge here. if (!string.IsNullOrEmpty(needsElectricCharge)) { switch (needsElectricCharge.ToLowerInvariant().Trim()) { case "true": case "yes": case "1": needsElectricChargeValue = true; break; case "false": case "no": case "0": needsElectricChargeValue = false; break; } } // Now parse consumeOnToggle and consumeWhileActive... if (!string.IsNullOrEmpty(consumeOnToggle)) { string[] tokens = consumeOnToggle.Split(','); if (tokens.Length == 3) { consumeOnToggleName = tokens[0].Trim(); if (!(PartResourceLibrary.Instance.GetDefinition(consumeOnToggleName) != null && float.TryParse(tokens[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out consumeOnToggleAmount))) { JUtil.LogErrorMessage(this, "Could not parse \"{0}\"", consumeOnToggle); } switch (tokens[2].Trim().ToLower()) { case "on": consumingOnToggleUp = true; break; case "off": consumingOnToggleDown = true; break; case "both": consumingOnToggleUp = true; consumingOnToggleDown = true; break; default: JUtil.LogErrorMessage(this, "So should I consume resources when turning on, turning off, or both in \"{0}\"?", consumeOnToggle); break; } } } if (!string.IsNullOrEmpty(consumeWhileActive)) { string[] tokens = consumeWhileActive.Split(','); if (tokens.Length == 2) { consumeWhileActiveName = tokens[0].Trim(); if (!(PartResourceLibrary.Instance.GetDefinition(consumeWhileActiveName) != null && float.TryParse(tokens[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out consumeWhileActiveAmount))) { JUtil.LogErrorMessage(this, "Could not parse \"{0}\"", consumeWhileActive); } else { consumingWhileActive = true; JUtil.LogMessage(this, "Switch in prop {0} prop id {1} will consume {2} while active at a rate of {3}", internalProp.propName, internalProp.propID, consumeWhileActiveName, consumeWhileActiveAmount); } } } if (groupList.ContainsKey(actionName)) { kspAction = groupList[actionName]; currentState = vessel.ActionGroups[kspAction]; // action group switches may not belong to a radio group switchGroupIdentifier = -1; } else { isCustomAction = true; switch (actionName) { case "intlight": persistentVarName = internalLightName; if (!string.IsNullOrEmpty(internalLightName)) { Light[] availableLights = internalModel.FindModelComponents <Light>(); if (availableLights != null && availableLights.Length > 0) { List <Light> lights = new List <Light>(availableLights); for (int i = lights.Count - 1; i >= 0; --i) { if (lights[i].name != internalLightName) { lights.RemoveAt(i); } } if (lights.Count > 0) { lightObjects = lights.ToArray(); needsElectricChargeValue |= string.IsNullOrEmpty(needsElectricCharge) || needsElectricChargeValue; } else { actionName = "dummy"; } } } else { actionName = "dummy"; } break; case "plugin": persistentVarName = string.Empty; comp.UpdateDataRefreshRate(refreshRate); foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { if (node.GetValue("name") == internalProp.propName) { foreach (ConfigNode pluginConfig in node.GetNodes("MODULE")[moduleID].GetNodes("PLUGINACTION")) { if (pluginConfig.HasValue("name") && pluginConfig.HasValue("actionMethod")) { string action = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("actionMethod").Trim(); actionHandler = (Action <bool>)comp.GetMethod(action, internalProp, typeof(Action <bool>)); if (actionHandler == null) { JUtil.LogErrorMessage(this, "Failed to instantiate action handler {0}", action); } else { if (pluginConfig.HasValue("stateMethod")) { string state = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("stateMethod").Trim(); stateVariable = "PLUGIN_" + state; } else if (pluginConfig.HasValue("stateVariable")) { stateVariable = pluginConfig.GetValue("stateVariable").Trim(); } isPluginAction = true; break; } } } } } if (actionHandler == null) { actionName = "dummy"; JUtil.LogMessage(this, "Plugin handlers did not start, reverting to dummy mode."); } break; case "transfer": persistentVarName = string.Empty; comp.UpdateDataRefreshRate(refreshRate); foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { if (node.GetValue("name") == internalProp.propName) { foreach (ConfigNode pluginConfig in node.GetNodes("MODULE")[moduleID].GetNodes("TRANSFERACTION")) { if ((pluginConfig.HasValue("name") || pluginConfig.HasValue("getVariable")) && pluginConfig.HasValue("perPodPersistenceName")) { transferPersistentName = pluginConfig.GetValue("perPodPersistenceName").Trim(); if (pluginConfig.HasValue("stateMethod")) { string state = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("stateMethod").Trim(); stateVariable = "PLUGIN_" + state; } else if (pluginConfig.HasValue("stateVariable")) { stateVariable = pluginConfig.GetValue("stateVariable").Trim(); } if (pluginConfig.HasValue("setMethod")) { string action = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("setMethod").Trim(); transferSetter = (Action <double>)comp.GetMethod(action, internalProp, typeof(Action <double>)); if (transferSetter == null) { JUtil.LogErrorMessage(this, "Failed to instantiate transfer handler {0}", pluginConfig.GetValue("name")); } else { //JUtil.LogMessage(this, "Got setter {0}", action); break; } } else if (pluginConfig.HasValue("getMethod")) { string action = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("getMethod").Trim(); var getter = (Func <double>)comp.GetMethod(action, internalProp, typeof(Func <double>)); if (getter == null) { JUtil.LogErrorMessage(this, "Failed to instantiate transfer handler {0}", pluginConfig.GetValue("name")); } else { transferGetter = "PLUGIN_" + action; //JUtil.LogMessage(this, "Got getter {0}", action); break; } } else if (pluginConfig.HasValue("getVariable")) { transferGetter = pluginConfig.GetValue("getVariable").Trim(); } } } } } if (string.IsNullOrEmpty(transferGetter) && transferSetter == null) { actionName = "dummy"; stateVariable = string.Empty; JUtil.LogMessage(this, "Transfer handlers did not start, reverting to dummy mode."); } break; default: persistentVarName = "switch" + internalProp.propID + "_" + moduleID; break; } if (!string.IsNullOrEmpty(perPodPersistenceName)) { persistentVarName = perPodPersistenceName; } else { // If there's no persistence name, there's no valid group id for this switch switchGroupIdentifier = -1; } } if (customGroupList.ContainsKey(actionName)) { customAction = customGroupList[actionName]; } if (needsElectricChargeValue || !string.IsNullOrEmpty(persistentVarName) || !string.IsNullOrEmpty(perPodMasterSwitchName) || !string.IsNullOrEmpty(masterVariableName) || !string.IsNullOrEmpty(transferGetter) || transferSetter != null) { rpmComp = RasterPropMonitorComputer.Instantiate(internalProp); comp.UpdateDataRefreshRate(refreshRate); if (!string.IsNullOrEmpty(masterVariableName)) { string[] range = masterVariableRange.Split(','); if (range.Length == 2) { masterVariable = new VariableOrNumberRange(masterVariableName, range[0], range[1]); } else { masterVariable = null; } } } // set up the toggle switch if (!string.IsNullOrEmpty(switchTransform)) { if (momentarySwitch) { SmarterButton.CreateButton(internalProp, switchTransform, Click, Click); } else { SmarterButton.CreateButton(internalProp, switchTransform, Click); } } if (isCustomAction) { if (isPluginAction && !string.IsNullOrEmpty(stateVariable)) { try { currentState = (comp.ProcessVariable(stateVariable, -1).MassageToInt()) > 0; } catch { // no-op } } else { if (rpmComp != null && !string.IsNullOrEmpty(persistentVarName)) { if (switchGroupIdentifier >= 0) { int activeSwitch = rpmComp.GetVar(persistentVarName, 0); currentState = customGroupState = (switchGroupIdentifier == activeSwitch); } else { currentState = customGroupState = rpmComp.GetBool(persistentVarName, initialState); } if (customAction == CustomActions.IntLight) { // We have to restore lighting after reading the // persistent variable. SetInternalLights(customGroupState); } } } } if (rpmComp != null && !rpmComp.HasVar(persistentVarName)) { if (switchGroupIdentifier >= 0) { if (currentState) { rpmComp.SetVar(persistentVarName, switchGroupIdentifier); } } else { rpmComp.SetVar(persistentVarName, currentState); } } if (!string.IsNullOrEmpty(animationName)) { // Set up the animation Animation[] animators = animateExterior ? part.FindModelAnimators(animationName) : internalProp.FindModelAnimators(animationName); if (animators.Length > 0) { anim = animators[0]; } else { JUtil.LogErrorMessage(this, "Could not find animation \"{0}\" on {2} \"{1}\"", animationName, animateExterior ? part.name : internalProp.name, animateExterior ? "part" : "prop"); return; } anim[animationName].wrapMode = WrapMode.Once; if (currentState ^ reverse) { anim[animationName].speed = float.MaxValue; anim[animationName].normalizedTime = 0; } else { anim[animationName].speed = float.MinValue; anim[animationName].normalizedTime = 1; } anim.Play(animationName); } else if (!string.IsNullOrEmpty(coloredObject)) { // Set up the color shift. Renderer colorShiftRenderer = internalProp.FindModelComponent <Renderer>(coloredObject); disabledColorValue = ConfigNode.ParseColor32(disabledColor); enabledColorValue = ConfigNode.ParseColor32(enabledColor); colorShiftMaterial = colorShiftRenderer.material; colorShiftMaterial.SetColor(colorName, (currentState ^ reverse ? enabledColorValue : disabledColorValue)); } else { JUtil.LogMessage(this, "Warning, neither color nor animation are defined in prop {0} #{1} (this may be okay).", internalProp.propName, internalProp.propID); } audioOutput = JUtil.SetupIVASound(internalProp, switchSound, switchSoundVolume, false); if (!string.IsNullOrEmpty(loopingSound) && loopingSoundVolume > 0.0f) { loopingOutput = JUtil.SetupIVASound(internalProp, loopingSound, loopingSoundVolume, true); } startupComplete = true; } catch { JUtil.AnnoyUser(this); enabled = false; throw; } }
public MonitorPage(int idNum, ConfigNode node, RasterPropMonitor thatMonitor) { ourMonitor = thatMonitor; screenWidth = ourMonitor.screenWidth; screenHeight = ourMonitor.screenHeight; cameraAspect = ourMonitor.cameraAspect; cameraObject = thatMonitor.cameraStructure; defaultColor = ourMonitor.defaultFontTintValue; screenXMin = 0; screenYMin = 0; pageNumber = idNum; isMutable = false; if (!node.HasData) { throw new ArgumentException("Empty page?"); } if (node.HasValue("name")) { string value = node.GetValue("name").Trim(); if (!IsValidPageName(value)) { JUtil.LogMessage(ourMonitor, "Warning, name given for page #{0} is invalid, ignoring.", pageNumber); } else { name = value; } } else { JUtil.LogMessage(ourMonitor, "Warning, page #{0} has no name. It's much better if it does.", pageNumber); } isDefault |= node.HasValue("default"); if (node.HasValue("button")) { SmarterButton.CreateButton(thatMonitor.internalProp, node.GetValue("button"), this, thatMonitor.PageButtonClick); } // Page locking system -- simple locking: simpleLockingPage |= node.HasValue("lockingPage"); // and name-based locking. if (node.HasValue("disableSwitchingTo")) { string[] tokens = node.GetValue("disableSwitchingTo").Split(','); foreach (string token in tokens) { disableSwitchingTo.Add(token.Trim()); } } unlocker |= node.HasValue("unlockerPage"); if (node.HasValue("localMargins")) { Vector4 margindata = ConfigNode.ParseVector4(node.GetValue("localMargins")); screenXMin = (int)margindata.x; screenYMin = (int)margindata.y; screenWidth = screenWidth - (int)margindata.z - screenXMin; screenHeight = screenHeight - (int)margindata.w - screenYMin; } pageFont = node.GetInt("defaultFontNumber") ?? 0; if (node.HasValue("defaultFontTint")) { defaultColor = ConfigNode.ParseColor32(node.GetValue("defaultFontTint")); } if (node.HasValue("techsRequired")) { techsRequired = node.GetValue("techsRequired").Split(new[] { ' ', ',', ';', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList(); } if (node.HasValue("fallbackOnNoTech")) { fallbackPageName = node.GetValue("fallbackOnNoTech").Trim(); } if (node.HasNode("CONTEXTREDIRECT")) { ConfigNode[] redirectnodes = node.GetNodes("CONTEXTREDIRECT"); for (int i = 0; i < redirectnodes.Length; ++i) { string[] redirects = redirectnodes[i].GetValues("redirect"); for (int j = 0; j < redirects.Length; ++j) { string[] tokens = redirects[j].Split(','); if (tokens.Length > 2 || !IsValidPageName(tokens[0].Trim()) || !IsValidPageName(tokens[1].Trim())) { JUtil.LogMessage(ourMonitor, "Warning, invalid page redirect statement on page #{0}.", pageNumber); continue; } redirectPages[tokens[0].Trim()] = tokens[1].Trim(); } string[] renumbers = redirectnodes[i].GetValues("renumber"); for (int j = 0; j < renumbers.Length; ++j) { string[] tokens = renumbers[j].Split(','); if (tokens.Length > 2) { JUtil.LogMessage(ourMonitor, "Warning, invalid global button redirect statement on page #{0}: requires two arguments.", pageNumber); continue; } int from, to; if (!int.TryParse(tokens[0], out from) || !int.TryParse(tokens[1], out to)) { JUtil.LogMessage(ourMonitor, "Warning, invalid global button redirect statement on page #{0}: something isn't a number", pageNumber); continue; } redirectGlobals[from] = to; } } JUtil.LogMessage(this, "Page '{2}' (#{0}) registers {1} page redirects and {3} global button redirects.", idNum, redirectPages.Count, name, redirectGlobals.Count); } foreach (ConfigNode handlerNode in node.GetNodes("PAGEHANDLER")) { MonoBehaviour handlerModule; HandlerSupportMethods supportMethods; MethodInfo handlerMethod = InstantiateHandler(handlerNode, ourMonitor, out handlerModule, out supportMethods); if (handlerMethod != null && handlerModule != null) { try { pageHandlerMethod = (Func <int, int, string>)Delegate.CreateDelegate(typeof(Func <int, int, string>), handlerModule, handlerMethod); } catch { JUtil.LogErrorMessage(ourMonitor, "Incorrect signature for the page handler method {0}", handlerModule.name); break; } pageHandlerS = supportMethods; isMutable = true; pageHandlerModule = handlerModule; break; } } if (pageHandlerMethod == null) { if (node.HasValue("text")) { text = JUtil.LoadPageDefinition(node.GetValue("text")); isMutable |= text.IndexOf("$&$", StringComparison.Ordinal) != -1; } } if (node.HasValue("textOverlay")) { textOverlay = JUtil.LoadPageDefinition(node.GetValue("textOverlay")); } foreach (ConfigNode handlerNode in node.GetNodes("BACKGROUNDHANDLER")) { MonoBehaviour handlerModule; HandlerSupportMethods supportMethods; MethodInfo handlerMethod = InstantiateHandler(handlerNode, ourMonitor, out handlerModule, out supportMethods); if (handlerMethod != null && handlerModule != null) { try { backgroundHandlerMethod = (Func <RenderTexture, float, bool>)Delegate.CreateDelegate(typeof(Func <RenderTexture, float, bool>), handlerModule, handlerMethod); } catch { JUtil.LogErrorMessage(ourMonitor, "Incorrect signature for the background handler method {0}", handlerModule.name); break; } backgroundHandlerS = supportMethods; isMutable = true; showNoSignal = node.HasValue("showNoSignal"); background = BackgroundType.Handler; backgroundHandlerModule = handlerModule; break; } } if (background == BackgroundType.None) { if (node.HasValue("cameraTransform")) { isMutable = true; background = BackgroundType.Camera; camera = node.GetValue("cameraTransform"); cameraFOV = defaultFOV; cameraFlickerChance = node.GetFloat("flickerChance") ?? 0; cameraFlickerRange = node.GetInt("flickerRange") ?? 0; if (node.HasValue("fov")) { float fov; cameraFOV = float.TryParse(node.GetValue("fov"), out fov) ? fov : defaultFOV; } else if (node.HasValue("zoomFov") && node.HasValue("zoomButtons")) { Vector3 zoomFov = ConfigNode.ParseVector3(node.GetValue("zoomFov")); Vector2 zoomButtons = ConfigNode.ParseVector2(node.GetValue("zoomButtons")); if ((int)zoomFov.z != 0 && ((int)zoomButtons.x != (int)zoomButtons.y)) { maxFOV = Math.Max(zoomFov.x, zoomFov.y); minFOV = Math.Min(zoomFov.x, zoomFov.y); zoomSteps = (int)zoomFov.z; zoomUpButton = (int)zoomButtons.x; zoomDownButton = (int)zoomButtons.y; zoomSkip = (maxFOV - minFOV) / zoomSteps; currentZoom = 0; cameraFOV = maxFOV; } else { JUtil.LogMessage(ourMonitor, "Ignored invalid camera zoom settings on page {0}.", pageNumber); } } } } if (background == BackgroundType.None) { if (node.HasValue("textureURL")) { string textureURL = node.GetValue("textureURL").EnforceSlashes(); if (GameDatabase.Instance.ExistsTexture(textureURL)) { backgroundTexture = GameDatabase.Instance.GetTexture(textureURL, false); background = BackgroundType.Texture; } } } if (node.HasValue("textureInterlayURL")) { string textureURL = node.GetValue("textureInterlayURL").EnforceSlashes(); if (GameDatabase.Instance.ExistsTexture(textureURL)) { interlayTexture = GameDatabase.Instance.GetTexture(textureURL, false); } else { JUtil.LogErrorMessage(ourMonitor, "Interlay texture {0} could not be loaded.", textureURL); } } if (node.HasValue("textureOverlayURL")) { string textureURL = node.GetValue("textureOverlayURL").EnforceSlashes(); if (GameDatabase.Instance.ExistsTexture(textureURL)) { overlayTexture = GameDatabase.Instance.GetTexture(textureURL, false); } else { JUtil.LogErrorMessage(ourMonitor, "Overlay texture {0} could not be loaded.", textureURL); } } }
public void Start() { if (!groupList.ContainsKey(actionName) && !customGroupList.ContainsKey(actionName)) { JUtil.LogErrorMessage(this, "Action \"{0}\" is not supported.", actionName); return; } // Parse the needs-electric-charge here. if (!string.IsNullOrEmpty(needsElectricCharge)) { switch (needsElectricCharge.ToLowerInvariant().Trim()) { case "true": case "yes": case "1": needsElectricChargeValue = true; break; case "false": case "no": case "0": needsElectricChargeValue = false; break; } } if (groupList.ContainsKey(actionName)) { oldState = vessel.ActionGroups[groupList[actionName]]; } else { isCustomAction = true; switch (actionName) { case "intlight": persistentVarName = internalLightName; lightObjects = internalModel.FindModelComponents <Light>(); needsElectricChargeValue |= string.IsNullOrEmpty(needsElectricCharge) || needsElectricChargeValue; break; case "plugin": persistentVarName = string.Empty; foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { if (node.GetValue("name") == internalProp.propName) { foreach (ConfigNode pluginConfig in node.GetNodes("MODULE")[moduleID].GetNodes("PLUGINACTION")) { if (pluginConfig.HasValue("name") && pluginConfig.HasValue("actionMethod")) { if (!InstantiateHandler(pluginConfig, this, out actionHandler, out stateHandler)) { JUtil.LogErrorMessage(this, "Failed to instantiate action handler {0}", pluginConfig.GetValue("name")); } else { isPluginAction = true; break; } } } } } if (actionHandler == null) { actionName = "dummy"; JUtil.LogMessage(this, "Plugin handlers did not start, reverting to dummy mode."); } break; default: persistentVarName = "switch" + internalProp.propID + "_" + moduleID; break; } if (!string.IsNullOrEmpty(perPodPersistenceName)) { persistentVarName = perPodPersistenceName; } persistence = new PersistenceAccessor(part); } if (needsElectricChargeValue) { comp = RasterPropMonitorComputer.Instantiate(internalProp); comp.UpdateRefreshRates(lightCheckRate, lightCheckRate); } // set up the toggle switch if (!string.IsNullOrEmpty(switchTransform)) { SmarterButton.CreateButton(internalProp, switchTransform, Click); } if (isCustomAction) { if (isPluginAction && stateHandler != null) { oldState = stateHandler(); } else { if (!string.IsNullOrEmpty(persistentVarName)) { oldState = customGroupList[actionName] = (persistence.GetBool(persistentVarName) ?? oldState); if (actionName == "intlight") { // We have to restore lighting after reading the // persistent variable. SetInternalLights(customGroupList[actionName]); } } } } if (!string.IsNullOrEmpty(animationName)) { // Set up the animation Animation[] animators = animateExterior ? part.FindModelAnimators(animationName) : internalProp.FindModelAnimators(animationName); if (animators.Length > 0) { anim = animators[0]; } else { JUtil.LogErrorMessage(this, "Could not find animation \"{0}\" on {2} \"{1}\"", animationName, animateExterior ? part.name : internalProp.name, animateExterior ? "part" : "prop"); return; } anim[animationName].wrapMode = WrapMode.Once; if (oldState ^ reverse) { anim[animationName].speed = float.MaxValue; anim[animationName].normalizedTime = 0; } else { anim[animationName].speed = float.MinValue; anim[animationName].normalizedTime = 1; } anim.Play(animationName); } else if (!string.IsNullOrEmpty(coloredObject)) { // Set up the color shift. colorShiftRenderer = internalProp.FindModelComponent <Renderer>(coloredObject); disabledColorValue = ConfigNode.ParseColor32(disabledColor); enabledColorValue = ConfigNode.ParseColor32(enabledColor); colorShiftRenderer.material.SetColor(colorName, (oldState ^ reverse ? enabledColorValue : disabledColorValue)); } else { JUtil.LogMessage(this, "Warning, neither color nor animation are defined."); } audioOutput = JUtil.SetupIVASound(internalProp, switchSound, switchSoundVolume, false); startupComplete = true; }
public void Start() { // If we're not in the correct location, there's no point doing anything. if (!InstallationPathWarning.Warn()) { return; } if (HighLogic.LoadedSceneIsEditor) { return; } try { rpmComp = RasterPropMonitorComputer.Instantiate(internalProp, true); JUtil.LogMessage(this, "Attaching monitor {2}-{1} to {0}", rpmComp.RPMCid, internalProp.propID, internalProp.internalModel.internalName); // Install the calculator module. rpmComp.UpdateDataRefreshRate(refreshDataRate); // Loading the font... List <Texture2D> fontTexture = new List <Texture2D>(); fontTexture.Add(LoadFont(this, internalProp, fontTransform)); // Damn KSP's config parser!!! if (!string.IsNullOrEmpty(emptyColor)) { emptyColorValue = ConfigNode.ParseColor32(emptyColor); } if (!string.IsNullOrEmpty(defaultFontTint)) { defaultFontTintValue = ConfigNode.ParseColor32(defaultFontTint); } if (!string.IsNullOrEmpty(fontDefinition)) { JUtil.LogMessage(this, "Loading font definition from {0}", fontDefinition); fontDefinitionString = File.ReadAllLines(KSPUtil.ApplicationRootPath + "GameData/" + fontDefinition.EnforceSlashes(), Encoding.UTF8)[0]; } // Now that is done, proceed to setting up the screen. screenTexture = new RenderTexture(screenPixelWidth, screenPixelHeight, 24, RenderTextureFormat.ARGB32); screenMat = internalProp.FindModelTransform(screenTransform).GetComponent <Renderer>().material; bool manuallyInvertY = false; if (SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 9") || SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 11") || SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 12")) { manuallyInvertY = (UnityEngine.QualitySettings.antiAliasing > 0); } foreach (string layerID in textureLayerID.Split()) { screenMat.SetTexture(layerID.Trim(), screenTexture); // This code was written for a much older flavor of Unity, and the Unity 2017.1 update broke // some assumptions about who managed the y-inversion issue between OpenGL and DX9. if (manuallyInvertY) { screenMat.SetTextureScale(layerID.Trim(), new Vector2(1.0f, -1.0f)); screenMat.SetTextureOffset(layerID.Trim(), new Vector2(0.0f, 1.0f)); } } if (GameDatabase.Instance.ExistsTexture(noSignalTextureURL.EnforceSlashes())) { noSignalTexture = GameDatabase.Instance.GetTexture(noSignalTextureURL.EnforceSlashes(), false); } // The neat trick. IConfigNode doesn't work. No amount of kicking got it to work. // Well, we don't need it. GameDatabase, gimme config nodes for all props! foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { // Now, we know our own prop name. if (node.GetValue("name") == internalProp.propName) { // So this is the configuration of our prop in memory. Nice place. // We know it contains at least one MODULE node, us. // And we know our moduleID, which is the number in order of being listed in the prop. // Therefore the module by that number is our module's own config node. ConfigNode moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] pageNodes = moduleConfig.GetNodes("PAGE"); // Which we can now parse for page definitions. for (int i = 0; i < pageNodes.Length; i++) { // Mwahahaha. try { var newPage = new MonitorPage(i, pageNodes[i], this); activePage = activePage ?? newPage; if (newPage.isDefault) { activePage = newPage; } pages.Add(newPage); } catch (ArgumentException e) { JUtil.LogMessage(this, "Warning - {0}", e); } } // Now that all pages are loaded, we can use the moment in the loop to suck in all the extra fonts. foreach (string value in moduleConfig.GetValues("extraFont")) { fontTexture.Add(LoadFont(this, internalProp, value)); } break; } } JUtil.LogMessage(this, "Done setting up pages, {0} pages ready.", pages.Count); textRenderer = new TextRenderer(fontTexture, new Vector2((float)fontLetterWidth, (float)fontLetterHeight), fontDefinitionString, 17, screenPixelWidth, screenPixelHeight); // Load our state from storage... persistentVarName = "activePage" + internalProp.propID; int activePageID = rpmComp.GetPersistentVariable(persistentVarName, pages.Count, false).MassageToInt(); if (activePageID < pages.Count) { activePage = pages[activePageID]; } activePage.Active(true); // If we have global buttons, set them up. if (!string.IsNullOrEmpty(globalButtons)) { string[] tokens = globalButtons.Split(','); for (int i = 0; i < tokens.Length; i++) { string buttonName = tokens[i].Trim(); // Notice that holes in the global button list ARE legal. if (!string.IsNullOrEmpty(buttonName)) { SmarterButton.CreateButton(internalProp, buttonName, i, GlobalButtonClick, GlobalButtonRelease); } } } audioOutput = JUtil.SetupIVASound(internalProp, buttonClickSound, buttonClickVolume, false); if (needsElectricCharge) { delResourceCallback = (Action <bool>)Delegate.CreateDelegate(typeof(Action <bool>), this, "ResourceDepletedCallback"); rpmComp.RegisterResourceCallback(resourceName, delResourceCallback); } if (needsCommConnection) { delCommConnectionCallback = (Action <float>)Delegate.CreateDelegate(typeof(Action <float>), this, "CommConnectionCallback"); rpmComp.RegisterVariableCallback("COMMNETVESSELCONTROLSTATE", delCommConnectionCallback); } // And if the try block never completed, startupComplete will never be true. startupComplete = true; } catch { JUtil.AnnoyUser(this); // We can also disable ourselves, that should help. enabled = false; // And now that we notified the user that config is borked, we rethrow the exception so that // it gets logged and we can debug. throw; } }
/// <summary> /// Start everything up and get it configured. /// </summary> public void Start() { try { rpmComp = RasterPropMonitorComputer.Instantiate(internalProp, true); Transform textObjTransform = internalProp.FindModelTransform(transformName); Vector3 localScale = internalProp.transform.localScale; Transform offsetTransform = new GameObject().transform; offsetTransform.gameObject.name = "JSILabel-" + this.internalProp.propID + "-" + this.GetHashCode().ToString(); offsetTransform.gameObject.layer = textObjTransform.gameObject.layer; offsetTransform.SetParent(textObjTransform, false); offsetTransform.Translate(transformOffset.x * localScale.x, transformOffset.y * localScale.y, 0.0f); textObj = offsetTransform.gameObject.AddComponent <JSITextMesh>(); font = JUtil.LoadFont(fontName, fontQuality); textObj.font = font; //textObj.fontSize = fontQuality; // This doesn't work with Unity-embedded fonts textObj.fontSize = font.fontSize; if (!string.IsNullOrEmpty(anchor)) { if (anchor == TextAnchor.LowerCenter.ToString()) { textObj.anchor = TextAnchor.LowerCenter; } else if (anchor == TextAnchor.LowerLeft.ToString()) { textObj.anchor = TextAnchor.LowerLeft; } else if (anchor == TextAnchor.LowerRight.ToString()) { textObj.anchor = TextAnchor.LowerRight; } else if (anchor == TextAnchor.MiddleCenter.ToString()) { textObj.anchor = TextAnchor.MiddleCenter; } else if (anchor == TextAnchor.MiddleLeft.ToString()) { textObj.anchor = TextAnchor.MiddleLeft; } else if (anchor == TextAnchor.MiddleRight.ToString()) { textObj.anchor = TextAnchor.MiddleRight; } else if (anchor == TextAnchor.UpperCenter.ToString()) { textObj.anchor = TextAnchor.UpperCenter; } else if (anchor == TextAnchor.UpperLeft.ToString()) { textObj.anchor = TextAnchor.UpperLeft; } else if (anchor == TextAnchor.UpperRight.ToString()) { textObj.anchor = TextAnchor.UpperRight; } else { JUtil.LogErrorMessage(this, "Unrecognized anchor '{0}' in config for {1} ({2})", anchor, internalProp.propID, internalProp.propName); } } if (!string.IsNullOrEmpty(alignment)) { if (alignment == TextAlignment.Center.ToString()) { textObj.alignment = TextAlignment.Center; } else if (alignment == TextAlignment.Left.ToString()) { textObj.alignment = TextAlignment.Left; } else if (alignment == TextAlignment.Right.ToString()) { textObj.alignment = TextAlignment.Right; } else { JUtil.LogErrorMessage(this, "Unrecognized alignment '{0}' in config for {1} ({2})", alignment, internalProp.propID, internalProp.propName); } } float sizeScalar = 32.0f / (float)font.fontSize; textObj.characterSize = fontSize * 0.00005f * sizeScalar; textObj.lineSpacing = textObj.lineSpacing * lineSpacing; // "Normal" mode if (string.IsNullOrEmpty(switchTransform)) { // Force oneshot if there's no variables: oneshot |= !labelText.Contains("$&$"); string sourceString = labelText.UnMangleConfigText(); if (!string.IsNullOrEmpty(sourceString) && sourceString.Length > 1) { // Alow a " character to escape leading whitespace if (sourceString[0] == '"') { sourceString = sourceString.Substring(1); } } labels.Add(new JSILabelSet(sourceString, rpmComp, oneshot)); if (!oneshot) { rpmComp.UpdateDataRefreshRate(refreshRate); } } else // Switchable mode { SmarterButton.CreateButton(internalProp, switchTransform, Click); audioOutput = JUtil.SetupIVASound(internalProp, switchSound, switchSoundVolume, false); foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { if (node.GetValue("name") == internalProp.propName) { ConfigNode moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] variableNodes = moduleConfig.GetNodes("VARIABLESET"); for (int i = 0; i < variableNodes.Length; i++) { try { bool lOneshot = false; if (variableNodes[i].HasValue("oneshot")) { bool.TryParse(variableNodes[i].GetValue("oneshot"), out lOneshot); } if (variableNodes[i].HasValue("labelText")) { string lText = variableNodes[i].GetValue("labelText"); string sourceString = lText.UnMangleConfigText(); lOneshot |= !lText.Contains("$&$"); labels.Add(new JSILabelSet(sourceString, rpmComp, lOneshot)); if (!lOneshot) { rpmComp.UpdateDataRefreshRate(refreshRate); } } } catch (ArgumentException e) { JUtil.LogErrorMessage(this, "Error in building prop number {1} - {0}", e.Message, internalProp.propID); } } break; } } } if (!string.IsNullOrEmpty(zeroColor)) { zeroColorValue = JUtil.ParseColor32(zeroColor, part, ref rpmComp); textObj.color = zeroColorValue; } bool usesMultiColor = false; if (!(string.IsNullOrEmpty(variableName) || string.IsNullOrEmpty(positiveColor) || string.IsNullOrEmpty(negativeColor) || string.IsNullOrEmpty(zeroColor))) { usesMultiColor = true; positiveColorValue = JUtil.ParseColor32(positiveColor, part, ref rpmComp); negativeColorValue = JUtil.ParseColor32(negativeColor, part, ref rpmComp); del = (Action <float>)Delegate.CreateDelegate(typeof(Action <float>), this, "OnCallback"); rpmComp.RegisterVariableCallback(variableName, del); registeredVessel = vessel.id; // Initialize the text color. Actually, callback registration takes care of that. } if (string.IsNullOrEmpty(emissive)) { if (usesMultiColor) { emissiveMode = EmissiveMode.active; } else { emissiveMode = EmissiveMode.always; } } else if (emissive.ToLower() == EmissiveMode.always.ToString()) { emissiveMode = EmissiveMode.always; } else if (emissive.ToLower() == EmissiveMode.never.ToString()) { emissiveMode = EmissiveMode.never; } else if (emissive.ToLower() == EmissiveMode.active.ToString()) { emissiveMode = EmissiveMode.active; } else if (emissive.ToLower() == EmissiveMode.passive.ToString()) { emissiveMode = EmissiveMode.passive; } else if (emissive.ToLower() == EmissiveMode.flash.ToString()) { if (flashRate > 0.0f) { emissiveMode = EmissiveMode.flash; fm = JUtil.InstallFlashModule(part, flashRate); if (fm != null) { fm.flashSubscribers += FlashToggle; } } else { emissiveMode = EmissiveMode.active; } } else { JUtil.LogErrorMessage(this, "Unrecognized emissive mode '{0}' in config for {1} ({2})", emissive, internalProp.propID, internalProp.propName); emissiveMode = EmissiveMode.always; } UpdateShader(); } catch (Exception e) { JUtil.LogErrorMessage(this, "Start failed in prop {1} ({2}) with exception {0}", e, internalProp.propID, internalProp.propName); labels.Add(new JSILabelSet("ERR", rpmComp, true)); } }
/// <summary> /// Configure the switch. /// </summary> public void Start() { if (HighLogic.LoadedSceneIsEditor) { return; } if (string.IsNullOrEmpty(switchTransform)) { throw new Exception("JSISwitch failed to configure: no switchTransform specified in prop " + internalProp.propName); } if (momentarySwitch) { SmarterButton.CreateButton(internalProp, switchTransform, Click, Click); } else { SmarterButton.CreateButton(internalProp, switchTransform, Click); } if (!string.IsNullOrEmpty(switchSound)) { switchAudio = JUtil.SetupIVASound(internalProp, switchSound, switchSoundVolume, false); } if (!string.IsNullOrEmpty(animationName)) { // Set up the animation Animation[] animators = internalProp.FindModelAnimators(animationName); //Animation[] animators = animateExterior ? part.FindModelAnimators(animationName) : internalProp.FindModelAnimators(animationName); if (animators.Length > 0) { anim = animators[0]; } else { JUtil.LogErrorMessage(this, "Could not find animation \"{0}\" on {2} \"{1}\"", animationName, internalProp.name, "prop"); //JUtil.LogErrorMessage(this, "Could not find animation \"{0}\" on {2} \"{1}\"", // animationName, animateExterior ? part.name : internalProp.name, animateExterior ? "part" : "prop"); return; } anim[animationName].wrapMode = WrapMode.Once; if (currentState ^ reverse) { anim[animationName].speed = float.MaxValue; anim[animationName].normalizedTime = 0.0f; } else { anim[animationName].speed = float.MinValue; anim[animationName].normalizedTime = 1.0f; } anim.Play(animationName); } // Now parse consumeOnToggle and consumeWhileActive... if (!string.IsNullOrEmpty(consumeOnToggle)) { string[] tokens = consumeOnToggle.Split(','); if (tokens.Length == 3) { consumeOnToggleName = tokens[0].Trim(); if (!(PartResourceLibrary.Instance.GetDefinition(consumeOnToggleName) != null && float.TryParse(tokens[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out consumeOnToggleAmount))) { JUtil.LogErrorMessage(this, "Could not parse \"{0}\"", consumeOnToggle); } switch (tokens[2].Trim().ToLower()) { case "on": consumingOnToggleUp = true; break; case "off": consumingOnToggleDown = true; break; case "both": consumingOnToggleUp = true; consumingOnToggleDown = true; break; default: JUtil.LogErrorMessage(this, "So should I consume resources when turning on, turning off, or both in \"{0}\"?", consumeOnToggle); break; } } } if (!string.IsNullOrEmpty(consumeWhileActive)) { string[] tokens = consumeWhileActive.Split(','); if (tokens.Length == 2) { consumeWhileActiveName = tokens[0].Trim(); if (!(PartResourceLibrary.Instance.GetDefinition(consumeWhileActiveName) != null && float.TryParse(tokens[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out consumeWhileActiveAmount))) { JUtil.LogErrorMessage(this, "Could not parse \"{0}\"", consumeWhileActive); } else { consumingWhileActive = true; JUtil.LogMessage(this, "Switch in prop {0} prop id {1} will consume {2} while active at a rate of {3}", internalProp.propName, internalProp.propID, consumeWhileActiveName, consumeWhileActiveAmount); } } } RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); comp.UpdateDataRefreshRate(refreshRate); if (!string.IsNullOrEmpty(masterVariableName)) { string[] range = masterVariableRange.Split(','); if (range.Length == 2) { masterVariable = new VariableOrNumberRange(masterVariableName, range[0], range[1]); } else { masterVariable = null; } } ConfigNode[] nodes = GameDatabase.Instance.GetConfigNodes("PROP"); for (int i = 0; i < nodes.Length; ++i) { if (nodes[i].GetValue("name") == internalProp.propName) { ConfigNode[] pluginNodes = nodes[i].GetNodes("MODULE")[moduleID].GetNodes("ACTION"); for (int j = 0; j < pluginNodes.Length; ++j) { try { IJSIAction newAction = AddAction(pluginNodes[j]); action.Add(newAction); if (newAction.IsMasterAction && masterActionIndex == -1) { masterActionIndex = action.Count - 1; } } catch (Exception e) { JUtil.LogErrorMessage(this, "Failed to create JSIAction: {0}", e); } } } } if (action.Count == 0) { JUtil.LogErrorMessage(this, "No actions were created for JSIAction in prop {0}", internalProp.propName); return; } if (masterActionIndex == -1) { masterActionIndex = 0; } JUtil.LogMessage(this, "Selected action {0} as the master action", masterActionIndex); startupComplete = true; }
public VariableAnimationSet(ConfigNode node, InternalProp thisProp) { part = thisProp.part; if (!node.HasData) { throw new ArgumentException("No data?!"); } string[] tokens = { }; if (node.HasValue("scale")) { tokens = node.GetValue("scale").Split(','); } if (tokens.Length != 2) { throw new ArgumentException("Could not parse 'scale' parameter."); } if (node.HasValue("variableName")) { string variableName; variableName = node.GetValue("variableName").Trim(); scaleEnds[2] = new VariableOrNumber(variableName, this); } else if (node.HasValue("stateMethod")) { RPMVesselComputer comp = RPMVesselComputer.Instance(part.vessel); Func <bool> stateFunction = (Func <bool>)comp.GetMethod(node.GetValue("stateMethod").Trim(), thisProp, typeof(Func <bool>)); if (stateFunction != null) { scaleEnds[2] = new VariableOrNumber(stateFunction, this); } else { throw new ArgumentException("Unrecognized stateMethod"); } } else { throw new ArgumentException("Missing variable name."); } scaleEnds[0] = new VariableOrNumber(tokens[0], this); scaleEnds[1] = new VariableOrNumber(tokens[1], this); // That takes care of the scale, now what to do about that scale: if (node.HasValue("reverse")) { if (!bool.TryParse(node.GetValue("reverse"), out reverse)) { throw new ArgumentException("So is 'reverse' true or false?"); } } if (node.HasValue("animationName")) { animationName = node.GetValue("animationName"); if (node.HasValue("animationSpeed")) { animationSpeed = float.Parse(node.GetValue("animationSpeed")); if (reverse) { animationSpeed = -animationSpeed; } } else { animationSpeed = 0.0f; } Animation[] anims = node.HasValue("animateExterior") ? thisProp.part.FindModelAnimators(animationName) : thisProp.FindModelAnimators(animationName); if (anims.Length > 0) { onAnim = anims[0]; onAnim.enabled = true; onAnim[animationName].speed = 0; onAnim[animationName].normalizedTime = reverse ? 1f : 0f; looping = node.HasValue("loopingAnimation"); if (looping) { onAnim[animationName].wrapMode = WrapMode.Loop; onAnim.wrapMode = WrapMode.Loop; onAnim[animationName].speed = animationSpeed; mode = Mode.LoopingAnimation; } else { onAnim[animationName].wrapMode = WrapMode.Once; mode = Mode.Animation; } onAnim.Play(); alwaysActive = node.HasValue("animateExterior"); } else { throw new ArgumentException("Animation could not be found."); } if (node.HasValue("stopAnimationName")) { stopAnimationName = node.GetValue("stopAnimationName"); anims = node.HasValue("animateExterior") ? thisProp.part.FindModelAnimators(stopAnimationName) : thisProp.FindModelAnimators(stopAnimationName); if (anims.Length > 0) { offAnim = anims[0]; offAnim.enabled = true; offAnim[stopAnimationName].speed = 0; offAnim[stopAnimationName].normalizedTime = reverse ? 1f : 0f; if (looping) { offAnim[stopAnimationName].wrapMode = WrapMode.Loop; offAnim.wrapMode = WrapMode.Loop; offAnim[stopAnimationName].speed = animationSpeed; mode = Mode.LoopingAnimation; } else { offAnim[stopAnimationName].wrapMode = WrapMode.Once; mode = Mode.Animation; } } } } else if (node.HasValue("activeColor") && node.HasValue("passiveColor") && node.HasValue("coloredObject")) { if (node.HasValue("colorName")) { colorName = node.GetValue("colorName"); } passiveColor = ConfigNode.ParseColor32(node.GetValue("passiveColor")); activeColor = ConfigNode.ParseColor32(node.GetValue("activeColor")); colorShiftRenderer = thisProp.FindModelComponent <Renderer>(node.GetValue("coloredObject")); colorShiftRenderer.material.SetColor(colorName, reverse ? activeColor : passiveColor); mode = Mode.Color; } else if (node.HasValue("controlledTransform") && node.HasValue("localRotationStart") && node.HasValue("localRotationEnd")) { controlledTransform = thisProp.FindModelTransform(node.GetValue("controlledTransform").Trim()); initialRotation = controlledTransform.localRotation; if (node.HasValue("longPath")) { longPath = true; vectorStart = ConfigNode.ParseVector3(node.GetValue("localRotationStart")); vectorEnd = ConfigNode.ParseVector3(node.GetValue("localRotationEnd")); } else { rotationStart = Quaternion.Euler(ConfigNode.ParseVector3(node.GetValue("localRotationStart"))); rotationEnd = Quaternion.Euler(ConfigNode.ParseVector3(node.GetValue("localRotationEnd"))); } mode = Mode.Rotation; } else if (node.HasValue("controlledTransform") && node.HasValue("localTranslationStart") && node.HasValue("localTranslationEnd")) { controlledTransform = thisProp.FindModelTransform(node.GetValue("controlledTransform").Trim()); initialPosition = controlledTransform.localPosition; vectorStart = ConfigNode.ParseVector3(node.GetValue("localTranslationStart")); vectorEnd = ConfigNode.ParseVector3(node.GetValue("localTranslationEnd")); mode = Mode.Translation; } else if (node.HasValue("controlledTransform") && node.HasValue("localScaleStart") && node.HasValue("localScaleEnd")) { controlledTransform = thisProp.FindModelTransform(node.GetValue("controlledTransform").Trim()); initialScale = controlledTransform.localScale; vectorStart = ConfigNode.ParseVector3(node.GetValue("localScaleStart")); vectorEnd = ConfigNode.ParseVector3(node.GetValue("localScaleEnd")); mode = Mode.Scale; } else if (node.HasValue("controlledTransform") && node.HasValue("textureLayers") && node.HasValue("textureShiftStart") && node.HasValue("textureShiftEnd")) { affectedMaterial = thisProp.FindModelTransform(node.GetValue("controlledTransform").Trim()).renderer.material; textureLayer = node.GetValue("textureLayers"); textureShiftStart = ConfigNode.ParseVector2(node.GetValue("textureShiftStart")); textureShiftEnd = ConfigNode.ParseVector2(node.GetValue("textureShiftEnd")); mode = Mode.TextureShift; } else if (node.HasValue("controlledTransform") && node.HasValue("textureLayers") && node.HasValue("textureScaleStart") && node.HasValue("textureScaleEnd")) { affectedMaterial = thisProp.FindModelTransform(node.GetValue("controlledTransform").Trim()).renderer.material; textureLayer = node.GetValue("textureLayers"); textureScaleStart = ConfigNode.ParseVector2(node.GetValue("textureScaleStart")); textureScaleEnd = ConfigNode.ParseVector2(node.GetValue("textureScaleEnd")); mode = Mode.TextureScale; } else { throw new ArgumentException("Cannot initiate any of the possible action modes."); } if (node.HasValue("threshold")) { threshold = ConfigNode.ParseVector2(node.GetValue("threshold")); } resourceAmount = 0.0f; if (threshold != Vector2.zero) { thresholdMode = true; float min = Mathf.Min(threshold.x, threshold.y); float max = Mathf.Max(threshold.x, threshold.y); threshold.x = min; threshold.y = max; if (node.HasValue("flashingDelay")) { flashingDelay = double.Parse(node.GetValue("flashingDelay")); } if (node.HasValue("alarmSound")) { alarmSoundVolume = 0.5f; if (node.HasValue("alarmSoundVolume")) { alarmSoundVolume = float.Parse(node.GetValue("alarmSoundVolume")); } audioOutput = JUtil.SetupIVASound(thisProp, node.GetValue("alarmSound"), alarmSoundVolume, false); if (node.HasValue("alarmMustPlayOnce")) { if (!bool.TryParse(node.GetValue("alarmMustPlayOnce"), out alarmMustPlayOnce)) { throw new ArgumentException("So is 'alarmMustPlayOnce' true or false?"); } } if (node.HasValue("alarmShutdownButton")) { SmarterButton.CreateButton(thisProp, node.GetValue("alarmShutdownButton"), AlarmShutdown); } if (node.HasValue("alarmSoundLooping")) { if (!bool.TryParse(node.GetValue("alarmSoundLooping"), out alarmSoundLooping)) { throw new ArgumentException("So is 'alarmSoundLooping' true or false?"); } audioOutput.audio.loop = alarmSoundLooping; } } if (node.HasValue("resourceAmount")) { resourceAmount = float.Parse(node.GetValue("resourceAmount")); } TurnOff(); } }
public void Start() { if (HighLogic.LoadedSceneIsEditor) { return; } try { textObjTransform = internalProp.FindModelTransform(labelTransform); textObj = InternalComponents.Instance.CreateText(fontName, fontSize, textObjTransform, string.Empty); activeLabel = 0; SmarterButton.CreateButton(internalProp, switchTransform, Click); ConfigNode moduleConfig = null; foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { if (node.GetValue("name") == internalProp.propName) { moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] variableNodes = moduleConfig.GetNodes("VARIABLESET"); for (int i = 0; i < variableNodes.Length; i++) { try { labelsEx.Add(new VariableLabelSet(variableNodes[i])); } catch (ArgumentException e) { JUtil.LogErrorMessage(this, "Error in building prop number {1} - {0}", e.Message, internalProp.propID); } } break; } } // Fallback: If there are no VARIABLESET blocks, we treat the module configuration itself as a variableset block. if (labelsEx.Count < 1 && moduleConfig != null) { try { labelsEx.Add(new VariableLabelSet(moduleConfig)); } catch (ArgumentException e) { JUtil.LogErrorMessage(this, "Error in building prop number {1} - {0}", e.Message, internalProp.propID); } } if (labelsEx.Count == 0) { JUtil.LogErrorMessage(this, "No labels defined."); throw new ArgumentException("No labels defined"); } colorShiftRenderer = internalProp.FindModelComponent <Renderer>(coloredObject); if (labelsEx[activeLabel].hasColor) { colorShiftRenderer.material.SetColor(colorName, labelsEx[activeLabel].color); } if (labelsEx[activeLabel].hasText) { if (labelsEx[activeLabel].oneShot) { // Fetching formatString directly is notionally bad // because there may be formatting stuff, but if // oneShot is true, we already know that this is a // constant string with no formatting. textObj.text.Text = labelsEx[activeLabel].label.formatString; } else { textObj.text.Text = ""; } } audioOutput = JUtil.SetupIVASound(internalProp, switchSound, switchSoundVolume, false); JUtil.LogMessage(this, "Configuration complete in prop {1}, supporting {0} variable indicators.", labelsEx.Count, internalProp.propID); } catch { JUtil.AnnoyUser(this); enabled = false; throw; } }
internal NumericInput(ConfigNode node, InternalProp internalProp) { if (!node.HasValue("switchTransform")) { throw new Exception("USERINPUTSET missing switchTransform"); } // XNOR! if (!(node.HasValue("increment") ^ node.HasNode("incrementCurve"))) { throw new Exception("USERINPUTSET missing increment or incrementCurve, or it has both"); } if (node.HasValue("increment") && !float.TryParse(node.GetValue("increment"), out increment)) { throw new Exception("USERINPUTSET bad increment"); } else if (node.HasNode("incrementCurve")) { ConfigNode incNode = node.GetNode("incrementCurve"); string[] keys = incNode.GetValues("key"); incrementCurve = new FloatCurve(); for (int i = 0; i < keys.Length; ++i) { string[] values = keys[i].Split(' '); if (values.Length == 2) { incrementCurve.Add(float.Parse(values[0]), float.Parse(values[1])); } else if (values.Length == 4) { incrementCurve.Add(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]), float.Parse(values[3])); } else { JUtil.LogErrorMessage(this, "Found a curve key with {0} entries?!?", values.Length); } } pressAndHold = true; } if (node.HasValue("reverse")) { bool.TryParse(node.GetValue("reverse"), out reverse); } if (node.HasValue("animationName")) { animationName = node.GetValue("animationName").Trim(); } float switchSoundVolume = 0.5f; if (node.HasValue("switchSoundVolume") && !float.TryParse("switchSoundVolume", out switchSoundVolume)) { switchSoundVolume = 0.5f; } if (node.HasValue("switchSound")) { audioOutput = JUtil.SetupIVASound(internalProp, node.GetValue("switchSound").Trim(), switchSoundVolume, false); } if (node.HasValue("customSpeed") && !float.TryParse("customSpeed", out customSpeed)) { customSpeed = 1.0f; } if (!string.IsNullOrEmpty(animationName)) { // Set up the animation Animation[] animators = internalProp.FindModelAnimators(animationName); if (animators.Length > 0) { anim = animators[0]; } else { JUtil.LogErrorMessage(this, "Could not find animation \"{0}\" on prop \"{1}\"", animationName, internalProp.name); return; } anim[animationName].wrapMode = WrapMode.Once; if (reverse) { anim[animationName].speed = float.MaxValue; anim[animationName].normalizedTime = 0.0f; } else { anim[animationName].speed = float.MinValue; anim[animationName].normalizedTime = 1.0f; } anim.Play(animationName); } string switchTransform = node.GetValue("switchTransform"); if (incrementCurve != null) { SmarterButton.CreateButton(internalProp, switchTransform, TimedClick, TimedRelease); } else { SmarterButton.CreateButton(internalProp, switchTransform, Click, TimedRelease); } }
public void Start() { if (HighLogic.LoadedSceneIsEditor) { return; } try { if (!groupList.ContainsKey(actionName) && !customGroupList.ContainsKey(actionName)) { JUtil.LogErrorMessage(this, "Action \"{0}\" is not supported.", actionName); return; } // Parse the needs-electric-charge here. if (!string.IsNullOrEmpty(needsElectricCharge)) { switch (needsElectricCharge.ToLowerInvariant().Trim()) { case "true": case "yes": case "1": needsElectricChargeValue = true; break; case "false": case "no": case "0": needsElectricChargeValue = false; break; } } // Now parse consumeOnToggle and consumeWhileActive... if (!string.IsNullOrEmpty(consumeOnToggle)) { string[] tokens = consumeOnToggle.Split(','); if (tokens.Length == 3) { consumeOnToggleName = tokens[0].Trim(); if (!(PartResourceLibrary.Instance.GetDefinition(consumeOnToggleName) != null && float.TryParse(tokens[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out consumeOnToggleAmount))) { JUtil.LogErrorMessage(this, "Could not parse \"{0}\"", consumeOnToggle); } switch (tokens[2].Trim().ToLower()) { case "on": consumingOnToggleUp = true; break; case "off": consumingOnToggleDown = true; break; case "both": consumingOnToggleUp = true; consumingOnToggleDown = true; break; default: JUtil.LogErrorMessage(this, "So should I consume resources when turning on, turning off, or both in \"{0}\"?", consumeOnToggle); break; } } } if (!string.IsNullOrEmpty(consumeWhileActive)) { string[] tokens = consumeWhileActive.Split(','); if (tokens.Length == 2) { consumeWhileActiveName = tokens[0].Trim(); if (!(PartResourceLibrary.Instance.GetDefinition(consumeWhileActiveName) != null && float.TryParse(tokens[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out consumeWhileActiveAmount))) { JUtil.LogErrorMessage(this, "Could not parse \"{0}\"", consumeWhileActive); } else { consumingWhileActive = true; JUtil.LogMessage(this, "Switch in prop {0} prop id {1} will consume {2} while active at a rate of {3}", internalProp.propName, internalProp.propID, consumeWhileActiveName, consumeWhileActiveAmount); } } } if (groupList.ContainsKey(actionName)) { currentState = vessel.ActionGroups[groupList[actionName]]; } else { isCustomAction = true; switch (actionName) { case "intlight": persistentVarName = internalLightName; lightObjects = internalModel.FindModelComponents <Light>(); needsElectricChargeValue |= string.IsNullOrEmpty(needsElectricCharge) || needsElectricChargeValue; break; case "plugin": persistentVarName = string.Empty; foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { if (node.GetValue("name") == internalProp.propName) { foreach (ConfigNode pluginConfig in node.GetNodes("MODULE")[moduleID].GetNodes("PLUGINACTION")) { if (pluginConfig.HasValue("name") && pluginConfig.HasValue("actionMethod")) { if (!InstantiateHandler(pluginConfig, this, out actionHandler, out stateHandler)) { JUtil.LogErrorMessage(this, "Failed to instantiate action handler {0}", pluginConfig.GetValue("name")); } else { isPluginAction = true; break; } } } } } if (actionHandler == null) { actionName = "dummy"; JUtil.LogMessage(this, "Plugin handlers did not start, reverting to dummy mode."); } break; default: persistentVarName = "switch" + internalProp.propID + "_" + moduleID; break; } if (!string.IsNullOrEmpty(perPodPersistenceName)) { persistentVarName = perPodPersistenceName; } persistence = new PersistenceAccessor(part); } if (needsElectricChargeValue) { comp = RasterPropMonitorComputer.Instantiate(internalProp); comp.UpdateRefreshRates(lightCheckRate, lightCheckRate); } // set up the toggle switch if (!string.IsNullOrEmpty(switchTransform)) { SmarterButton.CreateButton(internalProp, switchTransform, Click); } if (isCustomAction) { if (isPluginAction && stateHandler != null) { currentState = stateHandler(); } else { if (!string.IsNullOrEmpty(persistentVarName)) { currentState = customGroupList[actionName] = (persistence.GetBool(persistentVarName) ?? currentState); if (actionName == "intlight") { // We have to restore lighting after reading the // persistent variable. SetInternalLights(customGroupList[actionName]); } } } } if (!string.IsNullOrEmpty(animationName)) { // Set up the animation Animation[] animators = animateExterior ? part.FindModelAnimators(animationName) : internalProp.FindModelAnimators(animationName); if (animators.Length > 0) { anim = animators[0]; } else { JUtil.LogErrorMessage(this, "Could not find animation \"{0}\" on {2} \"{1}\"", animationName, animateExterior ? part.name : internalProp.name, animateExterior ? "part" : "prop"); return; } anim[animationName].wrapMode = WrapMode.Once; if (currentState ^ reverse) { anim[animationName].speed = float.MaxValue; anim[animationName].normalizedTime = 0; } else { anim[animationName].speed = float.MinValue; anim[animationName].normalizedTime = 1; } anim.Play(animationName); } else if (!string.IsNullOrEmpty(coloredObject)) { // Set up the color shift. colorShiftRenderer = internalProp.FindModelComponent <Renderer>(coloredObject); disabledColorValue = ConfigNode.ParseColor32(disabledColor); enabledColorValue = ConfigNode.ParseColor32(enabledColor); colorShiftRenderer.material.SetColor(colorName, (currentState ^ reverse ? enabledColorValue : disabledColorValue)); } else { JUtil.LogMessage(this, "Warning, neither color nor animation are defined."); } audioOutput = JUtil.SetupIVASound(internalProp, switchSound, switchSoundVolume, false); startupComplete = true; } catch { JUtil.AnnoyUser(this); enabled = false; throw; } }
/// <summary> /// Initialize and configure the callback handler. /// </summary> /// <param name="node"></param> /// <param name="variableName"></param> /// <param name="thisProp"></param> public CallbackAnimationSet(ConfigNode node, string variableName, InternalProp thisProp) { currentState = false; if (!node.HasData) { throw new ArgumentException("No data?!"); } string[] tokens = { }; if (node.HasValue("scale")) { tokens = node.GetValue("scale").Split(','); } if (tokens.Length != 2) { throw new ArgumentException("Could not parse 'scale' parameter."); } RasterPropMonitorComputer rpmComp = RasterPropMonitorComputer.Instantiate(thisProp, true); variable = new VariableOrNumberRange(rpmComp, variableName, tokens[0], tokens[1]); // That takes care of the scale, now what to do about that scale: if (node.HasValue("reverse")) { if (!bool.TryParse(node.GetValue("reverse"), out reverse)) { throw new ArgumentException("So is 'reverse' true or false?"); } } if (node.HasValue("flash")) { if (!bool.TryParse(node.GetValue("flash"), out flash)) { throw new ArgumentException("So is 'reverse' true or false?"); } } else { flash = false; } if (node.HasValue("alarmSound")) { alarmSoundVolume = 0.5f; if (node.HasValue("alarmSoundVolume")) { alarmSoundVolume = float.Parse(node.GetValue("alarmSoundVolume")); } audioOutput = JUtil.SetupIVASound(thisProp, node.GetValue("alarmSound"), alarmSoundVolume, false); if (node.HasValue("alarmMustPlayOnce")) { if (!bool.TryParse(node.GetValue("alarmMustPlayOnce"), out alarmMustPlayOnce)) { throw new ArgumentException("So is 'alarmMustPlayOnce' true or false?"); } } if (node.HasValue("alarmShutdownButton")) { SmarterButton.CreateButton(thisProp, node.GetValue("alarmShutdownButton"), AlarmShutdown); } if (node.HasValue("alarmSoundLooping")) { if (!bool.TryParse(node.GetValue("alarmSoundLooping"), out alarmSoundLooping)) { throw new ArgumentException("So is 'alarmSoundLooping' true or false?"); } audioOutput.audio.loop = alarmSoundLooping; } inIVA = (CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.IVA); GameEvents.OnCameraChange.Add(CameraChangeCallback); } if (node.HasValue("animationName")) { animationName = node.GetValue("animationName"); if (node.HasValue("animationSpeed")) { animationSpeed = float.Parse(node.GetValue("animationSpeed")); if (reverse) { animationSpeed = -animationSpeed; } } else { animationSpeed = 0.0f; } Animation[] anims = node.HasValue("animateExterior") ? thisProp.part.FindModelAnimators(animationName) : thisProp.FindModelAnimators(animationName); if (anims.Length > 0) { onAnim = anims[0]; onAnim.enabled = true; onAnim[animationName].speed = 0; onAnim[animationName].normalizedTime = reverse ? 1f : 0f; looping = node.HasValue("loopingAnimation"); if (looping) { onAnim[animationName].wrapMode = WrapMode.Loop; onAnim.wrapMode = WrapMode.Loop; onAnim[animationName].speed = animationSpeed; mode = Mode.LoopingAnimation; } else { onAnim[animationName].wrapMode = WrapMode.Once; mode = Mode.Animation; } onAnim.Play(); //alwaysActive = node.HasValue("animateExterior"); } else { throw new ArgumentException("Animation " + animationName + " could not be found."); } if (node.HasValue("stopAnimationName")) { stopAnimationName = node.GetValue("stopAnimationName"); anims = node.HasValue("animateExterior") ? thisProp.part.FindModelAnimators(stopAnimationName) : thisProp.FindModelAnimators(stopAnimationName); if (anims.Length > 0) { offAnim = anims[0]; offAnim.enabled = true; offAnim[stopAnimationName].speed = 0; offAnim[stopAnimationName].normalizedTime = reverse ? 1f : 0f; if (looping) { offAnim[stopAnimationName].wrapMode = WrapMode.Loop; offAnim.wrapMode = WrapMode.Loop; offAnim[stopAnimationName].speed = animationSpeed; mode = Mode.LoopingAnimation; } else { offAnim[stopAnimationName].wrapMode = WrapMode.Once; mode = Mode.Animation; } } } } else if (node.HasValue("activeColor") && node.HasValue("passiveColor") && node.HasValue("coloredObject")) { string colorNameString = "_EmissiveColor"; if (node.HasValue("colorName")) { colorNameString = node.GetValue("colorName"); } colorName = Shader.PropertyToID(colorNameString); if (reverse) { activeColor = JUtil.ParseColor32(node.GetValue("passiveColor"), thisProp.part, ref rpmComp); passiveColor = JUtil.ParseColor32(node.GetValue("activeColor"), thisProp.part, ref rpmComp); } else { passiveColor = JUtil.ParseColor32(node.GetValue("passiveColor"), thisProp.part, ref rpmComp); activeColor = JUtil.ParseColor32(node.GetValue("activeColor"), thisProp.part, ref rpmComp); } Renderer colorShiftRenderer = thisProp.FindModelComponent <Renderer>(node.GetValue("coloredObject")); affectedMaterial = colorShiftRenderer.material; affectedMaterial.SetColor(colorName, passiveColor); mode = Mode.Color; } else if (node.HasValue("controlledTransform") && node.HasValue("localRotationStart") && node.HasValue("localRotationEnd")) { controlledTransform = thisProp.FindModelTransform(node.GetValue("controlledTransform").Trim()); initialRotation = controlledTransform.localRotation; if (node.HasValue("longPath")) { longPath = true; if (reverse) { vectorEnd = ConfigNode.ParseVector3(node.GetValue("localRotationStart")); vectorStart = ConfigNode.ParseVector3(node.GetValue("localRotationEnd")); } else { vectorStart = ConfigNode.ParseVector3(node.GetValue("localRotationStart")); vectorEnd = ConfigNode.ParseVector3(node.GetValue("localRotationEnd")); } } else { if (reverse) { rotationEnd = Quaternion.Euler(ConfigNode.ParseVector3(node.GetValue("localRotationStart"))); rotationStart = Quaternion.Euler(ConfigNode.ParseVector3(node.GetValue("localRotationEnd"))); } else { rotationStart = Quaternion.Euler(ConfigNode.ParseVector3(node.GetValue("localRotationStart"))); rotationEnd = Quaternion.Euler(ConfigNode.ParseVector3(node.GetValue("localRotationEnd"))); } } mode = Mode.Rotation; } else if (node.HasValue("controlledTransform") && node.HasValue("localTranslationStart") && node.HasValue("localTranslationEnd")) { controlledTransform = thisProp.FindModelTransform(node.GetValue("controlledTransform").Trim()); initialPosition = controlledTransform.localPosition; if (reverse) { vectorEnd = ConfigNode.ParseVector3(node.GetValue("localTranslationStart")); vectorStart = ConfigNode.ParseVector3(node.GetValue("localTranslationEnd")); } else { vectorStart = ConfigNode.ParseVector3(node.GetValue("localTranslationStart")); vectorEnd = ConfigNode.ParseVector3(node.GetValue("localTranslationEnd")); } mode = Mode.Translation; } else if (node.HasValue("controlledTransform") && node.HasValue("localScaleStart") && node.HasValue("localScaleEnd")) { controlledTransform = thisProp.FindModelTransform(node.GetValue("controlledTransform").Trim()); initialScale = controlledTransform.localScale; if (reverse) { vectorEnd = ConfigNode.ParseVector3(node.GetValue("localScaleStart")); vectorStart = ConfigNode.ParseVector3(node.GetValue("localScaleEnd")); } else { vectorStart = ConfigNode.ParseVector3(node.GetValue("localScaleStart")); vectorEnd = ConfigNode.ParseVector3(node.GetValue("localScaleEnd")); } mode = Mode.Scale; } else if (node.HasValue("controlledTransform") && node.HasValue("textureLayers") && node.HasValue("textureShiftStart") && node.HasValue("textureShiftEnd")) { affectedMaterial = thisProp.FindModelTransform(node.GetValue("controlledTransform").Trim()).GetComponent <Renderer>().material; var textureLayers = node.GetValue("textureLayers").Split(','); for (int i = 0; i < textureLayers.Length; ++i) { textureLayer.Add(textureLayers[i].Trim()); } if (reverse) { textureShiftEnd = ConfigNode.ParseVector2(node.GetValue("textureShiftStart")); textureShiftStart = ConfigNode.ParseVector2(node.GetValue("textureShiftEnd")); } else { textureShiftStart = ConfigNode.ParseVector2(node.GetValue("textureShiftStart")); textureShiftEnd = ConfigNode.ParseVector2(node.GetValue("textureShiftEnd")); } mode = Mode.TextureShift; } else if (node.HasValue("controlledTransform") && node.HasValue("textureLayers") && node.HasValue("textureScaleStart") && node.HasValue("textureScaleEnd")) { affectedMaterial = thisProp.FindModelTransform(node.GetValue("controlledTransform").Trim()).GetComponent <Renderer>().material; var textureLayers = node.GetValue("textureLayers").Split(','); for (int i = 0; i < textureLayers.Length; ++i) { textureLayer.Add(textureLayers[i].Trim()); } if (reverse) { textureScaleEnd = ConfigNode.ParseVector2(node.GetValue("textureScaleStart")); textureScaleStart = ConfigNode.ParseVector2(node.GetValue("textureScaleEnd")); } else { textureScaleStart = ConfigNode.ParseVector2(node.GetValue("textureScaleStart")); textureScaleEnd = ConfigNode.ParseVector2(node.GetValue("textureScaleEnd")); } mode = Mode.TextureScale; } else { throw new ArgumentException("Cannot initiate any of the possible action modes."); } TurnOff(); }
public void Start() { InstallationPathWarning.Warn(); // Install the calculator module. comp = RasterPropMonitorComputer.Instantiate(internalProp); comp.UpdateRefreshRates(refreshTextRate, refreshDataRate); // Loading the font... fontTexture.Add(LoadFont(this, internalProp, fontTransform, false)); // Damn KSP's config parser!!! if (!string.IsNullOrEmpty(emptyColor)) { emptyColorValue = ConfigNode.ParseColor32(emptyColor); } if (!string.IsNullOrEmpty(defaultFontTint)) { defaultFontTintValue = ConfigNode.ParseColor32(defaultFontTint); } if (!string.IsNullOrEmpty(fontDefinition)) { JUtil.LogMessage(this, "Loading font definition from {0}", fontDefinition); fontDefinitionString = File.ReadAllLines(KSPUtil.ApplicationRootPath + "GameData/" + fontDefinition.EnforceSlashes(), Encoding.UTF8)[0]; } // We can pre-compute the rectangles the font characters will be copied from, this seems to make it slightly quicker... // although I'm not sure I'm not seeing things by this point. int fontLettersX = (fontTexture[0].width / fontLetterWidth); int fontLettersY = (fontTexture[0].height / fontLetterHeight); float letterSpanX = 1f / fontLettersX; float letterSpanY = 1f / fontLettersY; int lastCharacter = fontLettersX * fontLettersY; if (lastCharacter != fontDefinitionString.Length) { JUtil.LogMessage(this, "Warning, number of letters in the font definition does not match font bitmap size."); } for (int i = 0; i < lastCharacter && i < fontDefinitionString.Length; i++) { int xSource = i % fontLettersX; int ySource = (i - xSource) / fontLettersX; if (!fontCharacters.ContainsKey(fontDefinitionString[i])) { fontCharacters[fontDefinitionString[i]] = new Rect(letterSpanX * xSource, letterSpanY * (fontLettersY - ySource - 1), letterSpanX, letterSpanY); } } // And a little optimisation for superscript/subscript: fontLetterHalfHeight = fontLetterHeight / 2f; fontLetterHalfWidth = fontLetterWidth / 2f; fontLetterDoubleWidth = fontLetterWidth * 2f; // Now that is done, proceed to setting up the screen. screenTexture = new RenderTexture(screenPixelWidth, screenPixelHeight, 24, RenderTextureFormat.ARGB32); screenMat = internalProp.FindModelTransform(screenTransform).renderer.material; foreach (string layerID in textureLayerID.Split()) { screenMat.SetTexture(layerID.Trim(), screenTexture); } if (GameDatabase.Instance.ExistsTexture(noSignalTextureURL.EnforceSlashes())) { noSignalTexture = GameDatabase.Instance.GetTexture(noSignalTextureURL.EnforceSlashes(), false); } // Create camera instance... cameraStructure = new FlyingCamera(part, screenTexture, cameraAspect); // The neat trick. IConfigNode doesn't work. No amount of kicking got it to work. // Well, we don't need it. GameDatabase, gimme config nodes for all props! foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { // Now, we know our own prop name. if (node.GetValue("name") == internalProp.propName) { // So this is the configuration of our prop in memory. Nice place. // We know it contains at least one MODULE node, us. // And we know our moduleID, which is the number in order of being listed in the prop. // Therefore the module by that number is our module's own config node. ConfigNode moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] pageNodes = moduleConfig.GetNodes("PAGE"); // Which we can now parse for page definitions. for (int i = 0; i < pageNodes.Length; i++) { // Mwahahaha. try { var newPage = new MonitorPage(i, pageNodes[i], this); activePage = activePage ?? newPage; if (newPage.isDefault) { activePage = newPage; } pages.Add(newPage); } catch (ArgumentException e) { JUtil.LogMessage(this, "Warning - {0}", e); } } // Now that all pages are loaded, we can use the moment in the loop to suck in all the extra fonts. foreach (string value in moduleConfig.GetValues("extraFont")) { fontTexture.Add(LoadFont(this, internalProp, value, true)); } break; } } JUtil.LogMessage(this, "Done setting up pages, {0} pages ready.", pages.Count); // Load our state from storage... persistentVarName = "activePage" + internalProp.propID; persistence = new PersistenceAccessor(part); int?activePageID = persistence.GetVar(persistentVarName); if (activePageID != null && activePageID.Value < pages.Count) { activePage = pages[activePageID.Value]; } activePage.Active(true); // If we have global buttons, set them up. if (!string.IsNullOrEmpty(globalButtons)) { string[] tokens = globalButtons.Split(','); for (int i = 0; i < tokens.Length; i++) { string buttonName = tokens[i].Trim(); // Notice that holes in the global button list ARE legal. if (!string.IsNullOrEmpty(buttonName)) { SmarterButton.CreateButton(internalProp, buttonName, i, GlobalButtonClick, GlobalButtonRelease); } } } audioOutput = JUtil.SetupIVASound(internalProp, buttonClickSound, buttonClickVolume, false); startupComplete = true; }