Skip to content

How to Load an Anvil world

TheMeinerLP edited this page Aug 24, 2026 · 2 revisions

Load an Anvil world

Serve a stored Anvil world (r.<x>.<z>.mca region files) from a Minestom instance using FalcoAnvilLoader instead of the built-in AnvilLoader.

Before you start: falco-anvil on the classpath (How-to Add Falco to your build), and a world directory whose chunks are at or above the version floor on Reference Supported versions. Nothing switches to this loader by itself — a server keeps using whatever loader it uses today until it constructs a FalcoAnvilLoader explicitly.

Set the loader on an instance

  1. Create the instance, construct the loader from the world root and the dimension key, and set it:
import net.kyori.adventure.key.Key;
import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.world.DimensionType;
import net.onelitefeather.falco.anvil.FalcoAnvilLoader;

import java.nio.file.Path;

public final class Bootstrap {

    public static InstanceContainer createLobby() {
        InstanceContainer instance = MinecraftServer.getInstanceManager()
                .createInstanceContainer(DimensionType.OVERWORLD);

        Key dimension = DimensionType.OVERWORLD.key();
        FalcoAnvilLoader loader = new FalcoAnvilLoader(Path.of("worlds", "lobby"), dimension);

        instance.setChunkLoader(loader);
        instance.enableAutoChunkLoad(true);
        return instance;
    }
}
  1. Pass the world root, not the region directory. The loader resolves worldRoot/dimensions/<namespace>/<value>/region itself, and falls back to worldRoot/region when only the pre-26.1 layout exists.

  2. Call close() on server shutdown. It flushes and closes every open region file and writes the summary line. During operation a region file closes on its own once the last chunk read from it has been unloaded, so nothing has to be closed per chunk.

Hand the loader to a map provider instead

FalcoAnvilLoader is a plain net.minestom.server.instance.ChunkLoader, so anything that already accepts one takes it without knowing this library exists. Pass it to InstanceManager#createInstanceContainer(RegistryKey<DimensionType>, ChunkLoader):

import net.kyori.adventure.key.Key;
import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.ChunkLoader;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.registry.RegistryKey;
import net.minestom.server.world.DimensionType;
import net.onelitefeather.falco.anvil.FalcoAnvilLoader;

import java.nio.file.Path;

public final class MapLoaders {

    public static InstanceContainer open(Path worldRoot, RegistryKey<DimensionType> dimensionKey) {
        Key dimension = dimensionKey.key();
        ChunkLoader loader = new FalcoAnvilLoader(worldRoot, dimension);

        return MinecraftServer.getInstanceManager().createInstanceContainer(dimensionKey, loader);
    }
}

The relevant Falco signatures are:

Member Declaration
FalcoAnvilLoader(Path, Key) public FalcoAnvilLoader(Path worldRoot, Key dimension)
FalcoAnvilLoader(Path, Key, int) public FalcoAnvilLoader(Path worldRoot, Key dimension, int openRegionLimit)

A provider that keeps a world root per map passes that root and the dimension key of the instance it is building. Any other ChunkLoader is supplied the same way, which is what makes the choice reversible.

The falco-demo module does exactly this and is compiled on every build: LoaderKind#create constructs either loader from the same world description, and DemoServer hands the result to createInstanceContainer.

Raise the cached-region limit

The number of region files held in the cache defaults to 64 and is set through the three-argument constructor:

FalcoAnvilLoader loader = new FalcoAnvilLoader(worldRoot, dimension, 256);

Check it worked

The loader writes an opening log line naming the resolved region directory and the policies it resolved. Players see the stored world rather than freshly generated terrain, and AnvilDiagnostics#chunksLoaded() climbs while errors() stays at zero.

If it does not work

A load that throws AnvilChunkException rather than returning air is the loader working as designed — it found a chunk it could not read and refused to let a replacement be generated over it. Read reason() off the causing ChunkDataException and look it up on Reference Exceptions and faults. UNSUPPORTED_CHUNK_VERSION means the world predates the floor; How-to Migrate a world from an older version is the fix.

An IllegalStateException from loadChunk, saveChunk or saveChunks means close() has already run on this loader.

See also: Reference Exceptions and faults · Reference Supported versions · How-to Replace the version and unknown-entry policies · Explanation How the Anvil loader is built

Getting started

How-to guides

four more

Reference

six more

Background

nine more

Project record

Working on Falco

six more

Repository · Quick start · Issues

Clone this wiki locally