Jump to content

IItemHandler and Capability attempt [1.10.2]


Alexiy

Recommended Posts

Here is my first attempt at using Capability and IItemHandler. The tile seems to work fine, but I would like someone's review to verify that I did this right or if something can be improved.

 

public class TileStrongChest extends GeneralTileEntity implements IItemHandlerModifiable
{
    final static public String CHESTTYPE="Chest type",ITEMSTACK="Item stack";
    public int type;
    ItemStack[] storage;
    static public Capability<IItemHandler> iItemHandler=CapabilityItemHandler.ITEM_HANDLER_CAPABILITY;
    public ItemStackHandler itemStackHandler;
    public TileStrongChest(){super();}
    public TileStrongChest(int metadata)
    {
        super();
        type=metadata;
        storage=new ItemStack[metadata==0 ? 54 : metadata==1 ? 81 : 108];
        itemStackHandler=new ItemStackHandler(storage);
    }

    @Override
    public boolean hasCapability(Capability<?> capability, EnumFacing facing)
    {
        if(capability==iItemHandler) return true;
        return super.hasCapability(capability, facing);
    }

    @Override
    public <T> T getCapability(Capability<T> capability, EnumFacing facing)
    {
        if(capability==iItemHandler) return (T) this;
        return super.getCapability(capability, facing);
    }

    @Nullable
    @Override
    public ITextComponent getDisplayName()
    {
        int stacks=0;
        for (int i = 0; i < getSlots(); i++)
        {
            if(storage[i]!=null)stacks++;
        }
        return new TextComponentString(stacks+"/"+ getSlots());
    }

  
    @Override
    public int getSlots()
    {
        return storage.length;
    }

   
    @Override
    public ItemStack getStackInSlot(int slot)
    {
        return storage[slot];
    }

  
    @Override
    public ItemStack insertItem(int slot, ItemStack stack, boolean simulate)
    {
        return itemStackHandler.insertItem(slot,stack,simulate);
    }

   
    @Override
    public ItemStack extractItem(int slot, int amount, boolean simulate)
    {

        return itemStackHandler.extractItem(slot,amount,simulate);
    }

    
    @Override
    public void setStackInSlot(int slot, ItemStack stack)
    {
        storage[slot]=stack;
    }

    @Override
    public NBTTagCompound writeToNBT(NBTTagCompound compound)
    {
        NBTTagCompound nbtTagCompound=super.writeToNBT(compound);
        int number=0;
        for(ItemStack itemStack: storage)
        {
            if(itemStack!=null)
            {

                NBTTagCompound item=itemStack.writeToNBT(new NBTTagCompound());
                compound.setTag(ITEMSTACK+number,item);
            }
            number++;
        }
        nbtTagCompound.setShort(CHESTTYPE, (short) type);
        return nbtTagCompound;
    }

    @Override
    public void readFromNBT(NBTTagCompound compound)
    {
        super.readFromNBT(compound);
        type=compound.getShort(CHESTTYPE);
        switch (type)
        {
            case 0: storage=new ItemStack[54];break;
            case 1: storage=new ItemStack[81];break;
            case 2: storage=new ItemStack[108];break;
        }
        for (int i = 0; i < storage.length; i++)
        {
            ItemStack itemStack=ItemStack.loadItemStackFromNBT(compound.getCompoundTag(ITEMSTACK+i));
            if(itemStack!=null)storage[i]=itemStack;
        }
        itemStackHandler=new ItemStackHandler(storage);
    }
}

Link to comment
Share on other sites

The whole point of the Capability system is that you don't implement interfaces on your

TileEntity

, instead you store the objects in the

TileEntity

and override the

ICapabilityProvider

methods to return them. Forge's documentation explains this in more detail here. I also have a simple explanation here.

 

  • Don't implement
    IItemHandler

    on your

    TileEntity

    .

  • Either use the
    CapabilityItemHandler.ITEM_HANDLER_CAPABILITY

    field directly or annotate your own field with

    @CapabilityInject

    . Don't use the existing field to initialise your own.

  • Don't store the
    ItemStack

    array, only interact with your inventory through the

    ItemStackHandler


  • ItemStackHandler

    implements

    INBTSerializable

    , use this to write it to and read it from NBT

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

All right, I refactored it, now it looks like this:

public class TileStrongChest extends GeneralTileEntity
{
    final static public String CHESTTYPE = "Chest type", ITEMSTACKS = "Item stacks";
    public int type;

    public ItemStackHandler itemStackHandler;
    public TileStrongChest() {super();}

    public TileStrongChest(int metadata)
    {
        super();
        type = metadata;
        itemStackHandler=new ItemStackHandler(metadata==0 ? 54 : metadata==1 ? 81 : 108);
    }

    @Override
    public boolean hasCapability(Capability<?> capability, EnumFacing facing)
    {
        if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return true;
        return super.hasCapability(capability, facing);
    }

    @Override
    public <T> T getCapability(Capability<T> capability, EnumFacing facing)
    {
        if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return (T) itemStackHandler;
        return super.getCapability(capability, facing);
    }

    @Nullable
    @Override
    public ITextComponent getDisplayName()
    {
        int stacks=0;
        for (int i = 0; i < itemStackHandler.getSlots(); i++)
        {
            if(itemStackHandler.getStackInSlot(i)!=null)stacks++;
        }
        return new TextComponentString(stacks+"/"+ itemStackHandler.getSlots());
    }

    @Override
    public NBTTagCompound writeToNBT(NBTTagCompound compound)
    {
        NBTTagCompound nbtTagCompound=super.writeToNBT(compound);
        NBTTagCompound handlernbt= itemStackHandler.serializeNBT();
        nbtTagCompound.setTag(ITEMSTACKS,handlernbt);
        nbtTagCompound.setShort(CHESTTYPE, (short) type);
        return nbtTagCompound;
    }

    @Override
    public void readFromNBT(NBTTagCompound compound)
    {
        super.readFromNBT(compound);
        type=compound.getShort(CHESTTYPE);
        itemStackHandler=new ItemStackHandler();
        itemStackHandler.deserializeNBT(compound.getCompoundTag(ITEMSTACKS));
    }

}

 

Seems to be working.

Although I have read the docs few times, I didn't understand it right away. I assert that it needs to show an example, or a link to one.

Link to comment
Share on other sites

That looks correct.

 

I believe LexManos is strongly against the Forge documentation containing any "copy-pasta" code, i.e. fully working code blocks with minimal explanation apart from "copy this code into your code to make it work". If you have some well-documented example code, it may be added (though I don't speak for the Forge team).

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

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.

Announcements



×
×
  • Create New...

Important Information

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