Jump to content

[1.15.2] Creating a very basic fluidtank-block


Swordsaint

Recommended Posts

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 by Swordsaint
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

 

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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 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.

 

 

Link to comment
Share on other sites

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 by Swordsaint
Never celebrate too early
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

 

 

Link to comment
Share on other sites

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).

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.