In this tutorial we explain how you can make a chest that can hold 9 items (that's all you need right?) and opens a GUI so you can access those items.

Here is the block code. In this code we register our tile entity as well. In onBlockActivated() we actually open the GUI. Note that this is done on the server because a gui for a tile entity has to be 'opened' on both sides so that there is a mechanism in place for synchronizing the contents. The player.openGui() call happens on the server and this will be synced to the client using the IGuiHandler (more on this later). i.e. if you have a GUI open for a chest you want to see the items appear in real time as well as the other way around:

publicclassTestContainerBlockextendsBlockimplementsITileEntityProvider{publicstaticfinalintGUI_ID=1;publicTestContainerBlock(){super(Material.ROCK);setUnlocalizedName(ModTut.MODID+".testcontainerblock");setRegistryName("testcontainerblock");GameRegistry.register(this);GameRegistry.register(newItemBlock(this),getRegistryName());GameRegistry.registerTileEntity(TestContainerTileEntity.class,ModTut.MODID+"_testcontainerblock");}@SideOnly(Side.CLIENT)publicvoidinitModel(){ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(this),0,newModelResourceLocation(getRegistryName(),"inventory"));}@OverridepublicTileEntitycreateNewTileEntity(WorldworldIn,intmeta){returnnewTestContainerTileEntity();}@OverridepublicbooleanonBlockActivated(Worldworld,BlockPospos,IBlockStatestate,EntityPlayerplayer,EnumHandhand,ItemStackheldItem,EnumFacingside,floathitX,floathitY,floathitZ){// Only execute on the serverif(world.isRemote){returntrue;}TileEntityte=world.getTileEntity(pos);if(!(teinstanceofTestContainerTileEntity)){returnfalse;}player.openGui(ModTut.instance,GUI_ID,world,pos.getX(),pos.getY(),pos.getZ());returntrue;}}

The tile entity is what is actually storing the items. In this tutorial we will no longer use the vanilla IInventory system but instead we implement our inventory using the new recommended capability system (IItemHandler).

publicclassTestContainerTileEntityextendsTileEntity{publicstaticfinalintSIZE=9;// This item handler will hold our nine inventory slotsprivateItemStackHandleritemStackHandler=newItemStackHandler(SIZE){@OverrideprotectedvoidonContentsChanged(intslot){// We need to tell the tile entity that something has changed so// that the chest contents is persistedTestContainerTileEntity.this.markDirty();}};@OverridepublicvoidreadFromNBT(NBTTagCompoundcompound){super.readFromNBT(compound);if(compound.hasKey("items")){itemStackHandler.deserializeNBT((NBTTagCompound)compound.getTag("items"));}}@OverridepublicNBTTagCompoundwriteToNBT(NBTTagCompoundcompound){super.writeToNBT(compound);compound.setTag("items",itemStackHandler.serializeNBT());returncompound;}publicbooleancanInteractWith(EntityPlayerplayerIn){// If we are too far away from this tile entity you cannot use itreturn!isInvalid()&&playerIn.getDistanceSq(pos.add(0.5D,0.5D,0.5D))<=64D;}@OverridepublicbooleanhasCapability(Capability<?>capability,EnumFacingfacing){if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY){returntrue;}returnsuper.hasCapability(capability,facing);}@Overridepublic<T>TgetCapability(Capability<T>capability,EnumFacingfacing){if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY){return(T)itemStackHandler;}returnsuper.getCapability(capability,facing);}}

Here is the blockstate json (blockstates/testcontainerblock.json). Note that in this example we don't have our own block model but instead use the vanilla cube_all model:

This is not enough however. For a GUI to work we need actual GUI code and also a Container implementation. While it is the Tile Entity that holds the actual contents, it is the Container that is used to communicate between the GUI and the actual contents on the server. Keep in mind that when you open a GUI for a chest (for example) you not only see the slots from the chest itself but also slots from the player inventory. So the Container is a view on at least two inventories in this case.

When a GUI is opened in Minecraft this usually happens on the server side. There a Container implementation is used to indicate what inventory is being opened. On the client side a synchronized copy of that Container is also used and given to the actual GUI.

Here you see the Container for this example. Note how slots are added both for our own tile entity as well as the player inventory.

One note. It is crucial that you implement transferStackInSlot. If you don't your block will crash if the player uses shift-click on an item. In this example we copied the implementation that is also used by the vanilla chest. It basically transfers slots between hotbar/player inventory/chest depending on where the item started and where there is room.

publicclassTestContainerextendsContainer{privateTestContainerTileEntityte;publicTestContainer(IInventoryplayerInventory,TestContainerTileEntityte){this.te=te;// This container references items out of our own inventory (the 9 slots we hold ourselves)// as well as the slots from the player inventory so that the user can transfer items between// both inventories. The two calls below make sure that slots are defined for both inventories.addOwnSlots();addPlayerSlots(playerInventory);}privatevoidaddPlayerSlots(IInventoryplayerInventory){// Slots for the main inventoryfor(introw=0;row<3;++row){for(intcol=0;col<9;++col){intx=9+col*18;inty=row*18+70;this.addSlotToContainer(newSlot(playerInventory,col+row*9+10,x,y));}}// Slots for the hotbarfor(introw=0;row<9;++row){intx=9+row*18;inty=58+70;this.addSlotToContainer(newSlot(playerInventory,row,x,y));}}privatevoidaddOwnSlots(){IItemHandleritemHandler=this.te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY,null);intx=9;inty=6;// Add our own slotsintslotIndex=0;for(inti=0;i<itemHandler.getSlots();i++){addSlotToContainer(newSlotItemHandler(itemHandler,slotIndex,x,y));slotIndex++;x+=18;}}@Nullable@OverridepublicItemStacktransferStackInSlot(EntityPlayerplayerIn,intindex){ItemStackitemstack=null;Slotslot=this.inventorySlots.get(index);if(slot!=null&&slot.getHasStack()){ItemStackitemstack1=slot.getStack();itemstack=itemstack1.copy();if(index<TestContainerTileEntity.SIZE){if(!this.mergeItemStack(itemstack1,TestContainerTileEntity.SIZE,this.inventorySlots.size(),true)){returnnull;}}elseif(!this.mergeItemStack(itemstack1,0,TestContainerTileEntity.SIZE,false)){returnnull;}if(itemstack1.stackSize==0){slot.putStack(null);}else{slot.onSlotChanged();}}returnitemstack;}@OverridepublicbooleancanInteractWith(EntityPlayerplayerIn){returnte.canInteractWith(playerIn);}}

Now we also need a GUI. GUI's for containers usually extend from GuiContainer. In this simple case there is not much code we need to get this GUI working. You can of course add your own custom rendering to make this GUI more fancy as well as adding custom components and stuff like that:

Now there is one final thing you need to do and that is to tell Minecraft how to create your GUI and Container implementations. For this a IGuiHandler is needed which contains server and client side code to handle the GUI. In the example below we hardcoded the TestContainerTileEntity and TestContainer names. I recommend not doing that in your own code but using a simple framework. For example, you could have a GenericTileEntity that you can do 'instanceof' of and then have methods in that to create your gui and/or container. Or you can also make use of the given ID which is also given to player.openGui() as it was called above (GUI_ID). This example is just to demonstrate how it works.