Posted February 9, 20178 yr Hey guys, so i was wondering how would i go about storing data to a block after its broken? in that sense i have an EnergyBank, when broken id like the block to retain its energy, how would i go about doing that?
February 9, 20178 yr You need to save the TileEntity's data to the ItemStack's NBT (or capabilities). You can do this by overriding Block#getDrops to create an ItemStack with the appropriate data and then return a List<ItemStack> containing it. By default, the TileEntity is removed from the world before Block#getDrops is called. You need to delay this like Forge's patch to BlockFlowerPot does. Edited February 9, 20178 yr by Choonster 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.
February 9, 20178 yr Author Do you by any chance have a simple example of some data being saved to athe ItemStack's NBT with getDrops? if not thats all right, but thanks for the info will see what happens.
February 9, 20178 yr 2 minutes ago, abused_master said: Do you by any chance have a simple example of some data being saved to athe ItemStack's NBT with getDrops? if not thats all right, but thanks for the info will see what happens. Look at BlockSkull or BlockBanner. You can see an example of a TileEntity's IFluidHandler being saved to an ItemStack's IFluidHandlerItem here. 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.
February 10, 20178 yr I did this for my containers, because I wanted them to retain their inventory when broken. I created a method in my Tile Entity that looked like this: public void dropContainerWithInventory(World world, BlockPos pos, IBlockState state, EntityPlayer player, TileEntity tileEntity) { if (tileEntity != null && Item.getItemFromBlock(state.getBlock()) != null) { ItemStack stack = new ItemStack(this); NBTTagCompound inventoryTag = new NBTTagCompound(); tileEntity.writeToNBT(inventoryTag); NBTTagCompound masterTag = new NBTTagCompound(); masterTag.setTag("BlockEntityTag", inventoryTag); stack.setTagCompound(masterTag); spawnAsEntity(world, pos, stack); } world.setBlockToAir(pos); } If I remember right, you can delay the deletion of the tile entity by overriding removedByPlayer to return true if the willHarvest parameter is true. Edited February 10, 20178 yr by Daeruin
May 20, 20178 yr Author All right so when trying this on a fluid tank it would crash when breaking with java.lang.NullPointerException: Unexpected error at abused_master.techexpansion.blocks.tank.BlockTank.saveFluidToStack(BlockTank.java:151) at abused_master.techexpansion.blocks.tank.BlockTank.removedByPlayer(BlockTank.java:165) at net.minecraft.client.multiplayer.PlayerControllerMP.onPlayerDestroyBlock(PlayerControllerMP.java:192) at net.minecraft.client.multiplayer.PlayerControllerMP.onPlayerDamageBlock(PlayerControllerMP.java:339) at net.minecraft.client.Minecraft.sendClickBlockToController(Minecraft.java:1512) at net.minecraft.client.Minecraft.processKeyBinds(Minecraft.java:2298) at net.minecraft.client.Minecraft.runTickKeyboard(Minecraft.java:2061) at net.minecraft.client.Minecraft.runTick(Minecraft.java:1849) at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1127) at net.minecraft.client.Minecraft.run(Minecraft.java:407) at net.minecraft.client.main.Main.main(Main.java:118) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) at net.minecraft.launchwrapper.Launch.main(Launch.java:28) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97) at GradleStart.main(GradleStart.java:26) this is how i'm saving my data: public ItemStack saveFluidToStack(World world, BlockPos pos) { ItemStack stack = new ItemStack(Item.getItemFromBlock(this)); TileEntityTank te = (TileEntityTank) world.getTileEntity(pos); if (te.tank.getFluid() != null && te.tank.getFluidAmount() > 0) { final NBTTagCompound tileTag = te.writeToNBT(new NBTTagCompound()); stack.getTagCompound().setTag("TileData", tileTag); } return stack; } @Override public boolean removedByPlayer (IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest) { ItemStack dropStack = saveFluidToStack(world, pos); EntityItem item = new EntityItem(world, pos.getX(), pos.getY(), pos.getZ(), dropStack); world.spawnEntity(item); return world.setBlockToAir(pos); } @Override public int quantityDropped(Random random) { return 0; } @Override public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) { world.setBlockState(pos, state.withProperty(TYPE, TankTier.get(stack.getMetadata()))); final TileEntityTank tank = (TileEntityTank) world.getTileEntity(pos); if (stack.hasTagCompound()) { if (tank.tank != null) { tank.readFromNBT(stack.getTagCompound().getCompoundTag("TileData")); } } } Line 151 is stack.getTagCompound().setTag("TileData", tileTag); Edited May 20, 20178 yr by abused_master
May 20, 20178 yr ItemStacks don't have a stack compound tag by default, you need to create one and set it as the stack compound tag by calling ItemStack#setTagCompound. Alternatively, use a method like ItemStack#setTagInfo that automatically creates the stack compound tag if it doesn't exist and then calls NBTTagCompound#setTag on it with the specified key and value. 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.
May 20, 20178 yr Author All right i've used NBTTagCompound#setTag and it works fine, but when the block is broken it can be picked up but a ghost block remains on the floor, any idea what could be causing this? also when the block is broken then placed again with fluid inside it gives me this: [09:29:15] [Client thread/ERROR]: Received invalid update packet for null tile entity at BlockPos{x=-137, y=64, z=70} with data: {FluidName:"water",Amount:2000,FluidData:{FluidName:"water",Amount:2000},x:-137,y:64,z:70,id:"minecraft:tile_tank"} the fluid is also rendered at the old position instead of the new one my TileEntity Code: public class TileEntityTank extends TileEntityBase { public FluidTank tank; public TileEntityTank() { tank = new FluidTank(this.tier()); } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); if (nbt.hasKey("FluidData")) { tank.setFluid(FluidStack.loadFluidStackFromNBT(nbt.getCompoundTag("FluidData"))); } if(tank != null && tank.getFluid() != null) { tank.readFromNBT(nbt); } if (this.tank != null) { tank.setTileEntity(this); } } @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { if (tank != null && tank.getFluid() != null) { final NBTTagCompound tankTag = new NBTTagCompound(); tank.getFluid().writeToNBT(tankTag); nbt.setTag("FluidData", tankTag); } tank.writeToNBT(nbt); return super.writeToNBT(nbt); } public int tier() { return 60000; } @Override public void update() { if(!world.isRemote) { IBlockState state = world.getBlockState(pos); world.notifyBlockUpdate(pos, state, state, 8); } } @Override public boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing) { return this.getCapability(capability, facing) != null; } @Nullable @Override public <T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing) { if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { return (T) this.tank; } return super.getCapability(capability, facing); } }
May 20, 20178 yr Block#removedByPlayer is called on both sides, so you're spawning a real EntityItem on the server (which also spawns it on all nearby clients) and a "ghost" EntityItem on the client (that can't be interacted with because the server doesn't know about it). Entities should only be spawned on the server. Don't manually spawn the EntityItem, override Block#getDrops like I told you to in my first reply. If you store a compound tag in the "BlockEntityTag" key of an ItemStack's stack compound tag, Minecraft will automatically call TileEntity#readFromNBT with this tag when a player places the block. You don't need to do this yourself. Is the update method being called every tick (e.g. because it implements ITickable#update)? If so, you shouldn't be calling World#notifyBlockUpdate every tick, only call it to send the TileEntity's update packet or re-render the chunk (it always does both). It's possible that this is causing the TileEntity's update packet to be sent before the client knows that there's now a TileEntity at that position. The flags argument of World#notifyBlockUpdate is completely unused by the server and isn't sent to the client. Why are you reading/writing the tank and its contents from/to NBT separately? Just read/write the tank (FluidTank#readFromNBT/FluidTank#writeToNBT) and it will read/write its contents. Edited May 20, 20178 yr by Choonster 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.
May 20, 20178 yr Author All right i've fixed those, but the problem still persists, also when the block is broken then replaced, and the world is reloaded the contents disappear, this however does not occur if the block is not moved on initial placement
May 20, 20178 yr 9 minutes ago, abused_master said: All right i've fixed those, but the problem still persists, also when the block is broken then replaced, and the world is reloaded the contents disappear, this however does not occur if the block is not moved on initial placement Post your new Block and TileEntity classes. 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.