Jump to content

[Solved]Adding IItemHandler Capability to player makes it use items from the hotbar. - PlayerEntity + IItemHandler


Recommended Posts

Posted (edited)

I've been trying to figure out how to add a Capability to the player. I've used the Forge documentation so far. 

 

I'm trying to register the IItemhandler capability to the player. I've created a custom class called CustomItemBar with that registers an Event in my PreInit with an attachCapabilitiesEvent that checks if the entity is a player, then adds the capability.

 

I've created the following class to call events and contain a basic wrapper to call my capability from other locations: 

public class CustomItemBar {

    public static void register(){
        MinecraftForge.EVENT_BUS.register(new CustomItemBar());

    }
    @SubscribeEvent
    public void attachCapabilities(AttachCapabilitiesEvent<Entity> event){
        if(event.getObject() instanceof EntityPlayer) {
            event.addCapability(new ResourceLocation("InventoryCapability"), new AbilityProvider());
            System.out.println("Capability added");
        }
    }

    public static IItemHandler getHandler(Entity entity){
        if(entity.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null)){
            return entity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
        }
        return null;
    }

}

 

I add the capability through AbilityProvider which is as follows: 

public class AbilityProvider implements ICapabilitySerializable<NBTTagCompound>,ICapabilityProvider {

    public static ItemStackHandler handler = new ItemStackHandler(5);

    @Override
    public boolean hasCapability(Capability<?> capability, EnumFacing facing) {
        if (capability == ITEM_HANDLER_CAPABILITY) {

            System.out.println("has item handler capability");
            return true;
        }
        return false;
    }

    @Override
    public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
        if(capability == ITEM_HANDLER_CAPABILITY){
            System.out.println("We returned the handler");
            return (T)this.handler;
        }
        System.out.println("We returned null");
        return null;
    }


    @Override
    public NBTTagCompound serializeNBT() {
        return handler.serializeNBT();
    }

    @Override
    public void deserializeNBT(NBTTagCompound nbt) {
        handler.deserializeNBT(nbt);
    }

}

As you can see I'm using ItemStackHandler with a size of 5, 

 

When I launch the client everything works fine. When I log in to my world I get the proper 

System.out.println("Custom ability added");

 

line returned to me in the logs. 

 

However, this is where it goes wrong: When I try to use 

    public static IItemHandler getHandler(Entity entity){
        if(entity.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null)){
            return entity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
        }
        return null;
    }

in my items. I don't get the 

    @Override
    public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
        if(capability == ITEM_HANDLER_CAPABILITY){
            System.out.println("We returned the handler");
            return (T)this.handler;
        }
        System.out.println("We returned null");
        return null;
    }

 

Message that pops up here. Neither of them.

 

My implementation is as such: 

     final IItemHandler handler2 = CustomItemBar.getHandler(player);
	 handler2.insertItem(4, new ItemStack(RPVPItems.testitem, 5), false);

//and then for the item to tell me what's going on: 

        final IItemHandler handlerAbility = CustomItemBar.getHandler(player);
		if(handlerAbility.extractItem(4, 1, true) != null) {
            ItemStack information = handlerAbility.getStackInSlot(4);
            ItemStack stack = handlerAbility.extractItem(4, 1, false);
            System.out.println("slot 2 has " + information.getItem() + " and amount:" + information.stackSize);
            world.spawnEntityInWorld(new EntityItem(world, player.posX, player.posY, player.posZ, stack));
        }

 

 

The big issue I'm having here is that instead of adding and substracting items from my new Capability storage, the items get added to my hotbar in slot 5 (which makes sense, since slot 1 is id 0)

The commandlines will tell me that there's 4 items in slot 4, but this is obviously an issue since it's reading from my hotbar slot on my actual inventory, not from my Capability. 

 

 

TL:DR:

- The Capability seems to register just fine, no errors are thrown up.

- I try to add the pre-existing IItemhandler to my player, so I don't need to create another Interface.

- When I call the entity.getCapabilities it DOES detect the capability ITEM_HANDLER_CAPABILITY but it doesn't call the code in my overwritten getCapability in my provider.

- When I attempt to use the capability I instead interact with the items from my regular inventory in the same slot that I gave to the code.

 

 

For future people who're googling sollutions:

 

Like Choonster helpfully pointed out, I've created a new Interface extending IItemHandler, then I've created a new implementation of this interface extending ItemStackHandler and implementing my new IItemHandler copy.  I've injected it and registered it using conventional methods and added it to my EntityPlayer on login. For this to work I've had to create an additional Storage class, but that wasn't much of a problem. The code works perfectly fine now and my player has a custom Inventory of the slots I've dictated in my AbilityProvider.

Edited by oldcheese
Solved, many thanks to Choonster.
Posted

EntityPlayer already provides CapabilityItemHandler.ITEM_HANDLER_CAPABILITY itself, so it never delegates this to the attached ICapabilityProviders. You need to create your own interface that extends IItemHandler, register a capability for it and provide that from AbilityProvider instead.

 

AbilityProvider.handler is a static field, which means it's shared between all instances of AbilityProvider (and thus all instances of EntityPlayer you attach it to). It needs to be an instance field instead.

 

Your IDE should warn you about accessing a static field through this.

  • Like 1

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.

Posted
  On 8/24/2017 at 5:58 AM, Choonster said:

AbilityProvider.handler is a static field, which means it's shared between all instances of AbilityProvider (and thus all instances of EntityPlayer you attach it to). It needs to be an instance field instead.

 

Your IDE should warn you about accessing a static field through this.

Expand  

 

Ah. My bad. I hadn't thought about that, the other Capability I made used this, but on a server I see why that'd be horrid.

 

So basically ITEM_HANDLER_CAPABILITY is already registered to the player. Does this mean that the player's inventory is stored in CapabilityItemHandler? Would using ItemHandlerSlot yield the same results in this case as using regular slots? I don't see a reason to use that, I'm just curious.  Basically this entire thread revolves around me thinking I can expose the already existing IItemhandler again.

 

For future people who're googling sollutions:

 

Like Choonster helpfully pointed out, I've created a new Interface extending IItemHandler, then I've created a new implementation of this interface extending ItemStackHandler and implementing my new IItemHandler copy.  I've injected it and registered it using conventional methods and added it to my EntityPlayer on login. For this to work I've had to create an additional Storage class, but that wasn't much of a problem. The code works perfectly fine now and my player has a custom Inventory of the slots I've dictated in my AbilityProvider.

 

 

Posted (edited)
  On 8/24/2017 at 11:16 AM, oldcheese said:

So basically ITEM_HANDLER_CAPABILITY is already registered to the player. Does this mean that the player's inventory is stored in CapabilityItemHandler? Would using ItemHandlerSlot yield the same results in this case as using regular slots? I don't see a reason to use that, I'm just curious.  Basically this entire thread revolves around me thinking I can expose the already existing IItemhandler again.

Expand  

 

The player's inventory is stored in the EntityPlayer#inventory field, which is an instance of InventoryPlayer (an implementation of vanilla's IInventory interface).

 

Forge patches EntityPlayer to add the EntityPlayer#getCapability method, which exposes various IItemHandler wrappers of the InventoryPlayer (main, equipment or joined depending on the EnumFacing). These don't store the inventory contents themselves, they simply provide access to the underlying InventoryPlayer through the IItemHandler interface.

 

You can use a SlotItemHandler with one of these IItemHandler wrappers instead of a regular Slot with the InventoryPlayer to achieve the same result (access a player inventory slot in a GUI).

Edited by Choonster
  • Like 1

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.

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Sorry for the late response, but the game opened and I made a world but it's stuck at 0% Here's the latest.log https://mclo.gs/peEb1R8 I disabled The Factory Must Grow and soulsweapons
    • Hey everyone! Two of my friends downloaded this modpack and are having an issue with the blocks loading in correctly. Grass looks like bamboo, waystones look like two barrels stacked on eachother, and wheat looks like water and stairs. What is this problem? How can we fix it? Neither of my other friends or myself had this issue. 
    • I removed Yung's cave biome mod and It wasnt in one of those biomes however the log file said the same line (([25Apr2025 21:20:15.500] [Flywheel Task Executor #5/WARN] [Embeddium-MixinTaintDetector/]: Mod(s) [oculus] are modifying Embeddium class me.jellysquid.mods.sodium.client.render.vertex.serializers.VertexSerializerRegistryImpl, which may cause instability.))
    • Note: i had a couple of ideas, but i just don't know how to execute them. The main idea was to make the new block (let's exemplify with a mixer) be essentially a clone of the mechanical mixer (different texture tho) that would have a different recipe type (instead of mixing, advanced_mixing) and i would copy all the create mod recipes and edit the processing time while also adding the tier dependent ones.
    • Hi! Before everything, thank you for even reading. I'm coming here in need of help making a few aspects for a create mod addon. It's an addon that aims to add almost the full periodic table with realistic ways of obtaining all the elements and capability of almost full automation. For what purpose? A techy armor and to go to the moon and rocky planets of the solar system. It'll have 3 different tiers of machines (mixer, millstone, crushing wheels): basic (just the normal create mod machines but renamed), advanced (25% faster and has recipes only possible for this tier and above) end elite (75% faster than basic and recipes only available for this tier). The problem is, I'm not a coder. I know less than the basics. I know how to do everything else but these machine tiers and i need some help if you can.
  • Topics

×
×
  • Create New...

Important Information

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