Jump to content

[1.12] Battery item shares charge across all instances of item.


44tim44

Recommended Posts

So, I've made a modified furnace which only takes the custom item "Battery" as fuel. The battery can only have a stack of 1, and it's using a custom "durability" which tracks the amount of charge it holds.
Now for some reason, the charge of a Battery is shared across all instances of the item Battery in my inventory.
So if I put 1 Battery in a charging station, and 1 Battery in the furnace, the battery in the furnace lasts forever, since the other battery is constantly being charged.

Is this because the charge-increasing/-decreasing/setting/getting is being done inside the Battery-Item's class?
If so, how am I supposed to implement it otherwise? Am I supposed to make my own implemantion of ItemStack instead??

 

ItemBattery.java:

Spoiler

 


package com.bte.mod.item;

import com.bte.mod.BTEMod;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

import javax.annotation.Nullable;
import java.util.List;


public class ItemBattery extends Item {

    private int charge;
    private int maxCharge;

    public ItemBattery() {
        setUnlocalizedName("battery");
        setRegistryName("battery");
        //setMaxCharge(640);
        //setCharge(0);
        this.charge = 0;
        this.maxCharge = 640;
        setMaxStackSize(1);
        setCreativeTab(CreativeTabs.MISC);
    }

    public void setMaxCharge(int value){
        if(value < 1)
        {
            this.maxCharge = 1;
        }
        else
        {
            this.maxCharge = value;
        }
    }

    public int getMaxCharge(){
        return this.maxCharge;
    }

    public void decreaseCharge(){
        if(this.charge > 0)
        {
            this.charge--;
        }
    }

    public void increaseCharge(){
        if(this.charge < this.maxCharge)
        {
            this.charge++;
        }
    }

    public void setCharge(int value)
    {
        if(value > this.maxCharge)
        {
            this.charge = this.maxCharge;
        }
        else if(value < 0)
        {
            this.charge = 0;
        }
        else
        {
            this.charge = value;
        }
    }

    public int getCharge(){
        return this.charge;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn)
    {
        tooltip.add("Charge: " + this.charge + "/" + this.maxCharge);
    }


    @Override
    public boolean showDurabilityBar(ItemStack stack) {
        return true;
    }

    @Override
    public double getDurabilityForDisplay(ItemStack stack) {
        return (double)this.getMaxCharge() / (double)this.getCharge();
    }

    public void registerItemModel() {
        BTEMod.proxy.registerItemRenderer(this, 0, "battery");
    }
}

 

 

Link to comment
Share on other sites

Items (like Blocks) are singletons, so there is only 1 instance of your Item class being used for every item of that kind in the game. That's likely why all your batteries are sharing their charge.

 

If you wish to have an independent value for your item, it either needs to be stored in Metadata (limited amount of storage, I forget how much), or you will need to use capabilities.

 

Just search this forum for "item metadata" or "item capabilities" and you should find something to get you started. There is info on both of these in the forge docs as well.

 

*edit: Here's a link to a capabilities tutorial that I believe is helpful: https://www.planetminecraft.com/blog/forge-tutorial-capability-system/

Edited by Ugdhar
add link to capability tutorial
Link to comment
Share on other sites

Okay, I think I've started making progress, but I'm still completely new to Capabilities...

I have changed all usages in the charging station and the furnace to use:

ICharge charge = itemstack.getCapability(ChargeProvider.CHARGE_CAPABILITY,null);
return charge.getCharge();

instead of:

ItemBattery battery = (ItemBattery)itemstack.getItem();
return battery.getCharge();


However, I want to set the "maxCharge" of all battery items to, let's say, 6400.
And I want them all to start off with a "charge" of 0.

Where do I set these values?
I don't do it from inside the ItemBattery.java-class itself, right?

Link to comment
Share on other sites

3 minutes ago, 44tim44 said:

Okay, I think I've started making progress, but I'm still completely new to Capabilities...

I have changed all usages in the charging station and the furnace to use:


ICharge charge = itemstack.getCapability(ChargeProvider.CHARGE_CAPABILITY,null);
return charge.getCharge();

instead of:


ItemBattery battery = (ItemBattery)itemstack.getItem();
return battery.getCharge();


However, I want to set the "maxCharge" of all battery items to, let's say, 6400.
And I want them all to start off with a "charge" of 0.

Where do I set these values?
I don't do it from inside the ItemBattery.java-class itself, right?

I would say you could set those inside your item class if you wanted if they're the same for all batteries and wouldn't change per battery

Link to comment
Share on other sites

Okay, awesome, but how would I handle:

@Override
public double getDurabilityForDisplay(ItemStack stack) {
    return (double)this.getMaxCharge() / (double)this.getCharge();
}

which is also inside the ItemBattery?

Because then the getCharge wouldn't be correct, right?

Link to comment
Share on other sites

Um, okay, new problem!
I get a NullPointerException when trying to start the Client.

I know I haven't properly initialized the capability for my item somehow, but I don't know what I've done wrong...
 

java.lang.NullPointerException: Initializing game
	at com.bte.mod.capability.ChargeProvider.<init>(ChargeProvider.java:17)
	at com.bte.mod.item.ItemBattery.initCapabilities(ItemBattery.java:37)
	at net.minecraft.item.ItemStack.forgeInit(ItemStack.java:1350)

 

Spoiler

package com.bte.mod.capability;

import net.minecraft.nbt.NBTBase;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;

/**
 * Created by Timeout on 2017-08-23.
 */
public class ChargeProvider implements ICapabilitySerializable<NBTBase>
{
    @CapabilityInject(ICharge.class)
    public static final Capability<ICharge> CHARGE_CAPABILITY = null;

    private ICharge instance = CHARGE_CAPABILITY.getDefaultInstance();

    @Override
    public boolean hasCapability(Capability<?> capability, EnumFacing facing)
    {
        return capability == CHARGE_CAPABILITY;
    }

    @Override
    public <T> T getCapability(Capability<T> capability, EnumFacing facing)
    {
        return capability == CHARGE_CAPABILITY ? CHARGE_CAPABILITY.<T> cast(this.instance) : null;
    }

    @Override
    public NBTBase serializeNBT()
    {
        return CHARGE_CAPABILITY.getStorage().writeNBT(CHARGE_CAPABILITY, this.instance, null);
    }

    @Override
    public void deserializeNBT(NBTBase nbt)
    {
        CHARGE_CAPABILITY.getStorage().readNBT(CHARGE_CAPABILITY, this.instance, null, nbt);
    }
}

 

Spoiler

package com.bte.mod.item;

import com.bte.mod.BTEMod;
import com.bte.mod.capability.CapabilityHandler;
import com.bte.mod.capability.ChargeProvider;
import com.bte.mod.capability.ICharge;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

import javax.annotation.Nullable;
import java.util.List;

/**
 * Created by Timeout on 2017-08-22.
 */
public class ItemBattery extends Item {

    public ItemBattery() {
        setUnlocalizedName("battery");
        setRegistryName("battery");
        setMaxStackSize(1);
        setCreativeTab(CreativeTabs.MISC);
    }

    @Override
    @Nullable
    public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable NBTTagCompound nbt){
        return new ChargeProvider();
    }

    @SideOnly(Side.CLIENT)
    @Override
    public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn)
    {
        tooltip.add("Charge: " + stack.getCapability(ChargeProvider.CHARGE_CAPABILITY,null).getCharge() + "/" + stack.getCapability(ChargeProvider.CHARGE_CAPABILITY,null).getMaxCharge());
    }

    @Override
    public boolean showDurabilityBar(ItemStack stack) {
        return true;
    }

    @Override
    public double getDurabilityForDisplay(ItemStack stack) {
        return (double)stack.getCapability(ChargeProvider.CHARGE_CAPABILITY,null).getCharge() / (double)stack.getCapability(ChargeProvider.CHARGE_CAPABILITY,null).getMaxCharge();
    }

    public void registerItemModel() {
        BTEMod.proxy.registerItemRenderer(this, 0, "battery");
    }
}

 

 

EDIT:

Uh, okay nevermind.
The problem seems to occur whenever I try to

stack.getCapability(ChargeProvider.CHARGE_CAPABILITY,null).getCharge()

from within the ItemBattery.java.
I tried removing the tooltip, and that allowed the game to start, but as soon as it tried to render the Durability-bar, it crashed for the same reason.

 

I assume that is because the field charge is null in the capability, but I have default values set in the implementation...

 

public class Charge implements ICharge {

    private int charge = 0;
    private int maxCharge = 640;
    //...
}
Edited by 44tim44
new info
Link to comment
Share on other sites

Anybody have any idea what I've done wrong?

I'm completely stumped.

I basically followed this tutorial: https://www.planetminecraft.com/blog/forge-tutorial-capability-system/
But I don't have an eventHandler, since I'm attaching to an ItemStack and not an Entity, so I have this:

@Override
@Nullable
public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable NBTTagCompound nbt)
{
    return new ChargeProvider();
}

in my ItemBattery.java-class instead.

And as I said in the previous post, I now get an NPE for this line in my Provider:

private ICharge instance = CHARGE_CAPABILITY.getDefaultInstance();


EDIT: And sorry for tripleposting. Couldn't find a delete-post button...

Edited by 44tim44
Link to comment
Share on other sites

1 hour ago, Ugdhar said:

It would be much easier if you uploaded your entire codebase to github :)

 

Post all capability related classes otherwise pls (not to mention much harder to read code on here than github as well)

https://github.com/44tim44/Capability_Battery/tree/master/src/main/java/com/bte/mod

 

The classes of interest are all the capability-classes in ../capability/ and ItemBattery in ../item/.
 

Link to comment
Share on other sites

First thing I noticed, is you do not need to use the AttachCapabilitiesEvent for a capability that is part of your own item, the initCapabilities method you overrode takes care of that. You would only use that event for attaching to an item that you didn't code yourself (i.e. a Stick or something)

 

I haven't much time atm, so that's all I got for now, I'll look some more when I have more time. :)

Link to comment
Share on other sites

13 hours ago, Ugdhar said:

First thing I noticed, is you do not need to use the AttachCapabilitiesEvent for a capability that is part of your own item, the initCapabilities method you overrode takes care of that. You would only use that event for attaching to an item that you didn't code yourself (i.e. a Stick or something)

 

I haven't much time atm, so that's all I got for now, I'll look some more when I have more time. :)

Yeah, I was suspecting that!
But it does unfortunately not solve the actual problem...

But any help at all is appreciated. Thanks!

EDIT:
I found the problem for the NPE;
I had this:

CapabilityManager.INSTANCE.register(ICharge.class, new ChargeStorage(), Charge.class);
MinecraftForge.EVENT_BUS.register(new CapabilityHandler());

in init() instead of in preInit() in the proxy.

However, it seems as if the NBTwriting isn't working properly, because as soon as I close an inventory, the Battery resets it's charge to 0, despite actual charge before closing an inventory.

Edited by 44tim44
Link to comment
Share on other sites

Okay, I seem to have fixed everything. ...I think.
But if someone has the time to go through my implemation of the Charge-Capability properly, I'd really appreciate it, because I
 think I haven't properly initialized my ItemBattery to have it's correct starting charge and maxCharge.
I just have a default maxCharge in the capability itself, and it magically works as of now, but I'd really like for it to be done properly.

The GitHub is updated to latest version.
https://github.com/44tim44/Capability_Battery/tree/master/src/main/java/com/bte/mod

Link to comment
Share on other sites

I hate this:

https://github.com/44tim44/Capability_Battery/blob/master/src/main/java/com/bte/mod/proxy/CommonProxy.java#L19

There is no reason to pass the FML lifecycle events to the proxy classes. The only thing you do in those events can be handled by the main mod file just fine.

E.g. here's my common proxy:

https://github.com/Draco18s/ReasonableRealism/blob/master/src/main/java/com/draco18s/ores/CommonProxy.java

 

Look at how deliciously empty it is. There's exactly 1 external method call. Could it be in the main class? Sure, but with an existing method (needed by client proxy) it made sense to have it there. In your client proxy you do fuckall with most of those methods.

Edited by Draco18s

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

16 hours ago, Draco18s said:

I hate this:

https://github.com/44tim44/Capability_Battery/blob/master/src/main/java/com/bte/mod/proxy/CommonProxy.java#L19

There is no reason to pass the FML lifecycle events to the proxy classes. The only thing you do in those events can be handled by the main mod file just fine.

E.g. here's my common proxy:

https://github.com/Draco18s/ReasonableRealism/blob/master/src/main/java/com/draco18s/ores/CommonProxy.java

 

Look at how deliciously empty it is. There's exactly 1 external method call. Could it be in the main class? Sure, but with an existing method (needed by client proxy) it made sense to have it there. In your client proxy you do fuckall with most of those methods.

Soo,
I can just add all the contents of pre-/post-/Init to the respective methods in the main Mod-file instead?
Awesome. I was just following a tutorial for setting up the basic stuff, so I wasn't sure what I could or couldn't do.

Are there any things that NEED to be handled in the proxies, rather than the main Mod-file?

Link to comment
Share on other sites

7 hours ago, 44tim44 said:

Are there any things that NEED to be handled in the proxies, rather than the main Mod-file?

Yes, anything that can only be handled by the physical client must go in the Client Proxy. This includes model registration.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

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.