public void PageButtonClick(MonitorPage triggeredPage) { if (resourceDepleted || noCommConnection) { return; } // Apply page redirect like this: triggeredPage = FindPageByName(activePage.ContextRedirect(triggeredPage.name)) ?? triggeredPage; if (triggeredPage != activePage && (activePage.SwitchingPermitted(triggeredPage.name) || triggeredPage.unlocker)) { activePage.Active(false); activePage = triggeredPage; activePage.Active(true); rpmComp.SetPersistentVariable(persistentVarName, activePage.pageNumber, false); refreshDrawCountdown = refreshTextCountdown = 0; firstRenderComplete = false; PlayClickSound(audioOutput); } }
public void PageButtonClick(MonitorPage triggeredPage) { if (needsElectricCharge && electricChargeReserve < 0.01d) { return; } // Apply page redirect like this: triggeredPage = FindPageByName(activePage.ContextRedirect(triggeredPage.name)) ?? triggeredPage; if (triggeredPage != activePage && (activePage.SwitchingPermitted(triggeredPage.name) || triggeredPage.unlocker)) { activePage.Active(false); activePage = triggeredPage; activePage.Active(true); persistence.SetVar(persistentVarName, activePage.pageNumber); refreshDrawCountdown = refreshTextCountdown = 0; firstRenderComplete = false; PlayClickSound(audioOutput); } }
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 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; } }
public void PageButtonClick(MonitorPage triggeredPage) { if (resourceDepleted) { return; } // Apply page redirect like this: triggeredPage = FindPageByName(activePage.ContextRedirect(triggeredPage.name)) ?? triggeredPage; if (triggeredPage != activePage && (activePage.SwitchingPermitted(triggeredPage.name) || triggeredPage.unlocker)) { activePage.Active(false); activePage = triggeredPage; activePage.Active(true); rpmComp.SetPersistentVariable(persistentVarName, activePage.pageNumber, false); refreshDrawCountdown = refreshTextCountdown = 0; firstRenderComplete = false; PlayClickSound(audioOutput); } }
public void PageButtonClick(MonitorPage triggeredPage) { if (needsElectricCharge && electricChargeReserve < 0.01d) return; // Apply page redirect like this: triggeredPage = FindPageByName(activePage.ContextRedirect(triggeredPage.name)) ?? triggeredPage; if (triggeredPage != activePage && (activePage.SwitchingPermitted(triggeredPage.name) || triggeredPage.unlocker)) { activePage.Active(false); activePage = triggeredPage; activePage.Active(true); persistence.SetVar(persistentVarName, activePage.pageNumber); refreshDrawCountdown = refreshTextCountdown = 0; comp.updateForced = true; firstRenderComplete = false; PlayClickSound(audioOutput); } }
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; }