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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • I have done this now but have got the error:   'food(net.minecraft.world.food.FoodProperties)' in 'net.minecraft.world.item.Item.Properties' cannot be applied to                '(net.minecraftforge.registries.RegistryObject<net.minecraft.world.item.Item>)' public static final RegistryObject<Item> LEMON_JUICE = ITEMS.register( "lemon_juice", () -> new Item( new HoneyBottleItem.Properties().stacksTo(1).food( (new FoodProperties.Builder()) .nutrition(3) .saturationMod(0.25F) .effect(() -> new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, 1500), 0.01f ) .build() ) )); The code above is from the ModFoods class, the one below from the ModItems class. public static final RegistryObject<Item> LEMON_JUICE = ITEMS.register("lemon_juice", () -> new Item(new Item.Properties().food(ModFoods.LEMON_JUICE)));   I shall keep going between them to try and figure out the cause. I am sorry if this is too much for you to help with, though I thank you greatly for your patience and all the effort you have put in to help me.
    • I have been following these exact tutorials for quite a while, I must agree that they are amazing and easy to follow. I have registered the item in the ModFoods class, I tried to do it in ModItems (Where all the items should be registered) but got errors, I think I may need to revert this and figure it out from there. Once again, thank you for your help! 👍 Just looking back, I have noticed in your code you added ITEMS.register, which I am guessing means that they are being registered in ModFoods, I shall go through the process of trial and error to figure this out.
    • ♈+2349027025197ஜ Are you a pastor, business man or woman, politician, civil engineer, civil servant, security officer, entrepreneur, Job seeker, poor or rich Seeking how to join a brotherhood for protection and wealth here’s is your opportunity, but you should know there’s no ritual without repercussions but with the right guidance and support from this great temple your destiny is certain to be changed for the better and equally protected depending if you’re destined for greatness Call now for enquiry +2349027025197☎+2349027025197₩™ I want to join ILLUMINATI occult without human sacrificeGREATORLDRADO BROTHERHOOD OCCULT , Is The Club of the Riches and Famous; is the world oldest and largest fraternity made up of 3 Millions Members. We are one Family under one father who is the Supreme Being. In Greatorldrado BROTHERHOOD we believe that we were born in paradise and no member should struggle in this world. Hence all our new members are given Money Rewards once they join in order to upgrade their lifestyle.; interested viewers should contact us; on. +2349027025197 ۝ஐℰ+2349027025197 ₩Greatorldrado BROTHERHOOD OCCULT IS A SACRED FRATERNITY WITH A GRAND LODGE TEMPLE SITUATED IN G.R.A PHASE 1 PORT HARCOURT NIGERIA, OUR NUMBER ONE OBLIGATION IS TO MAKE EVERY INITIATE MEMBER HERE RICH AND FAMOUS IN OTHER RISE THE POWERS OF GUARDIANS OF AGE+. +2349027025197   SEARCHING ON HOW TO JOIN THE Greatorldrado BROTHERHOOD MONEY RITUAL OCCULT IS NOT THE PROBLEM BUT MAKE SURE YOU'VE THOUGHT ABOUT IT VERY WELL BEFORE REACHING US HERE BECAUSE NOT EVERYONE HAS THE HEART TO DO WHAT IT TAKES TO BECOME ONE OF US HERE, BUT IF YOU THINK YOU'RE SERIOUS MINDED AND READY TO RUN THE SPIRITUAL RACE OF LIFE IN OTHER TO ACQUIRE ALL YOU NEED HERE ON EARTH CONTACT SPIRITUAL GRANDMASTER NOW FOR INQUIRY +2349027025197   +2349027025197 Are you a pastor, business man or woman, politician, civil engineer, civil servant, security officer, entrepreneur, Job seeker, poor or rich Seeking how to join
    • Hi, I'm trying to use datagen to create json files in my own mod. This is my ModRecipeProvider class. public class ModRecipeProvider extends RecipeProvider implements IConditionBuilder { public ModRecipeProvider(PackOutput pOutput) { super(pOutput); } @Override protected void buildRecipes(Consumer<FinishedRecipe> pWriter) { ShapedRecipeBuilder.shaped(RecipeCategory.MISC, ModBlocks.COMPRESSED_DIAMOND_BLOCK.get()) .pattern("SSS") .pattern("SSS") .pattern("SSS") .define('S', ModItems.COMPRESSED_DIAMOND.get()) .unlockedBy(getHasName(ModItems.COMPRESSED_DIAMOND.get()), has(ModItems.COMPRESSED_DIAMOND.get())) .save(pWriter); ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, ModItems.COMPRESSED_DIAMOND.get(),9) .requires(ModBlocks.COMPRESSED_DIAMOND_BLOCK.get()) .unlockedBy(getHasName(ModBlocks.COMPRESSED_DIAMOND_BLOCK.get()), has(ModBlocks.COMPRESSED_DIAMOND_BLOCK.get())) .save(pWriter); ShapedRecipeBuilder.shaped(RecipeCategory.MISC, ModItems.COMPRESSED_DIAMOND.get()) .pattern("SSS") .pattern("SSS") .pattern("SSS") .define('S', Blocks.DIAMOND_BLOCK) .unlockedBy(getHasName(ModItems.COMPRESSED_DIAMOND.get()), has(ModItems.COMPRESSED_DIAMOND.get())) .save(pWriter); } } When I try to run the runData client, it shows an error:  Caused by: java.lang.IllegalStateException: Duplicate recipe compressed:compressed_diamond I know that it's caused by the fact that there are two recipes for the ModItems.COMPRESSED_DIAMOND. But I need both of these recipes, because I need a way to craft ModItems.COMPRESSED_DIAMOND_BLOCK and restore 9 diamond blocks from ModItems.COMPRESSED_DIAMOND. Is there a way to solve this?
  • Topics

×
×
  • Create New...

Important Information

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