Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ryanhcode/sable/llms.txt

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

SubLevelAssemblyHelper provides static utility methods for the two phases of sub-level creation: discovering which blocks belong together (gathering) and moving them into a new sub-level (assembly). The typical workflow calls gatherConnectedBlocks() first to identify a block set, inspects the GatherResult, and then passes the result to assembleBlocks().

assembleBlocks

public static ServerSubLevel assembleBlocks(
    ServerLevel level,
    BlockPos anchor,
    Iterable<BlockPos> blocks,
    BoundingBox3ic bounds
)
Moves a collection of blocks from the world into a freshly allocated sub-level and returns that sub-level. The anchor block is placed at the center of the sub-level’s plot; all other blocks are translated relative to it. Tracking points and retained entities within bounds are moved along with the blocks. If the anchor is already inside another sub-level, the new sub-level inherits that sub-level’s pose and velocity and is recorded as a split.
level
ServerLevel
required
The server level that currently contains the blocks to be assembled.
anchor
BlockPos
required
The block that will map to the center of the new sub-level’s plot. All other block positions are offset relative to this anchor.
blocks
Iterable<BlockPos>
required
Every block position to move into the sub-level. Typically the blocks set from a GatherResult.
bounds
BoundingBox3ic
required
Integer-precision bounding box used to determine which tracking points and hanging entities should be relocated. Typically the boundingBox from a GatherResult.
Returns the newly created and populated ServerSubLevel.
The container must be non-null (i.e., the level must have a SubLevelContainer attached) or an assertion error is thrown. In normal gameplay this is always satisfied for server levels.

gatherConnectedBlocks

public static GatherResult gatherConnectedBlocks(
    BlockPos gatherOrigin,
    ServerLevel level,
    int maximumBlocksToAssemble,
    @Nullable FrontierPredicate frontierPredicate
)
Performs a breadth-first search starting from gatherOrigin, expanding to all non-air blocks connected within a 3×3×3 neighbourhood. Pure-corner diagonals (where |dx| + |dy| + |dz| = 3) are excluded from connectivity, so only face and edge neighbours can propagate the frontier. Air blocks are never added to the result.
gatherOrigin
BlockPos
required
The block position from which gathering begins. If this position is air, the method returns immediately with State.NO_BLOCKS.
level
ServerLevel
required
The server level to read block states from.
maximumBlocksToAssemble
int
required
Hard cap on the number of blocks that may be gathered. If the search would exceed this limit, gathering stops immediately and the result carries State.TOO_MANY_BLOCKS.
frontierPredicate
FrontierPredicate
An optional filter evaluated for each candidate neighbour. Pass null to accept all non-air connections. See FrontierPredicate below.
Returns a GatherResult.

GatherResult

public record GatherResult(
    @Nullable Set<BlockPos> blocks,
    int checkedBlocks,
    @Nullable BoundingBox3i boundingBox,
    State assemblyState
)
Holds the output of gatherConnectedBlocks().
blocks
Set<BlockPos>
The set of block positions gathered. null when assemblyState is not SUCCESS.
checkedBlocks
int
The total number of blocks inspected during the search, including those rejected by the predicate or the air check.
boundingBox
BoundingBox3i
The axis-aligned integer bounding box enclosing all gathered blocks. null when assemblyState is not SUCCESS.
assemblyState
GatherResult.State
Indicates whether gathering succeeded or failed, and why.

GatherResult.State

ValueDescription
SUCCESSGathering completed within the block limit and found at least one block.
TOO_MANY_BLOCKSThe search reached maximumBlocksToAssemble before completing. blocks and boundingBox are null.
NO_BLOCKSThe gather origin was air, or the search completed with an empty result.

FrontierPredicate

@FunctionalInterface
public interface FrontierPredicate {
    boolean isValidConnection(
        BlockPos originPos,
        BlockState originState,
        BlockPos pos,
        BlockState state,
        @Nullable Direction directionFrom
    );
}
A functional interface that controls which neighbouring blocks the BFS is allowed to cross. Return true to allow the connection and add pos to the frontier, or false to block it.
originPos
BlockPos
The position of the block that is attempting to expand into pos.
originState
BlockState
The block state at originPos.
pos
BlockPos
The candidate neighbour position being evaluated.
state
BlockState
The block state at pos.
directionFrom
Direction
The cardinal direction from originPos to pos, or null when the connection is along an edge diagonal (|dx| + |dy| + |dz| = 2). Pure-corner diagonals are never evaluated.
Use directionFrom == null as a signal to apply stricter rules to diagonal connections, since those relationships are geometrically weaker than face-adjacent ones.

AssemblyTransform

public static class AssemblyTransform {
    public AssemblyTransform(
        BlockPos anchorPos,
        BlockPos resultingAnchorPos,
        int angle,
        Rotation rotation,
        ServerLevel resultingLevel
    )
}
Encapsulates the spatial mapping from source positions in a world to destination positions inside a sub-level plot. assembleBlocks() constructs this automatically; you only need to instantiate it directly if you are building a custom assembly pipeline.
anchorPos
BlockPos
required
The anchor block position in the source level.
resultingAnchorPos
BlockPos
required
The position in the destination level (plot center) that anchorPos maps to.
angle
int
required
Number of 90° counter-clockwise increments to rotate around the Y axis.
rotation
Rotation
required
The Minecraft Rotation equivalent of angle, used for rotating individual block states.
resultingLevel
ServerLevel
required
The destination level — typically the level that owns the target sub-level’s plot.

apply methods

SignatureDescription
Vec3 apply(Vec3 pos)Translates and rotates a continuous position from source space to destination space.
BlockPos apply(BlockPos pos)Converts a block position via the continuous overload and rounds to the nearest block.
BlockState apply(BlockState state)Rotates a block state using the transform’s Rotation, with special handling for bell attachment types.

Internal helpers

The following methods are used internally by assembleBlocks(). They are public but not intended for direct use:
  • moveBlocks(ServerLevel, AssemblyTransform, Iterable<BlockPos>) — copies block states and block entity data to the destination level, then replaces source blocks with air.
  • moveTrackingPoints(ServerLevel, BoundingBox3ic, ServerSubLevel, AssemblyTransform) — relocates saved tracking points that fall within bounds into the sub-level’s local coordinate space.

Usage example

// Phase 1: discover connected blocks
GatherResult result = SubLevelAssemblyHelper.gatherConnectedBlocks(
    clickedPos,
    serverLevel,
    4096,
    (originPos, originState, pos, state, dir) -> {
        // reject connections through leaves
        return !state.is(BlockTags.LEAVES);
    }
);

if (result.assemblyState() != GatherResult.State.SUCCESS) {
    // handle TOO_MANY_BLOCKS or NO_BLOCKS
    return;
}

// Phase 2: assemble into a sub-level
ServerSubLevel subLevel = SubLevelAssemblyHelper.assembleBlocks(
    serverLevel,
    clickedPos,
    result.blocks(),
    result.boundingBox()
);

Build docs developers (and LLMs) love