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.

SubLevelContainer is the main entry point for accessing and managing sub-levels within a Level. Each dimension has a container attached to it; use the static getContainer() methods to retrieve it. The concrete subtypes ServerSubLevelContainer and ClientSubLevelContainer expose side-specific operations and are returned when you pass a typed level.

Constants

ConstantValueDescription
DEFAULT_LOG_SIZE_LENGTH7log₂ of the side length (in chunks) of the plotgrid.
DEFAULT_LOG_PLOT_SIZE7log₂ of the number of chunks on a side of one plot.
DEFAULT_ORIGIN10000Origin of the plotyard in plot coordinates, placing it over 30 million blocks from spawn.

Static methods

getContainer(Level)

public static @Nullable SubLevelContainer getContainer(Level level)
Returns the SubLevelContainer attached to any Level, or null if one is not present.
level
Level
required
The level to retrieve the container from.

getContainer(ServerLevel)

public static @Nullable ServerSubLevelContainer getContainer(ServerLevel level)
Typed overload that returns a ServerSubLevelContainer directly, avoiding a cast. Returns null if no container is attached.
level
ServerLevel
required
The server-side level to retrieve the container from.

getContainer(ClientLevel)

public static @Nullable ClientSubLevelContainer getContainer(ClientLevel level)
Typed overload that returns a ClientSubLevelContainer directly. Returns null if no container is attached.
level
ClientLevel
required
The client-side level to retrieve the container from.

Instance methods

allocateNewSubLevel

public SubLevel allocateNewSubLevel(Pose3d pose)
Allocates a new sub-level in the first empty plot found by scanning the grid in row-major order.
pose
Pose3d
required
The initial position and orientation for the sub-level in global space.
Returns the newly allocated SubLevel.
Throws IllegalStateException if all plots in the grid are occupied.

allocateSubLevel

public SubLevel allocateSubLevel(UUID uuid, int x, int z, Pose3d pose)
Allocates a sub-level at an explicit local plot coordinate. Use this when you need deterministic placement, such as when restoring a saved world.
uuid
UUID
required
The unique identifier to assign to the new sub-level.
x
int
required
Local plot X coordinate within the grid (0-inclusive, grid-width-exclusive).
z
int
required
Local plot Z coordinate within the grid (0-inclusive, grid-width-exclusive).
pose
Pose3d
required
The initial position and orientation for the sub-level in global space.
Returns the newly allocated SubLevel.
Throws IllegalArgumentException if a sub-level already exists at the given coordinates or the coordinates are out of bounds.

removeSubLevel(SubLevel, SubLevelRemovalReason)

public void removeSubLevel(SubLevel subLevel, SubLevelRemovalReason reason)
Removes a sub-level by reference. Notifies all registered observers before the removal takes effect.
subLevel
SubLevel
required
The sub-level instance to remove.
reason
SubLevelRemovalReason
required
The reason for removal. When REMOVED, the plot slot is freed and the occupancy bit is cleared. When UNLOADED, the slot remains reserved.

removeSubLevel(int, int, SubLevelRemovalReason)

public void removeSubLevel(int x, int z, SubLevelRemovalReason reason)
Removes a sub-level by local plot coordinate.
x
int
required
Local plot X coordinate.
z
int
required
Local plot Z coordinate.
reason
SubLevelRemovalReason
required
The reason for removal.
Throws IllegalStateException if no sub-level exists at the given coordinates.

getSubLevel(UUID)

public @Nullable SubLevel getSubLevel(UUID uuid)
Looks up a loaded sub-level by its UUID. Returns null if no matching sub-level is currently loaded.
uuid
UUID
required
The unique identifier of the sub-level to retrieve.

getSubLevel(int, int)

public @Nullable SubLevel getSubLevel(int x, int z)
Returns the sub-level at the given local plot coordinates, or null if the slot is empty or out of bounds.
x
int
required
Local plot X coordinate.
z
int
required
Local plot Z coordinate.

getAllSubLevels

public List<? extends SubLevel> getAllSubLevels()
Returns a live list of all currently loaded sub-levels. On ServerSubLevelContainer this is narrowed to List<ServerSubLevel>; on ClientSubLevelContainer to List<ClientSubLevel>.

getLoadedCount

public int getLoadedCount()
Returns the number of sub-levels currently loaded in this container.

queryIntersecting

public Iterable<SubLevel> queryIntersecting(BoundingBox3dc bounds)
Returns all loaded sub-levels whose bounding box intersects the given volume.
bounds
BoundingBox3dc
required
The double-precision axis-aligned bounding box to test against.

getChunk

public @Nullable LevelChunk getChunk(ChunkPos pos)
Returns the LevelChunk at the given global chunk position if it belongs to a plot in this container, or null otherwise.
pos
ChunkPos
required
The global chunk position.

getPlot

public @Nullable LevelPlot getPlot(ChunkPos pos)
Returns the LevelPlot that owns the given global chunk position, or null if the position is not within any plot.
pos
ChunkPos
required
The global chunk position.

inBounds(ChunkPos)

public boolean inBounds(ChunkPos pos)
Returns true if the given global chunk position falls within the plotgrid boundaries.

inBounds(BlockPos)

public boolean inBounds(BlockPos pos)
Returns true if the given global block position falls within the plotgrid boundaries.

addObserver

public void addObserver(SubLevelObserver observer)
Registers a SubLevelObserver that will be notified of sub-level additions, removals, and ticks.
observer
SubLevelObserver
required
The observer to register. See the SubLevelObserver section below.

tick

public void tick()
Called by the engine every game tick. Ticks all loaded sub-levels, processes queued removals, and invokes SubLevelObserver.tick() on every registered observer. You do not need to call this manually.

getLevel

public Level getLevel()
Returns the Level this container is attached to. On ServerSubLevelContainer the return type is narrowed to ServerLevel; on ClientSubLevelContainer to ClientLevel.

getOrigin

public Vector2i getOrigin()
Returns the origin of the plotgrid in plot coordinates as a Vector2i(originX, originZ).

getLogPlotSize

public int getLogPlotSize()
Returns the log₂ of the number of chunks on a side of one plot. With the default value of 7, each plot is 128 × 128 chunks.

getLogSideLength

public int getLogSideLength()
Returns the log₂ of the number of plots on a side of the entire plotgrid. With the default value of 7, the grid is 128 × 128 plots.

SubLevelObserver

SubLevelObserver is a listener interface with default no-op implementations for all callbacks. Register instances with addObserver().
public interface SubLevelObserver {
    default void onSubLevelAdded(SubLevel subLevel) {}
    default void onSubLevelRemoved(SubLevel subLevel, SubLevelRemovalReason reason) {}
    default void tick(SubLevelContainer subLevels) {}
}
onSubLevelAdded(SubLevel)
callback
Called after a sub-level is successfully allocated and added to the container.
onSubLevelRemoved(SubLevel, SubLevelRemovalReason)
callback
Called before a sub-level is removed from the container. The sub-level is still accessible at this point.
tick(SubLevelContainer)
callback
Called once per game tick for the container. Use this for polling or per-tick bookkeeping tied to the grid.

Force-loading tickets (server only)

ServerSubLevelContainer exposes a ticket system to keep sub-levels loaded across server restarts. Tickets are persisted to saved data and re-applied on world load.

addForceLoadTicket

public <T> boolean addForceLoadTicket(
    ServerSubLevel subLevel,
    SubLevelLoadingTicketType<T> ticketType,
    T key
)
Adds a force-load ticket to a sub-level. Two tickets with the same type and key cannot coexist on the same sub-level. Returns true if the ticket was newly added, false if an identical ticket already existed.
subLevel
ServerSubLevel
required
The sub-level to add the ticket to.
ticketType
SubLevelLoadingTicketType<T>
required
The ticket type. Use SubLevelLoadingTicketType.COMMAND_FORCED or create your own with SubLevelLoadingTicketType.create().
key
T
required
A key value that uniquely identifies this ticket instance within the type.

removeForceLoadTicket

public <T> boolean removeForceLoadTicket(
    ServerSubLevel subLevel,
    SubLevelLoadingTicketType<T> ticketType,
    T key
)
Removes a previously added force-load ticket. Returns true if a matching ticket existed and was removed.
subLevel
ServerSubLevel
required
The sub-level to remove the ticket from.
ticketType
SubLevelLoadingTicketType<T>
required
The ticket type to remove.
key
T
required
The key that identifies the specific ticket to remove.

SubLevelLoadingTicketType

public record SubLevelLoadingTicketType<T>(ResourceLocation name, Codec<T> codec)
Represents a named category of loading ticket with a serialization codec for its key type.
  • COMMAND_FORCED — built-in type used by the /sable command to force-load sub-levels. Key type is Unit.
  • create(ResourceLocation, Codec<T>) — registers a new ticket type. Call this once at mod initialization.
  • byName(ResourceLocation) — looks up a registered type by its resource location.
Define a single SubLevelLoadingTicketType constant per logical use-case (e.g., one for your machine block). This makes it easy to remove all tickets of that type when the machine is destroyed.

Usage example

ServerSubLevelContainer container = SubLevelContainer.getContainer(serverLevel);
if (container != null) {
    Pose3d pose = new Pose3d();
    pose.position().set(x + 0.5, y + 0.5, z + 0.5);
    SubLevel subLevel = container.allocateNewSubLevel(pose);
}
To observe sub-level lifecycle events:
container.addObserver(new SubLevelObserver() {
    @Override
    public void onSubLevelAdded(SubLevel subLevel) {
        // react to a new sub-level being created
    }

    @Override
    public void onSubLevelRemoved(SubLevel subLevel, SubLevelRemovalReason reason) {
        // clean up references before the sub-level is destroyed
    }
});

Build docs developers (and LLMs) love