WaveFunctionP Posted May 5, 2015 Share Posted May 5, 2015 (edited) I'm looking through some sciencedata in a foreach loop, and for some reason or the other, it stopped working after docking.foreach (ScienceData data in FlightGlobals.ActiveVessel.FindPartModulesImplementing<ModuleScienceContainer>().First().GetData()) // search through all the data we have collected onboard to check if we've collected it already { isincontainer = false; Debug.Log(data.subjectID + currentScienceSubject.id); if (currentScienceSubject.id == data.subjectID) // we already have this data in our container, so we skip it {#if DEBUG Debug.Log("[For Science] Skipping: Found existing experiment data: " + currentScienceSubject.id); isincontainer = true; break;#endif } }I check in several places, but I don't think that FlightGlobals.ActiveVessel.FindPartModulesImplementing<ModuleScienceContainer>().First().GetData() is returning a value to iterate through after docking.I can run a crew report and store it and it will start working. It is just wierd, and I figure its some obscurity of object references that i don't understand or something, but i tried it a bunch of different ways. I'm made a new arrays, tried calling the object before the loop.To be clear, it works fine before docking, and while it is docked, but stops working after undocking on the vessel with no data (the data is transferred to one single container during docking). And debug log of the object says sciencedata as expected, but I get no errors whatsoever, so I don't know what else to inspect or how to try and figure it out.Here's the relevant transfer code.private void TransferScience() { if (ActiveContainer().GetActiveVesselDataCount() != ActiveContainer().GetScienceCount()) // only actually transfer if there is data to move to active container {#if DEBUG Debug.Log("[For Science] Tranfering science to container.");#endif ActiveContainer().StoreData(GetExperimentList().Cast<IScienceDataContainer>().ToList(), true); // this is what actually moves the data to the active container List<ModuleScienceContainer> containerstotransfer = GetContainerList(); // a temporary list of our containers containerstotransfer.Remove(ActiveContainer()); // we need to remove the container we storing the data in because that would be wierd and buggy ActiveContainer().StoreData(containerstotransfer.Cast<IScienceDataContainer>().ToList(), true); // now store all data from other containers } }Yes, I talk to myself a lot in my code. Edited May 5, 2015 by WaveFunctionP Quote Link to comment Share on other sites More sharing options...
Diazo Posted May 5, 2015 Share Posted May 5, 2015 Hmmm, the first oddity that jumps out at me is this line:foreach (ScienceData data in FlightGlobals.ActiveVessel.FindPartModulesImplementing<ModuleScienceContainer>().First().GetData())You are only looking at the .GetData() in the "first" ModuleScienceContainer on the vessel.Then when you dock, the "first" ModuleScienceContainer is now a different module in actuality but because your code has no way to look at different modules, it can no longer find the data.Would need some testing to prove that, but it is a place to start.D. Quote Link to comment Share on other sites More sharing options...
WaveFunctionP Posted May 5, 2015 Share Posted May 5, 2015 (edited) Hmmm, the first oddity that jumps out at me is this line:foreach (ScienceData data in FlightGlobals.ActiveVessel.FindPartModulesImplementing<ModuleScienceContainer>().First().GetData())You are only looking at the .GetData() in the "first" ModuleScienceContainer on the vessel.Then when you dock, the "first" ModuleScienceContainer is now a different module in actuality but because your code has no way to look at different modules, it can no longer find the data.Would need some testing to prove that, but it is a place to start.D.I just tried iterating a foreach loop through all the containers and the result was the same behavior.foreach (ModuleScienceContainer container in GetContainerList()) { foreach (ScienceData data in container.GetData()) // search through all the data we have collected onboard to check if we've collected it already { isincontainer = false; if (currentScienceSubject.id == data.subjectID) // we already have this data in our container, so we skip this experiment {#if DEBUG Debug.Log("[For Science] Skipping: Found existing experiment data: " + currentScienceSubject.id); isincontainer = true; // if this never goes off, this flag is used to actually fire off the experiment break;#endif } } }There are only two modulesciencecontainers between the two ships that I'm testing with. When I undock, the first one the list SHOULD be the only one on the list. I think. When I dock, it seems a random pod is chose to be at the top of the part tree and so it seem random which pod will get chosen, but still, only ever one pod get the data. And the pod with the data is the only one that continues to collect data properly. (wild guess inc!) I don't think that getdata()'s ScienceData[] object is getting reinitialized properly for the module after the data is removed, and I don't know how to force initialization.edit:Here's the error I get if I try to access the first data in the sciencedata array when the problem is occurring.InvalidOperationException: Operation is not valid due to the current state of the object at System.Linq.Enumerable.First[scienceData] (IEnumerable`1 source) [0x00000] in <filename unknown>:0 at ForScience.ForScience.RunScience () [0x00000] in <filename unknown>:0 at ForScience.ForScience.Update () [0x00000] in <filename unknown>:0 And ofcourse, it works fine as soon as i run a report and put some data into the container. Edited May 5, 2015 by WaveFunctionP Quote Link to comment Share on other sites More sharing options...
DMagic Posted May 5, 2015 Share Posted May 5, 2015 How does the GetContainerList method work? It seems there is still a First() in there somewhere. You should probably never use First() on something that may have no elements, use FirstOrDefault() then check if the return is null. Quote Link to comment Share on other sites More sharing options...
udk_lethal_d0se Posted May 5, 2015 Share Posted May 5, 2015 Hey DMagic,I ended up doing it this way with some reference to the code you provided, thanks again.private int GetActiveFactoryCount(Vessel v){ int c = 0; var factories = from pref in v.protoVessel.protoPartSnapshots where pref.modules.Any(a => a.moduleName == "KSP_Factory") select pref; if (factories.Count() != 0) { foreach (var p in factories) { ConfigNode node = p.modules[0].moduleValues; if (node.HasValue("isActive")) { if (bool.Parse(node.GetValue("isActive"))) { c++; } } } } return c;} Quote Link to comment Share on other sites More sharing options...
WaveFunctionP Posted May 5, 2015 Share Posted May 5, 2015 (edited) How does the GetContainerList method work? It seems there is still a First() in there somewhere. You should probably never use First() on something that may have no elements, use FirstOrDefault() then check if the return is null.GetContainerList() just returns FlightGlobals.ActiveVessel.FindPartModulesImplementing<ModuleScienceContainer>().First().GetData()I've tried FlightGlobals.ActiveVessel.FindPartModulesImplementing<ModuleScienceContainer>()[0].GetData() as well as checking for null.I just ended up skipping then container check with getstoreddata() == 0, and flagging to run the experiments.edit: The firstordefault thing is new to me, thanks for the tip.edit edit: I just tried the firstordefault and i'm finally getting null errors. That works like a charm! Edited May 5, 2015 by WaveFunctionP Quote Link to comment Share on other sites More sharing options...
DMagic Posted May 5, 2015 Share Posted May 5, 2015 What you need is something like:var containers = FlightGlobals.ActiveVessel.FindPartModulesImplementing<ModuleScienceContainer>();foreach (var container in containers){if (container == null)continue;var data = container.GetData(); }containers will be an IEnumerable with all of the ModuleScienceContainers in the vessel. You can just check each of them for data. Quote Link to comment Share on other sites More sharing options...
WaveFunctionP Posted May 5, 2015 Share Posted May 5, 2015 (edited) What you need is something like:var containers = FlightGlobals.ActiveVessel.FindPartModulesImplementing<ModuleScienceContainer>();foreach (var container in containers){if (container == null)continue;var data = container.GetData(); }containers will be an IEnumerable with all of the ModuleScienceContainers in the vessel. You can just check each of them for data.I could probably clean my logic up quite a bit with switch, continue and break in general. But after finding out the issue with nulls, I've been able to simplify that particular portion quite a bit with methods that I've tried but failed at before. This is the full method now.private void RunScience() { if (GetExperimentList() == null) {#if DEBUG Debug.Log("[For Science] GetExperiment() was null.");#endif } else { completedExperiments.Clear(); // clear our list of experiments that have been run so we start with a fresh list. foreach (ModuleScienceExperiment currentExperiment in GetExperimentList()) { var fixBiome = string.Empty; // some biomes don't have 4th string, so we just put an empty in to compare strings later if (currentExperiment.experiment.BiomeIsRelevantWhile(currentSituation())) fixBiome = currentBiome();// for those that do, we add it to the string // we build the current string to check against the available experiements var currentScienceSubject = ResearchAndDevelopment.GetExperimentSubject(currentExperiment.experiment, currentSituation(), currentBody(), fixBiome);// << squad's fancy string builder. ikr!, with all this work, we pretty much did all the work already // and we check the value to see if it is worth running var currentScienceValue = ResearchAndDevelopment.GetScienceValue(currentExperiment.experiment.baseValue * currentExperiment.experiment.dataScale, currentScienceSubject);#if DEBUG Debug.Log("[For Science] Checking experiment: " + currentScienceSubject.id);#endif if (completedExperiments.Contains(currentExperiment)) // do we have the same experiment onboard? {#if DEBUG Debug.Log("[For Science] Skipping: Experiment duplicate detected.");#endif } else if (!currentExperiment.rerunnable & !IsScientistOnBoard()) // no cheating goo and materials here {#if DEBUG Debug.Log("[For Science] Skipping: Experiment is not repeatable.");#endif } else if (!currentExperiment.experiment.IsAvailableWhile(currentSituation(), currentBody())) // this experiement isn't available here so we skip it {#if DEBUG Debug.Log("[For Science] Skipping: Experiment is not available for this situation/atmosphere.");#endif } else if (currentScienceValue == 0) // this experiment has little value so we skip it {#if DEBUG Debug.Log("[For Science] Skipping: No more science is available: ");#endif } else { ScienceData newdata = new ScienceData( currentExperiment.experiment.baseValue * currentScienceSubject.dataScale, currentExperiment.xmitDataScalar, 0f, currentScienceSubject.id, currentScienceSubject.title ); if (ActiveContainer() == null || !ActiveContainer().HasData(newdata)) {#if DEBUG Debug.Log("[For Science] Running experiment: " + currentScienceSubject.id);#endif //manually add data to avoid deployexperiment state issues ActiveContainer().AddData(newdata); //} } completedExperiments.Add(currentExperiment); // add this to the list of experiments to check for duplicates earlier in the runscience logic } } } } Edited May 5, 2015 by WaveFunctionP Quote Link to comment Share on other sites More sharing options...
parachutingturtle Posted May 6, 2015 Share Posted May 6, 2015 I have no idea how it would be done code-wise, but you could set the vessel to be unowned (like asteroids). I think there's a parameter for that in VESSEL{} in persistent.sfsthanks, but i've tried setting the vessel's discovery info to unowned (vessel.DiscoveryInfo.SetLevel(DiscoveryLevels.Unowned)), that doesn't help much, I can still switch to it via the map view or the key that switches between nearby vessels. Quote Link to comment Share on other sites More sharing options...
jandcando Posted May 7, 2015 Share Posted May 7, 2015 I have noticed that in the new resource definitions, there is a value called "hsp." My only guess as to what it does is that it has something to do with the heat capacity of the part that contains it. If someone knows what it does, please correct me.Also, I was looking at Ore.cfg in the Squad Resources folder, and I was wondering if there are other places to define resources. In the config, global definitions, planetary definitions, and biome definitions were made. Is there a way to do atmospheric ones?And about the tech tree- I have heard that I can use ModuleManager to add new nodes to the tree, kind of like what techManager used to do. If this is right, how do I go about doing it? Quote Link to comment Share on other sites More sharing options...
greystork Posted May 8, 2015 Share Posted May 8, 2015 (edited) Apologies in advance if this has been posted before. I am fiddling with a parts pack and am getting this error when my part model is loaded, and am wondering if anyone has seen it before and knows the remedy:File error:Failed to read past end of stream. at System.IO.BinaryReader.ReadByte () [0x00000] in <filename unknown>:0 at System.IO.BinaryReader.Read7BitEncodedInt () [0x00000] in <filename unknown>:0 at System.IO.BinaryReader.ReadString () [0x00000] in <filename unknown>:0 at A..ReadTextures (System.IO.BinaryReader br, UnityEngine.GameObject o) [0x00000] in <filename unknown>:0 at A..ReadChild (System.IO.BinaryReader br, UnityEngine.Transform parent) [0x00000] in <filename unknown>:0 at A.. (.UrlFile ) [0x00000] in <filename unknown>:0 (Filename: C:/buildslave/unity/build/artifacts/StandalonePlayerGenerated/UnityEngineDebug.cpp Line: 56)Model load error in 'C:\Program Files (x86)\Kerbal Space Program\GameData\BAE\Parts\Engines\BAEengine5mB1\BAEengine5mB1.mu'Thanks in advance!EDIT: Nevermind, I figured it out: just don't try to use DDS textures when you're exporting things from Unity. Edited May 10, 2015 by greystork Quote Link to comment Share on other sites More sharing options...
Adamantium9001 Posted May 8, 2015 Share Posted May 8, 2015 How do I add a new piece of data to the list of things that the game stores in persistent.sfs? Specifically, I want to keep track of what the in-game time was when certain events occurred, so I'm looking for something like this:CurrentGame.SetPersistentData("myTimestamp", Planetarium.GetUniversalTime()); //function I wish existed. Suppose UT is 100 hereUnityEngine.Debug.Log(CurrentGame.GetPersistentData("myTimestamp")); //would print "100"// -- user saves the game --// -- time passes --CurrentGame.SetPersistentData("myTimestamp", Planetarium.GetUniversalTime()); //Suppose UT is 200 hereUnityEngine.Debug.Log(CurrentGame.GetPersistentData("myTimestamp")); //would print "200"// -- user reloads last save --UnityEngine.Debug.Log(CurrentGame.GetPersistentData("myTimestamp")); //would print "100" Quote Link to comment Share on other sites More sharing options...
parachutingturtle Posted May 9, 2015 Share Posted May 9, 2015 How do I add a new piece of data to the list of things that the game stores in persistent.sfs? Specifically, I want to keep track of what the in-game time was when certain events occurredThe way of doing this would depend on wether you're writing a custom part (inherit from PartModule) or a plugin (inherit from MonoBehaviour). But in any case, you can't control when the game will be saved, so you'll need to store that time in a variable first, and set the persistent data whenever saving occurs.If you're in a plugin, you can do it something like this:void Start(){ GameEvents.onGameStateSave.Add(new EventData<ConfigNode>.OnEvent(OnSave)); GameEvents.onGameStateLoad.Add(new EventData<ConfigNode>.OnEvent(OnLoad)); //(...) other startup code here}private void OnSave(ConfigNode node){ node.RemoveValues("MyCustomDataKey"); node.AddValue("MyCustomDataKey", "my saved data here (serialized)");}private void OnLoad(ConfigNode node){ string[] vals = node.GetValues("MyCustomDataKey"); if (vals.Length > 0) { string loadedData = vals[0]; //do whatever you want with the loaded data here (deserialize, etc.) }} If you're in a PartModule, you just need to have a KspField (preferably a string or a number type), and store your value in that.Set it up like this:[KSPField(guiActive = false, isPersistant = true)]public string MyStoredData; Quote Link to comment Share on other sites More sharing options...
Adamantium9001 Posted May 9, 2015 Share Posted May 9, 2015 (edited) If you're in a plugin, you can do it something like this:THANK YOU! Follow-up:private void OnSave(ConfigNode node){ node.RemoveValues("MyCustomDataKey"); node.AddValue("MyCustomDataKey", "my saved data here (serialized)");}Am I correct in guessing that the "node" variable here is a ConfigNode containing the entire save file? If so, would it be best practice to do something like this instead?private void OnSave(ConfigNode node){ node.RemoveValues("MyModName"); ConfigNode data = new ConfigNode(); data.name = "MyModName"; data.AddValue("K1", "V1"); data.AddValue("K2", "V2"); node.SetNode("MyModName", data);}And am I even using those functions properly? Friggin' shoddy documentation...Edit: or maybe it would be better to do it this way?private void OnSave(ConfigNode node){ ConfigNode data = new ConfigNode(); data.name = "MyModName"; data.AddValue("K1", "V1"); data.AddValue("K2", "V2"); node.RemoveNode("MyModName"); node.AddNode(data);} Edited May 9, 2015 by Adamantium9001 Quote Link to comment Share on other sites More sharing options...
jandcando Posted May 10, 2015 Share Posted May 10, 2015 I hope I don't sound like I'm nagging, but does anyone have any answers to the questions I asked earlier? I feel overlooked... Quote Link to comment Share on other sites More sharing options...
parachutingturtle Posted May 10, 2015 Share Posted May 10, 2015 @Adamantium9001: I guess your last example would be fine, but I haven't actually tried that kind of thing yet. You can test it easily though, and see if the save file contains what you want it to contain.I hope I don't sound like I'm nagging, but does anyone have any answers to the questions I asked earlier? I feel overlooked...I can't help you with that. I feel like this thread is the best place to get overlooked. If it's important, why don't you make a separate thread for it? Quote Link to comment Share on other sites More sharing options...
Diazo Posted May 10, 2015 Share Posted May 10, 2015 (edited) @janecondo: I try to not post unless I have a decent answer, but maybe my speculation can at least point you in the right direction in this case.hsp: No clue. To check if it is heat, grab a heat shield and see what it's RESOURCES are. Checking the PART.cfg might be enough, or you might have to use a pluging to monitor the RESROUCES on the part in-game in real time.atmospheric resource: This is possible but no clue how to do it. I'd start by finding the definition for OXYGEN on Kerbin and see if that works for you. If OXYGEN is a special case and not really a resource, you'd probably be looking at a plug-in of some sort to return resource calls looking for atmosphere.Tech tree: Yes, the tree in KSP 1.0 is now ModuleManager configurable. I have no clue on the syntax needed, but check out the Tech Tree changing mods, I assume those would have reference code you could use. (There are two or three of those mods out there.)Hopefully that at least points you in the right direction.I can't help you with that. I feel like this thread is the best place to get overlooked. If it's important, why don't you make a separate thread for it?This thread is for smaller questions that can be answered in a post, you are unlikely to get more then a couple line answer. For janecondo's questions, this is probably the right place for them.If you have a more complex question, especially once you start posting example code, that is probably worth starting a thread for. It varies from person to person a lot of course, but that is how I see it.D. Edited May 10, 2015 by Diazo Quote Link to comment Share on other sites More sharing options...
NathanKell Posted May 10, 2015 Share Posted May 10, 2015 hsp is the mass specific heat of the resource, in kJ/tonne-K. Quote Link to comment Share on other sites More sharing options...
jandcando Posted May 10, 2015 Share Posted May 10, 2015 hsp is the mass specific heat of the resource, in kJ/tonne-K.Thanks. Quote Link to comment Share on other sites More sharing options...
udk_lethal_d0se Posted May 11, 2015 Share Posted May 11, 2015 Hey all,When leaving focus of a ship that's consuming/generating resources, where is the data stored when KSP processes background consumption. Example would be leaving a harvester mining for ore and changing back to the ship later, noting that the resource has been generated further. Quote Link to comment Share on other sites More sharing options...
Diazo Posted May 11, 2015 Share Posted May 11, 2015 I do not believe stock KSP does this.Try looking into the Background PRocessing mod (I think that was the name.)D. Quote Link to comment Share on other sites More sharing options...
NathanKell Posted May 11, 2015 Share Posted May 11, 2015 Correct, KSP does not process background resource changes. Some mods like TACLS (and IIRC the new stock ISRU) will calculate time-since-you-were-last-here and produce/consume resources all at once based on that time, but for as-time-passes background you need a mod like Background Processing. Quote Link to comment Share on other sites More sharing options...
mrsolarsail Posted May 12, 2015 Share Posted May 12, 2015 I'm developing a plugin to help plan flights by solar sail, and I could use some help. The main thread is here: http://forum.kerbalspaceprogram.com/threads/119579-WIP-1-0-2-SolarSailNavigator-v1-0-1-alphaI am currently showing a preview in map mode of the future trajectory using the LineRender, but I'd like something nicer - and constant screen width - like the normal orbit lines in map mode. Is there a good, clear example showing how to do this?Additionally, I want to render small meshes (e.g. squares) to show the sail attitude along the trajectory in map mode, but again, I'm having trouble finding some clear examples. Does anyone have suggestions?Thanks. Quote Link to comment Share on other sites More sharing options...
Niven Posted May 13, 2015 Share Posted May 13, 2015 Does anyone have any idea for an easy way to check if service/cargo bay doors are open/closed? For landing legs & solar panels I just used FindPartModulesImplementing to find each part and then looped through checking the state (legState/StateString), but <ModuleCargoBay> doesn't seem to have any state/status/etc value I can find. Quote Link to comment Share on other sites More sharing options...
TheKutKu Posted May 13, 2015 Share Posted May 13, 2015 (edited) Hi! I would like to know if i can use unity 4.6.5 to make a mod, because the ksp modding tutorial says i have to install a 4.3 version Edited May 13, 2015 by TheKutKu 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.