I'm 100% certain I've removed them all. I had another look just now and gave it another run and it's still not working :/
If you have a Github repository, please post a link and I'll take a look. Also, always post the most recent code / crash report - saying 'it still doesn't work' does not provide me with any useful information.
Finally fixed the formatting (mostly) of the tutorial to work with the forum editor changes, and moved all of the tips on updating to the end of the post.
This may have been asked before, so if it has then I apologize, I'm currently pressed for time. Do you have a link to the GUI texture used? If not, what would be the best thing to use? All I want to make is a simple quiver to hold a single stack of arrows. I've got the code started and am working on it, hopefully everything goes well. My problem now is just textures.
This may have been asked before, so if it has then I apologize, I'm currently pressed for time. Do you have a link to the GUI texture used? If not, what would be the best thing to use? All I want to make is a simple quiver to hold a single stack of arrows. I've got the code started and am working on it, hopefully everything goes well. My problem now is just textures.
Thanks.
I used the vanilla inventory gui texture (which is found in the vanilla .jar) and modified it by copying one of the slots and pasting it where I wanted it. Use GIMP, PhotoShop, or whatever you're comfortable with.
The func_110434_K() is underlined in red. I am in 1.7.10. Any suggestions on what I should change this to? I figured everything else out..
You could use some deduction to figure out what it should be: the final method takes an iconLocation, which I assume is a ResourceLocation type, so it probably has something to do with binding textures. This would imply that the previous function, the one in the Minecraft class, needs to return some type of object that has a method to bind a texture.
So, look in the Minecraft class and see if there is any method in there that returns an object that may have something to do with managing rendering, then check that object to see if it has a method that takes a ResourceLocation.
Btw, I already know what the method names are, but it's better if you learn how to figure these things out for yourself.
Oh I already long since found it on Google. Only issue I'm having now is the fact that it doesn't seem to want to save the inventory. The quiver 'eats' the arrows. Can't seem to get them back. Any idea what I'm doing wrong?
Still waiting to hear back about my GUI issue. If there's another tutorial somewhere I missed then please by all means point me to it, because I saw no other links in this tutorial. I have no issue with reading more, however Google searches have come up empty. I believe this is an issue with networking or packets, to which I've found no tutorials on that I understand, same for IExetndedEntityProperties. The last one, however, I found a tutorial for in 1.6, but it was so drastically different that inferring the transitions to 1.7.10 were impossible. Any help would be appreciated, as this is my first time doing anything with a GUI and I'm very excited that it works at all. This was a wonderful tutorial, I'm just missing a few steps is all, and I would love to be pointed in the right direction. I don't want anything written for me or anything like that - I just want to try to learn every piece of this without having to magically pull the knowledge out of my butt. And I do have a learning disability which I've overcome most of, so making it this far is a miracle for me. Just means I learn things slower, not much I can do about that. But thank you to anyone who helps me out. Hell, even a post containing a link to a decent tutorial for 1.7.10 would do it. I've been searching for a good few months to find tutorials on those things and I can't seem to find any.
You only asked about those two function names, and you replied that you found them via Google, so with what, exactly, are you still having trouble?
If you are not understanding IExtendedEntityProperties from the custom player inventory tutorial alone, you have but to look at the bottom of the main post for links to other tutorials, or in my profile, amongst which you will find one on IEEP.
Not sure if that's the problem or what it is. But basically the GUI opens up, I can put arrows in it and nothing else which is what I wanted, but when I go to open it again, the arrows aren't there. That's where I'm stuck at. I assumed IEEP was what I was missing, but I'm not sure. That's what I need help with.
However I will be checking your profile for other tutorials since you mentioned that. Seems like a great idea.
Anyway, I appreciate your help. Thanks for being patient with me.
Are you opening up the GUI on the server side? You shouldn't need any of the other tutorials if you followed this one - it contains everything you need to know to get a working custom inventory.
If you have Github or some other code repository, I could take a look, or you could post your IInventory, Container, IGuiHandler, code you use to open the GUI (is it a keybind? if so, you need to send a packet!), and IEEP classes. Use pastebin to share your code if you do, rather than pasting it all into the forum editor.
Sounds good. And no, no keybind. It's a use-on-right-click thing. Kinda odd, I realize, but it's more or less just to start out. I can fidget with everything else later. Although I don't know how to send a packet, either. And I don't have any IEEP classes, I was trying to learn those before but until I get them figured out I'm just keeping them out of the mod (unless I need them of course), to save space and clutter. GUI works fine, except for the fact that some of the slots are a bit off (things are rendering in the wrong places, but they still work - I can figure this one out on my own).
Okay, well before I go digging any further into your code, none of the FML-event methods should be static. Remove that.
Items, Blocks, and Entities should ALL be instantiated and registered during FMLPreInitializationEvent - move them there.
Renderers and recipes are registered where you have them; I'm not sure about the OreDictionary - that is either during pre-init after you register all of your blocks and items, or during init phase. I've never used it, so I can't tell you for sure without doing some research.
EDIT: See my actual InventoryItem implementation - you don't need the onUpdate part anymore.
EDIT 2: You also don't need any of that extra code in the Container. In your InventoryQuiver, I recommend you use the constant 'tagName' you created when reading and writing to NBT - in your write method, you did not use it - even though the value is the same, this is bad practice.
// Armor Slots
for (i = 0; i < 4; ++i){
this.addSlotToContainer(new SLOT_ARMOR(player, inventoryPlayer, inventoryPlayer.getSizeInventory() - 1 - i, 44, -1 + i * 18, i));
}
// Add vanilla PLAYER INVENTORY - just copied/pasted from vanilla classes
for (i = 0; i < 3; ++i){
for (int j = 0; j < 9; ++j){
this.addSlotToContainer(new Slot(inventoryPlayer, j + i * 9 + 9, 8 + j * 18, 91 + i * 18));
}
}
//Hotbar
for (i = 0; i < 9; ++i){
this.addSlotToContainer(new Slot(inventoryPlayer, i, 8 + i * 18, 149));
}
}
@Override
public boolean canInteractWith(EntityPlayer player){
return true;
}
/**
* Called when a player shift-clicks on a slot. You must override this or you will crash when someone does that.
* Basically the same as every other container I make, since I define the same constant indices for all of them
*/
public ItemStack transferStackInSlot(EntityPlayer player, int par2){
ItemStack itemstack = null;
Slot slot = (Slot) this.inventorySlots.get(par2);
if (slot != null && slot.getHasStack()){
ItemStack itemstack1 = slot.getStack();
itemstack = itemstack1.copy();
// Either armor slot or custom item slot was clicked
if (par2 < INV_START){
// try to place in player inventory / action bar
if (!this.mergeItemStack(itemstack1, INV_START, HOTBAR_END + 1, true)){
return null;
}
slot.onSlotChange(itemstack1, itemstack);
}
// Item is in inventory / hotbar, try to place either in custom or armor slots
else{
// if item is our custom item
if (itemstack1.getItem() instanceof MagicItemBase){
if (!this.mergeItemStack(itemstack1, 0, InventoryCustomPlayer.INV_SIZE, false)){
return null;
}
}
// if item is armor
else if (itemstack1.getItem() instanceof ItemArmor){
int type = ((ItemArmor) itemstack1.getItem()).armorType;
if (!this.mergeItemStack(itemstack1, ARMOR_START + type, ARMOR_START + type + 1, false)){
return null;
}
}
// item in player's inventory, but not in action bar
else if (par2 >= INV_START && par2 < HOTBAR_START){
// place in action bar
if (!this.mergeItemStack(itemstack1, HOTBAR_START, HOTBAR_START + 1, false)){
return null;
}
}
// item in action bar - place in player inventory
else if (par2 >= HOTBAR_START && par2 < HOTBAR_END + 1){
if (!this.mergeItemStack(itemstack1, INV_START, INV_END + 1, false)){
return null;
}
}
}
if (itemstack1.stackSize == 0){
slot.putStack((ItemStack) null);
}
else{
slot.onSlotChanged();
}
if (itemstack1.stackSize == itemstack.stackSize){
return null;
}
slot.onPickupFromSlot(player, itemstack1);
}
return itemstack;
}
}
ExtendetPlayer:
public class ExtendedPlayer implements IExtendedEntityProperties{
/*
Here I create a constant EXT_PROP_NAME for this class of properties. You need a unique name for every instance of IExtendedEntityProperties you make, and doing it at the top of each class as a constant makes
it very easy to organize and avoid typos. It's easiest to keep the same constant name in every class, as it will be distinguished by the class name: ExtendedPlayer.EXT_PROP_NAME vs. ExtendedEntity.EXT_PROP_NAME
Note that a single entity can have multiple extended properties, so each property should have a unique name. Try to come up with something more unique than the tutorial example.
*/
public final static String EXT_PROP_NAME = "DRPPlayerData";
private final EntityPlayer player;
//Variables to add
private int currentMana;
private int maxMana;
public final InventoryCustomPlayer inventory = new InventoryCustomPlayer();
public ExtendedPlayer(EntityPlayer player){
this.player = player;
// Start with max mana. Every player starts with the same amount.
this.currentMana = this.maxMana = 20;
}
/**
* Used to register these extended properties for the player during EntityConstructing event
* This method is for convenience only; it will make your code look nicer
*/
public static final void register(EntityPlayer player){
player.registerExtendedProperties(ExtendedPlayer.EXT_PROP_NAME, new ExtendedPlayer(player));
}
/**
* Returns ExtendedPlayer properties for player
* This method is for convenience only; it will make your code look nicer
*/
public static final ExtendedPlayer get(EntityPlayer player){
return (ExtendedPlayer) player.getExtendedProperties(EXT_PROP_NAME);
}
// Save any custom data that needs saving here
@Override
public void saveNBTData(NBTTagCompound compound){
NBTTagCompound nbtData = new NBTTagCompound();
// We only have 2 variables currently; save them both to the new tag
nbtData.setInteger("CurrentMana", this.currentMana);
nbtData.setInteger("MaxMana", this.maxMana);
/*
Now add our custom tag to the player's tag with a unique name (our property's name). This will allow you to save multiple types of properties and distinguish between them. If you only have one type, it isn't as important, but it will still avoid conflicts between your tag names and vanilla tag names. For instance, if you add some "Items" tag, that will conflict with vanilla. Not good. So just use a unique tag name.
*/
this.inventory.writeToNBT(nbtData);
compound.setTag(EXT_PROP_NAME, nbtData);
}
// Load whatever data you saved
@Override
public void loadNBTData(NBTTagCompound compound){
NBTTagCompound properties = (NBTTagCompound) compound.getTag(EXT_PROP_NAME);
// Get our data from the custom tag compound
this.currentMana = properties.getInteger("CurrentMana");
this.maxMana = properties.getInteger("MaxMana");
this.inventory.readFromNBT(properties);
// Just so you know it's working, add this line:
System.out.println("[TUT PROPS] Mana from NBT: " + this.currentMana + "/" + this.maxMana);
}
@Override
public void init(Entity entity, World world){}
IInventory:
public class InventoryCustomPlayer implements IInventory{
private final String name = "DRPInventory";
private final String tagName = "DRPInvTag";
public static final int INV_SIZE = 9,SLOT_BAG = 0,SLOT_POUCH = 1,SLOT_AMULETT = 2,SLOT_RING1 = 3,SLOT_RIGN2 = 4,SLOT_BELT = 5,SLOT_QUICKCAST1 = 6,SLOT_QUICKCAST2 = 7,SLOT_QUICKCAST3 = 8;
/** Inventory's size must be same as number of slots you add to the Container class */
ItemStack[] inventory = new ItemStack[INV_SIZE];
public InventoryCustomPlayer(){}
@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);
if (stack.stackSize == 0){
setInventorySlotContents(slot, null);
}
}
else{
setInventorySlotContents(slot, null);
}
this.markDirty();
}
return stack;
}
@Override
public ItemStack getStackInSlotOnClosing(int slot){
ItemStack stack = getStackInSlot(slot);
if (stack != null){
setInventorySlotContents(slot, null);
}
return stack;
}
What 'armor slot ID' ? It works exactly the same in 1.8 as it did in previous versions: make your own SlotArmor class that is public, and off you go. It is literally copied straight from vanilla code.
Since you have slots with a stack limit of 1, you will need to override the mergeItemStack method as I explained in the tutorial.
On a side note, your isItemValidForSlot logic is faulty: it will always return true, regardless of the item (and it will also crash if the itemstack is null):
// if the stack's item is not a MagicItemBase, this conditional is skipped
if (slot == SLOT_QUICKCAST3 && itemstack.getItem() instanceof MagicItemBase) {
return true;
}
return true; // and you still return true
// What you actually want, if I am correct, is more like the following:
// For any of the quick cast slots, only allow a MagicItemBase (or null)
if (slot >= SLOT_QUICKCAST1 && slot <= SLOT_QUICKCAST3) { // this covers all of your quick cast slots, assuming they are sequential
return itemstack == null || itemstack.getItem() instanceof MagicItemBase;
}
// now you can return true knowing that the slot in question cannot possibly be a quick cast slot:
return true;
Since you have slots with a stack limit of 1, you will need to override the mergeItemStack method as I explained in the tutorial.
On a side note, your isItemValidForSlot logic is faulty: it will always return true, regardless of the item (and it will also crash if the itemstack is null):
// if the stack's item is not a MagicItemBase, this conditional is skipped
if (slot == SLOT_QUICKCAST3 && itemstack.getItem() instanceof MagicItemBase) {
return true;
}
return true; // and you still return true
// What you actually want, if I am correct, is more like the following:
// For any of the quick cast slots, only allow a MagicItemBase (or null)
if (slot >= SLOT_QUICKCAST1 && slot <= SLOT_QUICKCAST3) { // this covers all of your quick cast slots, assuming they are sequential
return itemstack == null || itemstack.getItem() instanceof MagicItemBase;
}
// now you can return true knowing that the slot in question cannot possibly be a quick cast slot:
return true;
OH Fail thank you haven't though about it.
But the Slot class has solved this problem so I think it wasn't very importent ^^
Edit: I see now that I used slot ID 4 instant 1 for my testing purposes .... But the item is still dropping when I close the Inventory
I've pretty much got this working properly. Apart from on servers sometimes the stacks flicker when you move them and sometimes rearrange themselves. Any idea how to fix this?
Thank you!
Video on glitch below I originally thought it was a problem with Inventory Tweaks but I don't think it is now.
Your code should work exactly the same whether it is on a dedicated server or not, so if you're getting strange behavior, the first place I'd look is in your Container class. Make sure all of your slots are in the location you think they are, that none overlap, etc.
Also, when debugging your code, ALWAYS disable / remove any other mods that might be affecting it, such as Inventory Tweaks, otherwise it becomes very difficult to figure out if the bug is in your code, or caused by something else.
If you have a Github repository, please post a link and I'll take a look. Also, always post the most recent code / crash report - saying 'it still doesn't work' does not provide me with any useful information.
Finally fixed the formatting (mostly) of the tutorial to work with the forum editor changes, and moved all of the tips on updating to the end of the post.
This may have been asked before, so if it has then I apologize, I'm currently pressed for time. Do you have a link to the GUI texture used? If not, what would be the best thing to use? All I want to make is a simple quiver to hold a single stack of arrows. I've got the code started and am working on it, hopefully everything goes well. My problem now is just textures.
Thanks.
insert witty signature here
I used the vanilla inventory gui texture (which is found in the vanilla .jar) and modified it by copying one of the slots and pasting it where I wanted it. Use GIMP, PhotoShop, or whatever you're comfortable with.
Gotcha, thanks. One more thing if you don't mind (sorry). I'm having an issue with this:
this.mc.func_110434_K().func_110577_a(iconLocation);
The func_110434_K() is underlined in red. I am in 1.7.10. Any suggestions on what I should change this to? I figured everything else out..
insert witty signature here
You could use some deduction to figure out what it should be: the final method takes an iconLocation, which I assume is a ResourceLocation type, so it probably has something to do with binding textures. This would imply that the previous function, the one in the Minecraft class, needs to return some type of object that has a method to bind a texture.
So, look in the Minecraft class and see if there is any method in there that returns an object that may have something to do with managing rendering, then check that object to see if it has a method that takes a ResourceLocation.
Btw, I already know what the method names are, but it's better if you learn how to figure these things out for yourself.
Oh I already long since found it on Google. Only issue I'm having now is the fact that it doesn't seem to want to save the inventory. The quiver 'eats' the arrows. Can't seem to get them back. Any idea what I'm doing wrong?
insert witty signature here
Still waiting to hear back about my GUI issue. If there's another tutorial somewhere I missed then please by all means point me to it, because I saw no other links in this tutorial. I have no issue with reading more, however Google searches have come up empty. I believe this is an issue with networking or packets, to which I've found no tutorials on that I understand, same for IExetndedEntityProperties. The last one, however, I found a tutorial for in 1.6, but it was so drastically different that inferring the transitions to 1.7.10 were impossible. Any help would be appreciated, as this is my first time doing anything with a GUI and I'm very excited that it works at all. This was a wonderful tutorial, I'm just missing a few steps is all, and I would love to be pointed in the right direction. I don't want anything written for me or anything like that - I just want to try to learn every piece of this without having to magically pull the knowledge out of my butt. And I do have a learning disability which I've overcome most of, so making it this far is a miracle for me. Just means I learn things slower, not much I can do about that. But thank you to anyone who helps me out. Hell, even a post containing a link to a decent tutorial for 1.7.10 would do it. I've been searching for a good few months to find tutorials on those things and I can't seem to find any.
insert witty signature here
You only asked about those two function names, and you replied that you found them via Google, so with what, exactly, are you still having trouble?
If you are not understanding IExtendedEntityProperties from the custom player inventory tutorial alone, you have but to look at the bottom of the main post for links to other tutorials, or in my profile, amongst which you will find one on IEEP.
Not sure if that's the problem or what it is. But basically the GUI opens up, I can put arrows in it and nothing else which is what I wanted, but when I go to open it again, the arrows aren't there. That's where I'm stuck at. I assumed IEEP was what I was missing, but I'm not sure. That's what I need help with.
However I will be checking your profile for other tutorials since you mentioned that. Seems like a great idea.
Anyway, I appreciate your help. Thanks for being patient with me.
insert witty signature here
Are you opening up the GUI on the server side? You shouldn't need any of the other tutorials if you followed this one - it contains everything you need to know to get a working custom inventory.
If you have Github or some other code repository, I could take a look, or you could post your IInventory, Container, IGuiHandler, code you use to open the GUI (is it a keybind? if so, you need to send a packet!), and IEEP classes. Use pastebin to share your code if you do, rather than pasting it all into the forum editor.
Sounds good. And no, no keybind. It's a use-on-right-click thing. Kinda odd, I realize, but it's more or less just to start out. I can fidget with everything else later. Although I don't know how to send a packet, either. And I don't have any IEEP classes, I was trying to learn those before but until I get them figured out I'm just keeping them out of the mod (unless I need them of course), to save space and clutter. GUI works fine, except for the fact that some of the slots are a bit off (things are rendering in the wrong places, but they still work - I can figure this one out on my own).
ContainerQuiver.java: http://pastebin.com/JhkuHQVJ
GUIQuiver.java: http://pastebin.com/2ACtWVAe
SlotQuiverInv.java: http://pastebin.com/eBpcpZAr
InventoryQuiver.java: http://pastebin.com/VJ9QyAR8
ItemQuiver.java: http://pastebin.com/Smx6NXFx
CommonProxy.java: http://pastebin.com/7LFLKjGu
ZollernExtrasMod.java: http://pastebin.com/gkJNs1ub (this is the main mod file)
Thanks.
EDIT:: Whoops, forgot the ItemQuiver one. Sorry, it's added now.
insert witty signature here
Okay, well before I go digging any further into your code, none of the FML-event methods should be static. Remove that.
Items, Blocks, and Entities should ALL be instantiated and registered during FMLPreInitializationEvent - move them there.
Renderers and recipes are registered where you have them; I'm not sure about the OreDictionary - that is either during pre-init after you register all of your blocks and items, or during init phase. I've never used it, so I can't tell you for sure without doing some research.
EDIT: See my actual InventoryItem implementation - you don't need the onUpdate part anymore.
EDIT 2: You also don't need any of that extra code in the Container. In your InventoryQuiver, I recommend you use the constant 'tagName' you created when reading and writing to NBT - in your write method, you did not use it - even though the value is the same, this is bad practice.
I have a problem, and I can't figure out why it isn't working.
Here is my code:
public class ContainerCustomPlayer extends Container{
private static final int ARMOR_START = InventoryCustomPlayer.INV_SIZE, ARMOR_END = ARMOR_START+3,INV_START = ARMOR_END+1, INV_END = INV_START+26, HOTBAR_START = INV_END+1,HOTBAR_END = HOTBAR_START+8;
public ContainerCustomPlayer(EntityPlayer player, InventoryPlayer inventoryPlayer, InventoryCustomPlayer inventoryCustom){
int i;
//custom Slots
this.addSlotToContainer(new SLOT_POUCH(inventoryCustom, 0, 116, -1));
this.addSlotToContainer(new SLOT_POUCH(inventoryCustom, 1, 116, 17));
this.addSlotToContainer(new SLOT_POUCH(inventoryCustom, 2, 116, 35));
this.addSlotToContainer(new SLOT_POUCH(inventoryCustom, 3, 116, 53));
this.addSlotToContainer(new SLOT_POUCH(inventoryCustom, 4, 116, 71));
// Armor Slots
for (i = 0; i < 4; ++i){
this.addSlotToContainer(new SLOT_ARMOR(player, inventoryPlayer, inventoryPlayer.getSizeInventory() - 1 - i, 44, -1 + i * 18, i));
}
// Add vanilla PLAYER INVENTORY - just copied/pasted from vanilla classes
for (i = 0; i < 3; ++i){
for (int j = 0; j < 9; ++j){
this.addSlotToContainer(new Slot(inventoryPlayer, j + i * 9 + 9, 8 + j * 18, 91 + i * 18));
}
}
//Hotbar
for (i = 0; i < 9; ++i){
this.addSlotToContainer(new Slot(inventoryPlayer, i, 8 + i * 18, 149));
}
}
@Override
public boolean canInteractWith(EntityPlayer player){
return true;
}
/**
* Called when a player shift-clicks on a slot. You must override this or you will crash when someone does that.
* Basically the same as every other container I make, since I define the same constant indices for all of them
*/
public ItemStack transferStackInSlot(EntityPlayer player, int par2){
ItemStack itemstack = null;
Slot slot = (Slot) this.inventorySlots.get(par2);
if (slot != null && slot.getHasStack()){
ItemStack itemstack1 = slot.getStack();
itemstack = itemstack1.copy();
// Either armor slot or custom item slot was clicked
if (par2 < INV_START){
// try to place in player inventory / action bar
if (!this.mergeItemStack(itemstack1, INV_START, HOTBAR_END + 1, true)){
return null;
}
slot.onSlotChange(itemstack1, itemstack);
}
// Item is in inventory / hotbar, try to place either in custom or armor slots
else{
// if item is our custom item
if (itemstack1.getItem() instanceof MagicItemBase){
if (!this.mergeItemStack(itemstack1, 0, InventoryCustomPlayer.INV_SIZE, false)){
return null;
}
}
// if item is armor
else if (itemstack1.getItem() instanceof ItemArmor){
int type = ((ItemArmor) itemstack1.getItem()).armorType;
if (!this.mergeItemStack(itemstack1, ARMOR_START + type, ARMOR_START + type + 1, false)){
return null;
}
}
// item in player's inventory, but not in action bar
else if (par2 >= INV_START && par2 < HOTBAR_START){
// place in action bar
if (!this.mergeItemStack(itemstack1, HOTBAR_START, HOTBAR_START + 1, false)){
return null;
}
}
// item in action bar - place in player inventory
else if (par2 >= HOTBAR_START && par2 < HOTBAR_END + 1){
if (!this.mergeItemStack(itemstack1, INV_START, INV_END + 1, false)){
return null;
}
}
}
if (itemstack1.stackSize == 0){
slot.putStack((ItemStack) null);
}
else{
slot.onSlotChanged();
}
if (itemstack1.stackSize == itemstack.stackSize){
return null;
}
slot.onPickupFromSlot(player, itemstack1);
}
return itemstack;
}
}
ExtendetPlayer:
public class ExtendedPlayer implements IExtendedEntityProperties{
/*
Here I create a constant EXT_PROP_NAME for this class of properties. You need a unique name for every instance of IExtendedEntityProperties you make, and doing it at the top of each class as a constant makes
it very easy to organize and avoid typos. It's easiest to keep the same constant name in every class, as it will be distinguished by the class name: ExtendedPlayer.EXT_PROP_NAME vs. ExtendedEntity.EXT_PROP_NAME
Note that a single entity can have multiple extended properties, so each property should have a unique name. Try to come up with something more unique than the tutorial example.
*/
public final static String EXT_PROP_NAME = "DRPPlayerData";
private final EntityPlayer player;
//Variables to add
private int currentMana;
private int maxMana;
public final InventoryCustomPlayer inventory = new InventoryCustomPlayer();
public ExtendedPlayer(EntityPlayer player){
this.player = player;
// Start with max mana. Every player starts with the same amount.
this.currentMana = this.maxMana = 20;
}
/**
* Used to register these extended properties for the player during EntityConstructing event
* This method is for convenience only; it will make your code look nicer
*/
public static final void register(EntityPlayer player){
player.registerExtendedProperties(ExtendedPlayer.EXT_PROP_NAME, new ExtendedPlayer(player));
}
/**
* Returns ExtendedPlayer properties for player
* This method is for convenience only; it will make your code look nicer
*/
public static final ExtendedPlayer get(EntityPlayer player){
return (ExtendedPlayer) player.getExtendedProperties(EXT_PROP_NAME);
}
// Save any custom data that needs saving here
@Override
public void saveNBTData(NBTTagCompound compound){
NBTTagCompound nbtData = new NBTTagCompound();
// We only have 2 variables currently; save them both to the new tag
nbtData.setInteger("CurrentMana", this.currentMana);
nbtData.setInteger("MaxMana", this.maxMana);
/*
Now add our custom tag to the player's tag with a unique name (our property's name). This will allow you to save multiple types of properties and distinguish between them. If you only have one type, it isn't as important, but it will still avoid conflicts between your tag names and vanilla tag names. For instance, if you add some "Items" tag, that will conflict with vanilla. Not good. So just use a unique tag name.
*/
this.inventory.writeToNBT(nbtData);
compound.setTag(EXT_PROP_NAME, nbtData);
}
// Load whatever data you saved
@Override
public void loadNBTData(NBTTagCompound compound){
NBTTagCompound properties = (NBTTagCompound) compound.getTag(EXT_PROP_NAME);
// Get our data from the custom tag compound
this.currentMana = properties.getInteger("CurrentMana");
this.maxMana = properties.getInteger("MaxMana");
this.inventory.readFromNBT(properties);
// Just so you know it's working, add this line:
System.out.println("[TUT PROPS] Mana from NBT: " + this.currentMana + "/" + this.maxMana);
}
@Override
public void init(Entity entity, World world){}
IInventory:
public class InventoryCustomPlayer implements IInventory{
private final String name = "DRPInventory";
private final String tagName = "DRPInvTag";
public static final int INV_SIZE = 9,SLOT_BAG = 0,SLOT_POUCH = 1,SLOT_AMULETT = 2,SLOT_RING1 = 3,SLOT_RIGN2 = 4,SLOT_BELT = 5,SLOT_QUICKCAST1 = 6,SLOT_QUICKCAST2 = 7,SLOT_QUICKCAST3 = 8;
/** Inventory's size must be same as number of slots you add to the Container class */
ItemStack[] inventory = new ItemStack[INV_SIZE];
public InventoryCustomPlayer(){}
@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);
if (stack.stackSize == 0){
setInventorySlotContents(slot, null);
}
}
else{
setInventorySlotContents(slot, null);
}
this.markDirty();
}
return stack;
}
@Override
public ItemStack getStackInSlotOnClosing(int slot){
ItemStack stack = getStackInSlot(slot);
if (stack != null){
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();
}
this.markDirty();
}
/**
* Our custom slots are similar to armor - only one item per slot
*/
@Override
public int getInventoryStackLimit(){
return 1;
}
@Override
public boolean isUseableByPlayer(EntityPlayer entityplayer){
return true;
}
/**
* 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){
if(slot == SLOT_POUCH && itemstack.getItem().equals(itemPurse.itemPurse)){
return true;
}
if(slot == SLOT_QUICKCAST1 && itemstack.getItem() instanceof MagicItemBase){
return true;
}
if(slot == SLOT_QUICKCAST2 && itemstack.getItem() instanceof MagicItemBase){
return true;
}
if(slot == SLOT_QUICKCAST3 && itemstack.getItem() instanceof MagicItemBase){
return true;
}
return true;
}
public void writeToNBT(NBTTagCompound tagcompound){
NBTTagList nbttaglist = new NBTTagList();
for (int i = 0; i < this.getSizeInventory(); ++i){
if (this.getStackInSlot(i) != null){
NBTTagCompound nbttagcompound1 = new NBTTagCompound();
nbttagcompound1.setByte("Slot", (byte) i);
this.getStackInSlot(i).writeToNBT(nbttagcompound1);
nbttaglist.appendTag(nbttagcompound1);
}
}
tagcompound.setTag(tagName, nbttaglist);
}
public void readFromNBT(NBTTagCompound tagcompound){
NBTTagList nbttaglist = tagcompound.getTagList(tagName,10);
for (int i = 0; i < nbttaglist.tagCount(); ++i){
NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.getCompoundTagAt(i);
byte b0 = nbttagcompound1.getByte("Slot");
if (b0 >= 0 && b0 < this.getSizeInventory()){
this.setInventorySlotContents(b0, ItemStack.loadItemStackFromNBT(nbttagcompound1));
}
}
}
@Override
public String getName() {
return name;
}
@Override
public boolean hasCustomName() {
return name.length() > 0;
}
@Override
public IChatComponent getDisplayName() {
return null;
}
@Override
public void markDirty() {
for (int i = 0; i < this.getSizeInventory(); ++i){
if (this.getStackInSlot(i) != null && this.getStackInSlot(i).stackSize == 0){
this.setInventorySlotContents(i, null);
}
}
}
@Override
public void openInventory(EntityPlayer player) {}
@Override
public void closeInventory(EntityPlayer player) {}
@Override
public int getField(int id) {
return 0;
}
@Override
public void setField(int id, int value) {
}
@Override
public int getFieldCount() {
return 0;
}
@Override
public void clear() {
for (int i = 0; i < inventory.length; ++i) {
inventory[ i ] = null;
}
}
}
The problem is every time I put something into my custom Slot the Items just drops after I close the inventory.
when I reopen it its still in the slot I put it.
I am trying now to find the problem since 3 days....
I would be very glad about any help.
What 'armor slot ID' ? It works exactly the same in 1.8 as it did in previous versions: make your own SlotArmor class that is public, and off you go. It is literally copied straight from vanilla code.
On a side note, your isItemValidForSlot logic is faulty: it will always return true, regardless of the item (and it will also crash if the itemstack is null):
OH Fail thank you haven't though about it.
But the Slot class has solved this problem so I think it wasn't very importent ^^
Edit: I see now that I used slot ID 4 instant 1 for my testing purposes .... But the item is still dropping when I close the Inventory
Ps. can't look at this forum for 5 days now sorry
FINALLY got it to work. Thanks for your help and for the link to your repository, it was incredibly helpful.
insert witty signature here
Hey, fantastic tutorial!!!
I've pretty much got this working properly. Apart from on servers sometimes the stacks flicker when you move them and sometimes rearrange themselves. Any idea how to fix this?
Thank you!
Video on glitch below I originally thought it was a problem with Inventory Tweaks but I don't think it is now.
Flux Networks - CurseForge - Source Code
Practical Logistics 2 - CurseForge - Source Code
Calculator - CurseForge - Source Code
Bagelsmore - CurseForge - Source Code
Your code should work exactly the same whether it is on a dedicated server or not, so if you're getting strange behavior, the first place I'd look is in your Container class. Make sure all of your slots are in the location you think they are, that none overlap, etc.
Also, when debugging your code, ALWAYS disable / remove any other mods that might be affecting it, such as Inventory Tweaks, otherwise it becomes very difficult to figure out if the bug is in your code, or caused by something else.