Posted April 14, 20205 yr My goal is to create a simple block, which you can rightclick with a filled bucket. The bucket empties and the block stores the fluid. When you rightclick again (with an empty bucket), the bucket fills with the fluid and the tankblock empties. Pretty basic. Sadly, I'm having a very hard time implementing this. The fluidtank is called voidcollector (placeholder). I have set up a VoidCollector class extending block: public class VoidCollector extends Block { //public static final DirectionProperty FACING = HorizontalBlock.HORIZONTAL_FACING; public VoidCollector() { super(Properties.create(Material.ROCK)); //this.setDefaultState(this.stateContainer.getBaseState().with(FACING, Direction.SOUTH)); } @Override public boolean hasTileEntity(BlockState state){ return true; } @Nullable @Override public TileEntity createTileEntity(BlockState state, IBlockReader world){ return new VoidCollectorTile(); } } And a VoidCollectorTile class (Basically the example TileFluidHandler): public class VoidCollectorTile extends TileEntity { protected FluidTank tank = new FluidTank(FluidAttributes.BUCKET_VOLUME); private final LazyOptional<IFluidHandler> holder = LazyOptional.of(() -> tank); public VoidCollectorTile() { super(Registration.VOIDCOLLECTOR_TILE.get()); } @Override public void read(CompoundNBT tag) { super.read(tag); tank.readFromNBT(tag); } @Override public CompoundNBT write(CompoundNBT tag) { tag = super.write(tag); tank.writeToNBT(tag); return tag; } @Override @Nonnull public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> capability, @Nullable Direction facing) { if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) return holder.cast(); return super.getCapability(capability, facing); } public FluidTank getTank(){ return this.tank; } } My problem is now, that I have absolutely no clue how to implement the bucket functionality. I tried looking at sourcecodes of other mods (some fluid tank mods and openblocks, ..) but without success. I also couldn't find any posts or tutorials that answer my question. I then tried to just do it in the VoidCollector class by overriding onBlockActivation and checking if the player has a bucket in hand. But it 1. didnt work and 2. I highly doubt that thats the correct way to do it. I would be very thankful if someone could help me get a grasp of to implement something like this. Thanks. Edited April 14, 20205 yr by Swordsaint
April 14, 20205 yr Did you try looking at the vanilla implementation of the cauldron? it sounds pretty similar to what you want to do.
April 14, 20205 yr Author 6 minutes ago, chubel10 said: Did you try looking at the vanilla implementation of the cauldron? it sounds pretty similar to what you want to do. Yes, the vanilla cauldron doesn't use a tileentity. I want to use one though. Also, in the cauldron only water_bucket works. I basically would like to create a tank like openblock's tank. A tank which can store all types of fluids. The problem is, I have no clue how to check if the player is holding a bucket with fluid in it and how to access the FluidTank in the VoidCollectorTile on BlockActivation.
April 14, 20205 yr 2 minutes ago, Swordsaint said: I have no clue how to check if the player is holding a bucket with fluid in it and how to access the FluidTank in the VoidCollectorTile on BlockActivation. Check if player is holding bucket: player.getActiveItemStack() instanced BucketItem Get FluidTank in tile (pseudocode): void onBlockActivated(args) { TileEntity te = world.getTileEntity(pos); if (te instanceof YourTileEntity) { LazyOptional<IFluidHandler> fluidHandler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side); // Do stuff } } Some tips: Spoiler Modder Support: Spoiler 1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code. 2. Always post your code. 3. Never copy and paste code. You won't learn anything from doing that. 4. Quote Programming via Eclipse's hotfixes will get you nowhere 5. Learn to use your IDE, especially the debugger. 6. Quote The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it. Support & Bug Reports: Spoiler 1. Read the EAQ before asking for help. Remember to provide the appropriate log(s). 2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.
April 14, 20205 yr Author 56 minutes ago, DavidM said: Check if player is holding bucket: player.getActiveItemStack() instanced BucketItem Get FluidTank in tile (pseudocode): void onBlockActivated(args) { TileEntity te = world.getTileEntity(pos); if (te instanceof YourTileEntity) { LazyOptional<IFluidHandler> fluidHandler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side); // Do stuff } } Thanks a lot! I came up with this code: public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult p_225533_6_) { ItemStack itemstack = player.getHeldItem(handIn); if(itemstack.getItem() instanceof BucketItem){ VoidCollectorTile te = (VoidCollectorTile) worldIn.getTileEntity(pos); if(te instanceof VoidCollectorTile){ if(itemstack.getItem() != Items.BUCKET){ BucketItem bi = (BucketItem) itemstack.getItem(); te.getTank().fill(new FluidStack(bi.getFluid(), 1000), IFluidHandler.FluidAction.EXECUTE); player.setHeldItem(handIn, new ItemStack(Items.BUCKET)); return ActionResultType.SUCCESS; } else { if(te.getTank().getFluidAmount() < 1000) return ActionResultType.FAIL; te.getTank().drain(1000, IFluidHandler.FluidAction.EXECUTE); //SET PLAYER ITEM IN HANDIN TO BUCKET WITH FLUID IN te.getTank().getFluid() } } return ActionResultType.FAIL; } I have one more problem though, I don't know how to create a Bucketitem with the right fluid (the one from the tank). I fiddled around with the BucketItem constructor and how to use it, but I am unable to come up with an instruction that returns a Bucket filled with the tankfluid. If you could elaborate on how to do it I would be very thankful and this thread would probably be solved.
April 14, 20205 yr 38 minutes ago, Swordsaint said: I have one more problem though, I don't know how to create a Bucketitem with the right fluid (the one from the tank). I fiddled around with the BucketItem constructor and how to use it, but I am unable to come up with an instruction that returns a Bucket filled with the tankfluid. If you could elaborate on how to do it I would be very thankful and this thread would probably be solved. BucketItem is an Item, which is singleton; there can only be one instance of it during the entire game. What you are looking for is an ItemStack of BucketItem with the correct liquid, which is done (if I recall correctly) by a capability in the ItemStack. Check out FluidBucketWrapper class. Also, currently your code executes on both the client and server; however, it should only happen on the server (since it is block placement and inventory changing). Check the side the code is on via World#isRemote (which is true on client and false on server) and only run the code when it is on server. Edited April 14, 20205 yr by DavidM Some tips: Spoiler Modder Support: Spoiler 1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code. 2. Always post your code. 3. Never copy and paste code. You won't learn anything from doing that. 4. Quote Programming via Eclipse's hotfixes will get you nowhere 5. Learn to use your IDE, especially the debugger. 6. Quote The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it. Support & Bug Reports: Spoiler 1. Read the EAQ before asking for help. Remember to provide the appropriate log(s). 2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.
April 15, 20205 yr Author 22 hours ago, DavidM said: BucketItem is an Item, which is singleton; there can only be one instance of it during the entire game. What you are looking for is an ItemStack of BucketItem with the correct liquid, which is done (if I recall correctly) by a capability in the ItemStack. Check out FluidBucketWrapper class. Also, currently your code executes on both the client and server; however, it should only happen on the server (since it is block placement and inventory changing). Check the side the code is on via World#isRemote (which is true on client and false on server) and only run the code when it is on server. Thank you! I took some inspiration from the vanilla cauldron and how it handled the logic and this is what i came up with: public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult p_225533_6_) { ItemStack itemstack = player.getHeldItem(handIn); if (itemstack.isEmpty()) { return ActionResultType.PASS; } else { VoidCollectorTile te = (VoidCollectorTile) worldIn.getTileEntity(pos); Item item = itemstack.getItem(); if (itemstack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY).isPresent() && item != Items.BUCKET) { BucketItem bi = (BucketItem) itemstack.getItem(); if (te.getTank().getSpace() > 1000 && (bi.getFluid().isEquivalentTo(te.getTank().getFluid().getRawFluid()) || te.getTank().isEmpty()) && !worldIn.isRemote) { if (!player.abilities.isCreativeMode) { player.setHeldItem(handIn, new ItemStack(Items.BUCKET)); } te.getTank().fill(new FluidStack(bi.getFluid(), 1000), IFluidHandler.FluidAction.EXECUTE); worldIn.playSound((PlayerEntity) null, pos, SoundEvents.ITEM_BUCKET_EMPTY, SoundCategory.BLOCKS, 1.0F, 1.0F); } } else { if (itemstack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY).isPresent() && te.getTank().getFluidAmount() >= 1000 && !worldIn.isRemote) { if (!player.abilities.isCreativeMode) { itemstack.shrink(1); if (itemstack.isEmpty()) { player.setHeldItem(handIn, FluidUtil.getFilledBucket(new FluidStack(te.getTank().getFluid().getRawFluid(), 1000))); } else if (!player.inventory.addItemStackToInventory(new ItemStack(Items.WATER_BUCKET))) { player.dropItem((FluidUtil.getFilledBucket(new FluidStack(te.getTank().getFluid().getRawFluid(), 1000))), false); } } te.getTank().getFluid().shrink(1000); worldIn.playSound((PlayerEntity) null, pos, SoundEvents.ITEM_BUCKET_FILL, SoundCategory.BLOCKS, 1.0F, 1.0F); } } return ActionResultType.SUCCESS; } } There's still some things I have to fix. I also still have to test how this interacts with lets say, OpenBlock's tanks (on RightClick). But it really helped me a lot! Edited April 15, 20205 yr by Swordsaint Never celebrate too early
April 15, 20205 yr Author 55 minutes ago, Swordsaint said: Thank you! I took some inspiration from the vanilla cauldron and how it handled the logic and this is what i came up with: public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult p_225533_6_) { ItemStack itemstack = player.getHeldItem(handIn); if (itemstack.isEmpty()) { return ActionResultType.PASS; } else { VoidCollectorTile te = (VoidCollectorTile) worldIn.getTileEntity(pos); Item item = itemstack.getItem(); if (itemstack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY).isPresent() && item != Items.BUCKET) { BucketItem bi = (BucketItem) itemstack.getItem(); if (te.getTank().getSpace() > 1000 && (bi.getFluid().isEquivalentTo(te.getTank().getFluid().getRawFluid()) || te.getTank().isEmpty()) && !worldIn.isRemote) { if (!player.abilities.isCreativeMode) { player.setHeldItem(handIn, new ItemStack(Items.BUCKET)); } te.getTank().fill(new FluidStack(bi.getFluid(), 1000), IFluidHandler.FluidAction.EXECUTE); worldIn.playSound((PlayerEntity) null, pos, SoundEvents.ITEM_BUCKET_EMPTY, SoundCategory.BLOCKS, 1.0F, 1.0F); } } else { if (itemstack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY).isPresent() && te.getTank().getFluidAmount() >= 1000 && !worldIn.isRemote) { if (!player.abilities.isCreativeMode) { itemstack.shrink(1); if (itemstack.isEmpty()) { player.setHeldItem(handIn, FluidUtil.getFilledBucket(new FluidStack(te.getTank().getFluid().getRawFluid(), 1000))); } else if (!player.inventory.addItemStackToInventory(new ItemStack(Items.WATER_BUCKET))) { player.dropItem((FluidUtil.getFilledBucket(new FluidStack(te.getTank().getFluid().getRawFluid(), 1000))), false); } } te.getTank().getFluid().shrink(1000); worldIn.playSound((PlayerEntity) null, pos, SoundEvents.ITEM_BUCKET_FILL, SoundCategory.BLOCKS, 1.0F, 1.0F); } } return ActionResultType.SUCCESS; } } There's still some things I have to fix. I also still have to test how this interacts with lets say, OpenBlock's tanks (on RightClick). But it really helped me a lot! Well, If i rightclick the tank with a modded item like a tank from "LargeFluidTank", the game crashes due to being unable to cast the Modded Item to Bucket Item. I'll have to gain some experience and fix this bug later.
April 15, 20205 yr 27 minutes ago, Swordsaint said: Well, If i rightclick the tank with a modded item like a tank from "LargeFluidTank", the game crashes due to being unable to cast the Modded Item to Bucket Item. I'll have to gain some experience and fix this bug later. You can either 1) Check before cast or even better 2) look for the fluid handler capability in the ItemStack. The second method is compatible with other mods (as long as the other mod creates tanks properly by giving it a fluid handler capability). Some tips: Spoiler Modder Support: Spoiler 1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code. 2. Always post your code. 3. Never copy and paste code. You won't learn anything from doing that. 4. Quote Programming via Eclipse's hotfixes will get you nowhere 5. Learn to use your IDE, especially the debugger. 6. Quote The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it. Support & Bug Reports: Spoiler 1. Read the EAQ before asking for help. Remember to provide the appropriate log(s). 2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.
April 15, 20205 yr Author 19 minutes ago, DavidM said: You can either 1) Check before cast or even better 2) look for the fluid handler capability in the ItemStack. The second method is compatible with other mods (as long as the other mod creates tanks properly by giving it a fluid handler capability). Thank you! Sadly the capability system is giving me a rough time, it will probably take me some time to understand them completely and be able to use them in the proper way. (I guess they are easy af but i'm just not able to get a grasp of the idea haha).
April 15, 20205 yr If you want your block to work with all items from other mods you can use the Forge provided method: FluidUtil.interactWithFluidHandler(player, hand, world, pos, side) which returns a boolean value if it is successful.
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.