Minecraft: Java Edition 26.3
calcite
A Minecraft server that runs the world on every core of the machine. It's written in Calx, and plugins can be written in Calx or in anything that builds to WASM.
pre-releasePhase 6, simulation, is in progressWhat it does
Calcite is written from scratch, with no code from vanilla, Paper or any other server.
Every core
The world is split into regions that tick in parallel, in lockstep. A busy server uses the whole machine, and gets the same result on one thread as on 32.
Plugins
phase 7Plugins in Calx run natively, at full speed. Plugins in any language that builds to WASM run in a sandbox. Both use the same API.
The same files
server.properties, the operators, the whitelist and the ban lists are read where vanilla keeps them, so moving a server over is starting a different program in the same folder.
Worlds and data packs
Worlds are saved in vanilla’s format, so an existing one moves to Calcite and back. Data packs such as Terralith generate as they do on vanilla.
Logins and proxies
Online and offline mode, signed chat, and Velocity’s modern forwarding.
Pregeneration
The pregen command is built in and takes Chunky’s subcommands. A task carries on after a restart, and steps aside while players are loading in.
The console
A live dashboard on a terminal, and vanilla’s exact log lines in a file or a pipe, so hosting panels read it as they read vanilla.
Recording and replay
A server can record everything it’s sent and replay it later, tick for tick, so a bug a player hit can be seen again and its fix checked.
Performance
Each tick, the world's regions run in parallel on every core. The tick never waits for the disk or the network: encoding, compression and saving happen on other threads. These numbers are from recorded runs on one machine, an i9-13900K with 32 threads on Windows 11.
A tick has 50 ms, here the window's width. At its left end is how much of it Calcite took with 100 players joining, walking outward and chatting, over 5 runs. The rest of the band is time the tick had to spare.
- 0.42 ms on average
- 1.11 ms at the 99th percentile
- 1.64 ms the longest
Vanilla parity
A test rig gives vanilla's server and Calcite the same inputs and compares what comes out bit for bit, so a near miss counts as a failure. When matching vanilla and being fast pull apart, vanilla wins wherever a player, a farm or a data pack could notice.
- 01 structure starts89 cases
- 02 biomes210 cases
- 03 noise1,824 cases
- 04 surface246 cases
- 05 carvers219 cases
- 06 features605 cases
- 07 light34 cases
A world is made in steps, and a chunk takes its next only once the chunks around it have taken theirs, so the edge of a world being made looks like this strip. Each chunk here is a step further on than the one to its left, and replays that step. Under each step is how many of the rig's cases compare it with vanilla's.
- Worldgen passes the rig’s suites in the Overworld, the Nether and the End, on a grid of seeds.
- With Terralith and Terratonic, every one of 264 sampled chunks has what must be vanilla’s.
- Light matches vanilla’s exactly: every block gets the same light level, from 0 to 15.
- Logins match vanilla’s packet for packet.
- Worlds move between vanilla and Calcite in both directions.
- The 8 places Calcite differs on purpose are listed, each a vanilla bug fixed or a limit stated.
Plugins
Every plugin is written against one host API. Native plugins are Calx and run at full speed. WASM plugins can come from any language that builds to WASM, and run in a sandbox that stops a runaway one.
- A command is a function, and the client tab-completes and checks its arguments.
- Events are typed, and run in the region where they happen.
- Plugins keep data on players, chunks and entities, saved with the world.
- Reloading a plugin keeps its state, and every plugin is profiled all the time.
@save(per: Player) struct Homes { homes: SortedMap<HomeName, Location> = {} } @command("sethome", permission: USE) fn sethome(p: Player, name: HomeName = HomeName("home")) ! Text { let data = p.data(Homes) let full = data.homes.len() >= config.max_homes if full and not data.homes.has(name) and not p.has(UNLIMITED) { fail t"<red>You already have {config.max_homes} homes. Delete one with /delhome." } data.homes.put(name, p.location()) p.send(t"<green>Home <white>{name.0}</white> set.") }
From the homes sample plugin, in the draft syntax the API was designed with. It compiles once the plugin host is built.
Roadmap
Calcite is built in 10 phases, and each ends at a gate it has to pass before the next starts. Phases 0 to 5 have passed. Phase 6, simulation, is in progress, and it's done when you can play an ordinary survival session on Calcite without noticing a difference.
Get started
Install Calx, build Calcite with one command, and start it in a folder of its own, as you would vanilla's server. The guide has each step, and what to set up after.
# install Calx irm https://calxlang.com/install.ps1 | iex # build Calcite git clone https://github.com/ellipog/calcite cd calcite calx build --release src/calcite.calx -o server/calcite.exe # start it, then join localhost cd server .\calcite.exe
# install Calx curl -fsSL https://calxlang.com/install.sh | sh # build Calcite git clone https://github.com/ellipog/calcite cd calcite calx build --release src/calcite.calx -o server/calcite # start it, then join localhost cd server ./calcite