Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/hbmmods/hbm-s-nuclear-tech-git/llms.txt

Use this file to discover all available pages before exploring further.

NTM’s fluid system is one of its most distinctive features. Rather than using Forge’s standard fluid API as a universal bus, NTM implements its own typed network layer — FluidNetMK2 — built on top of the same NodeNet/UNINOS graph infrastructure as the power system. Every pipe, tank, and machine port on a fluid network is typed: a pipe set to carry DIESEL will never carry STEAM, and two adjacent pipes of different types will not merge into a single network. This hard separation eliminates fluid contamination accidents and makes large, multi-fluid factory floors predictable to reason about.

FluidNetMK2 and FluidNode

FluidNetMK2 extends NodeNet<IFluidReceiverMK2, IFluidProviderMK2, FluidNode> and is parameterised by a FluidType at construction time. Each network instance is responsible for exactly one fluid type:
public FluidNetMK2(FluidType type) {
    this.type = type;
    // initialise pressure-indexed provider and receiver arrays
}
FluidNode is the graph node class for fluid conductors. It extends GenNode<FluidNetMK2> and holds a set of DirPos connections — the positions and directions it can connect toward:
public class FluidNode extends GenNode<FluidNetMK2> {
    public FluidNode(INetworkProvider<FluidNetMK2> provider, BlockPos... positions) {
        super(provider, positions);
    }

    @Override
    public FluidNode setConnections(DirPos... connections) {
        super.setConnections(connections);
        return this;
    }
}
When a pipe is placed or a chunk loads, it creates a FluidNode and registers it into the shared UNINOS nodespace. The nodespace performs a graph traversal to merge adjacent same-type nodes into one FluidNetMK2 instance.

Network Update Loop

Each game tick, FluidNetMK2.update() runs in three phases:
1

Setup providers

Iterates all registered IFluidProviderMK2 entries. Stale entries (no heartbeat for >3 seconds) are pruned. Each provider declares a pressure range via getProvidingPressureRange(type), and its available volume at each pressure is added to the fluidAvailable array.
2

Setup receivers

Iterates all registered IFluidReceiverMK2 entries, similarly pruned. Each receiver declares a pressure range via getReceivingPressureRange(type) and a demand volume via getDemand(type, p). Demand is sorted by ConnectionPriority, mirroring the power network’s priority system.
3

Transfer fluid

For each pressure level (from 0 to HIGHEST_VALID_PRESSURE), and then from highest to lowest priority tier, each receiver is sent a share of available fluid proportional to its demand. Providers are then drained in proportion to how much they contributed.
A fluidTracker counter accumulates total fluid moved, useful for throughput monitoring.

Key Interfaces

The base interface for any block that can participate in a fluid network — pipes, machines, tanks. The key method is:
public default boolean canConnect(FluidType type, ForgeDirection dir) {
    return dir != ForgeDirection.UNKNOWN;
}
Override this to restrict which sides a block exposes to the network, or to filter which fluid types are accepted on a given face.
IFluidPipeMK2 extends IFluidConnectorMK2 and is the conductor interface for fluid pipe tile entities. It provides a default createNode(FluidType type) implementation that constructs a FluidNode with connections on all six cardinal faces and registers it into the UNINOS nodespace, forming the graph structure that links tanks and machines together.IFluidConnectorBlockMK2 is a separate interface for blocks that need world-context-aware connection logic. Unlike IFluidConnectorMK2, its single method receives the full world reference and block position, allowing connection checks that depend on neighbouring block state:
public interface IFluidConnectorBlockMK2 {
    /** dir is the face that is connected to, the direction going outwards from the block */
    boolean canConnect(FluidType type, IBlockAccess world, int x, int y, int z, ForgeDirection dir);
}
Fluid-carrying items (buckets, canisters, flasks) implement IFillableItem:
public interface IFillableItem {
    boolean acceptsFluid(FluidType type, ItemStack stack);
    int tryFill(FluidType type, int amount, ItemStack stack);
    boolean providesFluid(FluidType type, ItemStack stack);
    int tryEmpty(FluidType type, int amount, ItemStack stack);
    FluidType getFirstFluidType(ItemStack stack);
    int getFill(ItemStack stack);
}
tryFill returns the remainder that could not be added; tryEmpty returns fluid up to the requested amount. Items typically store fluid type and fill level in NBT, allowing the same canister item to hold any compatible fluid type.

Fluid Identification

A critical concept in NTM, described in the in-game manual’s Fluid Identification article, is that all pipes and tanks must have their fluid type explicitly assigned before they can transport fluid. This is done using the Fluid Identifier tool:
  • Shift-click on the Fluid Identifier to open its GUI; save up to two fluid types (left/right click slots).
  • Right-click in the air to swap the primary and secondary saved type.
  • Right-click a pipe or tank to assign the primary type to that block.
  • Shift-click a pipe to propagate the type to all connected pipes of the same current type, up to 64 blocks away.
Some machines feature a fluid identifier slot in their GUI — inserting the identifier item there changes the machine’s internal tank type without needing external right-clicking.
Pipes of different fluid types will never connect, even when physically adjacent. This is by design: it means you can run a diesel line and a water line side-by-side without any risk of cross-contamination.

Fluid Types (the Fluids Registry)

All fluid types are registered as static fields on the Fluids class. They are grouped into broad categories:
FluidDescription
WATERStandard water, used in cooling, boilers
STEAMLow-grade steam from boilers
HOTSTEAMHigher-temperature steam for more powerful turbines
SUPERHOTSTEAMSuperheated steam from high-efficiency heat exchangers
ULTRAHOTSTEAMMaximum-grade steam, from reactor heat at extreme temperatures
SPENTSTEAMExhaust steam after passing through a turbine
HEAVYWATERD₂O, used in CANDU-style reactor moderation

Connecting a Fluid Network

1

Place pipes

Lay IFluidPipeMK2 pipes between your fluid source (tank, machine output port) and destination.
2

Assign fluid type

Use a Fluid Identifier to right-click each pipe (or shift-click to propagate to all connected pipes). All pipes in a network segment must share the same type.
3

Connect machines

Machines with fluid ports automatically connect when a pipe of the correct type is placed adjacent to their input/output face. Check the machine GUI to confirm the tank type is set.
4

Verify flow

With fluid in the source tank, the network will begin distributing it each tick. Use the fluidTracker value (visible in some diagnostic tools) to confirm flow is occurring.

Legacy Fluid System

The legacy interfaces IFluidStandardReceiver and IFluidStandardSender pre-date the MK2 network and are no longer used for new machines. They lack pressure support, priority scheduling, and the UNINOS graph structure. Do not use them for any new development; they exist only for backwards compatibility with older NTM machine blocks that have not yet been migrated.

Further Reading

  • Fluid Handling — The in-game manual concept article (fluidhandling.json) covers pipe placement and tank setup from a survival gameplay perspective.
  • Fluid Identification — The fluidid.json manual article explains the Fluid Identifier tool in detail, including how to use it on multi-type machines and what happens when you re-identify an already-typed pipe.

Build docs developers (and LLMs) love