Cephei

The official unoffical "help a fellow plugin developer" thread

Recommended Posts

Heh, you are quick. Check the edit to my previous post for what I think is a more likely culprit.

Having said that, for KSP to save your data to the persistent file you must either:

a) Assign that field the KSPField attribute with persistent = true. Then keep this value updated as whatever value is in this field when OnSave is called will be saved. Any calculations done in OnSave will not save with this method. (My biggest headache with KSPFields).

B) Grab the data directly using node.GetValue() and node.SetValue() for loading and saving. This overrides KSP's automatic save/load of the KSPField. I prefer this method as I know exactly what is being loaded and saved.

For the first method, you are limited to certain data types. Notably double does not work, you have to use float.

For the second method, I only use strings and manually convert everything back and forth. It probably makes my save/load code more complex then it needs to be, but I know exactly what is going on this way.

D.

Well i'm not even trying to make it persistent, as in saved with the game save, I just need the values that are defined in the part.cfg (or an override) to be made available to my PartModule when in Flight.

Share this post


Link to post
Share on other sites

In that case, the straightforward way would be to get rid of the subnodes.

With the following module in your part.cfg (changed from your example):


MODULE
{
name = FlightDataRecorder
foo = bar
num = 42
body = kerbin
bodyval = 1.0
}

Then in your partmodue:


public class FlightDataRecorder : PartModule
{
[KSPField, false, false] //persistent false, guiActive false
string body;
[KSPField, false, false] //persistent false, guiActive false
float bodyval;
}
public void Update()
{
print("Test " + body + " " + bodyval); //should print "Test kerbin 1" to the log each update.
}
}

This way loses you the flexibility of the sub-nodes, but anything that is given the KSPField attribute checks the part.cfg for it's default value. By setting persistent to false, it should never save back to the part definition and will always reset to default on load.

If you really want to use subnodes, you will need to look at putting the GetNode and SetNode commands into the OnLoad and OnSave routines as subnodes do not automatically load or save to the best of my knowledge.

D.

Share this post


Link to post
Share on other sites

Well I really want the subnodes for flexibility :( I'd prefer not to hard code things like body names or else the mod won't work with mods that change those.

So I tried doing this:


public override void OnLoad(ConfigNode node)
{
print("FlightDataRecorder: OnLoad");
print("FlightDataRecorder: " + node.ToString());
if (node.HasNode("BODY"))
{
ConfigNode[] bodyNodes = node.GetNodes("BODY");
foreach (ConfigNode bodyNode in bodyNodes)
{
print("Found body " + bodyNode.GetValue("name"));
bodyValues.Add(bodyNode.GetValue("name"), Convert.ToDouble(bodyNode.GetValue("value")));
}
}
base.OnLoad(node);
}


public override void OnSave(ConfigNode node)
{
print("FlightDataRecorder: onSave()");
print("DUMPING BODY VALES");
foreach (var key in bodyValues.Keys)
{
print("key:" + key + ", value:" + bodyValues[key]);
ConfigNode bodyNode = node.AddNode("BODY");
bodyNode.AddValue("name", key);
bodyNode.AddValue("value", bodyValues[key]);
}
base.OnSave(node);
}

But it didn't make any difference. In fact from what I can see the OnSave() is being called BEFORE the OnLoad() when you add the part to a Vessel in the VAB. OnSave() gets called, but OnLoad() never does until you move into the Flight scene. So trying to keep the values from OnLoad is pointless.

Nothing I can figure to do will allow the values loaded from the part.cfg to make it through to an actual instance of my part :(

Edited by Agathorn

Share this post


Link to post
Share on other sites

If I understand some of what i'm reading in my research, it looks like i'm going to have to build a custom class that can pack and unpack itself for KSPField.

Surely someone has done this before though that is what is driving me batty.

Share this post


Link to post
Share on other sites

Okay, let's get really simple.

part.cfg


MODULE
{
name = FlightDataRecorder
testValue = 1.1
}

partModule


public class FlightDataRecorder : PartModule
{
[KSPField(isPersistant = false, guiActive = false)]
public float testValue = 0;
public override void OnLoad(ConfigNode node)
{
}
public override void OnSave(ConfigNode node)
{
}
public void Update()
{
print("Test " + testValue);
}

Should spam "Test 1.1" to the log window every update pass. If it spams "Test 0", that means the partModule can not find the value from the part.cfg.

If it does not, the config node is not setup correctly and you need to get that straightened out before trying to load data from it.

D.

edit: Added the empty OnSave and OnLoad calls. I'm not sure those matter for just loading the default value, but better safe then sorry.

Edited by Diazo

Share this post


Link to post
Share on other sites

Ok your simple example works. Also whats with the Update() method vs the OnUpdate() method? I only knew about OnUpdate().

Share this post


Link to post
Share on other sites

They are the same as far as I know.

The example code I used way back when to get started used Update so that is what I keep using as it works.

D.

edit: Errr, I think I may have realized the problem.

I don't think BODY is a valid node name, I'm pretty sure you have to use Module.

Can you try:


MODULE
{
name = FlightDataRecorder
testValue = 1.1
MODULE
{
name = Kerbin
testValueKerbin = 1.4
}
}

And then does this work in the part module:


OnLoad
{
ConfigNode testNode = node.GetNode("Kerbin");
string testVal = node.GetValue("testValue");
string testValKerbin = testNode.GetValue("testValueKerbin");
print("TEST " + testVal + " " + testValKerbin);
}

Does that print "TEST 1.1 1.4" to the log window?

Edited by Diazo

Share this post


Link to post
Share on other sites

Ok well Update() actually seems to get called more often (OnUpdate only gets called in Flight scene).

Anyway the basic example works, but now I still need to figure out how tt work with sub config nodes. I tried looking through NathanKells code in ModularFuels where he does use them, but there is so much other code there that I got lost.

Share this post


Link to post
Share on other sites

I'm almost ready with updating my mod, but I only need 1 more thing. I already have it working to active/deactive the struts via RMB while flying your craft, but now I want to add that function ALSO for EVA.

#region Actions

[KSPAction("Toggle")]
public void ToggleStrut(KSPActionParam param)
{
IsEnabled = !IsEnabled;
CheckHit();
}

[KSPAction("Activate")]
public void ActivateStrut(KSPActionParam param)
{
this.ActivateStrut();
}

[KSPAction("Deactivate")]
public void DeactivateStrut(KSPActionParam param)
{
this.DeactivateStrut();
}

#endregion

#region Events

[KSPEvent(guiActive = true, guiName = "Activate", active = true, guiActiveUnfocused = true, unfocusedRange = 2f)]
public void ActivateStrut()
{
IsEnabled = true;
CheckHit();
this.Events["ActivateStrut"].guiActiveEditor = false;
this.Events["DeactivateStrut"].guiActiveEditor = true;
}

[KSPEvent(guiActive = true, guiName = "Deactivate", active = false, guiActiveUnfocused = true, unfocusedRange = 2f)]
public void DeactivateStrut()
{
IsEnabled = false;
CheckHit();
this.Events["ActivateStrut"].guiActiveEditor = true;
this.Events["DeactivateStrut"].guiActiveEditor = false;
}

#endregion

Do I need to add 'externalToEVAOnly = true' to do that or something else?

Share this post


Link to post
Share on other sites
I'm almost ready with updating my mod, but I only need 1 more thing. I already have it working to active/deactive the struts via RMB while flying your craft, but now I want to add that function ALSO for EVA.

Do I need to add 'externalToEVAOnly = true' to do that or something else?

Yes adding externalToEVAOnly = true is what makes events usable in EVA, but EVA events are specific to EVA, you won't be able to use your event normally any more.

The way to fix this is to create a separate event for EVA only and call your original event from that:


[KSPEvent(guiActive = true, guiName = "Deactivate", active = false, guiActiveUnfocused = true, unfocusedRange = 2f, externalToEVAOnly=true)]
public void EVADeactivateStrut()
{
DeactivateStrut();
}

IIRC unfocused range is the distance the Kerbal must be from the part to be able to trigger the EVA event.

Share this post


Link to post
Share on other sites
Yes adding externalToEVAOnly = true is what makes events usable in EVA, but EVA events are specific to EVA, you won't be able to use your event normally any more.

The way to fix this is to create a separate event for EVA only and call your original event from that:


[KSPEvent(guiActive = true, guiName = "Deactivate", active = false, guiActiveUnfocused = true, unfocusedRange = 2f, externalToEVAOnly=true)]
public void EVADeactivateStrut()
{
DeactivateStrut();
}

IIRC unfocused range is the distance the Kerbal must be from the part to be able to trigger the EVA event.

Thx for the help, will add it now and test it.

Share this post


Link to post
Share on other sites
Ok well Update() actually seems to get called more often (OnUpdate only gets called in Flight scene).

Update() is called by any Unity Monobehaviour class once every frame. OnUpdate() is a KSP thing that is called by part modules once every frame, but only if the part is activated; this is usually by staging or by forcing activation in your OnStart() method.

Anyway the basic example works, but now I still need to figure out how tt work with sub config nodes. I tried looking through NathanKells code in ModularFuels where he does use them, but there is so much other code there that I got lost.

I've never tried this with KSPFields in a part module.

You might have to manually load the confignode in your OnLoad() method, bot not using the default ConfigNode.


public override void OnLoad(ConfigNode node)
{
foreach (ConfigNode part_node in GameDatabase.Instance.GetConfigNodes("Part"))
{
if (part_node.GetValue("name") == "your_part_name")
{
ConfigNode[] body_node = part_node.GetNodes("BODY")
...Do something with body_nodes...
}
}
}

This would be for non-nested nodes, just BODY{} nodes within your part.cfg file, but you can just go down the chain of nodes if you want to nest them within the module node.

As far as I know any config node (which should include the PART{} that part.cfg files use) is added to GameDatabase, so you should be able to access it there. You could, alternatively, just stash your settings in a different config file, instead of adding it to the part.cfg file, the loading method would be the same. As for saving anything in those nodes, I'm not so sure, but it sounds like that's not what you're trying to do.

Share this post


Link to post
Share on other sites


[KSPEvent(guiActive = true, guiName = "Deactivate", active = false, guiActiveUnfocused = true, unfocusedRange = 2f, externalToEVAOnly=true)]
public void EVADeactivateStrut()
{
DeactivateStrut();
}

I think you want to set guiActive = false and active = true. guiActive is what controls whether the button is visible when you right-click on it while controlling the vessel with the part on it. active is just the global activation setting (I think), so unless you're setting active = true somewhere else, which it looks like you might be doing, then this should be true.

And also, you should only need one KSPEvent for both EVA activation and standard activation. The externalToEVAOnly just means that only an EVA Kerbal can activate the KSPEvent while the part is not on your current vessel, it doesn't prevent you from using the regular right-click mechanism.

So in that case you would want to set guiActive, guiActiveUnfocused, and externalToEVAOnly = true. This should give you a one method KSPEvent to control the function both while on the active vessel and while EVA.

Edited by DMagic

Share this post


Link to post
Share on other sites

How would I tell if a Kerbil is near a part? Either EVA or on land, but I want to determine if the Kerbal being controlled is essentially able to touch the part, so that an action on the part can only be performed if they can touch it.

Share this post


Link to post
Share on other sites

float kerbalDistanceToPart = Vector3.Distance(kerbal.transform.position, targetPart.collider.ClosestPointOnBounds(kerbal.transform.position));

will return kerbalDistanceToPart as a number in meters between the center of mass of the kerbal and the closest edge of the part to the kerbal's center of mass..

Note that a kerbal on EVA does not have a valid collider to do a .ClosestPointOnBounds to.

D.

Share this post


Link to post
Share on other sites
float kerbalDistanceToPart = Vector3.Distance(kerbal.transform.position, targetPart.collider.ClosestPointOnBounds(kerbal.transform.position));

will return kerbalDistanceToPart as a number in meters between the center of mass of the kerbal and the closest edge of the part to the kerbal's center of mass..

Note that a kerbal on EVA does not have a valid collider to do a .ClosestPointOnBounds to.

D.

Oh very nice thank you. Even more help than I expected :D

Share this post


Link to post
Share on other sites

Ok so I guess I'll ask here. Was going to start a thread but I figured I'd see what this was first.

My question is, how hard will it be learning C# coming from a background of java? I see many similarities in the two looking through other developers source codes and a I also see differences, obviously I'm talking about syntax as the keywords are quite different.

Can anyone point me to some decent resources that aren't aimed at beginner programmers but still cover a good portion of the c# basics using semi-advanced concepts?

Lastly, should I be focusing on learning the .net framework or is plugging into KSP not going to require a strong knowledge of it? Pre-thanks for any answers.

Share this post


Link to post
Share on other sites

Programming is programming. If you truly understand the fundamentals than learning another language is trivial. Its learning the KSP API that is the cumbersome part, especially with essentially zero documentation. Java and C# are extremely similar and won't take much of a leap.

Share this post


Link to post
Share on other sites
Programming is programming. If you truly understand the fundamentals than learning another language is trivial. Its learning the KSP API that is the cumbersome part, especially with essentially zero documentation. Java and C# are extremely similar and won't take much of a leap.

Yeah, I kind of figured that seeing as I can READ other's code decently. The issue I'm worried about is adapting to the few differences, like keywords. Actually, googling around a bit has waylaid some of my fears on syntax, I guess some of the differences I saw were just different modder's preferences (like using do while loops rather than while {//do stuff}).

Yeah, considering that, I'll just jump in and try it. Time to get used to Visual Studio, probably the most daunting part of all this, learning a new IDE. It's like a new pair of shoes, the old one is all broken in and comfy and you feel bad leaving them. Haha.

Share this post


Link to post
Share on other sites

ah, great! people are talking about programming/scripting in KSP! Exactly what I was going to ask about!

My questions (forgive if they have been answered already):

1: Is there a Wiki / Documentation for making scripts in KSP?

2: Can you place a script in a part.cfg file to be activated when the part is? (ex, run script when engine activates)

Thanks!!

Share this post


Link to post
Share on other sites
some of the differences I saw were just different modder's preferences (like using do while loops rather than while {//do stuff}).

"do-while" and "while" loops are not just preference. They work differently.

Share this post


Link to post
Share on other sites
"do-while" and "while" loops are not just preference. They work differently.

Right you are. Thanks for pointing me to learn something new. The books I taught myself with didn't cover do-while loops or the difference. Thanks for correcting that and not letting it just drift away, I appreciate a learning opportunity.

ah, great! people are talking about programming/scripting in KSP! Exactly what I was going to ask about!

My questions (forgive if they have been answered already):

1: Is there a Wiki / Documentation for making scripts in KSP?

2: Can you place a script in a part.cfg file to be activated when the part is? (ex, run script when engine activates)

Thanks!!

The best documentation I've been able to find is:

http://wiki.kerbalspaceprogram.com/wiki/Category:Community_API_Documentation

https://github.com/Anatid/XML-Documentation-for-the-KSP-API

I don't know exactly how up to date either of those resources are but they seem to give a good stepping off point.

Share this post


Link to post
Share on other sites

How would I go about getting the mission elapsed time (MET) in a PartModule's OnUpdate?

Share this post


Link to post
Share on other sites

How can I put variables in the partmodule in the .cfg file and then read them in the plugin partmodule?

Share this post


Link to post
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.