Jump to content

Trouble trying to add an item to a KIS inventory


Recommended Posts

I am trying to add new functionality to my WalkAbout mod so that it will spawn kerbals with selected items already in their inventory. Currently, I am still in the proof-of-concept stage.

The problem I am having is that I can't seem to get KIS to add an item to an inventory. Below is a snippet of the code I am using to test things out (the Debug() method is my extension method to write messages to the log file):
 

if (inventory != null)
{
    var items = WalkAboutPendingItems.InventoryItems[kerbal.name];
    "performing getinfo on inventory".Debug();
    var info = ModuleKISInventoryType.InvokeMember("GetInfo", System.Reflection.BindingFlags.InvokeMethod, null, inventory, new object[0]);
    $"obtained info from inventory [{info}]".Debug();

    foreach (var itemName in items)
    {
        $"{kerbal.name} has a {itemName} to be added".Debug();

        var defPart = PartLoader.getPartInfoByName(itemName);
        $"obtained part [{defPart}] for item [{itemName}]".Debug();
        if (defPart != null)
        {
            $"invoking AddItem member using defPart [{defPart.GetType()}]".Debug();
            ModuleKISInventoryType.InvokeMember("AddItem", System.Reflection.BindingFlags.InvokeMethod, null, inventory, new object[] { defPart });
            $"If you can read this then ... hurray! It worked! {itemName} is in the inventory".Debug();
        }
        else
        {
            "Cannot add item to inventory".Debug();
        }
    }
}

And the resulting entries from the log file:

[LOG 07:36:21.281] WalkAbout: performing getinfo on inventory
[LOG 07:36:21.282] WalkAbout: obtained info from inventory [<b>Max Volume</b>: 300.00 L
<b>Internal access</b>: ALLOWED
<b>External access</b>: ALLOWED
]
[LOG 07:36:21.283] WalkAbout: Jebediah Kerman has a KIS.wrench to be added
[LOG 07:36:21.283] WalkAbout: obtained part [AvailablePart] for item [KIS.wrench]
[LOG 07:36:21.284] WalkAbout: invoking AddItem member using defPart [AvailablePart]
[EXC 07:36:21.287] MissingMethodException: The best match for method AddItem has some invalid parameter.
    System.MonoType.InvokeMember (System.String name, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object target, System.Object[] args, System.Reflection.ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, System.String[] namedParameters)
    System.Type.InvokeMember (System.String name, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object target, System.Object[] args)
    KspWalkAbout.WalkAboutEva.Start ()

As you can see, I have properly obtained the kerbal's ModuleKISInventory object and can query it for info by invoking "GetInfo". The call to invoke "AddItem" uses the same object and the only difference is that I am passing an AvailablePart object (just as is shown here). I just can't figure out where I've gone wrong.

Any help would be appreciated.

Edited by Antipodes
Pasted code was unreadable
Link to comment
Share on other sites

Seems like github is down so I cannot check but from the old version of KIS that I have, the method AddItem has this signature--->

AddItem(Part part, float qty = 1f, int slot = -1)

Therefore, I would call it in this way as probably reflection doesn't get the default parameters:

ModuleKISInventoryType.InvokeMember("AddItem", System.Reflection.BindingFlags.InvokeMethod, null, inventory, new object[] { defPart, 1f, -1 });  

edit, from what i've found, you can also use "Type.Missing" so---> new object[] { defPart, Type.Missing, Type.Missing });  

Edited by Dagger
Link to comment
Share on other sites

40 minutes ago, Dagger said:

ModuleKISInventoryType.InvokeMember("AddItem", System.Reflection.BindingFlags.InvokeMethod, null, inventory, new object[] { defPart, 1f, -1 });

Thanks Dagger, but unfortunately, that didn't work - I had exactly the same error.

40 minutes ago, Dagger said:

edit, from what i've found, you can also use "Type.Missing" so---> new object[] { defPart, Type.Missing, Type.Missing });  

Nor did this one.

The link that I have to ModuleKISInventory shows the following two signatures for AddItem()

KIS_Item AddItem(AvailablePart availablePart, ConfigNode partNode, float qty = 1, int slot = -1)
KIS_Item AddItem(Part part, float qty = 1, int slot = -1)

which matches what you suggested, but they don't seem to be working for me.

Link to comment
Share on other sites

3 hours ago, Antipodes said:

[LOG 07:36:21.284] WalkAbout: invoking AddItem member using defPart [AvailablePart]

That's actually a problem. AddItem requires parameter of type Part, and you provide AvailablePart. The right code would look like this:

ModuleKISInventoryType.InvokeMember(
    "AddItem",
    System.Reflection.BindingFlags.InvokeMethod,
    null,
    inventory,
    new object[] { defPart.prefab });

Btw, you may want looking into DRE mod. They use KIS via assembly reference. If KIS doesn't exist then the relevant part of the mod just not get loaded.

Link to comment
Share on other sites

17 hours ago, IgorZ said:

That's actually a problem. AddItem requires parameter of type Part, and you provide AvailablePart. The right code would look like this:


ModuleKISInventoryType.InvokeMember(
    "AddItem",
    System.Reflection.BindingFlags.InvokeMethod,
    null,
    inventory,
    new object[] { defPart.prefab });

Btw, you may want looking into DRE mod. They use KIS via assembly reference. If KIS doesn't exist then the relevant part of the mod just not get loaded.

Sorry, IgorZ. No luck. I changed the defPart to defPart.partPrefab but I had the exact same error.

Which mod do you mean when you say "DRE mod"? Deadly Reentry?

Link to comment
Share on other sites

18 hours ago, Diazo said:

Have you got more code? ModuleKISInventory.AddItem() is not a static method, where in your code are you telling it you are trying to invoke .AddItem on a specific instance of ModuleKISInventory?

D.

My apologies, Diazo. I thought I had replied to you, bu I guess I didn't actually post the message. I wasn't ignoring you.

The following code shows how I obtain the type of the ModuleKISInventory class (ModuleKISInventoryType) and then how I get the specific instance being used by the kerbal on EVA (inventory):

Component inventory = null;
var ModuleKISInventoryType = KIS.GetType("KIS.ModuleKISInventory");
var modules = FlightGlobals.ActiveVessel.GetComponents(ModuleKISInventoryType);
foreach (var module in modules)
{
    if (module.GetType().ToString() == "KIS.ModuleKISInventory")
    {
        inventory = module;
        break;
    }
}

The call to AddItem is accomplished by invoking the member on the object representing the ModuleKISInventory's type:

ModuleKISInventoryType.InvokeMember("AddItem", System.Reflection.BindingFlags.InvokeMethod, null, inventory, new object[] { part });

This is where the error occurs.

Link to comment
Share on other sites

the code seems correct, can you try it with another binding flag like:  BindingFlags.Public and filling the optional parameters?

Anyway, being the method public couldn't you just cast the object "inventory" to a ModuleKISInventory type?

something like: 

ModuleKISInventory inventory = FlightGlobals.ActiveVessel.GetComponents<ModuleKISInventory>().First();
inventory.AddItem(.......)

Edited by Dagger
Link to comment
Share on other sites

6 hours ago, Dagger said:

the code seems correct, can you try it with another binding flag like:  BindingFlags.Public and filling the optional parameters?

I'll try fiddling with the BindingFlags to see if that helps. I don't understand, though, why the call to invoke GetInfo() works, but the call for AddItem() fails.

6 hours ago, Dagger said:

Anyway, being the method public couldn't you just cast the object "inventory" to a ModuleKISInventory type?

something like: 

ModuleKISInventory inventory = FlightGlobals.ActiveVessel.GetComponents<ModuleKISInventory>().First();
inventory.AddItem(.......)

That would require me to add a reference to KIS dlls in WalkAbout. I did not want to have to force the user to install KIS in order to use WalkAbout, nor did I want to copy the KIS dlls into WalkAbout's installation. If you know of another way in which I could accomplish this and still be able to reference the ModuleKISInventory type directly, I would be VERY interested.

Link to comment
Share on other sites

8 hours ago, Antipodes said:

Sorry, IgorZ. No luck. I changed the defPart to defPart.partPrefab but I had the exact same error.

It's impossible to get exact same error. Original error mentions the old type: "using defPart [AvailablePart]", Now you use different type. If you get exactly this text in the error then it means you did your code wrong. At the very least the new error text should look like this: "using defPart [Part]".

8 hours ago, Antipodes said:

Which mod do you mean when you say "DRE mod"? Deadly Reentry?

Yes, it's Deadly Reentry.

Plus, take a look at the forum thread explaining how to deal with the overloaded methods via reflections. "AddItem" is an overloaded method, and you need to call the right version with the right arguments. For the testing purpose I'd recommend you to pass all three arguments in the call to ensure the right method is found. Once it worked you may start experimenting with the default arguments.

Link to comment
Share on other sites

6 hours ago, IgorZ said:

It's impossible to get exact same error. Original error mentions the old type: "using defPart [AvailablePart]", Now you use different type. If you get exactly this text in the error then it means you did your code wrong. At the very least the new error text should look like this: "using defPart [Part]".

Plus, take a look at the forum thread explaining how to deal with the overloaded methods via reflections. "AddItem" is an overloaded method, and you need to call the right version with the right arguments. For the testing purpose I'd recommend you to pass all three arguments in the call to ensure the right method is found. Once it worked you may start experimenting with the default arguments.

Okay, true - you can't get the exact same error. I meant that I had the same "invalid parameters" error on the same call under the same circumstances.

I will look into what Deadly Reentry is doing. As I said, this is just the proof-of-concept - if I can get this to work, then I can plan out how to fully implement it.

I will also look into the forum thread you linked to. I am sure that one of the tests I did was with all three parameters included, but I will try again to make sure of it.

Link to comment
Share on other sites

2 hours ago, Antipodes said:

I will also look into the forum thread you linked to. I am sure that one of the tests I did was with all three parameters included, but I will try again to make sure of it.

For what it's worth. In this thread you've tried three arguments in response of @Dagger's suggestion. And the suggestion was the following:

On 10/21/2016 at 9:24 AM, Dagger said:

ModuleKISInventoryType.InvokeMember("AddItem", System.Reflection.BindingFlags.InvokeMethod, null, inventory, new object[] { defPart, 1f, -1 });  

Which will not work, of course, since "defPart" is still a wrong type.

Link to comment
Share on other sites

SUCCESS ! ! ! !

Thank you to IgorZ and Dagger! It turns out that I had not tried both your suggested at the same time. That is, I had not added the extra parameters AND passed the .partPrefab. When I did that it worked! So the final call looks like:

var part = PartLoader.getPartInfoByName(itemName).partPrefab;
ModuleKISInventoryType.InvokeMember("AddItem", System.Reflection.BindingFlags.InvokeMethod, null, inventory, new object[] { part, 1f, -1 });

I still have some investigating to do because I want to know why it fails when I use

ModuleKISInventoryType.InvokeMember("AddItem", System.Reflection.BindingFlags.InvokeMethod, null, inventory, new object[] { part, Type.Missing, Type.Missing });

but I have a working call now and I can proceed.

Thanks again, everyone.

Edited by Antipodes
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...