Jump to content

Accessing KSPFields from other PartModules


Recommended Posts

Trying to access a value in another partmodule, to do math to it. It's a public variable, also assigned as a persistent KSPField.

Probably just my general noobiness in regards to C#, but how can I access it? Have tried:

myvariable = part.NameSpace.PartModuleName.variablename;

However, it doesn't seem to recognize any of those fields as being part of the Part object. Any help would be much-appreciated, thanks in advance!

Link to comment
Share on other sites

You need an actual instance of the target PartModule to work on. Say my PartModule is attached to a command pod and I want to know some info about the ModuleReactionWheel attached to it. Here are two ways to find a ModuleReactionWheel on the same part:

var rw = part.Modules.OfType<ModuleReactionWheel>().Single();
rw = part.FindModulesImplementing<ModuleReactionWheel>().First();

Debug.Log(string.Format("ypr torque: {0}, {1}, {2}", rw.YawTorque, rw.PitchTorque, rw.RollTorque));

And since it's somewhat related, if I wanted to know about every ModuleReactionWheel on the vessel my part is attached to, you can easily find out with:

vessel.FindPartModulesImplementing<ModuleReactionWheel>()

If it's possible that your target PartModule doesn't exist on your part, use [single/First]OrDefault() instead of Single/First() and check for null before trying to work on it.

Link to comment
Share on other sites

I'm not sure I follow all your steps...

Let's say I want to access the magnetic field magnitude in the Interstellar mod (source):

[KSPField(isPersistant = false, guiActive = true, guiName = "|B|")]
public string Bmag;

And then add a field in my own PartModule, say, multiplying Bmag by 2 and placing it back on the part, the line in my code would look like:

Using FNPlugin;
//other stuff goes here
var rw = part.Modules.OfType<DTMagnetometer>().Single();
rw = part.FindModulesImplementing<DTMagnetometer>().First();

[KSPField(isPersistant = false, guiActive = true, guiName = "|B|")]
public string Bmag_times2;

//inside an OnUpdate function:
Bmag_times2 = rw.Bmag*2;

I must be missing something with this, since it's still throwing errors at me.

Edited by Felger
Link to comment
Share on other sites

Is your PartModule attached to the magnetometer? If not then it won't be able to find the module.

You'll need to use


vessel.FindModulesImplementing<DTMagnetometer>().First();

Another problem is that the field is a string, not a double/float. You'll need to convert the Bmag value back into a float before you can modify it.

Link to comment
Share on other sites

Yes, I'm attaching the PartModule to the part with a ModuleManager config file.

In reality, the magnetometer was just an arbitrary example that was easy to find. I'm trying to interface with Infernal Robotics and get some data on the robotics components themselves, which are available as public variables in the MuMechToggle PartModule.

I'm still confused, then. Is there a way to tell what the output of all of this stuff will be? IE, what kind of variable do I need to declare to correctly receive all this stuff on the right hand side of the equals sign? Will the output be a Part object? Maybe I need to start over and try to understand what the code is actually doing.

var rw = part.Modules.OfType<ModuleReactionWheel>().Single();

var rw doesn't seem to be a valid variable declaration, what kind of variable do I need to set?

I understand that 'part' needs to be the part object associated with the part we're attaching this PartModule to, but how do I get that?

Modules I've found in the API, seems to return a list of modules installed on the part.

OfType doesn't seem to be associated with Part.Modules, however System.Linq seems to have something on it, perhaps searching through the PartModule list for some a particular class.

And I'm not really sure what Single() does, besides its association with single-precision floats.

rw = part.FindModulesImplementing<DTMagnetometer>().First();

On the next line of code, it just seems to be implementing one method, FindModulesImplementing<>(), perhaps finding the first instance of that PartModule in the previously returned list?

Sorry for all the questions, I'm very new to C#, and only middling at object oriented programming, still trying to wrap my head around everything.

Link to comment
Share on other sites

var rw = part.Modules.OfType<ModuleReactionWheel>().Single();

var rw doesn't seem to be a valid variable declaration, what kind of variable do I need to set?

var just infers the type based on the right-hand side. That line is equivalent to ModuleReactionWheel rw = part.Modules.OfType<ModuleReactionWheel>().Single();

I understand that 'part' needs to be the part object associated with the part we're attaching this PartModule to, but how do I get that?

You inherit that from PartModule, along with a bunch of other stuff

OfType doesn't seem to be associated with Part.Modules, however System.Linq seems to have something on it, perhaps searching through the PartModule list for some a particular class.

And I'm not really sure what Single() does, besides its association with single-precision floats.

That's exactly what it does. part.Modules.OfType<ModuleReactionWheel>() returns an IEnumerable containing all ModuleReactionWheel instances found in part.Modules. Single() takes the first one, should there be more than one found

rw = part.FindModulesImplementing<DTMagnetometer>().First();

On the next line of code, it just seems to be implementing one method, FindModulesImplementing<>(), perhaps finding the first instance of that PartModule in the previously returned list?

No, that's just an alternative method. This line returns a List<DTMagnetometer> rather than IEnumerable. First() takes the first item in the list.

Link to comment
Share on other sites

No it returns a list of all the partmodules of that type on the ship. The big problem here is that you will need to have a direct dependancy to the KSPI code and will need to refer the files as you build, you'd mostly want to have soft dependencies in KSP unless really needed, and you'll have to learn to use reflection for that.

Link to comment
Share on other sites

Actually, if you get lucky and want to get the value of a KSPField, KSP offers a work-around.

I use the following method from my mod to check Davon's Thrust control for which throttle (0 though 5) an engine is assigned to.

if(part.Modules.Contains("DifferentialThrustEngineModule")) //Devon Throttle Control Installed?
{
foreach(PartModule pm in part.Modules) //should be a shorter way to do this, but a foreach cycle works
{
if (pm.moduleName=="DifferentialThrustEngineModule") //find the desired partmodule, note we stay as type PartModule, we do not cast to DifferentialThrustEngineModule
{
DavonThrottleID = (float)pm.Fields.GetValue("throttleFloatSelect"); //which throttle is engine assigned to?
}
}
}

Make sure you design your code so that if the module is not found, your code does not break.

Again, this only works on KSPField values that are set to public, otherwise your options are a dependency or reflection as noted.

D.

Link to comment
Share on other sites

Again, this only works on KSPField values that are set to public, otherwise your options are a dependency or reflection as noted.

That thing works on reflection :P Also, it might be important to note that your KSPFields /need/ to be public. Just as well as KSPEvents and KSPActions

Link to comment
Share on other sites

Trying Diazo's code, that worked for me, changing thusly:

            if (part.Modules.Contains("MuMechToggle")) //Devon Throttle Control Installed?
{
foreach (PartModule pm in part.Modules) //should be a shorter way to do this, but a foreach cycle works
{
if (pm.moduleName == "MuMechToggle") //find the desired partmodule, note we stay as type PartModule, we do not cast to DifferentialThrustEngineModule
{
rotation = (float)pm.Fields.GetValue("rotation"); //which throttle is engine assigned to?
}
}
}

Tinkering with xEvilReeperx's method, I finally got it happy-ish (not really sure what I was doing wrong, but came home from work today tried again and it's more or less happy).

Running in the same scope as Diazo's code,

            var rw = part.FindModulesImplementing<MuMechToggle>().First();

Gives an error on MuMechToggle (Infernal Robotic's module that does the robotics-ing), saying it can't find the module even though I'm using InfernalRobotics; and MuMechToggle is a public class.

Is there some way around this? As I'm also going to be looking to grab other things from MuMechToggle, like the functions to move the gimbals, and EvilReeper's solution seems much simpler / more elegant.

Link to comment
Share on other sites

On that note, Stupid_Chris, is there a reference you can point me at where I can teach myself how to use reflection? What I've found with basic googling doesn't seem all that related to what I'm trying to do, but I'll keep looking.

Link to comment
Share on other sites

Is that your exact code? Assuming you added a reference to IR in your project (and it sounds like you have), you'll find MuMechToggle in MuMech, not InfernalRobotics. So, something like this:

using MuMech;

[...inside some object]
var mmt = part.FindModulesImplementing<MuMechToggle>().First();

Or you can skip the using and specify it directly:

var mmt = part.FindModulesImplementing<MuMech.MuMechToggle>().First();

Link to comment
Share on other sites

On that note, Stupid_Chris, is there a reference you can point me at where I can teach myself how to use reflection? What I've found with basic googling doesn't seem all that related to what I'm trying to do, but I'll keep looking.

I learned using the windows documents, I prefer self-teaching. Else if google didn't reveal anything else useful I wouldn't know where to look. Reflection is /hard/.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

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...