Jump to content

[1.10.2] Custom inventory item (backpack) duplicate item and unable to retrieve


Islandil

Recommended Posts

I implemented an item when shift right clicked open a GUI with the inventory and 2 more slot using mainly https://github.com/coolAlias/Forge_Tutorials/blob/master/InventoryItemTutorial.java as inspiration.

After a day of debugging I don't understand why when I put item inside my custom inventory the quantity is double and why when I try to retrieve from the custom inventory the item are deleted.

 

l46Ce9ps13QcIdnGw.gif

 

Here is a part of the Container

 

@Nullable
    @Override
    public ItemStack transferStackInSlot(EntityPlayer player, int fromSlotIndex) {
        ItemStack previous = null;
        Slot fromSlot = (Slot) this.inventorySlots.get(fromSlotIndex);

        if (fromSlot != null && fromSlot.getHasStack()) {
            ItemStack current = fromSlot.getStack();
            previous = current.copy();

            if (fromSlotIndex < INVENTORY_START) {
                // Player to inventory
                if (!this.mergeItemStack(current, HOTBAR_START, INVENTORY_START, false))
                    return null;
            } else {
                // Inventory to player
                if (!this.mergeItemStack(current, INVENTORY_START, INVENTORY_START + inventory.getSizeInventory(), false))
                    return null;
            }

            if (current.stackSize == 0) {
                fromSlot.putStack((ItemStack) null);
            } else {
                fromSlot.onSlotChanged();
            }

            if (current.stackSize == previous.stackSize) {
                return null;
            }
            fromSlot.onPickupFromSlot(player, current);
        }
        return previous;
    }

    @Nullable
    @Override
    public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, EntityPlayer player) {
        if (slotId >= 0
                && getSlot(slotId) != null
                && getSlot(slotId).getStack() == player.getHeldItem(EnumHand.MAIN_HAND)) {
            return null;
        }
        return super.slotClick(slotId, dragType, clickTypeIn, player);
    }

 

and the IInventory

 

@Nullable
    @Override
    public ItemStack decrStackSize(int index, int amount) {
        ItemStack stack = getStackInSlot(index);
        if (stack != null) {
            if (amount < stack.stackSize) {
                setInventorySlotContents(index, stack.splitStack(amount));
            } else if (amount == stack.stackSize) {
                removeStackFromSlot(index);
            } else {
                throw new IllegalArgumentException("Cannot remove " + amount + " from a stack size of " + stack.stackSize);
            }
        }
        return stack;
    }

    // Remove an item from the inventory
    @Nullable
    @Override
    public ItemStack removeStackFromSlot(int index) {
        ItemStack removedStack = getStackInSlot(index);
        if (indexInRange(index)) {
            inventory[getLinkedIndex(index)] = null;
        }
        return removedStack;
    }

    // Add an item to the inventory
    @Override
    public void setInventorySlotContents(int index, @Nullable ItemStack stack) {
        if (isItemValidForSlot(index, stack)) {
            inventory[getLinkedIndex(index)] = stack;
        }
        markDirty();
    }

@Override
    public void markDirty() {
        for (int i = 0; i < getSizeInventory(); ++i) {
            if (inventory[i] != null
                    && inventory[i].stackSize == 0) {
                inventory[i] = null;
            }
        }
        writeToNBT(inventoryItem.getTagCompound());
    }

// Get inventory content stored inside NBT tags on item stack
    public void readFromNBT(NBTTagCompound compound) {
        NBTTagList itemsList = compound.getTagList(NBT_TAG_LIST_KEY, Constants.NBT.TAG_COMPOUND);
        for (int i = 0; i < itemsList.tagCount(); ++i) {
            NBTTagCompound item = itemsList.getCompoundTagAt(i);
            int slot = item.getInteger(NBT_TAG_ITEM_SLOT_KEY);
            if (indexInRange(slot)) {
                inventory[slot] = ItemStack.loadItemStackFromNBT(item);
            }
        }
    }

    // Write inventory data to NBT tag list on item stack
    public void writeToNBT(NBTTagCompound compound) {
        NBTTagList itemsList = new NBTTagList();
        for (int i = 0; i < getSizeInventory(); ++i) {
            if (inventory[i] != null) {
                NBTTagCompound item = new NBTTagCompound();
                item.setInteger(NBT_TAG_ITEM_SLOT_KEY, i);
                inventory[i].writeToNBT(item);
                itemsList.appendTag(item);
            }
        }
        compound.setTag(NBT_TAG_LIST_KEY, itemsList);
    }

Link to comment
Share on other sites

The duplication came from not overriding this method inside the Container

 

    @Override
    public boolean getCanCraft(EntityPlayer player) {
        return false;
    }

 

But when I try to retrieve item from the additional inventory slots the amount is zero. So my second problem is still here.

Link to comment
Share on other sites

@Nullable
    @Override
    public ItemStack getStackInSlot(int index) {
        return indexInRange(index) ? inventory[getLinkedIndex(index)] : null;
    }

 

private boolean indexInRange(int index) {
        index = getLinkedIndex(index);
        if (index >= 0 && index < getSizeInventory()) {
            return true;
        } else {
            throw new IndexOutOfBoundsException("Access index " + index + " is outside inventory index range, max " + getSizeInventory());
        }
    }

    private int getLinkedIndex(int index) {
        return index - ItemContainer.INVENTORY_START;
    }

Link to comment
Share on other sites

public static final int INVENTORY_START = 36;

 

I use this in my custom Container to add the hotbar (0-8) next the player inventory (9-35) and next my two additional slots (36-37), since I need to calculate the corresponding index in my IInventory (0-1) I use a constant. Bad practice ?

Link to comment
Share on other sites

I use this in my custom Container to add the hotbar (0-8) next the player inventory (9-35) and next my two additional slots (36-37), since I need to calculate the corresponding index in my IInventory (0-1) I use a constant. Bad practice ?

 

Maybe you miss my edit, sorry.

Link to comment
Share on other sites

Changed the getLinkedIndex to return the index parameter. Now isIndexInRange throw IndexOutOfBoundsException. Because the index given is 36 and 37 and is out side 0-1.

 

private boolean isIndexInRange(int index) {
        index = getLinkedIndex(index);
        if (index >= 0 && index < getSizeInventory()) {
            return true;
        } else {
            throw new IndexOutOfBoundsException("Access index " + index + " is outside inventory index range, max " + getSizeInventory());
        }
    }

    private int getLinkedIndex(int index) {
        return index;
    }

 

It seems that the Container send the slot index and not the inventory index. Is there a problem in my Container ?

Link to comment
Share on other sites

Container

 

 

 

public class ItemContainer extends Container {

    public static final int HOTBAR_START = 0;
    public static final int PLAYER_INVENTORY_START = 9;
    public static final int PLAYER_ARMOR_INVENTORY_START = 36;
    public static final int INVENTORY_START = 36;

    private final ItemInventory inventory;
    private final IInventory playerInventory;

    public ItemContainer(IInventory playerInventory, ItemInventory inventory) {
        this.inventory = inventory;
        this.playerInventory = playerInventory;

        // Hotbar slots
        for (int x = 0; x < 9; x++) {
            addSlotToContainer(new Slot(playerInventory, x, 8 + x * 18, 142));
        }

        // Player inventory slots
        for (int y = 0; y < 3; y++) {
            for (int x = 0; x < 9; x++) {
                addSlotToContainer(new Slot(playerInventory, x + y * 9 + PLAYER_INVENTORY_START, 8 + x * 18, 84 + y * 18));
            }
        }

        // Player armor slots
        /*for (int y = 0; y < 4; y++) {
            addSlotToContainer(new Slot(playerInventory, y + PLAYER_ARMOR_INVENTORY_START, 8, 8 + y * 18));
        }*/

        // Inventory slots
        for (int y = 0; y < inventory.getSizeInventory(); y++) {
            addSlotToContainer(new SlotItemInventory(inventory, y + INVENTORY_START, 80, 8 + y * 18));
        }
    }

    @Nullable
    @Override
    public ItemStack transferStackInSlot(EntityPlayer player, int fromSlotIndex) {
        ItemStack previous = null;
        Slot fromSlot = (Slot) this.inventorySlots.get(fromSlotIndex);

        if (fromSlot != null && fromSlot.getHasStack()) {
            ItemStack current = fromSlot.getStack();
            previous = current.copy();

            if (fromSlotIndex < INVENTORY_START) {
                // Inventory to player
                if (!this.mergeItemStack(current, INVENTORY_START, INVENTORY_START + inventory.getSizeInventory(), true)) {
                    return null;
                }
                fromSlot.onSlotChange(current, previous);
            } else {
                // Player to inventory
                if (!this.mergeItemStack(current, HOTBAR_START, INVENTORY_START, false)) {
                    return null;
                }
            }

            if (current.stackSize == 0) {
                fromSlot.putStack((ItemStack) null);
            } else {
                fromSlot.onSlotChanged();
            }

            if (current.stackSize == previous.stackSize) {
                return null;
            }
            fromSlot.onPickupFromSlot(player, current);
        }
        return previous;
    }

    @Override
    public boolean canInteractWith(EntityPlayer player) {
        return inventory.isUseableByPlayer(player);
    }

    @Nullable
    @Override
    public ItemStack slotClick(int slotId, int dragType, ClickType clickType, EntityPlayer player) {
        if (slotId >= 0
                && getSlot(slotId) != null
                && getSlot(slotId).getStack() == player.getHeldItem(EnumHand.MAIN_HAND)) {
            return null;
        }
        return super.slotClick(slotId, dragType, clickType, player);
    }

    public ItemInventory getItemInventory() {
        return inventory;
    }

    @Override
    public boolean getCanCraft(EntityPlayer player) {
        return false;
    }

    // Provide filtering ability on item inventory
    public class SlotItemInventory extends Slot {

        ItemInventory inventory;

        public SlotItemInventory(ItemInventory inventory, int index, int xPosition, int yPosition) {
            super(inventory, index, xPosition, yPosition);

            this.inventory = inventory;
        }

        @Override
        public boolean isItemValid(@Nullable ItemStack stack) {
            return stack != null ? inventory.isWhitelisted(stack.getItem()) && !inventory.isBlacklisted(stack.getItem()) : true;
        }
    }
}

 

 

 

IInventory

 

 

 

public class ItemInventory implements IInventory {

    private static final String NBT_TAG_LIST_KEY = MYMOD.MODID + ":item_inventory_items_list";
    private static final String NBT_TAG_ITEM_SLOT_KEY = MYMOD.MODID + ":item_inventory_item_slot";

    private final String name;
    private final ItemStack inventoryItem;

    protected String ID;
    protected String IDTagKey;

    private ItemStack[] inventory;
    private Item[] whitelist;
    private Item[] blacklist;
    private boolean whitelistEnabled = true;

    public ItemInventory(ItemStack stack, int sizeInventory, String name) {
        this.inventoryItem = stack;
        this.inventory = new ItemStack[sizeInventory];
        this.name = name;
        this.IDTagKey = MYMOD.MODID + ":" + name + "_ID";

        if (!stack.hasTagCompound() || ID == null) {
            stack.setTagCompound(new NBTTagCompound());
            this.ID = UUID.randomUUID().toString();
            stack.getTagCompound().setString(IDTagKey, ID);
        }

        readFromNBT(stack.getTagCompound());
    }

    @Override
    public int getSizeInventory() {
        return inventory.length;
    }

    @Nullable
    @Override
    public ItemStack getStackInSlot(int index) {
        return isIndexInRange(index) ? inventory[getLinkedIndex(index)] : null;
    }

    @Nullable
    @Override
    public ItemStack decrStackSize(int index, int amount) {
        ItemStack stack = getStackInSlot(index);
        if (stack != null) {
            if (amount <= stack.stackSize) {
                setInventorySlotContents(index, stack.splitStack(amount));
            } else {
                throw new IllegalArgumentException("Cannot remove " + amount + " from a stack size of " + stack.stackSize);
            }
        }
        return stack;
    }

    // Remove an item from the inventory
    @Nullable
    @Override
    public ItemStack removeStackFromSlot(int index) {
        ItemStack stack = getStackInSlot(index);
        setInventorySlotContents(index, null);
        return stack;
    }

    // Add an item to the inventory
    @Override
    public void setInventorySlotContents(int index, @Nullable ItemStack stack) {
        inventory[getLinkedIndex(index)] = stack;
        if (stack != null && stack.stackSize > getInventoryStackLimit()) {
            stack.stackSize = getInventoryStackLimit();
        }
        markDirty();
    }

    @Override
    public int getInventoryStackLimit() {
        return 64;
    }

    @Override
    public void markDirty() {
        for (int i = 0; i < getSizeInventory(); ++i) {
            if (inventory[i] != null
                    && inventory[i].stackSize == 0) {
                inventory[i] = null;
            }
        }
        writeToNBT(inventoryItem.getTagCompound());
    }

    @Override
    public boolean isUseableByPlayer(EntityPlayer player) {
        return true;
    }

    @Override
    public void openInventory(EntityPlayer player) {
    }

    @Override
    public void closeInventory(EntityPlayer player) {
    }

    // Check if the new item is valid for this inventory
    @Override
    public boolean isItemValidForSlot(int index, ItemStack stack) {
        return isWhitelisted(stack.getItem()) && !isBlacklisted(stack.getItem());
    }

    @Override
    public int getField(int id) {
        return 0;
    }

    @Override
    public void clear() {
        for (int i = 0; i < getSizeInventory(); i++) {
            removeStackFromSlot(i);
        }
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public boolean hasCustomName() {
        return false;
    }

    @Override
    public ITextComponent getDisplayName() {
        return null;
    }

    @Override
    public void setField(int id, int value) {
    }

    @Override
    public int getFieldCount() {
        return 0;
    }

    public Item[] getWhitelist() {
        return whitelist;
    }

    public void setWhitelist(Item[] whitelist) {
        whitelistEnabled = true;
        this.whitelist = whitelist;
    }

    public boolean isWhitelisted(Item item) {
        if (whitelistEnabled
                && whitelist != null) {
            for (Item itemWhitelisted : whitelist) {
                if (itemWhitelisted == item) {
                    return true;
                }
            }
        }
        return false;
    }

    public Item[] getBlacklist() {
        return blacklist;
    }

    public void setBlacklist(Item[] blacklist) {
        whitelistEnabled = false;
        this.blacklist = blacklist;
    }

    public boolean isBlacklisted(Item item) {
        if (!whitelistEnabled
                && blacklist != null) {
            for (Item itemBlackisted : blacklist) {
                if (itemBlackisted == item) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isIndexInRange(int index) {
        index = getLinkedIndex(index);
        if (index >= 0 && index < getSizeInventory()) {
            return true;
        } else {
            throw new IndexOutOfBoundsException("Access index " + index + " is outside inventory index range, max " + getSizeInventory());
        }
    }

    private int getLinkedIndex(int index) {
        return index;
    }

    // Get inventory content stored inside NBT tags on item stack
    public void readFromNBT(NBTTagCompound compound) {
        NBTTagList itemsList = compound.getTagList(NBT_TAG_LIST_KEY, Constants.NBT.TAG_COMPOUND);
        for (int i = 0; i < itemsList.tagCount(); ++i) {
            NBTTagCompound item = itemsList.getCompoundTagAt(i);
            int slot = item.getInteger(NBT_TAG_ITEM_SLOT_KEY);
            if (isIndexInRange(slot)) {
                inventory[slot] = ItemStack.loadItemStackFromNBT(item);
            }
        }
    }

    // Write inventory data to NBT tag list on item stack
    public void writeToNBT(NBTTagCompound compound) {
        NBTTagList itemsList = new NBTTagList();
        for (int i = 0; i < getSizeInventory(); ++i) {
            if (inventory[i] != null) {
                NBTTagCompound item = new NBTTagCompound();
                item.setInteger(NBT_TAG_ITEM_SLOT_KEY, i);
                inventory[i].writeToNBT(item);
                itemsList.appendTag(item);
            }
        }
        compound.setTag(NBT_TAG_LIST_KEY, itemsList);
    }
}

 

 

Link to comment
Share on other sites

 

    @Nullable
    @Override
    public ItemStack removeStackFromSlot(int index) {
        ItemStack stack = getStackInSlot(index);
        setInventorySlotContents(index, null);
        return stack;
    }

 

Instead of

ItemStack stack = getStackInSlot(index);
// Do this
ItemStack stack = itemstacks[index];

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

Try this for decrStackSize

 

if (this.mainSlots[index].stackSize <= count) {
            	itemstack = this.mainSlots[index];
            	this.mainSlots[index] = null;
            	return itemstack;
        	}
        	else {
            	itemstack = this.mainSlots[index].splitStack(count);
            	if (this.mainSlots[index].stackSize == 0) {
            		this.mainSlots[index] = null;
            	}
            	return itemstack;
        	}

 

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

Did this implementation (otherwise I was getting a out of bounds exception)

 

@Nullable
    @Override
    public ItemStack decrStackSize(int index, int amount) {
        ItemStack stack;
        if (inventory[getLinkedIndex(index)].stackSize <= amount) {
            stack = inventory[getLinkedIndex(index)];
            inventory[getLinkedIndex(index)] = null;
        }
        else {
            stack = inventory[getLinkedIndex(index)].splitStack(amount);
            if (inventory[getLinkedIndex(index)].stackSize == 0) {
                inventory[getLinkedIndex(index)] = null;
            }
        }
        return stack;
    }

 

And it works.

 

Thanks a lot !

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.