Unable to cast object of type error 'inventory_item' to type 'inventory_slot'

Godot Version

4.2.1.stable.mono

Question

I’ve been trying to code this video in C# from GDscript but I keep getting a type casting error when trying to update the slots.

ERROR: System.InvalidCastException: Unable to cast object of type ‘inventory_item’ to type ‘inventory_slot’.

I don’t know how to get it to accept any type so it can update the slots whenever a new item is added to the inventory. Any help is appreciated.

public partial class inventory : Control
{
    private inventory_array inv;
    private Node[] slots;

	public override void _Ready()
	{
		inv = (inventory_array)GD.Load("res://resources/misc/PlayerInventory.tres");
		slots = GetNode<GridContainer>("TextureRect/GridContainer").GetChildren().ToArray();

		inv.Connect("Update", new Callable(this, MethodName.UpdateSlots));
		UpdateSlots();
	}

	public void UpdateSlots()
    {
        for (int i = 0; i < Math.Min(inv.Slots.Count, slots.Length); i++)
        {	
			inventory_visual slotScript = slots[i].GetNode<inventory_visual>(".");
            // ERROR HERE:
			slotScript.Update(inv.Slots[i]);
        }
    }
}
public partial class inventory_visual : Panel
{
	public override void _Ready()
	{
		itemVisual = GetNode<TextureRect>("CenterContainer/Panel/ItemDisplay");
        amountText = GetNode<Label>("CenterContainer/Panel/Label");
	}

    public void Update(inventory_slot slot)
    {
        if (slot.Item == null)
        {
            itemVisual.Visible = false;
            amountText.Visible = false;
        }
        else
        {
            itemVisual.Visible = true;
            itemVisual.Texture = slot.Item.Texture;
            if (slot.Amount > 1){
                amountText.Visible = true;
            }
            amountText.Text = slot.Amount.ToString();
        }
    }
}
public partial class inventory_array : Resource
{
    [Signal]
    public delegate void UpdateEventHandler();
    [Export]
    public Array<inventory_slot> Slots { get; set; } = new Array<inventory_slot>();

    public void Insert(inventory_item item){
        var itemSlots = Slots.Where(slot => slot.Item == item).ToArray();
        if (itemSlots.Any())
        {
            itemSlots[0].Amount += 1;
        }
        else
        {
            var emptySlots = Slots.Where(slot => slot.Item == null).ToArray();
            if (emptySlots.Any())
            {
                emptySlots[0].Item = item;
                emptySlots[0].Amount = 1;
            }
        }
        EmitSignal("Update");
    }
}
public partial class inventory_slot : Resource
{
    [Export]
    public inventory_item Item { get; set; }
    [Export]
    public int Amount = 0;
}
public partial class inventory_item : Resource
{
    [Export]
    public string Name { get; set; } = "";
    [Export]
    public Texture2D Texture { get; set; }
}

if I am seeing this right:

inv.Slots[i]

is of type ‘inventory_slot’, I think if you want the ‘inventory_item’ in that slot, you need:

inv.Slots[i].Item?

2 Likes
public void UpdateSlots()
    {
		GD.Print("Script: inventory | Method: UpdateSlots");
        for (int i = 0; i < Math.Min(inv.Slots.Count, slots.Length); i++)
        {	
			// inventory_slot slot = new inventory_slot();
			// inv.Slots[i] = slot;

			inventory_visual slotScript = slots[i].GetNode<inventory_visual>(".");
			slotScript.Update(inv.Slots[i].Item);
        }
    }

I get this error:
Argument 1: cannot convert from ‘inventory_item’ to ‘inventory_slot’

I guess it should be:

slotScript.Update(inv.Slots[i]);

which is what you had before and it gave the same error.

the Update on the inventory_visual class accepts an inventory_slot object it seems like the above should work.

maybe print what type inv.Slots[i] is before it goes into that Update function?

Unfortunately I still get that same cast type error when I print out inv.Slots[i]

But, it allows me to print this:

GD.Print(inv.Slots);

It just prints out all of the resources in the Slots array.

errors in console show more than we can help you. is usually more than one line

Hopefully this helps:

E 0:00:01:0228   object System.Runtime.CompilerServices.CastHelpers.ChkCastAny(System.Void*, object): System.InvalidCastException: Unable to cast object of type 'inventory_item' to type 'inventory_slot'.
  <C++ Error>    System.InvalidCastException
  <C++ Source>   :0 @ object System.Runtime.CompilerServices.CastHelpers.ChkCastAny(System.Void*, object)
  <Stack Trace>  :0 @ object System.Runtime.CompilerServices.CastHelpers.ChkCastAny(System.Void*, object)
                 VariantUtils.generic.cs:385 @ T Godot.NativeInterop.VariantUtils.ConvertTo<T>(Godot.NativeInterop.godot_variant&)
                 Array.cs:1409 @ T Godot.Collections.Array`1.get_Item(int)
                 inventory.cs:57 @ void inventory.UpdateSlots()
                 inventory.cs:45 @ void inventory._Ready()
                 Node.cs:2117 @ bool Godot.Node.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name&, Godot.NativeInterop.NativeVariantPtrArgs, Godot.NativeInterop.godot_variant&)
                 CanvasItem.cs:1370 @ bool Godot.CanvasItem.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name&, Godot.NativeInterop.NativeVariantPtrArgs, Godot.NativeInterop.godot_variant&)
                 Control.cs:2841 @ bool Godot.Control.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name&, Godot.NativeInterop.NativeVariantPtrArgs, Godot.NativeInterop.godot_variant&)
                 inventory_ScriptMethods.generated.cs:98 @ bool inventory.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name&, Godot.NativeInterop.NativeVariantPtrArgs, Godot.NativeInterop.godot_variant&)
                 CSharpInstanceBridge.cs:24 @ Godot.NativeInterop.godot_bool Godot.Bridge.CSharpInstanceBridge.Call(nint, Godot.NativeInterop.godot_string_name*, Godot.NativeInterop.godot_variant**, int, Godot.NativeInterop.godot_variant_call_error*, Godot.NativeInterop.godot_variant*)

Btw, on the inventory_array slots array variable, I imagine that is on a node and you are plugging in assets into the slots array, what assets are you plugging into those, what type or resource are they?

Maybe you plugged in an inventory_item asset instead of an inventory_slot asset?

If I understand what you’re saying correctly, I think I’m plugging in resources as seen below. When I posted this I had an apple resource in slot 0 and it considered that an ‘inventory_item’. I switched it back to an empty resource and I get the same error but instead it says unable to cast object of type error ‘godot.resource’ to type ‘inventory_slot’.

Something to take note of, maybe, is that when I changed the code in UpdateSlots to this it doesn’t give a type error:

inv.Slots[i] = new inventory_slot();
inventory_visual slotScript = slots[i].GetNode<inventory_visual>(".");
slotScript.Update(inv.Slots[i]);

However it creates new inventory_slots every time UpdateSlots is called which is most likely a problem and isn’t a solution. I went to collect an apple in game and it didn’t show up in the inventory.

It is possible, that C# has stricter rules about typed arrays, than GDScript has. So not everything that works in GDScript may work in C# in the same way.

so yeah, that is why I think what you have plugged into that player inventory array are not all inventory_slot resource types. If you click on one of those, or expand that window, what do you see?

Just the resource. Path leads back to PlayerInventory.tres.

That looks like an inventory_item resource and not an inventory_slot resource as ‘Name’ is one of the properties, that array takes inventory_slot resources right?

Yeah it does, inventory_item resources also have a texture though.

[Export]
public Array<inventory_slot> Slots { get; set; } = new Array<inventory_slot>();

I mean on the node where you drag and drop the resource into each element, if the array type is inventory_slot but you drop in an inventory_item resource, you will get that error.

Export resource properties allow any type of resource to be put in, it’s annoying, but then in the code when it loads it, there could be a mismatch.

It’s attached to the player node, if that’s what you meant? I’m new to Godot and C# so not completely familiar with everything. I still get that error despite whether it’s a resource or an inventory_item though.

so that array Slots has 20 elements in it, I imagine you dragged and dropped some resource files into those slots? Check to make sure they are inventory_slot resources and not inventory_item resources, as that array only takes inventory_slot resources.

expand the array by clicking here

expand one of the array elements and find the resource at that path

then you can see what type of resource it is, the script on that resource should be inventory_slot, at least that is what the Slots array is looking for.

Are you able to provide the source code? I’ll take a look into it then.

Essentially what I did was for every slot is added a New Resource but I didn’t drag anything into them except for when I added an inventory_item to see what would happen.

In regards to the script it’s the inventory_array one:

Maybe I can upload the project file.