theSpeare Posted March 7, 2014 Share Posted March 7, 2014 (edited) Is there a global "time" value? Something like MET but instead as a more universal clock that would have started when you started your game. Seems a lot more reliable than MET for some things.EDIT: Did some poking around and foundPlanetarium.GetUniversalTime (); Edited March 7, 2014 by theSpeare Quote Link to comment Share on other sites More sharing options...
Diazo Posted March 7, 2014 Share Posted March 7, 2014 Planatarium.GetUniversalTime() is what I use also.It returns the in-game seconds since that saved game started.Note this means it rolls back when you revert a flight and that because it is a double it returns a decimal value, not an integer.D. Quote Link to comment Share on other sites More sharing options...
Diazo Posted March 9, 2014 Share Posted March 9, 2014 Okay, what I hope is a simple question.I'm trying to catch a null ref exception here.When in the VAB, EditorLogic.SortedShipList is a List of Parts on the ship being assembled. However, until you place the first part this list is null as no parts have been placed yet.So, null check as follows:public void Update() { print("Upd start"); if (EditorLogic.SortedShipList == null) { print("it's null"); } print("update end"); }Supposedly null is a valid variable to compare against in C# so this is supposed to work. (Google c# null check returns a page of results on this.)However, that if statement is throwing a null ref exception when I run this code. I've tried several variations and the only conclusion I can come to is that EditorLogic itself is null and so the actual NullRef being thrown on my if statement is there, not at SortedShipList.But how do I check for null on EditorLogic then? if(EditorLogic == null)throws me an error in visual studio that "EditorLogic is a type but used like a variable" and won't compile.I can simply ignore this as no code should be running anyway if EditorLogic.SortedShipList is empty, but spamming the log with a NullRef every update frame is a bad idea.Anyone have any ideas?D. Quote Link to comment Share on other sites More sharing options...
xEvilReeperx Posted March 9, 2014 Share Posted March 9, 2014 I'm trying to catch a null ref exception here.public void Update() { print("Upd start"); if (EditorLogic.SortedShipList == null) { print("it's null"); } print("update end"); }...However, that if statement is throwing a null ref exception when I run this code. I've tried several variations and the only conclusion I can come to is that EditorLogic itself is null and so the actual NullRef being thrown on my if statement is there, not at SortedShipList.But how do I check for null on EditorLogic then? if(EditorLogic == null)EditorLogic.SortedShipList probably calls a function that depends on an EditorLogic instance existing. You almost have it; if (EditorLogic.fetch != null) should do the job Quote Link to comment Share on other sites More sharing options...
Faark Posted March 9, 2014 Share Posted March 9, 2014 There are barely any cases where it is okay to ignore an exception, and those mostly consist of unexpected IO states (network connection removed, stuff like this). Though admittedly have to live what KSP throws at us...Anyway, back to your Exception. EditorLogic is a property, not a field. That means it is a function call, thus it can ofc throw an exception. It is kind of a standard to make Properties not throw exception and execute very fast (since they look like fields) and you should follow that while developing, but you can't really depend on that for external code that isn't a professional library. KSP has quite a few objects where you have to check for them being valid before accessing them. Another example is most of FlightGlobals static stuff, that you shouldn't use unless FlightGlobals.ready is set. As for EditorLogic, it is following a singleton pattern, so try checking .fetch property to check whether there is an actual instance those static shortcut can use (since there also is an non-static List<Part> getSortedShipList() ). Quote Link to comment Share on other sites More sharing options...
MrHappyFace Posted March 9, 2014 Share Posted March 9, 2014 How do i use Config.Load? whenever i use it to load a file at this path: L:/Games/KSP FULL/KSP Directory/KSP_0.23.0/GameData/ExoPlanet/StockSolarSystem/PluginData/Moho/Planet.cfg with the text in it: "recipient = Moho", it throws a NullPointerException Quote Link to comment Share on other sites More sharing options...
Diazo Posted March 10, 2014 Share Posted March 10, 2014 Okay, I'm now confused.if (EditorLogic.fetch != null) returns true, so my code continues. The very next lineif (EditorLogic.SortedShipList != null)then throws a NullRef exception.I am now at a loss as to what is going on here.I'll keep messing with it, but I'm not sure where to go from here.D. Quote Link to comment Share on other sites More sharing options...
xEvilReeperx Posted March 10, 2014 Share Posted March 10, 2014 Okay, I'm now confused.if (EditorLogic.fetch != null) returns true, so my code continues. The very next lineif (EditorLogic.SortedShipList != null)then throws a NullRef exception.Try adding a check to see if any parts exist. The game has special emphasis on a root part so I'd start thereif (EditorLogic.fetch != null && EditorLogic.startPod != null) Quote Link to comment Share on other sites More sharing options...
Diazo Posted March 10, 2014 Share Posted March 10, 2014 In messing around I hacked this together that will work for my purposes: public void Update() { try { if(EditorLogic.SortedShipList.Count >= 1) //throw nullref if it can't Count the list { ShipListOk = true; //List exists, we are good to go } } catch //NullRef! SortedShipList is not present { ShipListOk = false; //Stop running code } if (ShipListOk) //SortedShipLists exists? { if (EditorLogic.SortedShipList.First<Part>() != null) //check first part in list is not null (see post) { ShipListOk = true; } else { ShipListOk = false; } } if (ShipListOk) //all data needed is present, run the rest of my code { //run code } } } }There are two conditions I had to satisfy. First, when you load the editor, SortedShipList is in some weird uninitialized state that was throwing the NullRefs ealier, so we try/catch that.However, when you edit a ship and then remove all parts, there is a single Part left in SortedShipList even though there are no parts on screen. This single part is Null as expected however, so if(EditorLogic.SortedShipList.First<Part>() != null) works as expected here.If both conditions are satisfied, ShipListOk stays true and I run my code. If ShipListOk is false, skip all the rest of the code in the Update() event.D.edit@Evil: That's essentially what I did in adding the second condition check. I used a different second check then you did, but the logic is the same. Quote Link to comment Share on other sites More sharing options...
Diazo Posted March 10, 2014 Share Posted March 10, 2014 (edited) edit: Erm, I just realized you are trying Config.Load, not ConfigNode.Load. I'll leave my example as it also covers loading data from a file but it may not be exactly what you are looking for.How do i use Config.Load? whenever i use it to load a file at this path: L:/Games/KSP FULL/KSP Directory/KSP_0.23.0/GameData/ExoPlanet/StockSolarSystem/PluginData/Moho/Planet.cfg with the text in it: "recipient = Moho", it throws a NullPointerExceptionHere's a copy paste that works from my mod. This is all in Start()TWR1Node = ConfigNode.Load(KSPUtil.ApplicationRootPath + "GameData/Diazo/TWR1/TWR1.cfg"); //load .cfg fileTWR1KeyCodeString = TWR1Node.GetValue("TWR1Key"); //get the value of the TWR1Key valueSo if there was a single line in the TWR1.cfg file:TWR1Key = HelloWorldthe variable TWR1KeyCodeString would have a value of "HellowWorld".Note that anything you read in like this will be a string. You have to convert it to another format if you want an int, float, etc.Note you may have to addusing KSP.IOat the top in your dependencies as I think KSPUtil.ApplicationRootPath may be out of there.D. Edited March 10, 2014 by Diazo Quote Link to comment Share on other sites More sharing options...
Diazo Posted March 13, 2014 Share Posted March 13, 2014 Alright. This is a question about referring to data in a list, inside a class, inside a list.I'll lay out a specific example:AGXPart is a class with 2 properties, Part agxP and List<BaseAction> agBA.I then make a List<AGXPart> AGXVessel that holds all the parts on a vessel, and a list for each part of that part's baseactions.I then wanted to get the Name property of the first part in the list as a string to display.In pseudo code, I'm after something like this: "DisplayString" = AGXVessel.First(AGXPart.agxP.name);I'm currently working around it as follows (pseudo-code):AGXPart1 = AGXVessel.First();"DisplayString' = AGXPart1.agxP.name;but I'm pretty sure there should be a way to do this without having to instantiate an AGXPart object just to get the data string out.Any ideas?D. Quote Link to comment Share on other sites More sharing options...
Padishar Posted March 13, 2014 Share Posted March 13, 2014 (edited) In pseudo code, I'm after something like this: "DisplayString" = AGXVessel.First(AGXPart.agxP.name);I'm currently working around it as follows (pseudo-code):AGXPart1 = AGXVessel.First();"DisplayString' = AGXPart1.agxP.name;but I'm pretty sure there should be a way to do this without having to instantiate an AGXPart object just to get the data string out.Firstly, when you assign an object like this it actually only assigns the reference to the object, it doesn't create a new copy of the object.Second, you just have your expression a bit mixed up, you need:String name = AGXVessel.First().agxP.name;...though, actually, your other solution is better as it enables you to test if First() returned an object (if the list is empty it would return null and you would get an exception). If you've already tested if the list is not empty then you can safely use the shortcut version... Edited March 13, 2014 by Padishar Quote Link to comment Share on other sites More sharing options...
Faark Posted March 13, 2014 Share Posted March 13, 2014 I'm not 100% sure what your problem is. If you are designing classes, there isn't any problem with designing a simple "tree" structure similar to KSP (pseudo-example, KSP is ofc a little more complicated):class FlightGlobals{ public static List<Vesel> Vessels;}class Vessel{ public List<Part> Parts;}class Part{ public String Name;}UnityEngine.Debug.Log(FlightGlobals.Vessels[1337].Parts.First().Name);What i don't understand is "without an instance". The only way to store a string in an class is via an instance or a static var.Ofc you could write all into a single line: AGXVessel.Parts.First().Name (yours looks a little odd, btw) Quote Link to comment Share on other sites More sharing options...
Padishar Posted March 13, 2014 Share Posted March 13, 2014 Storing references to core game objects (e.g. Part) across calls to your plugin (or for use by a background thread) is dangerous as you can't be sure that the core game engine doesn't change the objects between the calls. E.g. what would happen if a Part you have a reference to is removed from the rocket (e.g. the user stages or something blows up on your craft) and your code goes on to treat it as still being a part of the ship then unexpected things will happen. I have been modifying the KER vessel simulation code to avoid such problems, mainly by creating my own data structures for the background thread to use so it doesn't have to access any core game data when it might be changing... Quote Link to comment Share on other sites More sharing options...
Diazo Posted March 13, 2014 Share Posted March 13, 2014 (edited) @Padishar: That you for that. Also the tidbit about the way I listed allows for testing if the object exists is something I'll keep in mind.@Faark: Oops, I think I used instance the wrong way. From my previous post on the line "AGXPart1 = AGXVessel.First();" I was meaning the creation of the AGXPart1 object(reference?) which I felt was an extra step I did not need.Thank you for the tip about the nested classes though, I will sit down and see if that would work better for me. However because I'm working with lists of Classes defined by KSP and not by me I'll have to see if I want to change my data structure.This gives me lots of things to look into tonight, we'll see what I can find.D.edit: I can confirm String name = AGXVessel.First().agxP.name; works exactly as advertised. Edited March 14, 2014 by Diazo Quote Link to comment Share on other sites More sharing options...
notfirestorm Posted March 15, 2014 Share Posted March 15, 2014 Hey all, I'm running into a problem I thought would be simple to solve. I want to try to grab all the resource types a vessel might have / have storage for. I thought vessel.GetActiveResources() would give me what I wanted, but it only gives me resources that flow everywhere (stuff like ElectricCharge & MonoPropellent, but not LiquidFuel or Oxidizer). Here's the code I used: GUILayout.BeginVertical(); foreach (Vessel.ActiveResource resource in vessel.GetActiveResources()) { GUILayout.BeginHorizontal(); GUILayout.Label(resource.info.name); GUILayout.EndHorizontal(); } GUILayout.EndVertical();Y'all have any insights or suggestions? Quote Link to comment Share on other sites More sharing options...
stupid_chris Posted March 15, 2014 Share Posted March 15, 2014 Hey all, I'm running into a problem I thought would be simple to solve. I want to try to grab all the resource types a vessel might have / have storage for. I thought vessel.GetActiveResources() would give me what I wanted, but it only gives me resources that flow everywhere (stuff like ElectricCharge & MonoPropellent, but not LiquidFuel or Oxidizer). Here's the code I used: GUILayout.BeginVertical(); foreach (Vessel.ActiveResource resource in vessel.GetActiveResources()) { GUILayout.BeginHorizontal(); GUILayout.Label(resource.info.name); GUILayout.EndHorizontal(); } GUILayout.EndVertical();Y'all have any insights or suggestions?I believe ActiveResources are exactly that, resources currently being used in the ship. If you want the list of resource storage, you need to loop through the parts, like this: private List<PartResource> GetResources() { return new List<PartResource>(this.vessel.Parts.SelectMany(p => p.Resources.list).GroupBy(r => r.resourceName).Select(g => g.First())); }That is using linq is you're comfortable with it. A more conventional way to do it would be like this. private List<PartResource> GetResources() { List<PartResource> resources = new List<PartResource>(); foreach (Part part in this.vessel.Parts) { foreach (PartResource resource in part.Resources) { if (!resources.Contains(resource)) { resources.Add(resource); } } } return resources; }then you can use the same code as before (nearly) to show labels private void ShowResources() { GUILayout.BeginVertical(); foreach (PartResource resource in GetResources()) { GUILayout.BeginHorizontal(); GUILayout.Label(resource.resourceName); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } Quote Link to comment Share on other sites More sharing options...
notfirestorm Posted March 15, 2014 Share Posted March 15, 2014 I believe ActiveResources are exactly that, resources currently being used in the ship. If you want the list of resource storage, you need to loop through the parts, like this:Thanks for the info and code. It does seem odd though that ActiveResources() always seems to return resources on the vessel that flow everywhere, whether they're in use or not. Looping through the parts to get the storage does seem a more reliable way of getting resources, so I'll go with that. Thanks again. Quote Link to comment Share on other sites More sharing options...
microsoftenator Posted March 18, 2014 Share Posted March 18, 2014 I'm trying to figure out how ModuleEnginesFX works (in the context of plugins). In particular how their sound works. When I try to get the AudioSource for the RAPIER, I get one with the clip property set to null, which doesn't seem right. Quote Link to comment Share on other sites More sharing options...
Padishar Posted March 18, 2014 Share Posted March 18, 2014 This is probably because rapiers have two ModuleEnginesFX modules (or possibly more, but definitely at least two). There is also a MultiModeEngine module which has members that specify which one is active (the KER plugin reads MultiModeEngine.mode and then looks for the ModuleEnginesFX whose engineID member matches the mode). Quote Link to comment Share on other sites More sharing options...
oakwhiz Posted March 20, 2014 Share Posted March 20, 2014 Does anybody know if it is possible to spawn a single part as a new vessel in orbit, through the tracking station?It seems almost impossible to simply create a new vessel through the API. Quote Link to comment Share on other sites More sharing options...
Diazo Posted March 20, 2014 Share Posted March 20, 2014 Alright.How should I go about saving data when I am in the VAB/SPH?I have not been able to get a Save or OnSave to work and reading the documentation I believe those are in the PartModule only. OnDestroy kind of works and is where I was running my save routine.The problem with that is that the OnDestroy in KSP.exe does not pause and so saving in OnDestroy works for a few items as they process fast, but with how much data my mod is saving, objects were being destroyed before I could save them.I've switched to a mouse detection method where I save if the mouse is over the Save/Launch/Exit buttons in the top right of the screen which works 100% of the time, but I know there are mods out there that allow you to exit the editor in other ways.Does anyone know of any sort of trigger equivalent to the partModule's OnSave method for the editor?If not, the two options I can think of are something like a 15 second timer, but I'm worried on ships with hundreds of parts this will be a noticeable hiccup that will quickly get annoying.The other option is to move to using the PartModule's OnSave, but I have to calculate my value before saving and I'd rather calculate it once and then save it to each part from the editor (as I'm currently trying to do) instead of having each PartModule calculate the same value to save each each time the save method is called.Anyone have thoughts on this?D. Quote Link to comment Share on other sites More sharing options...
DMagic Posted March 20, 2014 Share Posted March 20, 2014 (edited) Alright.How should I go about saving data when I am in the VAB/SPH?You just need to run some code when you exit the VAB/SPH right? Is there a GameEvent that will work for this? Maybe GameEvents.onGameSceneLoadRequested; add a check to see if you're still in the editor if you don't want it work anywhere else. Or will that have the same problem as your OnDestroy issue?Edit:Another question. Does anyone know how, or if it's possible, to get the degree symbol (°) to show in the right click menu? Using a KSPField I can get it to show a string, and update that string, but all of my attempts to add the degree symbol fail. I have tried directly adding it to the string with alt+0176 or alt+248, I have also tried using the UTF-8 hex code \0xB0, and other variations on that. Everything displays only a blank spot in the end, there are no errors and the rest of the string is fine, just nothing is displayed where the symbol is supposed to be. I am compiling with UTF-8.Edit 2: Directly adding the symbol to a string works fine for writing to the debug window, the hex code doesn't though. So it seems this is an issue with the right-click menu specifically. Edited March 20, 2014 by DMagic Quote Link to comment Share on other sites More sharing options...
Diazo Posted March 20, 2014 Share Posted March 20, 2014 That is a line of thought for me to follow. I had not tried that one.The other thought I've had since my last post was to do it in the PartModule's OnSave, but simply make a method call to a method in my editor code that has a 3 second timer.So the first part on the ship calls the save method, my values are calculated and saved both to the part and a local variable, then the second part calls the save method, but because it is within 3 seconds, the save method just passes the local variables back without doing all the calculations again.My only worry with that is that the parts with call OnSave in parallel, not in series, so I have the calculations being performed for each part all at the same time, which is even worse from a performance perspective.D. Quote Link to comment Share on other sites More sharing options...
Faark Posted March 20, 2014 Share Posted March 20, 2014 (edited) The other option is to move to using the PartModule's OnSave, but I have to calculate my value before saving and I'd rather calculate it once and then save it to each part from the editor (as I'm currently trying to do) instead of having each PartModule calculate the same value to save each each time the save method is called.Keep it simple, especially for the first test release. Couldn't you just combine all of the current parts AG assignments into a single string? Kinda like struts do...I don't see how else you could save data into a ShipConstruct and thus a .craft file. A dummy part might work as well, but would make even more problems when removing your mod.ps: Are you sure your problems are Multi-Threading related? Would surprise me. Can't await to inspect your code for details Edited March 20, 2014 by Faark 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.