User Tools

Site Tools


Sidebar

Setup

Basics

Advanced

Items

Blocks and Block Entities

Fluids

Entities

World Generation

Recipe Types

Miscellaneous

Events

Mixins

Dynamic Data Generation

Tutorials for Minecraft 1.15

Tutorials for Minecraft 1.14

Contribute to Fabric

Extremely Strange People

tutorial:transfer-api_simpletank

Fabric Transfer API: Creating a simple tank

This article is part of a series on the Fabric Transfer API. Link to the home page of the series.

Let's see how we can make a block entity contain some fluid:

public class MyTankBlockEntity extends BlockEntity {
	// This field is going to contain the amount, and the fluid variant (more on that in a bit).
	public final SingleVariantStorage<FluidVariant> fluidStorage = new SingleVariantStorage<>() {
		@Override
		protected FluidVariant getBlankVariant() {
			return FluidVariant.blank();
		}
 
		@Override
		protected long getCapacity(FluidVariant variant) {
			// Here, you can pick your capacity depending on the fluid variant.
			// For example, if we want to store 8 buckets of any fluid:
			return 8 * FluidConstants.BUCKET;
		}
 
		@Override
		protected void onFinalCommit() {
			// Called after a successful insertion or extraction, markDirty to ensure the new amount and variant will be saved properly.
			markDirty();
		}
	};
 
	@Override
	public NbtCompound writeNbt(NbtCompound tag) {
		tag.put("fluidVariant", fluidStorage.variant.toNbt());
		tag.putLong("amount", fluidStorage.amount);
		return super.writeNbt(tag);
	}
	@Override
	public void readNbt(NbtCompound tag) {
		super.readNbt(tag);
		fluidStorage.variant = FluidVariant.fromNbt(tag.getCompound("fluidVariant"));
		fluidStorage.amount = tag.getLong("amount");
	}
}

Alright, now we can contain some fluid, and we are properly saving it if it changes. Now, we must register ensure that other mods can properly interact with our tank:

BlockEntityType<MyTankBlockEntity> MY_TANK = // see block entity tutorial
 
// Put this in your mod initializer, after you have created the block entity type:
FluidStorage.SIDED.registerForBlockEntity((myTank, direction) -> myTank.fluidStorage, MY_TANK);

But wait, what is a FluidVariant ?

A FluidVariant is what the Transfer API uses to represent the “type” of a fluid. It contains the Fluid in the minecraft sense, and also an optional NBT compound tag:

// Creating a fluid variant from a fluid, without an NBT tag.
FluidVariant waterVariant = FluidVariant.of(Fluids.WATER);
waterVariant.getFluid() // returns Fluids.WATER
waterVariant.copyNbt() // returns a copy of the optional nbt tag, in this case null
// Creating a fluid variant from a fluid, with an NBT tag.
NbtCompound customTag = new NbtCompound();
customTag.putBoolean("magic", true);
FluidVariant magicWater = FluidVariant.of(Fluids.WATER, customTag);

Variants are always compared with .equals, NEVER WITH == !

waterVariant.equals(waterVariant); // returns true
waterVariant.equals(magicWater); // returns false
// You can easily test if a variant has some fluid:
waterVariant.isOf(Fluids.WATER); // returns true
magicWater.isOf(Fluids.WATER); // returns true

They can easily be serialized to and from NBT or network packets:

// NBT
NbtCompound compound = variant.toNbt();
FluidVariant variant = FluidVariant.fromNbt(compound);
// Network packets
variant.toPacket(buf);
FluidVariant variant = FluidVariant.fromPacket(buf);

More on Fabric API Lookup

To understand what the call to FluidStorage.SIDED does, please have a look at the Usage Example in the documentation of ''BlockApiLookup''. The Fabric API Lookup system allows blocks to expose interfaces such as Storage<FluidVariant>, so that pipes and other devices can use them.

tutorial/transfer-api_simpletank.txt · Last modified: 2021/10/29 20:46 by technici4n