User Tools

Site Tools


tutorial:transfer-api

This is an old revision of the document!


[WIP] Understanding the Fabric Transfer API

This tutorial gives a brief overview of how the Fabric Transfer API works, and how you can use it for your own mods. For any question, please go to the #fluid-volume-api-debating channel on the discord server.

Creating a simple tank

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.1635540302.txt.gz · Last modified: 2021/10/29 20:45 by technici4n