44tim44 Posted August 23, 2017 Posted August 23, 2017 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"); } } Quote
Ugdhar Posted August 23, 2017 Posted August 23, 2017 (edited) 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 August 23, 2017 by Ugdhar add link to capability tutorial Quote
44tim44 Posted August 23, 2017 Author Posted August 23, 2017 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? Quote
Ugdhar Posted August 23, 2017 Posted August 23, 2017 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 Quote
44tim44 Posted August 23, 2017 Author Posted August 23, 2017 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? Quote
44tim44 Posted August 23, 2017 Author Posted August 23, 2017 (edited) 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 August 23, 2017 by 44tim44 new info Quote
44tim44 Posted August 23, 2017 Author Posted August 23, 2017 (edited) 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 August 23, 2017 by 44tim44 Quote
Ugdhar Posted August 23, 2017 Posted August 23, 2017 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) Quote
44tim44 Posted August 23, 2017 Author Posted August 23, 2017 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/. Quote
Ugdhar Posted August 23, 2017 Posted August 23, 2017 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. Quote
44tim44 Posted August 24, 2017 Author Posted August 24, 2017 (edited) 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 August 24, 2017 by 44tim44 Quote
44tim44 Posted August 24, 2017 Author Posted August 24, 2017 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 Quote
Draco18s Posted August 24, 2017 Posted August 24, 2017 (edited) 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 August 24, 2017 by Draco18s Quote 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.
44tim44 Posted August 25, 2017 Author Posted August 25, 2017 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? Quote
Draco18s Posted August 25, 2017 Posted August 25, 2017 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. Quote 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.
Recommended Posts
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.