How to open JUST the chest inventory

So I’ve been working with custom inventories and I’ve been trying to understand how they work but with very little documentation online it’s become somewhat difficult. All I have so far is this:
Player player = (Player)src;
Inventory inv = Inventory.builder().build(KitPvP.instance); player.openInventory(inv);
The problem here is that it opens the player’s inventory as well as the custom chest inventory. I also want to know if anyone has any documentation that I can look at in order to make something like a button system in the custom inventory.

It will open the player inventory. There is no inventory screen in vanilla minecraft that does not have the player inventory attached.

As for a good documentation for custom inventories. Your not the first to ask for one and probably wont be the last so I may end up writing a unofficial one XD. So here is a brief overview.

First of all. Use the inventory builder to build a inventory that you want. We will be adding to the inventory builder later.

You should have a blank inventory and the player you wish to display to.

Inventory inv;
Player player;

Now you want to build the items you wish to use as buttons, you can use the ItemStack.Builder() for this.

ItemStack button1;

Now if i want to add that to slot 1,5 (as in the second row, sixth column) then you would use the query function

Inventory inv;
Slot slot = inv.query(QueryOperationTypes.INVENTORY_PROPERTY.of(SlotPos.of(1, 5)));

Now you have the slot. Set the items

Slot slot;
ItemStack button;
slot.set(button);

Now you should have a custom inventory with all the buttons in the right place, but there is the problem that they are clickable and draggable. They dont act as buttons.

This is where the inventory builder comes back into play, as it has a wonderful ability of allowing inventory events to only occur if its that inventory that was used.

Inventory.builder().listener(AffectedSlotEvent.class, event -> {
    //Event code in here
})

Use that to check what slot was affected. If the slot was one of your buttons then cancel the event, find out which button (ie, what slot its in) and then react how you wish.

It maybe a lot to take in and just out right confusing however in normal minecraft, the inventory code is a mess. So much so that forge mods just make there own, so for sponge to react well to both vanilla and modded inventories, a huge amount of planning was needed.

2 Likes

That would be very very VERY useful if you were to make your own documentation for making inventories. Thanks for all this though it was very helpful!

I keep getting an error because the button and the inventory aren’t being initialized. Also, I’m getting an error because of the listener wants Class instead of Class and I’m kind of confused as to what the event -> means. Sorry for all the questions but I’m really new to plugins, most of my knowledge is with modding.

Player player = (Player)src;
Inventory inv;
Slot slot = inv.query(QueryOperationTypes.INVENTORY_PROPERTY.of(SlotPos.of(1, 5)));
ItemStack button;
slot.set(button);
Inventory.builder().listener(AffectSlotEvent.class, event -> { //Event code in here });
player.openInventory(inv);

When ItemStack button1; or something like that is said, what is meant is that you have created an ItemStack and named it button1. Though this is valid Java it is not meant to tell you to write it literally; it means to do whatever initialization you want to do, but regardless of how, do this next part. For example, this block of code:

does not mean to write literally that code. It means that if you already have a Slot named slot, and an ItemStack named button, then slot.set(button) will do what you want to do there.

1 Like

Also -> is not the event. Its a lamda expression, something that was introduced in Java 8, the event that is actually being listened for is the AffectedSlotEvent.class just before it. And the event parameter is named event.

But as pieflavour said, you need to write your own code in the variable. Fix that and hopefully we can sort out the rest.

Ok so I have this now:

Player player = (Player)src;
Inventory inv = Inventory.builder().build(KitPvP.instance);
Slot slot = inv.query(QueryOperationTypes.INVENTORY_PROPERTY.of(SlotPos.of(1, 5)));
ItemStack button = ItemStack.of(ItemTypes.APPLE, 1);
slot.set(button);
player.openInventory(inv);

This compiles fine but when I try to run it I end up getting an exception stating that EmptyInventoryImpl cannot be cast to Slot. Also, I’m still kinda confused as to what I put in the lamda expression because the methods that are given for the event parameter don’t say anything about which slot the user is affecting or anything.

So in the inventory builder you need to specify the size. Otherwises it will be a Empty Inventory SpongeAPI/EmptyInventory.java at stable-7 · SpongePowered/SpongeAPI · GitHub that can not accept queries.

As for the event. Look closer you will find there is a method that allows you to get the transactions of the slots.

I’m very confused as to how to set the size of the inventory because the size method just returns the size of the inventory. Would I use the InventoryTransformation thing?

It also says that the getTransactions method is undefined for type E whenever I try to call it

The size method would return just the size of the inventory. As defining the size of the inventory is part of the creation of the inventory, the method for defining it can be found in the Inventory.builder(). The inventory size is definded by setting the inventory property of SpongeAPI/InventoryDimension.java at stable-7 · SpongePowered/SpongeAPI · GitHub the string required for the inventory property is found in that class too.

As for the event. Make sure the .class event is spelt correctly and imported. That error occurs if what your throwing at it is not extending E (which is definded by the generics of the method/class)

Player player = (Player)src;
Inventory inv = Inventory.builder().property(“inventorydimension”, new InventoryDimension(10,5)).build(KitPvP.instance);
Slot slot = inv.query(QueryOperationTypes.INVENTORY_PROPERTY.of(SlotPos.of(1, 5)));
ItemStack button = ItemStack.of(ItemTypes.APPLE, 1);
slot.set(button);
player.openInventory(inv);

I’m not sure what I’m doing wrong exactly

You should be using InventoryDimension.of(9, 6)

9 being the width of the inventory and 6 being the height. Also use the of instead of the constructor

you’re a genius.

1 Like

Ok so I have the GUI working perfectly now. Only problem I’m still having is the code for the button. I’m still getting an error where it says that the listener wants “Class” instead of Class.

Inventory.builder().listener(AffectSlotEvent.class, event -> {
List t = ((AffectSlotEvent) event).getTransactions();
if(t.get(0).equals(slot))
{
event.setCancelled(true);
}
});

I don’t believe AffectSlotEvent is valid for a inventory object. Use ClickInventoryEvent

Post to my tutorial for custom inventories.

This helped tremendously, thank you for the resource.