Malah Posted March 24, 2016 Share Posted March 24, 2016 (edited) Hello, is there a way to use the GenericAppFrame used on the EngineersReport and on the ContractsApp for our mods which has applauncher's button? I've tried to use it but I haven't found how to do it without many errors from many variables used in the GenericAppFrame class. Thanks Edited March 24, 2016 by Malah Quote Link to comment Share on other sites More sharing options...
Padishar Posted March 24, 2016 Share Posted March 24, 2016 (edited) 13 minutes ago, Malah said: Hello, is there a way to use the GenericAppFrame used on the EngineersReport and on the ContractsApp for our mods which has applauncher's button? I've tried to use it but I haven't found how to do it without many errors from many variables used in the GenericAppFrame class. Thanks Even if it is possible, there is little point trying to do any sort of complex interaction with stock UI code at this point because KSP 1.1 is just around the corner and the UI code has been totally overhauled. Edited March 24, 2016 by Padishar Quote Link to comment Share on other sites More sharing options...
Malah Posted March 24, 2016 Share Posted March 24, 2016 1 hour ago, Padishar said: Even if it is possible, there is little point trying to do any sort of complex interaction with stock UI code at this point because KSP 1.1 is just around the corner and the UI code has been totally overhauled. Yes but I want to learn how to do it, perhaps that on the 1.1, I could use this new knowledge Quote Link to comment Share on other sites More sharing options...
Superfluous J Posted April 14, 2016 Share Posted April 14, 2016 While retractable things (say, Solar panels) are moving, the "extend" and "retract" buttons are not visible. Once they stop moving, the appropriate button becomes displayed. I know that buttons are KSPEvent() and I can make one that shows up or not. I even figured out how to enable and disable them (and change their text, in case that's needed). However, I can't seem to grasp how to change these states based on the status of the part. Specifically, this is for All Y'All. I'm trying to make it so my buttons work the same way the stock ones do visually. So you only have one button "Extend all" and that only is there if the selected panel is retracted. When you click it, it goes away, the panel (and all panels) extends, then when it's done extending a "Retract all" button appears. Quote Link to comment Share on other sites More sharing options...
Crzyrndm Posted April 14, 2016 Share Posted April 14, 2016 (edited) void ExtendAll() { // stuff StartCoroutine(waitForExtended()); } System.Collections.IEnumerator waitForExtended() { while (module.State != extended) // replace with actual state checks obviously... yield return new WaitForSeconds(1.0); // check once per second whether the tate change has finished // set retract event visible } If it doesn't have an event, you can always just poll it until it is where you want it Edited April 14, 2016 by Crzyrndm Quote Link to comment Share on other sites More sharing options...
Superfluous J Posted April 14, 2016 Share Posted April 14, 2016 28 minutes ago, Crzyrndm said: void ExtendAll() { // stuff StartCoroutine(waitForExtended()); } System.Collections.IEnumerator waitForExtended() { while (module.State != extended) // replace with actual state checks obviously... yield return new WaitForSeconds(1.0); // check once per second whether the tate change has finished // set retract event visible } If it doesn't have an event, you can always just poll it until it is where you want it That actually makes sense to me. Thank you. I may need a little more help with the "module.state != extended" part as that looks like pseudocode, especially with the comment I don't actually know how to check that state, either on the part or the module or what. I also don't know how to find out what it should be, or even the exact syntax. For fun I just tried typing "module" into VS (which is pretty helpful in at least letting you know you're on the right track) and it doesn't seem to be valid. Quote Link to comment Share on other sites More sharing options...
Crzyrndm Posted April 14, 2016 Share Posted April 14, 2016 (edited) Module is one of the things (Part Modules...) you just called extend on, probably the one on the same part as your module. Using solar panels as an example // if your module is running alongside the solar panel module (extends PartModule) // get a solar panel module to work on ModuleDeployableSolarPanel solarPanel = part.Modules.OfType<ModuleDeployableSolarPanel>().FirstOrDefault(); if (solarPanel == null) return; // incase we don't find any (which is stupid, but w/e) // wait for it to finish extending while (solarPanel.panelState == ModuleDeployableSolarPanel.panelStates.Extending) // blah blah blah... Much easier if you are already running inside the solar panel though because the solarPanel reference above is the object running the code. Objects can access their own properties without all the fuss // if your module extends ModuleDeployableSolarPanel while (panelState == panelStates.Extending) // blah Edited April 14, 2016 by Crzyrndm Quote Link to comment Share on other sites More sharing options...
Superfluous J Posted April 14, 2016 Share Posted April 14, 2016 17 minutes ago, Crzyrndm said: Much easier if you are already running inside the solar panel though because the solarPanel reference above is the object running the code. Objects can access their own properties without all the fuss // if your module extends ModuleDeployableSolarPanel while (panelState == panelStates.Extending) // blah I think something like this should work for me as this will always be running in a Solar panel. However, it's still not liking the syntax for some reason. I think it's because I'm not actually modifying ModuleDepoloyableSolarPanel, but instead adding a new module. Among all the things I don't know is how to tell it I'm in a solar panel. Here's the full code I have so far. I put the error as a comment on the line that the compiler's complaining about: public class AYA_Solar_Test : PartModule { public bool togglesolar = true; // may need changed to take into account already open panels [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "Extend All TEST")] public void ToggleAllSolar() { foreach (Part eachPart in vessel.Parts) { var panel = eachPart.FindModuleImplementing<ModuleDeployableSolarPanel>(); if (togglesolar) if (panel != null) panel.Extend(); if (!togglesolar) if (panel != null) panel.Retract(); } Events["ToggleAllSolar"].guiActive = false; while (panelState == panelstates.Extending) // CS0103 The name 'panelState' does not exist in th current context (Same with panelStates) { // do stuff } if (togglesolar) Events["ToggleAllSolar"].guiName = "Retract All TEST"; if (!togglesolar) Events["ToggleAllSolar"].guiName = "Extend All TEST"; togglesolar = !togglesolar; } } Quote Link to comment Share on other sites More sharing options...
Crzyrndm Posted April 14, 2016 Share Posted April 14, 2016 (edited) 1) You need to use the first method. Your class is not a solar panel, it operates on objects that are solar panels 2) The "StartCoroutine" and second function in my first answer is extremely important. The structure you have there will freeze the game indefinitely because KSP can't do anything while you're in that while loop. When a Coroutine "yields", the function gets paused and lets KSP continue until some condition is met (the 1 second time period in my example) and then it unpauses the function again (repeat until it reaches the end of the function). Edited April 14, 2016 by Crzyrndm Quote Link to comment Share on other sites More sharing options...
Superfluous J Posted April 14, 2016 Share Posted April 14, 2016 Just now, Crzyrndm said: 1) You need to use the first method. Your class is not a solar panel, it operates on objects that are solar panels 2) The "StartCoroutine" and second function in my first answer is extremely important. The structure you have there will freeze the game indefinitely because KSP can't do anything while you're in that while loop. When a Coroutine "yields", the function gets paused and lets KSP continue until some condition is met (the 1 second time period in my example) and then it unpauses the function again. 1) Aha. Am I right in thinking that that first method will just pick the first Solar Panel it finds? I don't mind that as a backup, but I'd prefer it pick the actual part we're dealing with if possible. It should be a solar panel, I'm setting that in a modulemanager config. 2) Oops. I thought maybe I could simplify it I'll fiddle a bit more and undoubtedly come up with something else that I can't figure out. As always, thank you very much. Quote Link to comment Share on other sites More sharing options...
Crzyrndm Posted April 14, 2016 Share Posted April 14, 2016 (edited) 33 minutes ago, 5thHorseman said: Am I right in thinking that that first method will just pick the first Solar Panel it finds? Yes. I was just getting a reference to work with because I wasn't looking at how you'd done it. You can get that reference however you like // inside the extend loop // existing code StartCoroutine(checkState(panel)); // one for each panel we're extending // end loop // and the check state function IEnumerator checkState(ModuleDeployableSolarPanel panel) { while (panel.panelState...) // change button visibility on this panel } Edited April 14, 2016 by Crzyrndm Quote Link to comment Share on other sites More sharing options...
Superfluous J Posted April 14, 2016 Share Posted April 14, 2016 Just now, Crzyrndm said: Yes. I was just getting a reference to work with because I wasn't looking at how you'd done it // inside the extend loop // existing code StartCoroutine(checkState(panel)); // one for each panel we're extending // end loop // and the check state function IEnumerator checkState(ModuleDeployableSolarPanel panel) { // change button visibility } So wait, that would change the visibility of each button in all of the panels' right click menus? That's actually super cool and I didn't even know I wanted it to work that way until just now. Okay one last thing and I'm (hopefully) out of your hair. VS is complaining that I have to return a value, but I don't even know what an IEnumerator is. I tried 1 and 0 but it says Int doesn't count. Quote Link to comment Share on other sites More sharing options...
Crzyrndm Posted April 14, 2016 Share Posted April 14, 2016 That's just saying there needs to be a yield statement in the function (if there isn't, you'll get that indefinite freeze :P) while(/*extending*/) yield return new WaitForSeconds(1.0); Quote Link to comment Share on other sites More sharing options...
Superfluous J Posted April 14, 2016 Share Posted April 14, 2016 (edited) This is making my brain implode on itself. I really do thank you for this it's no end of help but I think I've reached my limit for the day. I'll go over all of this again after a good sleep and maybe a stiff drink. But probably not in that order. Edited April 14, 2016 by 5thHorseman Quote Link to comment Share on other sites More sharing options...
Superfluous J Posted April 15, 2016 Share Posted April 15, 2016 (edited) Okay as expected some liquidity and sleep has invigorated me anew, and I'm seeming to make progress. However I seem to still be missing some critical things, and would love some more help. @Crzyrndm, If you've said something above that I didn't implement below, don't think I'm ignoring you. I'm just .that. .lost. here. Here's the code I have. It technically works but not the way I want. the text ("extend all" and "retract all") don't change and the buttons don't disappear during movement, but the panels DO all extend and retract: public class AYA_Solar_Test : PartModule { [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "UNINITIALIZED!")] public void ToggleAllSolar() { foreach (Part eachPart in vessel.Parts) { var panel = eachPart.FindModuleImplementing<ModuleDeployableSolarPanel>(); if (panel != null) { if (panel.panelState == ModuleDeployableSolarPanel.panelStates.RETRACTED) { panel.Extend(); } if (panel.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED) { panel.Retract(); } StartCoroutine(waitForExtendRetractSolar(panel)); } } } public System.Collections.IEnumerator waitForExtendRetractSolar(ModuleDeployableSolarPanel solarPanel) { solarPanel.Events["ToggleAllSolar"].guiActive = false; while (solarPanel.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDING || solarPanel.panelState == ModuleDeployableSolarPanel.panelStates.RETRACTING) { yield return new WaitForSeconds(1); } if (solarPanel.panelState == ModuleDeployableSolarPanel.panelStates.RETRACTED) { solarPanel.Events["ToggleAllSolar"].guiName = "Extend All TEST"; } if (solarPanel.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED) { solarPanel.Events["ToggleAllSolar"].guiName = "Retract All TEST"; } solarPanel.Events["ToggleAllSolar"].guiActive = true; yield return new WaitForSeconds(0) ; // This is totally a kludge I have it in here because it doesn't error out. I'll happily fix it if someone tells me how. } } Earlier, I had this code and it worked perfectly. The hide/reveal part worked, and the text changed from "extend" to "retract" as expected. However, it only did it on the panel I right-clicked on. The other panels extended and retracted, but their buttons stayed visible and their text didn't change. It's why I made the changes in the first code block: public class AYA_Solar_Test : PartModule { [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "Extend All TEST")] public void ToggleAllSolar() { foreach (Part eachPart in vessel.Parts) { var panel = eachPart.FindModuleImplementing<ModuleDeployableSolarPanel>(); if (panel != null) { if (panel.panelState == ModuleDeployableSolarPanel.panelStates.RETRACTED) { panel.Extend(); } if (panel.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED) { panel.Retract(); } StartCoroutine(waitForExtendRetractSolar(panel)); } } } System.Collections.IEnumerator waitForExtendRetractSolar(ModuleDeployableSolarPanel solarPanel) { Events["ToggleAllSolar"].guiActive = false; while (solarPanel.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDING || solarPanel.panelState == ModuleDeployableSolarPanel.panelStates.RETRACTING) { yield return new WaitForSeconds(1); } if (solarPanel.panelState == ModuleDeployableSolarPanel.panelStates.RETRACTED) { Events["ToggleAllSolar"].guiName = "Extend All TEST"; } if (solarPanel.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED) { Events["ToggleAllSolar"].guiName = "Retract All TEST"; } Events["ToggleAllSolar"].guiActive = true; // blah blah blah... yield return new WaitForSeconds(0) ; // This is totally a kludge I have it in here because it doesn't error out. I'll happily fix it if someone tells me how. } } Also, note that final "yield return." If someone could tell me the correct way to get out of that function (just "return" doesn't fly with Visual Studio) I'd appreciate it, though I'll happily keep the code there if it works. I don't think it's causing any problems (though my opinion is at best suspect on these matters) Edited April 15, 2016 by 5thHorseman Quote Link to comment Share on other sites More sharing options...
blowfish Posted April 15, 2016 Share Posted April 15, 2016 @5thHorseman I don't think you need a statement there at all. But for future reference yield break will end the enumeration. Quote Link to comment Share on other sites More sharing options...
Superfluous J Posted April 15, 2016 Share Posted April 15, 2016 (edited) 35 minutes ago, blowfish said: @5thHorseman I don't think you need a statement there at all. But for future reference yield break will end the enumeration. Weird. I had no statement there and VS was giving me an error. I just removed it to get the error, and VS is totally fine with it. #NoobModder UPDATE: After much fiddling I'm almost positive I just don't have the correct syntax for something. Nothing I do will modify the text or the visibility of the button on other solar panels. All I can do is modify those on the CURRENT one (my first code block above). Other than knowing that, though, I've got no clue where to proceed. UPDATE 2: More fiddling, and digging through logging. I found that in the coroutine the following line gets a null reference exception: solarPanel.Events["ToggleAllSolar"].guiActive = false; solarPanel.Events["ToggleAllSolar"].guiActive = false; I think it's because this is the "ModuleDeployableSolarPanel" module and I need to reference, on the same part with that module, the AYA_Solar_Test module. I just (as always) don't know how to do that. Edited April 15, 2016 by 5thHorseman Quote Link to comment Share on other sites More sharing options...
Crzyrndm Posted April 15, 2016 Share Posted April 15, 2016 Aya_Solar_Test myModule = solarPanel.part.Modules.OfType<AYA_Solar_Test>()[0]; Assuming your module is always on the same part as the solar panel Quote Link to comment Share on other sites More sharing options...
Superfluous J Posted April 15, 2016 Share Posted April 15, 2016 Just now, Crzyrndm said: Aya_Solar_Test myModule = solarPanel.part.Modules.OfType<AYA_Solar_Test>()[0]; Assuming your module is always on the same part as the solar panel It should be, unless the user screws around with the modulemanager config. I suppose I could check for it and then skip it if the module's not there? Check if it's null? That code gets this error: Error CS0021 Cannot apply indexing with [] to an expression of type 'IEnumerable<AYA_Solar_Test>' Removing the [0] at the end gets: Error CS0266 Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<AllYAll.AYA_Solar_Test>' to 'AllYAll.AYA_Solar_Test'. An explicit conversion exists (are you missing a cast?) Quote Link to comment Share on other sites More sharing options...
Crzyrndm Posted April 15, 2016 Share Posted April 15, 2016 erps, .FirstOrDefault() is what you want, and yea a null check in case there isn't one present Quote Link to comment Share on other sites More sharing options...
Padishar Posted April 15, 2016 Share Posted April 15, 2016 (edited) ...deleted... You need to get the instance of your module that is on the same part as the solarPanel and change the events on that. What Crzyrndm said looks like it should work... Edited April 15, 2016 by Padishar Quote Link to comment Share on other sites More sharing options...
Aerospike Posted April 18, 2016 Share Posted April 18, 2016 Hello fellow modders! I'm pretty new to modding KSP and working with Unity so please forgive me if I ask really stupid questions. I would like to interact with the stock GUI (if that is at all possible and allowed?), more specifically I would like to suppress (or close) a window to show my own window instead. Searching the forums for combinations of "stock", "GUI", "interact with", "modify", "customize", didn't bring up anything that helped me. I just found some statements that "working/interacting with" the stock GUI tends to be PITA from a modding perspective, but no detailed informations and/or examples. Any advise regarding this matter would be greatly appreciated. Even if the answer is "that is impossible" I would be happy, since that means I can focus my energy on other aspects. Thanks! (For those with signatures disabled: I would like to make KISS replace the default "quicksave as..." dialog, so it doesn't need an additional keybinding.) Quote Link to comment Share on other sites More sharing options...
xEvilReeperx Posted April 19, 2016 Share Posted April 19, 2016 3 hours ago, Aerospike said: I would like to interact with the stock GUI (if that is at all possible and allowed?), more specifically I would like to suppress (or close) a window to show my own window instead. Searching the forums for combinations of "stock", "GUI", "interact with", "modify", "customize", didn't bring up anything that helped me. I just found some statements that "working/interacting with" the stock GUI tends to be PITA from a modding perspective, but no detailed informations and/or examples. A lot of the interesting GUI stuff can be private (and therefore not directly accessible without breaking rules) so you might have to jump through some hoops to make things work. In 1.0.5, I'd say your best bet would be registering for GameEvents.onInputLocksModified and checking for the quicksave dialog control lock. You might be forced to use FindObjectOfType<PopupDialog> afterwards to get the dialog itself since I don't see any convenient references anywhere. The same tactic should work fine for 1.1. The advantage in 1.1 is that the dialog uses the new GUI system and exposes the dialog prefab (PopupDialogController.PopupDialogBase) which allows you to do almost anything you want to it, although I'd still go down the "replace it with own version" route than trying to tweak it to do what I want Quote Link to comment Share on other sites More sharing options...
Aerospike Posted April 19, 2016 Share Posted April 19, 2016 Thank you xEvilReeperx! Now once again I just wish there was an official API documentation to find out more about this stuff (I do know the community-generated one). I have already "ported" the KISS dialog to the new GUI (not made a pre-release of the new one yet), so I'm fine with only adding that feature to the KSP 1.1 branch if that makes things easier. Since you brought up control locks: do I have to implement control locks myself in some way? Currently I pause the game before showing the dialog (as the stock "quicksave as" does) and so far I have not had an issue with accidentally controlling the vessel. Quote Link to comment Share on other sites More sharing options...
xEvilReeperx Posted April 19, 2016 Share Posted April 19, 2016 Up to you. I would, just in case there is some non-obvious edge case Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.