NOTICE: Due to continuing issues with the forum editor, I am no longer maintaining this page, but the same (and up-to-date with nicer formatting) tutorials can be found on Github (links below).
Here I will cover how to create an Item that stores an Inventory, like a backpack, as well as how to add additional inventory slots to the player, allowing you to have slots for things like amulets, rings, or whatever.
Edited to include notes in the Item class about using 'onItemRightClick' vs. 'onItemUse' to access the inventory, as 'onItemRightClick' ONLY works if you also set your item to have a max use duration. Otherwise, your gui will open but any changes you make will not be saved. This has to do with the way these 2 vanilla methods function. 'onItemUse' will always work correctly, so I suggest using that if you can.
EDIT: Actually, BOTH of these methods require you to override this method:
@Override
public int getMaxItemUseDuration(ItemStack itemstack)
{
return 1;
}
coolAlias, I just wanted to ask if you can make a tutorial about opening a item with a inventory but in a completely new GUI or if I can remove the player model and just make it bigger. Thanks for all these amazing tutorials
coolAlias, I just wanted to ask if you can make a tutorial about opening a item with a inventory but in a completely new GUI or if I can remove the player model and just make it bigger. Thanks for all these amazing tutorials
You're welcome
Are there not any gui tutorials? I haven't looked. Anyway, yes, you can just remove the player model - look at any tile entity based gui, such as furnace.
I'm pretty sure gui texture files are limited in that they must be a multiple of 256x256 pixels, but within that you can make it any size you want (up to the max of 256). Look at the inventory texture I provided and you'll see there's still plenty of room to expand it - it's only about 176x165 pixels. Delete the renderPlayerModel code from the Gui class and you can use that space, too.
Increasing the texture size to 512x512 or larger doesn't make the gui any larger, just higher resolution.
Updated to include instructions on how to make the Item multi-player compatible.
For those who don't want to read the whole tutorial again:
NOTE: Using 'Keyboard' works for single player but WILL crash on a multi-player server. To make your item multi-player-compatible, you will need to set up a custom KeyBinding and KeyHandler. See SoBiohazardous' tutorial on how to set that up, as well as my post there for some more advanced stuff.
New tutorial up on how to override the default player inventory screen with your own customized inventory with custom slots, such as a shield or amulet. Let me know if anything needs clarification
Updated to Forge 871. Only things that needed changing were in the Gui:
Three things you'll need to change in your GUI files:
1. I18n.func_135053_a() is now I18n.getString()
2. mc.func_110434_K() is now mc.renderEngine
3. renderEngine.func_110577_a() is now renderEngine.bindTexture()
Added Step 6 to "Inventory Item Tutorial", describing an improved method of saving Inventory contents without the need for onUpdate method. This will also allow you to interact with the inventory from outside of a Gui, so you can add items directly to your custom inventory.
Thanks to Country_Gamer for bringing up this issue.
EDIT: Ended up re-writing the tutorial as this method is so much better than using onUpdate. There is no longer a step 6, so I'll put the most important details here for those of you who don't want to reread the whole thing:
Things to ADD:
// Add a variable to InventoryItem to store the parent ItemStack:
private final ItemStack stack;
// Initialize it in the Constructor:
public InventoryItem(ItemStack itemstack)
{
this.stack = itemstack;
if (!this.stack.hasTagCompound()) { this.stack.setTagCompound(new NBTTagCompound()); }
readFromNBT(this.stack.getTagCompound());
}
// then just add this one line to the end of onInventoryChanged():
this.writeToNBT(this.stack.getTagCompound());
Things to REMOVE:
- onUpdate method in Item class, unless you use it to open the Gui with Keyboard (recommended to put that in a KeyHandler instead! Then you can still remove onUpdate safely)
- writeToNBT and slotClick methods in Container class
- needsUpdate and containerStack variables in Container class
I think that covers it all; if not, check the updated tutorial!
I have just tried working through the "InventoryItem" tutorial, and I keep getting errors in "readFromNBT", specifically "method tagCount() is undefined" and "method atTag() is undefined"
I'm using the Eclipse editor, and Forge 1.6.4-9.11.1.921
--------
Oops. My first post didn't show up until after I posted this one. Sorry.
I have just tried working through the "InventoryItem" tutorial, and I keep getting errors in "readFromNBT", specifically "method tagCount() is undefined" and "method atTag() is undefined"
I'm using the Eclipse editor, and Forge 1.6.4-9.11.1.921
--------
Oops. My first post didn't show up until after I posted this one. Sorry.
Those methods both belong to 'NBTTagList', did you import that class?
Those methods both belong to 'NBTTagList', did you import that class?
Yes, I did import that class, but I must have been looking at the wrong line when following the tutorial. I had miscast "items" as "NBTTagCompund". Got it fixed now.
@1froghog1 - I thought the example in the tutorial was pretty clear, but if you need more information, check out the Forge wiki article on packet handling. There's not really much else I can do to help you understand. If you have a specific question, you can post that, though.
---- Minecraft Crash Report ----
// Oh - I know what I did wrong!
Time: 11/5/13 7:08 PM
Description: Reading NBT data
java.lang.ClassCastException: net.minecraft.nbt.NBTTagByte cannot be cast to net.minecraft.nbt.NBTTagInt
at net.minecraft.nbt.NBTTagCompound.getInteger(NBTTagCompound.java:233)
at Vikymod.Vikydronemod.InventoryItem.readFromNBT(InventoryItem.java:162)
at Vikymod.Vikydronemod.InventoryItem.<init>(InventoryItem.java:34)
at Vikymod.Vikydronemod.CommonProxy.getServerGuiElement(CommonProxy.java:29)
at cpw.mods.fml.common.network.NetworkRegistry.openRemoteGui(NetworkRegistry.java:308)
at cpw.mods.fml.common.network.FMLNetworkHandler.openGui(FMLNetworkHandler.java:352)
at net.minecraft.entity.player.EntityPlayer.openGui(EntityPlayer.java:2480)
at Vikymod.Vikydronemod.Vikydronearmor.onItemRightClick(Vikydronearmor.java:59)
at net.minecraft.item.ItemStack.useItemRightClick(ItemStack.java:176)
at net.minecraft.item.ItemInWorldManager.tryUseItem(ItemInWorldManager.java:353)
at net.minecraft.network.NetServerHandler.handlePlace(NetServerHandler.java:542)
at net.minecraft.network.packet.Packet15Place.processPacket(Packet15Place.java:79)
at net.minecraft.network.MemoryConnection.processReadPackets(MemoryConnection.java:89)
at net.minecraft.network.NetServerHandler.networkTick(NetServerHandler.java:141)
at net.minecraft.network.NetworkListenThread.networkTick(NetworkListenThread.java:54)
at net.minecraft.server.integrated.IntegratedServerListenThread.networkTick(IntegratedServerListenThread.java:109)
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:691)
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:587)
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:129)
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:484)
at net.minecraft.server.ThreadMinecraftServer.run(ThreadMinecraftServer.java:16)
A detailed walkthrough of the error, its code path and all known details is as follows:
---------------------------------------------------------------------------------------
-- Corrupt NBT tag --
Details:
Tag type found: BYTE
Tag type expected: INT
Tag name: Slot
Stacktrace:
at net.minecraft.nbt.NBTTagCompound.getInteger(NBTTagCompound.java:233)
at Vikymod.Vikydronemod.InventoryItem.readFromNBT(InventoryItem.java:162)
at Vikymod.Vikydronemod.InventoryItem.<init>(InventoryItem.java:34)
at Vikymod.Vikydronemod.CommonProxy.getServerGuiElement(CommonProxy.java:29)
at cpw.mods.fml.common.network.NetworkRegistry.openRemoteGui(NetworkRegistry.java:308)
at cpw.mods.fml.common.network.FMLNetworkHandler.openGui(FMLNetworkHandler.java:352)
at net.minecraft.entity.player.EntityPlayer.openGui(EntityPlayer.java:2480)
at Vikymod.Vikydronemod.Vikydronearmor.onItemRightClick(Vikydronearmor.java:59)
at net.minecraft.item.ItemStack.useItemRightClick(ItemStack.java:176)
at net.minecraft.item.ItemInWorldManager.tryUseItem(ItemInWorldManager.java:353)
at net.minecraft.network.NetServerHandler.handlePlace(NetServerHandler.java:542)
at net.minecraft.network.packet.Packet15Place.processPacket(Packet15Place.java:79)
at net.minecraft.network.MemoryConnection.processReadPackets(MemoryConnection.java:89)
at net.minecraft.network.NetServerHandler.networkTick(NetServerHandler.java:141)
-- Ticking connection --
Details:
Connection: net.minecraft.network.NetServerHandler@cd0d11
Stacktrace:
at net.minecraft.network.NetworkListenThread.networkTick(NetworkListenThread.java:54)
at net.minecraft.server.integrated.IntegratedServerListenThread.networkTick(IntegratedServerListenThread.java:109)
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:691)
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:587)
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:129)
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:484)
at net.minecraft.server.ThreadMinecraftServer.run(ThreadMinecraftServer.java:16)
-- System Details --
Details:
Minecraft Version: 1.6.4
Operating System: Windows XP (x86) version 5.1
Java Version: 1.7.0_25, Oracle Corporation
Java VM Version: Java HotSpot(TM) Client VM (mixed mode, sharing), Oracle Corporation
Memory: 50029112 bytes (47 MB) / 213958656 bytes (204 MB) up to 259522560 bytes (247 MB)
JVM Flags: 0 total;
AABB Pool Size: 4767 (266952 bytes; 0 MB) allocated, 4262 (238672 bytes; 0 MB) used
Suspicious classes: FML and Forge are installed
IntCache: cache: 1, tcache: 0, allocated: 1, tallocated: 63
FML: MCP v8.11 FML v6.4.3.883 Minecraft Forge 9.11.0.883 4 mods loaded, 4 mods active
mcp{8.09} [Minecraft Coder Pack] (minecraft.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available
FML{6.4.3.883} [Forge Mod Loader] (bin) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available
Forge{9.11.0.883} [Minecraft Forge] (bin) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available
vikydronemod{1.1} [vikydronemod] (bin) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available
Profiler Position: N/A (disabled)
Vec3 Pool Size: 3513 (196728 bytes; 0 MB) allocated, 3358 (188048 bytes; 0 MB) used
Player Count: 1 / 8; [EntityPlayerMP['Player369'/196, l='new mod', x=-309.80, y=63.00, z=10.66]]
Type: Integrated Server (map_client.txt)
Is Modded: Definitely; Client brand changed to 'fml,forge'
here's my Inventory Item code :
package Vikymod.Vikydronemod;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
public class InventoryItem extends TileEntity implements IInventory
{
private String name = "Inventory Item";
/** Provides NBT Tag Compound to reference */
private final ItemStack stack;
/** Defining your inventory size this way is handy */
public static final int INV_SIZE = 8;
/** Inventory's size must be same as number of slots you add to the Container class */
ItemStack[] inventory = new ItemStack[INV_SIZE];
/**
* @param itemstack - the ItemStack to which this inventory belongs
*/
public InventoryItem(ItemStack itemstack)
{
this.stack = itemstack;
// Create a new NBT Tag Compound if one doesn't already exist, or you will crash
if (!this.stack.hasTagCompound()) { this.stack.setTagCompound(new NBTTagCompound()); }
// Read the inventory contents from NBT
readFromNBT(this.stack.getTagCompound());
}
@Override
public int getSizeInventory()
{
return inventory.length;
}
@Override
public ItemStack getStackInSlot(int slot)
{
return inventory[slot];
}
@Override
public ItemStack decrStackSize(int slot, int amount)
{
ItemStack stack = getStackInSlot(slot);
if(stack != null)
{
if(stack.stackSize > amount)
{
stack = stack.splitStack(amount);
// Don't forget this line or your inventory will not be saved!
this.onInventoryChanged();
}
else
{
setInventorySlotContents(slot, null);
}
}
return stack;
}
@Override
public ItemStack getStackInSlotOnClosing(int slot)
{
ItemStack stack = getStackInSlot(slot);
setInventorySlotContents(slot, null);
return stack;
}
@Override
public void setInventorySlotContents(int slot, ItemStack itemstack)
{
this.inventory[slot] = itemstack;
if (itemstack != null && itemstack.stackSize > this.getInventoryStackLimit())
{
itemstack.stackSize = this.getInventoryStackLimit();
}
// Don't forget this line or your inventory will not be saved!
this.onInventoryChanged();
}
@Override
public String getInvName()
{
return name;
}
@Override
public boolean isInvNameLocalized()
{
return name.length() > 0;
}
@Override
public int getInventoryStackLimit()
{
return 64;
}
/**
* This is the method that will handle saving the inventory contents, as it is called (or should be called!)
* anytime the inventory changes. Perfect. Much better than using onUpdate in an Item, as this will also
* let you change things in your inventory without ever opening a Gui, if you want.
*/
@Override
public void onInventoryChanged()
{
for (int i = 0; i < this.getSizeInventory(); ++i)
{
if (this.getStackInSlot(i) != null && this.getStackInSlot(i).stackSize == 0)
this.setInventorySlotContents(i, null);
}
// This line here does the work:
this.writeToNBT(this.stack.getTagCompound());
}
@Override
public boolean isUseableByPlayer(EntityPlayer entityplayer)
{
return true;
}
@Override
public void openChest() {}
@Override
public void closeChest() {}
/**
* This method doesn't seem to do what it claims to do, as
* items can still be left-clicked and placed in the inventory
* even when this returns false
*/
@Override
public boolean isItemValidForSlot(int slot, ItemStack itemstack)
{
// Don't want to be able to store the inventory item within itself
// Bad things will happen, like losing your inventory
// Actually, this needs a custom Slot to work
return !(itemstack.getItem() instanceof Vikydronearmor);
}
/**
* A custom method to read our inventory from an ItemStack's NBT compound
*/
public void readFromNBT(NBTTagCompound compound)
{
// Gets the custom taglist we wrote to this compound, if any
NBTTagList items = compound.getTagList("ItemInventory");
for (int i = 0; i < items.tagCount(); ++i)
{
NBTTagCompound item = (NBTTagCompound) items.tagAt(i);
int slot = item.getInteger("Slot");
// Just double-checking that the saved slot index is within our inventory array bounds
if (slot >= 0 && slot < getSizeInventory())
{
setInventorySlotContents(slot, ItemStack.loadItemStackFromNBT(item));
}
}
}
/**
* A custom method to write our inventory to an ItemStack's NBT compound
*/
public void writeToNBT(NBTTagCompound compound)
{
// Create a new NBT Tag List to store itemstacks as NBT Tags
NBTTagList items= new NBTTagList();
for (int i = 0; i < getSizeInventory(); ++i)
{
// Only write stacks that contain items
if (getStackInSlot(i) != null)
{
// Make a new NBT Tag Compound to write the itemstack and slot index to
NBTTagCompound item = new NBTTagCompound();
item.setInteger("Slot", i);
// Writes the itemstack in slot(i) to the Tag Compound we just made
getStackInSlot(i).writeToNBT(item);
// add the tag compound to our tag list
items.appendTag(item);
}
}
// Add the TagList to the ItemStack's Tag Compound with the name "ItemInventory"
compound.setTag("ItemInventory", items);
}
}
NOTICE: Due to continuing issues with the forum editor, I am no longer maintaining this page, but the same (and up-to-date with nicer formatting) tutorials can be found on Github (links below).
Here I will cover how to create an Item that stores an Inventory, like a backpack, as well as how to add additional inventory slots to the player, allowing you to have slots for things like amulets, rings, or whatever.
Creating an Item that stores an Inventory
(such as a Backpack)
Github Link
Custom Player Inventory
Github Link
Be sure to check out my other tutorials as well (more in my profile!):
- Modding With APIs
- EventHandler and IExtendedEntityProperties
- Custom Inventories in Items and Players
- Multi-Input/Output Furnace
- Rendering Your Custom Item Texture
- Overriding shift-click in custom Containers
- Using Potions in Crafting Recipes
- Enchanted Books and Crafting Recipes
EDIT: Actually, BOTH of these methods require you to override this method:
You're welcome
Are there not any gui tutorials? I haven't looked. Anyway, yes, you can just remove the player model - look at any tile entity based gui, such as furnace.
I'm pretty sure gui texture files are limited in that they must be a multiple of 256x256 pixels, but within that you can make it any size you want (up to the max of 256). Look at the inventory texture I provided and you'll see there's still plenty of room to expand it - it's only about 176x165 pixels. Delete the renderPlayerModel code from the Gui class and you can use that space, too.
Increasing the texture size to 512x512 or larger doesn't make the gui any larger, just higher resolution.
For those who don't want to read the whole tutorial again:
NOTE: Using 'Keyboard' works for single player but WILL crash on a multi-player server. To make your item multi-player-compatible, you will need to set up a custom KeyBinding and KeyHandler. See SoBiohazardous' tutorial on how to set that up, as well as my post there for some more advanced stuff.
I'll be putting up a new tutorial on adding custom slots to the player inventory shortly. I'll split the OP into two sections.
Three things you'll need to change in your GUI files:
1. I18n.func_135053_a() is now I18n.getString()
2. mc.func_110434_K() is now mc.renderEngine
3. renderEngine.func_110577_a() is now renderEngine.bindTexture()
Thanks to Country_Gamer for bringing up this issue.
EDIT: Ended up re-writing the tutorial as this method is so much better than using onUpdate. There is no longer a step 6, so I'll put the most important details here for those of you who don't want to reread the whole thing:
Things to ADD:
Things to REMOVE:
- onUpdate method in Item class, unless you use it to open the Gui with Keyboard (recommended to put that in a KeyHandler instead! Then you can still remove onUpdate safely)
- writeToNBT and slotClick methods in Container class
- needsUpdate and containerStack variables in Container class
Using Eclipse, and Forge 1.6.4-9.11.1.921
I'm using the Eclipse editor, and Forge 1.6.4-9.11.1.921
--------
Oops. My first post didn't show up until after I posted this one. Sorry.
Those methods both belong to 'NBTTagList', did you import that class?
Yes, I did import that class, but I must have been looking at the wrong line when following the tutorial. I had miscast "items" as "NBTTagCompund". Got it fixed now.
Thanks for the help.
http://www.planetminecraft.com/mod/couple-of-new-mobs/
http://www.planetminecraft.com/mod/couple-of-new-mobs/