Inventory Slots

Hey there!
I’m new to sponge developing and I want to put an item in a specific slot.
How do I get the item in a slot? Or how do I set the item in a slot?
Thanks!

Inventory inv;
GridInventory gridInv = inv.getInventoryProperty(GrIdInventory.class);
Slot slot = gridInv.getSlot(x, y).get();

//Get itemstack in slot
Optional<ItemStack> opItem = slot.peek();

//Set itemstack in slot
ItemStack item;
slot.set(item);

Please note i am doing this from memory so some of the functions may have typos and may not return exactly. But currently on my phone so no ide to check

@MoseMister
GridInventory isn’t an InventoryProperty, so that won’t compile. But you’re on the right track.

@AwPer_Dev
First, it’s important to know what the context is behind what you’re doing - the methods for working with an inventory differ based on whether you have a chest, a player’s inventory, or some other implementation. An inventory is a combination of 0, 1, or more slots and contains multiple layers, so you need to specify what you’re looking for through queries.

For example, the player’s inventory (player.getInventory()) contains multiple inventories - the main inventory, the hotbar, the player’s armor, and potentially more as a result of mods. To target a specific slot, you need to first query the part of inventory you’re interested in. For simplicities sake, I’m looking for the top left slot of the player’s main inventory. We can get that using:

Inventory main = player.getInventory().query(MainPlayerInventory.class);

At this point, the inventory we have could be one of three things:

  • An empty inventory, if there was no match in the query (in this case, that shouldn’t happen - but you never know thanks to mods).
  • A single MainPlayerInventory object representing the player’s main inventory
  • An InventoryAdaptor containing multiple MainPlayerInventory objects, one of which is (hopefully) the player’s main inventory (also shouldn’t happen, but… mods :confused:)

We’re going to presume that nothing is interfering with the inventory structure and the second one occurred, but it’s important to note the possibility of other results (as we’ll be dealing with this later).

Next, the MainPlayerInventory contains the player’s hotbar and grid inventories. We can get the grid inventory from here, and then finally get the slot in column - row order (which places the top left slot at 0, 0). I’ll leave you to handle the returned Optional as you see fit.

Optional<Slot> slot = ((MainPlayerInventory) main).getGrid().getSlot(0, 0);

As said above, a lot of this depends on what you’re trying to do and the context of the situation. It’s always better to include detail so people know exactly what you’re trying to accomplish and set you on the right path. Giving directions to a location without knowing where you’re starting from is a losing battle.

3 Likes

Hey there! Thanks you guys for the response!
I can’t seem to find a MainPlayerInventory class though?
I did find a regular PlayerInventory class.
Any thoughts? @Simon_Flash

It means you’re not using API 7, which is another reason to include detail in the original post :wink:

From the looks of it, PlayerInventory should have the methods that you need. Though it might seem like player.getInventory() would return a PlayerInventory this may not always be the case, so you will need to query for that as well. Alternatively, you can query for the GridInventory directly or even a SlotIndex - it all depends on the context of your use and what assumptions you make about the underlying implementation.

Hey! So I figured this part out but now I’m stack at setting a players inventory. I’ve been trying to do it with for loops and slots but I was wondering if there isn’t a easier/better way to do it!

I do not belive there is a “setInventoryAs(Inventory)” or a “from” in the actual inventory (there is for the builder for custom inventories). So my way would be to get all the Slots of your saved inventory and then bring them over to the other inventory. Something along the lines of the following.

Inventory savedInv;
Inventory newInventory;
Iterable<Slot> slots = savedInv.slots();
for(Slot slot : slots) {
  if(slot.peek().isPresent()) {
    //slot did not contain a itemstack
    continue;
  }
  //gets the slots index (essentially Bukkits position) from the slot
  Optional<SlotIndex> opIndex = slot.getInventoryProperty(SlotIndex.class);
  if(!opIndex.isPresent()){
    //no index value for slot could be found - unlikely - add anyway?
    continue;
  }
  //gets the slot from the new inventory
  Slot slot2 = (Slot)newInventory.query(opIndex.get());
  //sets the new slot with the old one
  slot2.set(slot.peek().get());
}

I have not tested this, but I was looking at GitHub this time, so hopefully right. (Sponge really need a “apply(Inventory, boolean)” (Inventory: inventory you wish to be added to. boolean: Override existing ItemStack’s)to the inventory. May make a pull request to add this in.

Thanks for the reply! The problem is that I’m not using that version :/. I’m using an API for minecraft version 1.10.2.

I’ll try to make it work with my api tomorrow thanks

= slot.getProperty(SlotIndex.class, "slotindex") for older API

1 Like

Ohh! Awesome, I’ve been doing that but without the “slotindex” next to it
Thanks

Its the same for all other InventoryProperties. (lowercased classname)
So e.g.:
getProperty(SlotPos.class, "slotpos")
etc.

Using another String will not work.

1 Like

It seems like I can’t cast slot index to a slot though :confused:

You could use a for statement to check all the slots and then check what slot has that slotIndex. After that use that slot

You should be able to use the query() method on the containing inventory to find the slot by it’s SlotIndex. If that doesn’t work, try passing SlotPos.of(other.getProperty(SlotPos.class, "slotpos")) as the parameter instead.

Hey there! Thanks for all your help but that still didn’t work! Do you guys have an idea?

Because you still need to have context with your inventory. For example, take a look at this representation of the MainPlayerInventory, which contains the main storage and player’s hotbar.

| | | | | | | | | |
|-|-|-|-|-|-|-|-|-|-|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| | | | | | | | | |
| 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |

This inventory actually contains two inventories, so we’ll number those as well.

| | | | | | | | | |
|-|-|-|-|-|-|-|-|-|-|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| | | | | | | | | |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Additionally, this can be extended to row and column InventoryAdapters, but my understanding is that should only exist as the result of a query.

The order returned by inventory.slots() is the same order slots are indexed in.

Notice that the SlotIndex 1 exists in three inventories - the MainPlayerInventory, GridInventory, and Hotbar. When you query for an index, it matches all the slots available - which, as I’ve mentioned above, returns an InventoryAdapter containing the three slots (though actually two as they overlap). To retrieve the actual result, you need to get it from that adapter.

Inventory inv;
Inventory result = inv.query(SlotIndex.of(1)); //Theoretically an adapter
Slot slot = result.first(); //The first slot or empty inventory

There are two takeaway points from this, first of which is context is key. Minecraft stores the inventory as a list of slots, so the fact that we have an API available to separate this into different containers and views is pretty remarkable in itself. However, the API can only provide context to a certain extent, so you need to understand what you’re working with and meet it the rest of the way.

I’ve also said this before, but please include information about what you’re doing. As much as I’d like to be a master of ESP I’m not, so for myself and others to know what you’re doing you’ll have to provide details. In 90% of cases, the most important piece of this is the code you’re using. You can either post it with code blocks here if it’s short-ish, or attach a gist with it if it becomes rather lengthy - but having it saves everyone time.

1 Like

Thanks for the reply! again!
So what I’m trying to do here is just use a saved inventory and make a player have that inventory. So for example you clear the players inventory and you have it saved and now you want to put it back.
I’ve tried this:

public static void revert(Inventory i, Player p){
    Inventory savedInv = i;
    Inventory newInventory = p.getInventory();
    Iterable<Slot> slots = savedInv.slots();

    //return if slot doesn't contain an itemstack
    for(Slot slot : slots) {
        if(!(slot.peek().isPresent())) {
            //slot did not contain a itemstack
            continue;

        }
        //gets the slots index (essentially Bukkits position) from the slot
        Optional<SlotPos> slotpos = slot.getProperty(SlotPos.class, "slotpos");
        if(!slotpos.isPresent()){
            //no index value for slot could be found - unlikely - add anyway?
            continue;
        }
        //gets the slot from the new inventory
        Inventory result = newInventory.query(SlotPos.of(slotpos));
        //sets the new slot with the old one
        result.first().set(slot.peek().get());

    }
}

This didn’t work for me. I’m currently using version 5.1.0 of the sponge api.
I hope this helps and I’m sorry for not doing this earlier.