Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

Oh, then its clear why i didn't find it. :D

Jep i also tried using the .SpawnEVA(Kerbal) Method but it had the same result.

I saw the .removeCrewMember in another thread and tried it out but you are right, the Kerbal is removed by the .SpawnEVA(Kerbal) and this call is not needed.

Another difference i saw in your code was that you were getting the reference to the Kerbal in another way. I tried this out too but still the same error. :(

I just out of curiosity added a counter variable in the Update() method and ejected the Kerbal when it reached 50.

This strangely worked like i wanted. But to be honest i don't want to make it work this way. It is too hacky and error-prone...

Update:

I narrowed it down, it works as intended when it is executed after the third call of Update()...

Edited by Nils277
Link to comment
Share on other sites

Ugh, loading race condition.

The issue you are hitting is that the Update() starts executing before everything is loaded.

As you are talking about running in Start(), for flight mode only you can check the FlightGlobals.holdPhysics bool, that bool only goes true once everything is loaded and the physics system kicks in.

Note that this bool goes false when non-phyics timewarp is engaged as well.

This race condition exists in other scenes also, but I'm not aware of anything you can check in those scenes to know that everything is loaded.

D.

Link to comment
Share on other sites

I was afraid it had to do with race-contitions. There wouldn't be many other reasons for that behaviour.

But i think i have found the solution for that problem. One must register for the GameEvents.onFlightReady event. This is fired once the vessel is fully loaded. When waiting for the event to eject the Kerbals it runs as it should.

Thanks for the help :)

Edited by Nils277
Link to comment
Share on other sites

I was afraid it had to do with race-contitions. There wouldn't be many other reasons for that behaviour.

But i think i have found the solution for that problem. One must register for the GameEvents.onFlightReady event. This is fired once the vessel is fully loaded. When waiting for the event to eject the Kerbals it runs as it should.

Thanks for the help :)

I just do this at the top of update or fixed update to handle load race conditions.


[TABLE="class: highlight tab-size js-file-line-container"]
[TR]
[TD="class: blob-code blob-code-inner js-file-line"][COLOR=#A71D5D]if[/COLOR] (Time.timeSinceLevelLoad < [COLOR=#0086B3]2.0f[/COLOR]) [COLOR=#969896]// Check not loading level
[/COLOR]{
[COLOR=#969896] return;
}
[/COLOR]
[/TD]
[/TR]
[/TABLE]

Link to comment
Share on other sites

Need some help.

I want to do something when any Vessel (not the ActiveVessel) is unloaded from physics range, but unfortunately neither GameEvents.onVesselDestroy nor GameEvents.onVesselGoOnRails seem to fire in this case, although I can see "xxxVesselNamexxx Unloaded" in the logs. Is it the intended behaviour or am I missing something? I really don't want to check whether the loaded vessel count changed in every FixedUpdate, but this might be my solution.

Link to comment
Share on other sites

I think the "Pack" events are what you need to look at?

I toyed with this myself a bit and ended up using a different method without hooking into game events though so I'm not 100% sure.

I do know that .onVesselGoOn/OffRails fires when physics turns on/off, so non-physcis time warp is what usually triggers this event, but that doesn't actually answer your question.

D.

Link to comment
Share on other sites

I think the "Pack" events are what you need to look at?

I toyed with this myself a bit and ended up using a different method without hooking into game events though so I'm not 100% sure.

I do know that .onVesselGoOn/OffRails fires when physics turns on/off, so non-physcis time warp is what usually triggers this event, but that doesn't actually answer your question.

D.

Thank you, will look around more but for now I've ended up with this crude code:


private void FixedUpdate()
{
//because OnVesselDestroy and OnVesselGoOnRails seem to only work for active vessel I had to build this stupid workaround
if(HighLogic.LoadedSceneIsFlight)
{
if(FlightGlobals.Vessels.Count(v => v.loaded) != loadedVesselCounter)
{
RebuildServoGroups ();
loadedVesselCounter = FlightGlobals.Vessels.Count(v => v.loaded);
}
}
}

Link to comment
Share on other sites

I'm having issues getting started, and it's probably something dumb that doesn't warrant its own thread...

I'm using VS2010, and I'm trying to set it up so I can debug stuff properly. I copied the win32_development\player_win.exe file (from Unity 4.6.4) and renamed it KSP.exe. If I start the program, I get the splash screen, with the random text hints changing every few seconds, but no progress bar. It seems to be stuck there indefinitely, and the log is getting spammed with this:

[LOG 00:40:27.889] [KSP Version]: 1.0.4.861 (WindowsPlayer) ====================================
Kerbal Space Program - 1.0.4.861 (WindowsPlayer)




OS: Windows 7 Service Pack 1 (6.1.7601) 64bit
CPU: AMD FX(tm)-8350 Eight-Core Processor (8)
RAM: 16345
GPU: NVIDIA GeForce GTX 970 (3072MB)
SM: 30 (Direct3D 9.0c [nvd3dum.dll 9.18.13.4752])
RT Formats: ARGB32, Depth, ARGBHalf, RGB565, Default, DefaultHDR, ARGBFloat, RGFloat, RGHalf, RFloat, RHalf, R8




Log started: Thu, Jul 30, 2015 00:40:27




[EXC 00:40:27.905] ArgumentException: get_isPlaying can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
InputDevices..ctor ()
GameSettings..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for GameSettings
[EXC 00:40:27.908] ArgumentException: PropertyToID can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
HighLogic..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for HighLogic
[EXC 00:40:27.911] ArgumentException: get_isPlaying can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
InputDevices..ctor ()
GameSettings..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for GameSettings
[EXC 00:40:27.914] ArgumentException: get_isPlaying can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
InputDevices..ctor ()
GameSettings..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for GameSettings
[EXC 00:40:27.921] ArgumentException: PropertyToID can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
PhysicsGlobals..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for PhysicsGlobals
[EXC 00:40:27.966] ArgumentException: PropertyToID can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
HighLogic..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for HighLogic
[EXC 00:40:27.972] ArgumentException: get_isPlaying can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
InputDevices..ctor ()
GameSettings..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for GameSettings
[EXC 00:40:27.975] ArgumentException: get_isPlaying can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
InputDevices..ctor ()
GameSettings..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for GameSettings
[EXC 00:40:27.987] ArgumentException: get_isPlaying can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
InputDevices..ctor ()
GameSettings..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for GameSettings
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
LoadingScreen:Start()
[EXC 00:40:28.074] ArgumentException: get_isPlaying can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
InputDevices..ctor ()
GameSettings..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for GameSettings
[EXC 00:40:28.103] ArgumentException: PropertyToID can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
HighLogic..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for HighLogic

And it goes on forever... hundreds of thousands of lines of that, over and over.

I don't even have a mod added yet. The original KSP.exe still works fine on that install, which is a copy-paste of my Steam install (with all the mods and savegames removed). It also works fine with the non-development player_win.exe file.

Any ideas on what I'm doing wrong? Do the debug version require some SDK I would be missing?

Edited by Samapico
Formatting
Link to comment
Share on other sites

If you're just getting started, you can use the normal KSP.exe with no changes and it'll probably be easier (less work to build a new version). It does sound like you haven't run the patcher which is probably your problem

I'm just getting started with KSP modding, but I have experience with Visual Studio, and I'd feel pretty lost if I can't put breakpoints everywhere :P And it only needs a nice post-build event to make everything pretty easy for each build.

And YES, that was it! Thank you, kind sir. I missed the link on the first line of that post, for some reason...

Link to comment
Share on other sites

Hello I am looking to update/change a plugin or personal use and am looking for some advice as I am an noob to coding.

The mod is here. The changes I want to make are these.

* I want the plugin to use Nitrogen gas from RealFuels

* On Eva I want to subtract 500 liters of N2 gas. If there is any less than that I want to divide the actual amount by 500 and use this ratio to fill the kerbals Evapropellant to the same ratio

* On boarding I want to subtract all the Evaprop and divide the remainder by 5 and multiply this by 500 and refill the N2 in the pod.

I am confused by the logic of this part of the plugin.



public void onEvaStart(GameEvents.FromToAction<Part, Part> data)
{
double fuel = data.from.RequestResource("MonoPropellant", 5);
if (fuel < 5)
{
data.to.RequestResource("EVA Propellant", 5 - fuel);
}
}

My understanding is it will take 5 MP from the pod and if there is less than 5 the Kerbal gets 5 - what's available?!? That seems backward to me. Please help me understand the logic of the plugin. Thanks!

Link to comment
Share on other sites


public void onEvaStart(GameEvents.FromToAction<Part, Part> data)
{
double fuel = data.from.RequestResource("Nitrogen", 500);
if (fuel < 500)
{
double fillRatio = fuel / 500;
double missingRatio = 1 - fillRatio;
double evaFill = 5 * missingRatio;
data.to.RequestResource("EVA Propellant", evaFill);
}
}

So that makes a lot more sense and gives me understanding of the second part. So here is what I though would do what I posted above. Let me know if there is a simpler way or I am doing something dumb

Link to comment
Share on other sites

So this is seriously mystifying me. How can a dictionary element be null right after I've assigned it to something that is definitely not null?


private static Dictionary<string, TankType> tankTypes = new Dictionary<string,TankType>();

...

foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("MINIMFT_TANK_TYPE"))
{
TankType t = new TankType();
t.Load(node);
tankTypes.Add(t.tankName, t);
Debug.Log("Loaded TankType " + t.tankName); // works fine
Debug.Log("Is null: " + (tankTypes[t.tankName] == null).ToString()); // true?????
}

Link to comment
Share on other sites

The only thing in there I have a question about is the null compare line, I've never seen that before. That does not mean it's wrong however, but the way I would check that is:

Debug.Log("Is null: " + tankTypes[t.tankName].tankName; //as the last line instead.

If it's valid, that line will print the tankName string again, if it is in fact null, it will throw a nullref error.

Nothing else jumps out at me as being an issue in that code snippet.

The other possibility is that you never initialize the dictionary, but since it is static I don't think you need to?

D.

Link to comment
Share on other sites

The only thing in there I have a question about is the null compare line, I've never seen that before. That does not mean it's wrong however, but the way I would check that is:

Debug.Log("Is null: " + tankTypes[t.tankName].tankName; //as the last line instead.

If it's valid, that line will print the tankName string again, if it is in fact null, it will throw a nullref error.

Nothing else jumps out at me as being an issue in that code snippet.

The other possibility is that you never initialize the dictionary, but since it is static I don't think you need to?

D.

I initialized the dictionary when I declared it. And I'm not getting an error in any of this code. After the fact, I can iterate through the dictionary and see all of the keys I added ... just that their values are null, and when I try to dereference them I get an NRE (as your code would imply).

Edited by blowfish
Link to comment
Share on other sites

I think I figured it out. TankType was an indirect subclass of MonoBehaviour, and apparently Unity doesn't like MonoBehaviour instances to be initialized with new. Changing that fixed this part.

New, related question: I have a TankType field in a part module, which doesn't seem to be surviving the part instantiation process (prefab -> actual part). Does it need to be one of Unity's serializable types in order to get copied?

EDIT: TankType has the [serializable] attribute, which means that Unity should be able to serialize it anyway...

Edited by blowfish
Link to comment
Share on other sites

I'm not sure it is exactly the issue you are running into, but protoPart -> actual part is not a straight copy.

I know for sure that the partModule objects get reinitialized fresh. In my own tests I would add an action to a partModule via code at the main menu and then when I went to the editor and placed the part, that action would not copy across even though I could still see it in the protoPart database.

The only reason I can think for doing this is that the partModule objects are not copied but reinitialized fresh from defaults.

Whether this applies to you or not I can't say, but I no longer try and edit the protoPart database, I add extra KSPfields and use a module manager patch instead. It's not worth the time investment to figure out what copies and what gets reinitialized to me.

D.

Link to comment
Share on other sites

I'm not sure it is exactly the issue you are running into, but protoPart -> actual part is not a straight copy.

I know for sure that the partModule objects get reinitialized fresh. In my own tests I would add an action to a partModule via code at the main menu and then when I went to the editor and placed the part, that action would not copy across even though I could still see it in the protoPart database.

The only reason I can think for doing this is that the partModule objects are not copied but reinitialized fresh from defaults.

Whether this applies to you or not I can't say, but I no longer try and edit the protoPart database, I add extra KSPfields and use a module manager patch instead. It's not worth the time investment to figure out what copies and what gets reinitialized to me.

D.

I think I figured it out. The PartPrefab->Part process is done using the Unity.Object.Instantiate method, which does use the serialization process, which is how fields are copied (it doesn't load from config again). I fixed the problem by having TankType be a subclass of MonoBehaviour and attaching it to a GameObject properly. Still not sure why it failed with the [serializable] attribute though...

Link to comment
Share on other sites

Hi can anyone tell a complete beginner how to fetch other modules info? I have a custom partModule on an engine right now and I want to use the engines currentThrottle for some stuff but I can't figure out how to do that.

Link to comment
Share on other sites

Hi can anyone tell a complete beginner how to fetch other modules info? I have a custom partModule on an engine right now and I want to use the engines currentThrottle for some stuff but I can't figure out how to do that.

You can use part.FindModuleImplementing<ModuleEngines>(); (returns the first engine module) or part.FindModulesImplementing<ModuleEngines>(); (returns all engine modules). If you're looking for a particular engine module, e.g. on a multi-mode engine, or whichever engine module is active, you probably want to use the latter then sort through the list.

Link to comment
Share on other sites

If it is a stock module so you know it's loaded:

this.part.Modules.OfType<ModuleEngine>() returns a list of all ModuleEngines on the same part as your partModule. Add a .First() on the end for the first ModuleEngine.

If it is not a stock module this.part.Modules.Where(pm => pm.ModuleName == "NameOfPartModule") returns all partModules on the same part with that moduleName.

Hope that gets you going,

D.

Link to comment
Share on other sites

You can use part.FindModuleImplementing<ModuleEngines>(); (returns the first engine module) or part.FindModulesImplementing<ModuleEngines>(); (returns all engine modules). If you're looking for a particular engine module, e.g. on a multi-mode engine, or whichever engine module is active, you probably want to use the latter then sort through the list.

Alright thanks a lot! MonoDevelop doesn't seem to complain but just to be sure should I define it as 'ModuleEngines x = part.FindMo...;'? I'm very new to this you see :)

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...