public double Evaluate(RPMVesselComputer comp, PersistenceAccessor persistence) { float result = comp.ProcessVariable(sourceVariable, persistence).MassageToFloat(); Vector2 sourceRange; if (!string.IsNullOrEmpty(sourceMinStr)) { sourceRange.x = comp.ProcessVariable(sourceMinStr, persistence).MassageToFloat(); } else { sourceRange.x = sourceMin; } if (!string.IsNullOrEmpty(sourceMaxStr)) { sourceRange.y = comp.ProcessVariable(sourceMaxStr, persistence).MassageToFloat(); } else { sourceRange.y = sourceMax; } return(JUtil.DualLerp(mappedRange, sourceRange, result)); }
public double Evaluate(RPMVesselComputer comp, PersistenceAccessor persistence) { float result = comp.ProcessVariable(sourceVariable, persistence).MassageToFloat(); Vector2 sourceRange; if (!string.IsNullOrEmpty(sourceMinStr)) { sourceRange.x = comp.ProcessVariable(sourceMinStr, persistence).MassageToFloat(); } else { sourceRange.x = sourceMin; } if (!string.IsNullOrEmpty(sourceMaxStr)) { sourceRange.y = comp.ProcessVariable(sourceMaxStr, persistence).MassageToFloat(); } else { sourceRange.y = sourceMax; } return JUtil.DualLerp(mappedRange, sourceRange, result); }
public void Start() { if (string.IsNullOrEmpty(soundURL)) { JUtil.LogMessage(this, "JSIInternalBackgroundNoise called with no soundURL"); Destroy(this); return; } if (needsElectricCharge) { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); comp.UpdateDataRefreshRate(soundCheckRate); electricChargeReserve = comp.ProcessVariable(resourceName).MassageToFloat(); } audioOutput = new FXGroup("RPM" + internalModel.internalName + vessel.id); audioOutput.audio = internalModel.gameObject.AddComponent <AudioSource>(); audioOutput.audio.clip = GameDatabase.Instance.GetAudioClip(soundURL.EnforceSlashes()); audioOutput.audio.Stop(); audioOutput.audio.volume = GameSettings.SHIP_VOLUME * soundVolume; audioOutput.audio.rolloffMode = AudioRolloffMode.Logarithmic; audioOutput.audio.maxDistance = 10f; audioOutput.audio.minDistance = 8f; audioOutput.audio.dopplerLevel = 0f; audioOutput.audio.panStereo = 0f; audioOutput.audio.playOnAwake = false; audioOutput.audio.priority = 255; audioOutput.audio.loop = true; audioOutput.audio.pitch = 1f; }
public static string ProcessString(string input, RPMVesselComputer comp) { try { if (input.IndexOf(JUtil.VariableListSeparator[0], StringComparison.Ordinal) >= 0) { string[] tokens = input.Split(JUtil.VariableListSeparator, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length != 2) { return("FORMAT ERROR"); } else { string[] vars = tokens[1].Split(JUtil.VariableSeparator, StringSplitOptions.RemoveEmptyEntries); var variables = new object[vars.Length]; for (int i = 0; i < vars.Length; i++) { variables[i] = comp.ProcessVariable(vars[i]); } string output = string.Format(fp, tokens[0], variables); return(output.TrimEnd()); } } } catch (Exception e) { JUtil.LogErrorMessage(comp, "Bad format on string {0}", input); throw e; } return(input.TrimEnd()); }
public override void OnUpdate() { if (!JUtil.UserIsInPod(part)) { StopPlaying(); return; } if (needsElectricCharge) { soundCheckCountdown--; if (soundCheckCountdown <= 0) { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); soundCheckCountdown = soundCheckRate; electricChargeReserve = comp.ProcessVariable(resourceName).MassageToFloat(); if (electricChargeReserve < 0.01f) { StopPlaying(); return; } } } StartPlaying(); }
public override void OnUpdate() { if (!JUtil.UserIsInPod(part)) { StopPlaying(); return; } if (needsElectricCharge) { soundCheckCountdown--; if (soundCheckCountdown <= 0) { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); soundCheckCountdown = soundCheckRate; electricChargeReserve = (float)comp.ProcessVariable("SYSR_ELECTRICCHARGE"); if (electricChargeReserve < 0.01f) { StopPlaying(); return; } } } StartPlaying(); }
public static string ProcessString(string input, RPMVesselComputer comp, PersistenceAccessor persistence) { try { if (input.IndexOf(JUtil.VariableListSeparator[0], StringComparison.Ordinal) >= 0) { string[] tokens = input.Split(JUtil.VariableListSeparator, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length != 2) { return "FORMAT ERROR"; } else { string[] vars = tokens[1].Split(JUtil.VariableSeparator, StringSplitOptions.RemoveEmptyEntries); var variables = new object[vars.Length]; for (int i = 0; i < vars.Length; i++) { variables[i] = comp.ProcessVariable(vars[i], persistence); } string output = string.Format(fp, tokens[0], variables); return output.TrimEnd(); } } } catch (Exception e) { JUtil.LogMessage(comp, "Bad format on string {0}", input); throw e; } return input.TrimEnd(); }
/// <summary> /// Evaluate the variable, returning it in destination. /// </summary> /// <param name="destination"></param> /// <param name="comp"></param> /// <returns></returns> public bool Get(out double destination, RPMVesselComputer comp) { if (type == VoNType.ConstantString) { destination = 0.0; return(false); } else if (type == VoNType.VariableValue) { numericValue = comp.ProcessVariable(variableName).MassageToDouble(); if (double.IsNaN(numericValue) || double.IsInfinity(numericValue)) { if (!warningMade) { JUtil.LogMessage(this, "Warning: {0} can fail to produce a usable number.", variableName); warningMade = true; } destination = numericValue; return(false); } } destination = numericValue; return(true); }
private void CheckForElectricCharge() { if (needsElectricCharge) { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); electricChargeReserve = comp.ProcessVariable(resourceName).MassageToFloat(); } }
private void CheckForElectricCharge() { if (needsElectricCharge) { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); electricChargeReserve = (double)comp.ProcessVariable("SYSR_ELECTRICCHARGE", null); } }
public void Start() { if (HighLogic.LoadedSceneIsEditor) { return; } try { ConfigNode moduleConfig = null; foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { if (node.GetValue("name") == internalProp.propName) { if (string.IsNullOrEmpty(variableName)) { JUtil.LogErrorMessage(this, "Configuration failed in prop {0} ({1}), no variableName.", internalProp.propID, internalProp.propName); throw new ArgumentNullException(); } moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] variableNodes = moduleConfig.GetNodes("VARIABLESET"); for (int i = 0; i < variableNodes.Length; i++) { try { variableSets.Add(new CallbackAnimationSet(variableNodes[i], variableName, internalProp)); } catch (ArgumentException e) { JUtil.LogErrorMessage(this, "Error in building prop number {1} - {0}", e.Message, internalProp.propID); } } break; } } RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); del = (Action <RPMVesselComputer, float>)Delegate.CreateDelegate(typeof(Action <RPMVesselComputer, float>), this, "OnCallback"); float value = comp.ProcessVariable(variableName).MassageToFloat(); for (int i = 0; i < variableSets.Count; ++i) { variableSets[i].Update(comp, value); } comp.RegisterCallback(variableName, del); JUtil.LogMessage(this, "Configuration complete in prop {1} ({2}), supporting {0} callback animators.", variableSets.Count, internalProp.propID, internalProp.propName); } catch { JUtil.AnnoyUser(this); enabled = false; throw; } }
public void Update(double time, RPMVesselComputer comp) { double value = isFlat ? flatValue : comp.ProcessVariable(variableName).MassageToDouble(); if (double.IsNaN(value) || double.IsInfinity(value)) { return; } points.Add(new Vector2d(time, value)); if (points.Count > maxPoints) { points.RemoveRange(0, points.Count - maxPoints); } }
public static string ProcessString(StringProcessorFormatter formatter, RPMVesselComputer comp) { if (formatter.usesComp) { for (int i = 0; i < formatter.sourceVariables.Length; ++i) { formatter.sourceValues[i] = comp.ProcessVariable(formatter.sourceVariables[i]); } return(string.Format(formatter.formatString, formatter.sourceValues)); } else { return(formatter.formatString); } }
public void Start() { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); Transform textObjTransform = internalProp.FindModelTransform(transformName); textObj = InternalComponents.Instance.CreateText(fontName, fontSize, textObjTransform, string.Empty); // Force oneshot if there's no variables: oneshot |= !labelText.Contains("$&$"); string sourceString = labelText.UnMangleConfigText(); // Alow a " character to escape leading whitespace if (sourceString[0] == '"') { sourceString = sourceString.Substring(1); } spf = new StringProcessorFormatter(sourceString); if (!oneshot) { comp.UpdateDataRefreshRate(refreshRate); } if (!(string.IsNullOrEmpty(variableName) || string.IsNullOrEmpty(positiveColor) || string.IsNullOrEmpty(negativeColor) || string.IsNullOrEmpty(zeroColor))) { positiveColorValue = ConfigNode.ParseColor32(positiveColor); negativeColorValue = ConfigNode.ParseColor32(negativeColor); zeroColorValue = ConfigNode.ParseColor32(zeroColor); del = (Action <RPMVesselComputer, float>)Delegate.CreateDelegate(typeof(Action <RPMVesselComputer, float>), this, "OnCallback"); comp.RegisterCallback(variableName, del); // Initialize the text color. float value = comp.ProcessVariable(variableName).MassageToFloat(); if (value < 0.0f) { textObj.text.Color = negativeColorValue; } else if (value > 0.0f) { textObj.text.Color = positiveColorValue; } else { textObj.text.Color = zeroColorValue; } } }
public object Evaluate(RPMVesselComputer comp) { if (type == VoNType.ConstantNumeric) { return(numericValue); } else if (type == VoNType.ConstantString) { return(stringValue); } else if (type == VoNType.VariableValue) { return(comp.ProcessVariable(variableName)); } else { return(null); } }
/// <summary> /// Evaluate the variable, returning it in destination. /// </summary> /// <param name="destination"></param> /// <param name="comp"></param> /// <returns></returns> public bool Get(out float destination, RPMVesselComputer comp) { if (!string.IsNullOrEmpty(variableName)) { value = comp.ProcessVariable(variableName).MassageToFloat(); if (float.IsNaN(value) || float.IsInfinity(value)) { if (!warningMade) { JUtil.LogMessage(this, "Warning: {0} can fail to produce a usable number.", variableName); warningMade = true; } destination = value; return(false); } } destination = value; return(true); }
public override void OnUpdate() { if (HighLogic.LoadedSceneIsEditor) { return; } if (!startupComplete) { return; } if (!JUtil.IsActiveVessel(vessel)) { if (loopingOutput != null && currentState == true) { loopingOutput.audio.volume = 0.0f; } return; } else if (loopingOutput != null && currentState == true && loopingOutput.Active) { loopingOutput.audio.volume = loopingSoundVolume * GameSettings.SHIP_VOLUME; } if (consumingWhileActive && currentState && !forcedShutdown) { float requesting = (consumeWhileActiveAmount * TimeWarp.deltaTime); float extracted = part.RequestResource(consumeWhileActiveName, requesting); if (Math.Abs(extracted - requesting) > Math.Abs(requesting / 2)) { // We don't have enough of the resource or can't produce more negative resource, so we should shut down... forcedShutdown = true; JUtil.LogMessage(this, "Could not consume {0}, asked for {1}, got {2} shutting switch down.", consumeWhileActiveName, requesting, extracted); } } // Bizarre, but looks like I need to animate things offscreen if I want them in the right condition when camera comes back. // So there's no check for internal cameras. bool newState; if (isPluginAction && !string.IsNullOrEmpty(stateVariable)) { try { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); newState = (comp.ProcessVariable(stateVariable, -1).MassageToInt()) > 0; } catch { newState = currentState; } } else if (isCustomAction) { if (string.IsNullOrEmpty(switchTransform) && !string.IsNullOrEmpty(perPodPersistenceName)) { if (switchGroupIdentifier >= 0) { int activeGroupId = rpmComp.GetVar(persistentVarName, 0); newState = (switchGroupIdentifier == activeGroupId); customGroupState = newState; } else { // If the switch transform is not given, and the global comp.Persistence value is, this means this is a slave module. newState = rpmComp.GetBool(persistentVarName, false); } } else { // Otherwise it's a master module. But it still might have to follow the clicks on other copies of the same prop... if (!string.IsNullOrEmpty(perPodPersistenceName)) { if (switchGroupIdentifier >= 0) { int activeGroupId = rpmComp.GetVar(persistentVarName, 0); newState = (switchGroupIdentifier == activeGroupId); customGroupState = newState; } else { newState = rpmComp.GetBool(persistentVarName, customGroupState); } } else { newState = customGroupState; } } } else { newState = vessel.ActionGroups[kspAction]; } // If needsElectricCharge is true and there is no charge, the state value is overridden to false and the click action is reexecuted. if (needsElectricChargeValue) { lightCheckCountdown--; if (lightCheckCountdown <= 0) { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); lightCheckCountdown = refreshRate; forcedShutdown |= currentState && comp.ProcessVariable(resourceName).MassageToFloat() < 0.01f; } } if (!string.IsNullOrEmpty(perPodMasterSwitchName)) { bool switchEnabled = rpmComp.GetBool(perPodMasterSwitchName, false); if (!switchEnabled) { // If the master switch is 'off', this switch needs to turn off newState = false; forcedShutdown = true; } } if (masterVariable != null) { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); if (!masterVariable.IsInRange(comp)) { newState = false; forcedShutdown = true; } } if (forcedShutdown) { if (currentState) { Click(); } newState = false; forcedShutdown = false; } if (newState != currentState) { // If we're consuming resources on toggle, do that now. if ((consumingOnToggleUp && newState) || (consumingOnToggleDown && !newState)) { float extracted = part.RequestResource(consumeOnToggleName, consumeOnToggleAmount); if (Math.Abs(extracted - consumeOnToggleAmount) > Math.Abs(consumeOnToggleAmount / 2)) { // We don't have enough of the resource, so we force a shutdown on the next loop. // This ensures the animations will play at least once. forcedShutdown = true; } } if (audioOutput != null && (CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.IVA || CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.Internal)) { audioOutput.audio.Play(); } if (loopingOutput != null && (CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.IVA || CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.Internal)) { if (newState) { loopingOutput.audio.Play(); } else { loopingOutput.audio.Stop(); } } if (anim != null) { if (newState ^ reverse) { anim[animationName].normalizedTime = 0; anim[animationName].speed = 1f * customSpeed; anim.Play(animationName); } else { anim[animationName].normalizedTime = 1; anim[animationName].speed = -1f * customSpeed; anim.Play(animationName); } } else if (colorShiftMaterial != null) { colorShiftMaterial.SetColor(colorName, (newState ^ reverse ? enabledColorValue : disabledColorValue)); } currentState = newState; } }
public void Click() { bool switchEnabled = true; if (!forcedShutdown) { if (!string.IsNullOrEmpty(perPodMasterSwitchName)) { switchEnabled = rpmComp.GetBool(perPodMasterSwitchName, false); } if (masterVariable != null) { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); switchEnabled = masterVariable.IsInRange(comp); } } if (!switchEnabled) { // If the master switch is 'off' and we're not here because // of a forced shutdown, don't allow this switch to work. // early return return; } if (isCustomAction) { if (switchGroupIdentifier >= 0) { if (!forcedShutdown && !customGroupState) { customGroupState = true; if (!string.IsNullOrEmpty(persistentVarName)) { rpmComp.SetVar(persistentVarName, switchGroupIdentifier); } } // else: can't turn off a radio group switch. } else if (customAction == CustomActions.Plugin && !string.IsNullOrEmpty(stateVariable)) { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); int ivalue = comp.ProcessVariable(stateVariable, -1).MassageToInt(); customGroupState = (ivalue < 1) && !forcedShutdown; } else { customGroupState = !customGroupState; if (!string.IsNullOrEmpty(persistentVarName)) { rpmComp.SetVar(persistentVarName, customGroupState); } } } else { vessel.ActionGroups.ToggleGroup(kspAction); } // Now we do extra things that with regular actions can't happen. switch (customAction) { case CustomActions.IntLight: SetInternalLights(customGroupState); break; case CustomActions.Plugin: actionHandler(customGroupState); break; case CustomActions.Stage: if (InputLockManager.IsUnlocked(ControlTypes.STAGING)) { Staging.ActivateNextStage(); } break; case CustomActions.Transfer: if (!string.IsNullOrEmpty(stateVariable)) { // stateVariable can disable the button functionality. RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); int ivalue = comp.ProcessVariable(stateVariable, -1).MassageToInt(); if (ivalue < 1) { return; // early - button disabled } } if (!string.IsNullOrEmpty(transferGetter)) { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); float value = comp.ProcessVariable(transferGetter, internalProp.propID).MassageToFloat(); rpmComp.SetVar(transferPersistentName, (int)value); } else if (rpmComp.HasVar(transferPersistentName)) { transferSetter((double)rpmComp.GetVar(transferPersistentName)); } break; } }
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 void RenderData(RenderTexture screen, RPMVesselComputer comp) { float leftVal, rightVal; if (!scale[0].Get(out leftVal, comp) || !scale[1].Get(out rightVal, comp)) { return; // bad values - can't render } float eval = comp.ProcessVariable(variableName).MassageToFloat(); if (float.IsInfinity(eval) || float.IsNaN(eval)) { return; // bad value - can't render } float ratio = Mathf.InverseLerp(leftVal, rightVal, eval); if (thresholdMode) { if (ratio >= threshold.x && ratio <= threshold.y) { if (flashingDelay > 0.0f) { if (lastStateChange + flashingDelay < Planetarium.GetUniversalTime()) { lastStateChange = Planetarium.GetUniversalTime(); lastState = 1.0f - lastState; } ratio = lastState; } else { ratio = 1.0f; } } else { ratio = 0.0f; } } if (reverse) { ratio = 1.0f - ratio; } switch (graphType) { case GraphType.VerticalDown: DrawVerticalDown(ratio); break; case GraphType.VerticalUp: DrawVerticalUp(ratio); break; case GraphType.VerticalSplit: DrawVerticalSplit(ratio); break; case GraphType.HorizontalLeft: DrawHorizontalLeft(ratio); break; case GraphType.HorizontalRight: DrawHorizontalRight(ratio); break; case GraphType.HorizontalSplit: DrawHorizontalSplit(ratio); break; case GraphType.Lamp: DrawLamp(ratio); break; default: throw new NotImplementedException("Unimplemented graphType " + graphType.ToString()); } }
private void UpdateOdometer() { double thisUpdate = Planetarium.GetUniversalTime(); float dT = (float)(thisUpdate - lastUpdate) * odometerRotationScalar; RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); float value; if (!string.IsNullOrEmpty(perPodPersistenceName)) { bool state = rpmComp.GetBool(perPodPersistenceName, false); value = comp.ProcessVariable((state) ? altVariable : variable).MassageToFloat(); } else { value = comp.ProcessVariable(variable).MassageToFloat(); } // Make sure the value isn't going to be a problem. if (float.IsNaN(value)) { value = 0.0f; } if (value < 0.0f) { signGoalCoord = 0.625f; } else if (value > 0.0f) { signGoalCoord = 0.875f; } else { signGoalCoord = 0.75f; } signCurrentCoord = JUtil.DualLerp(signCurrentCoord, signGoalCoord, 0.0f, 1.0f, dT); value = Mathf.Abs(value); if (oMode == OdometerMode.SI) { float leadingDigitExponent; if (value < 0.001f) { leadingDigitExponent = -3.0f; } else { leadingDigitExponent = Mathf.Floor(Mathf.Log10(value)); } // siExponent is the location relative to the original decimal of // the SI prefix. Is is always the greatest multiple-of-3 less // than the leadingDigitExponent. int siIndex = (int)Mathf.Floor(leadingDigitExponent / 3.0f); if (siIndex > 3) { siIndex = 3; } int siExponent = siIndex * 3; prefixGoalCoord = (float)(siIndex + 1) * 0.125f; prefixCurrentCoord = JUtil.DualLerp(prefixCurrentCoord, prefixGoalCoord, 0.0f, 1.0f, dT); float scaledValue = value / Mathf.Pow(10.0f, (float)(siExponent - 3)); int intValue = (int)(scaledValue); for (int i = 5; i >= 0; --i) { float thisCoord = (float)(intValue % 10) / 10.0f; if (i == 5) { // So we can display fractional values: // However, we also quantize it to make it easier to // read during the transition from 9 to 0. thisCoord = Mathf.Floor((scaledValue % 10.0f) * 2.0f) / 20.0f; } intValue = intValue / 10; goalCoordinate[i] = thisCoord; } } else if (oMode == OdometerMode.TIME_HHHMMSS) { // Clamp the value value = Mathf.Min(value, 59.0f + 59.0f * 60.0f + 999.0f * 60.0f * 24.0f); // seconds float thisCoord = Mathf.Floor((value % 10.0f) * 2.0f) / 20.0f; goalCoordinate[6] = thisCoord; int intValue = (int)(value) / 10; // tens of seconds thisCoord = (float)(intValue % 6) / 10.0f; goalCoordinate[5] = thisCoord; intValue /= 6; // minutes thisCoord = (float)(intValue % 10) / 10.0f; goalCoordinate[4] = thisCoord; intValue /= 10; // tens of minutes thisCoord = (float)(intValue % 6) / 10.0f; goalCoordinate[3] = thisCoord; intValue /= 6; for (int i = 2; i >= 0; --i) { thisCoord = (float)(intValue % 10) / 10.0f; intValue = intValue / 10; goalCoordinate[i] = thisCoord; } } else { int intValue = (int)(value); for (int i = 7; i >= 0; --i) { float thisCoord = (float)(intValue % 10) / 10.0f; if (i == 7) { thisCoord = Mathf.Floor((value % 10.0f) * 2.0f) / 20.0f; } intValue = intValue / 10; goalCoordinate[i] = thisCoord; } } // Update interpolants for (int i = 0; i < 8; ++i) { if (currentCoordinate[i] != goalCoordinate[i]) { float startingPoint; float endingPoint; if (Mathf.Abs(currentCoordinate[i] - goalCoordinate[i]) <= 0.5f) { startingPoint = currentCoordinate[i]; endingPoint = goalCoordinate[i]; } else if (goalCoordinate[i] < currentCoordinate[i]) { startingPoint = currentCoordinate[i]; endingPoint = goalCoordinate[i] + 1.0f; } else { startingPoint = currentCoordinate[i] + 1.0f; endingPoint = goalCoordinate[i]; } // This lerp causes a rotation that starts quickly but // slows down close to the goal. It actually looks // pretty good for typical incrementing counts, while the // rapid spinning of small values is chaotic enough that // you can't really tell what's going on, anyway. float goal = JUtil.DualLerp(startingPoint, endingPoint, 0.0f, 1.0f, dT); if (goal > 1.0f) { goal -= 1.0f; } currentCoordinate[i] = goal; } } lastUpdate = thisUpdate; }
public void Update(double time, RPMVesselComputer comp, PersistenceAccessor persistence) { double value = isFlat ? flatValue : comp.ProcessVariable(variableName, persistence).MassageToDouble(); if (double.IsNaN(value) || double.IsInfinity(value)) { return; } points.Add(new Vector2d(time, value)); if (points.Count > maxPoints) { points.RemoveRange(0, points.Count - maxPoints); } }
public void RenderData(RenderTexture screen, RPMVesselComputer comp) { float leftVal, rightVal; if (!scale[0].Get(out leftVal, comp) || !scale[1].Get(out rightVal, comp)) { return; // bad values - can't render } float eval = comp.ProcessVariable(variableName).MassageToFloat(); if (float.IsInfinity(eval) || float.IsNaN(eval)) { return; // bad value - can't render } float ratio = Mathf.InverseLerp(leftVal, rightVal, eval); if (thresholdMode) { if (ratio >= threshold.x && ratio <= threshold.y) { if (flashingDelay > 0.0f) { if (lastStateChange + flashingDelay < Planetarium.GetUniversalTime()) { lastStateChange = Planetarium.GetUniversalTime(); lastState = 1.0f - lastState; } ratio = lastState; } else { ratio = 1.0f; } } else { ratio = 0.0f; } } if (reverse) { ratio = 1.0f - ratio; } switch (graphType) { case GraphType.VerticalDown: DrawVerticalDown(ratio); break; case GraphType.VerticalUp: DrawVerticalUp(ratio); break; case GraphType.VerticalSplit: DrawVerticalSplit(ratio); break; case GraphType.HorizontalLeft: DrawHorizontalLeft(ratio); break; case GraphType.HorizontalRight: DrawHorizontalRight(ratio); break; case GraphType.HorizontalSplit: DrawHorizontalSplit(ratio); break; case GraphType.Lamp: DrawLamp(ratio); break; default: throw new NotImplementedException("Unimplemented graphType " + graphType.ToString()); } }
public void Click() { RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); bool switchEnabled = true; if (!forcedShutdown) { if (perPodMasterSwitchValid) { switchEnabled = comp.GetPersistentVariable(perPodMasterSwitchName, false); } if (masterVariable != null) { switchEnabled = masterVariable.IsInRange(comp); } } if (!switchEnabled) { // If the master switch is 'off' and we're not here because // of a forced shutdown, don't allow this switch to work. // early return return; } if (isCustomAction) { if (switchGroupIdentifier >= 0) { if (!forcedShutdown && !customGroupState) { customGroupState = true; if (persistentVarValid) { comp.SetPersistentVariable(persistentVarName, switchGroupIdentifier); } } // else: can't turn off a radio group switch. } else if (customAction == CustomActions.Plugin && stateVariableValid) { int ivalue = comp.ProcessVariable(stateVariable).MassageToInt(); customGroupState = (ivalue < 1) && !forcedShutdown; } else { customGroupState = !customGroupState; if (persistentVarValid) { comp.SetPersistentVariable(persistentVarName, customGroupState); } } } else { vessel.ActionGroups.ToggleGroup(kspAction); } // Now we do extra things that with regular actions can't happen. switch (customAction) { case CustomActions.IntLight: SetInternalLights(customGroupState); break; case CustomActions.Plugin: actionHandler(customGroupState); break; case CustomActions.Stage: if (InputLockManager.IsUnlocked(ControlTypes.STAGING)) { StageManager.ActivateNextStage(); } break; case CustomActions.TransferToPersistent: if (stateVariableValid) { // stateVariable can disable the button functionality. int ivalue = comp.ProcessVariable(stateVariable).MassageToInt(); if (ivalue < 1) { return; // early - button disabled } } float getValue = comp.ProcessVariable(transferGetter).MassageToFloat(); comp.SetPersistentVariable(transferPersistentName, getValue); break; case CustomActions.TransferFromPersistent: if (stateVariableValid) { // stateVariable can disable the button functionality. int ivalue = comp.ProcessVariable(stateVariable).MassageToInt(); if (ivalue < 1) { return; // early - button disabled } } if (comp.HasPersistentVariable(transferPersistentName)) { transferSetter(comp.GetPersistentVariable(transferPersistentName, 0.0).MassageToDouble()); } break; case CustomActions.TransferFromVariable: if (stateVariableValid) { // stateVariable can disable the button functionality. int ivalue = comp.ProcessVariable(stateVariable).MassageToInt(); if (ivalue < 1) { return; // early - button disabled } } double xferValue = comp.ProcessVariable(transferGetter).MassageToDouble(); transferSetter(xferValue); break; case CustomActions.Transfer: JUtil.LogInfo(this, "The deprecated CustomActions.Transfer path was executed"); /*if (stateVariableValid) * { * // stateVariable can disable the button functionality. * int ivalue = comp.ProcessVariable(stateVariable).MassageToInt(); * if (ivalue < 1) * { * return; // early - button disabled * } * } * if (!string.IsNullOrEmpty(transferGetter)) * { * float value = comp.ProcessVariable(transferGetter).MassageToFloat(); * comp.SetPersistentVariable(transferPersistentName, value); * } * else if (comp.HasPersistentVariable(transferPersistentName)) * { * transferSetter(comp.GetPersistentVariable(transferPersistentName, 0.0).MassageToDouble()); * }*/ break; } }
/// <summary> /// Evaluate the variable, returning it in destination. /// </summary> /// <param name="destination"></param> /// <param name="comp"></param> /// <returns></returns> public bool Get(out float destination, RPMVesselComputer comp) { if (!string.IsNullOrEmpty(variableName)) { value = comp.ProcessVariable(variableName).MassageToFloat(); if (float.IsNaN(value) || float.IsInfinity(value)) { if (!warningMade) { JUtil.LogMessage(this, "Warning: {0} can fail to produce a usable number.", variableName); warningMade = true; } destination = value; return false; } } destination = value; return true; }