Minestom

A Minecraft server implementation,
open-source and without any code from Mojang.

public static void main(String[] args) {
    // Initialization
    MinecraftServer minecraftServer = MinecraftServer.init();

    InstanceManager instanceManager = MinecraftServer.getInstanceManager();
    // Create the instance
    InstanceContainer instanceContainer = instanceManager.createInstanceContainer();
    // Set the ChunkGenerator
    instanceContainer.setChunkGenerator(new GeneratorDemo());

    // Add an event callback to specify the spawning instance (and the spawn position)
    GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
    globalEventHandler.addListener(PlayerLoginEvent.class, event -> {
        final Player player = event.getPlayer();
        event.setSpawningInstance(instanceContainer);
        player.setRespawnPoint(new Pos(0, 42, 0));
    });

    // Start the server on port 25565
    minecraftServer.start("0.0.0.0", 25565);
}

Introduction

A complete rewrite of Minecraft server software, open-source and without any code from Mojang.

The main difference from default Minecraft is that Minestom does not contain any features by default. However, we have a complete API that allows you to make anything possible with extensions, similar to how plugins and mods work.

This is a developer API; It is not meant to be used by the end-users.

Replacing Bukkit/Forge/Sponge with this will not work since we do not implement any of their APIs.

// Get the instance manager
InstanceManager instanceManager = MinecraftServer.getInstanceManager();

// Create the instance
InstanceContainer instanceContainer = instanceManager.createInstanceContainer();

// Set the ChunkGenerator
instanceContainer.setChunkGenerator(/* chunk generator here */);

// Make chunks automatically load
instanceContainer.enableAutoChunkLoad(true);

Instances

Worlds in default Minecraft are great for playing with friends, but scaling them up can be unmanageable. The best examples of this can be found in minigames; it's hard to separate worlds properly and all worlds are saved in files. Plus, there's a lot of overhead caused by unnecessary data contained in them.

Instances are our lightweight solution to it. You can copy and send them to another player in no time, create a serializer, decide if they're saved in memory only, and more.

Being able to create instances on the go is a must-have that can help push many more projects forward.

Instances also come with performance benefits. Unlike other implementations of worlds that may be fully singlethreaded or use one thread per world, Minestom uses a set number of threads (a thread pool) to manage chunks independently from instances so that lag can be reduced.

Find out more about instances on the wiki
public class DemoHandler implements BlockHandler {
    @Override
    public void onPlace(@NotNull Placement placement) {
        if (placement instanceof PlayerPlacement) {
            // A player placed the block
        }
        Block block = placement.getBlock();
        System.out.println("The block " + block.name() + " has been placed");
    }

    @Override
    public @NotNull NamespaceID getNamespaceId() {
        // Required for serialization purpose
        return NamespaceID.from("minestom:demo");
    }
}

///////////////////////////////////////////////////////////////////////////
// Usage
///////////////////////////////////////////////////////////////////////////

Block tnt = Block.TNT;
// Create a new block with the specified handler.
// Be aware that block objects can be reused, handlers should
// therefore never assume to be assigned to a single block.
tnt = tnt.withHandler(new DemoHandler());
// Share the same handler reference with multiple blocks
BlockHandler handler = new DemoHandler();
Block stone = Block.STONE.withHandler(handler);
Block grass = Block.GRASS.withHandler(handler);

Blocks

By default, Minestom doesn't know what a chest is. You have to tell the server to open an inventory when someone clicks on it. Every one of these special blocks (a block that isn't only visual) has to be registered, but after that, they can just be placed in the world.

However, all blocks are visually there, and you only need to add functionality.

Find out more about blocks on the wiki
// Creating a chicken that runs after you
// but unfortunately does not fly
final Entity chicken = new Entity(EntityType.CHICKEN);
chicken.addAIGroup(ImmutableList.of(
            new DoNothingGoal(chicken, 500, 0.1f),
            new MeleeAttackGoal(chicken, 2, 500, TimeUnit.MILLISECOND),
            new RandomStrollGoal(chicken, 4)
        ),
        ImmutableList.of(
            new LastEntityDamagerTarget(chicken, 15),
            new ClosestEntityTarget(chicken, 15, Player.class)
        ));
final Instance instance = ...; // Instance to spawn the chicken in
final Pos spawnPosition = new Pos(0, 42, 0);
chicken.setInstance(instance, spawnPosition);

Entities

The terms "passive" or "aggressive" mobs do not exist. Nobody forbids you from making a flying chicken that rushes at any players that come too close. Doing this with NMS is a mess because of obfuscation and the large inheritance, but it's easy with Minestom.

Find out more about entities on the wiki
// Create the inventory
Inventory inventory = new Inventory(InventoryType.CHEST_1_ROW, "The inventory name");
// Open the inventory for the player
// (Opening the same inventory for multiple players would result in a shared interface)
player.openInventory(inventory);
// Close the current player inventory
player.closeInventory();

Inventories

Inventories have evolved a lot from just being storage containers. They are often used as a client<->server interface with clickable items and callbacks. Minestom supports it natively without having to program all the basic stuff yourself!

Find out more about inventories on the wiki
public class PotionCommand extends Command {
    private final ArgumentPotionEffect potion;
    private final Argumentlnteger duration;

    public PotionCommand() {
        super("potion");

        setCondition(Conditions::playerOnly);
        setDefaultExecutor(((sender, args) ->
            sender.sendMessage(Component.text("Usage: /potion <type> <duration (seconds)>")));

        potion = ArgumentType.Potion("potion");
        duration = ArgumentType.Integer("duration");

        addSyntax(this::onPotionCommand, potion, duration);
    }

    private void onPotionCommand(CommandSender sender, CommandContext context) {
        final Player player = (Player) sender;
        final PotionEffect potionEffect = context.get(potion);
        final Integer duration = context.get(this.duration);
        player.sendMessage(Component.text(player.getActiveEffects().toString()));
        player.addEffect(new Potion( potionEffect, (byte) 0, duration * MinecraftServer.TICK_PER_SECOND));
    }
}

Commands

Commands are the simplest way of communication between clients and server. In 1.13, Minecraft started using a new library for commands named Brigadier. Minestom has integrated an API that allows you to use the features it adds.

Find out more about commands on the wiki