Use this file to discover all available pages before exploring further.
NTM’s fluid infrastructure went through a major redesign that produced the MK2 fluid network, built on the same UNINOS node framework that powers the energy system. Unlike Forge’s built-in FluidStack/FluidRegistry model, NTM fluids are identified by FluidType objects registered in com.hbm.inventory.fluid.Fluids — a catalogue of over one hundred fluid types ranging from ordinary water and steam to exotic substances like deuterium, balefire, and various plasma states. Tile entities connect to the network by implementing IFluidConnectorMK2 and calling tryProvide or trySubscribe each tick; pipe blocks implement IFluidPipeMK2 to create and own the nodes that link those tiles together. The legacy interfaces (IFluidStandardReceiver, IFluidStandardSender, IFluidStandardTransceiver) remain functional but are deprecated and delegate directly to their MK2 equivalents.
All three legacy interfaces now extend their MK2 counterparts. You will not lose functionality by keeping legacy code, but the MK2 variants give you pressure-tier support and clearer intent.
Both IFluidProviderMK2 and IFluidReceiverMK2 extend IFluidUserMK2, which supplies shared constants and the tank accessor:
package api.hbm.fluidmk2;import api.hbm.tile.ILoadedTile;public interface IFluidUserMK2 extends IFluidConnectorMK2, ILoadedTile { /** Maximum pressure tier index (inclusive). Pressure values run 0 – 5. */ public static final int HIGHEST_VALID_PRESSURE = 5; /** Convenience constant: pressure range covering only tier 0. */ public static final int[] DEFAULT_PRESSURE_RANGE = new int[] {0, 0}; /** Returns all tanks belonging to this tile (used by the network for bookkeeping). */ public FluidTank[] getAllTanks();}
package api.hbm.fluidmk2;import com.hbm.inventory.fluid.FluidType;import net.minecraftforge.common.util.ForgeDirection;public interface IFluidConnectorMK2 { /** * Whether the given side of this tile accepts connections for the given fluid type. * dir is the side of THIS block that is being queried. * Default: accept all six cardinal sides for any fluid. */ public default boolean canConnect(FluidType type, ForgeDirection dir) { return dir != ForgeDirection.UNKNOWN; }}
Implement this on the Block class (not the tile entity) when connectivity must be evaluated from block-access data (e.g. oriented valves):
package api.hbm.fluidmk2;import com.hbm.inventory.fluid.FluidType;import net.minecraft.world.IBlockAccess;import net.minecraftforge.common.util.ForgeDirection;public interface IFluidConnectorBlockMK2 { /** * dir is the face going outwards from the block — the direction of the connection. */ public boolean canConnect(FluidType type, IBlockAccess world, int x, int y, int z, ForgeDirection dir);}
Pipe tiles implement IFluidPipeMK2 to gain the createNode(FluidType) helper, which registers a six-way FluidNode for the given fluid type into UNINOS:
package api.hbm.fluidmk2;import com.hbm.inventory.fluid.FluidType;public interface IFluidPipeMK2 extends IFluidConnectorMK2 { /** * Creates and returns a FluidNode centred on this tile with six-directional * connections. Call this when the pipe tile is placed or a neighbour changes. * Each fluid type that this pipe carries needs its own node. */ public default FluidNode createNode(FluidType type) { ... }}
package api.hbm.fluidmk2;import com.hbm.inventory.fluid.FluidType;public interface IFluidProviderMK2 extends IFluidUserMK2 { /** Remove the given amount of fluid from internal storage. */ public void useUpFluid(FluidType type, int pressure, long amount); /** Returns how much fluid is available to the network this tick. */ public long getFluidAvailable(FluidType type, int pressure); /** Maximum fluid that can leave per tick. Default: effectively unlimited. */ public default long getProviderSpeed(FluidType type, int pressure) { return 1_000_000_000; } /** Pressure tiers this provider can serve. Default: tier 0 only. */ public default int[] getProvidingPressureRange(FluidType type) { return DEFAULT_PRESSURE_RANGE; }}
package api.hbm.fluidmk2;import com.hbm.inventory.fluid.FluidType;import api.hbm.energymk2.IEnergyReceiverMK2.ConnectionPriority;public interface IFluidReceiverMK2 extends IFluidUserMK2 { /** Accept fluid. Returns the remainder that could not be stored. */ public long transferFluid(FluidType type, int pressure, long amount); /** How much of this fluid/pressure the tile still needs this tick. */ public long getDemand(FluidType type, int pressure); /** Maximum fluid accepted per tick. Default: effectively unlimited. */ public default long getReceiverSpeed(FluidType type, int pressure) { return 1_000_000_000; } /** Pressure tiers this receiver can accept. Default: tier 0 only. */ public default int[] getReceivingPressureRange(FluidType type) { return DEFAULT_PRESSURE_RANGE; } /** * Subscribe to a FluidNetMK2 via the pipe at (x,y,z) on face dir. * Call every tick for each adjacent pipe face. */ public default void trySubscribe(FluidType type, World world, int x, int y, int z, ForgeDirection dir) { ... } /** Priority within the network for this receiver. */ public default ConnectionPriority getFluidPriority() { return ConnectionPriority.NORMAL; }}
FluidNetMK2 is created and managed internally by UNINOS. Its per-tick update() method:
Collects all registered providers and sums available fluid per pressure tier.
Collects all registered receivers, groups by priority and pressure tier.
Distributes fluid proportionally within each priority group, highest first.
Debits providers proportionally based on their contribution weight.
Handles rounding errors via a bounded retry loop (max 100 iterations).
public class FluidNetMK2 extends NodeNet<IFluidReceiverMK2, IFluidProviderMK2, FluidNode> { /** The fluid type this network transports. Set at construction. */ protected FluidType type; /** Total fluid (mB equivalent) transferred since last tracker reset. */ public long fluidTracker = 0L;}
Items that carry fluids (canisters, drums, buckets) implement IFillableItem:
package api.hbm.fluidmk2;import com.hbm.inventory.fluid.FluidType;import net.minecraft.item.ItemStack;public interface IFillableItem { /** True if this stack can accept the given fluid type. */ public boolean acceptsFluid(FluidType type, ItemStack stack); /** Fill the stack with up to `amount` units. Returns the remainder. */ public int tryFill(FluidType type, int amount, ItemStack stack); /** True if this stack can supply the given fluid type to a tile. */ public boolean providesFluid(FluidType type, ItemStack stack); /** Drain up to `amount` units from the stack. Returns the remainder. */ public int tryEmpty(FluidType type, int amount, ItemStack stack); /** Returns the primary fluid type currently held, or null. */ public FluidType getFirstFluidType(ItemStack stack); /** Returns the current fill level for the primary fluid. */ public int getFill(ItemStack stack);}
The three legacy interfaces in api.hbm.fluid still work and simply extend their MK2 counterparts with convenience helpers. Prefer the MK2 versions for new code.
IFluidStandardReceiver (deprecated)
@Deprecatedpublic interface IFluidStandardReceiver extends IFluidStandardReceiverMK2 { /** Subscribe to all six adjacent pipe positions in one call. */ public default void subscribeToAllAround(FluidType type, TileEntity tile) { ... } /** Unsubscribe from all adjacent pipe positions. */ public default void unsubscribeToAllAround(FluidType type, TileEntity tile) { ... }}
IFluidStandardSender (deprecated)
@Deprecatedpublic interface IFluidStandardSender extends IFluidStandardSenderMK2 { /** Push fluid from a tank to one face. */ public default void sendFluid(FluidTank tank, World world, int x, int y, int z, ForgeDirection dir) { ... } /** Push fluid from a tank to all six adjacent tiles in one call. */ public default void sendFluidToAll(FluidTank tank, TileEntity tile) { ... }}
Addon mods can listen for fluid registration via IFluidRegisterListener (see api.hbm.fluidmk2.IFluidRegisterListener), registered through Fluids.additionalListeners. This lets you define your own FluidType objects after NTM has set up its core fluids, ensuring your types receive proper IDs and network providers.
Full Implementation Example: Simple Fluid Tank Tile
package com.example.mymod.tile;import api.hbm.fluidmk2.IFluidStandardReceiverMK2;import api.hbm.fluidmk2.IFluidStandardSenderMK2;import com.hbm.inventory.fluid.FluidType;import com.hbm.inventory.fluid.Fluids;import com.hbm.inventory.fluid.tank.FluidTank;import net.minecraft.nbt.NBTTagCompound;import net.minecraft.tileentity.TileEntity;import net.minecraftforge.common.util.ForgeDirection;/** * A simple bidirectional fluid tank that accepts water on all sides * and can also output water to adjacent pipes/tiles. */public class TileEntityMyFluidTank extends TileEntity implements IFluidStandardReceiverMK2, IFluidStandardSenderMK2 { // FluidTank(FluidType type, int maxFill, int pressure) private final FluidTank tank = new FluidTank(Fluids.WATER, 16_000, 0); // ------------------------------------------------------- // IFluidUserMK2 — expose all tanks // ------------------------------------------------------- @Override public FluidTank[] getAllTanks() { return new FluidTank[]{ tank }; } // ------------------------------------------------------- // IFluidStandardReceiverMK2 — incoming fluid // ------------------------------------------------------- @Override public FluidTank[] getReceivingTanks() { return getAllTanks(); } // ------------------------------------------------------- // IFluidStandardSenderMK2 — outgoing fluid // ------------------------------------------------------- @Override public FluidTank[] getSendingTanks() { return getAllTanks(); } // ------------------------------------------------------- // IFluidConnectorMK2 — restrict to water only // ------------------------------------------------------- @Override public boolean canConnect(FluidType type, ForgeDirection dir) { return type == Fluids.WATER && dir != ForgeDirection.UNKNOWN; } // ------------------------------------------------------- // TileEntity lifecycle // ------------------------------------------------------- @Override public void updateEntity() { if (worldObj.isRemote) return; // Subscribe as a receiver on every adjacent pipe face for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { trySubscribe(Fluids.WATER, worldObj, xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ, dir); } // Also push fluid out (acts as a pass-through / buffer) for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { tryProvide(tank, worldObj, xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ, dir); } } // ------------------------------------------------------- // NBT persistence // ------------------------------------------------------- @Override public void writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); tag.setInteger("waterFill", tank.getFill()); } @Override public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); tank.setFill(tag.getInteger("waterFill")); }}
IFluidStandardReceiverMK2 and IFluidStandardSenderMK2 together implement all of IFluidProviderMK2 and IFluidReceiverMK2 via default methods, so you only need to provide getReceivingTanks(), getSendingTanks(), and getAllTanks(). Implementing both interfaces on the same tile makes it a full transceiver — the equivalent of the deprecated IFluidStandardTransceiver.
The MK2 fluid network supports six pressure tiers (indices 0–5), controlled by the HIGHEST_VALID_PRESSURE = 5 constant on IFluidUserMK2. The pressure is stored per-tank in FluidTank and is used by the network to match compatible providers with receivers:
A provider serving tier 1 will only supply receivers that accept tier 1.
A receiver that accepts tiers 0–2 must override getReceivingPressureRange() to return new int[]{ 0, 2 }.
IFluidStandardReceiverMK2 and IFluidStandardSenderMK2 derive the pressure range automatically from the tanks you expose via getReceivingTanks() / getSendingTanks().
// Manually declare a pressure range spanning tiers 0 through 3:@Overridepublic int[] getReceivingPressureRange(FluidType type) { return new int[]{ 0, 3 };}