- Rust 75.4%
- Java 23.1%
- Python 0.8%
- Shell 0.7%
|
All checks were successful
bit-identity / bit-identity (b1.7.3) (push) Successful in 54s
bit-identity / bit-identity (b1.8.1) (push) Successful in 1m17s
bit-identity / bit-identity (1.12.2) (push) Successful in 2m26s
ci / release (macos-arm64) (push) Successful in 2m18s
bit-identity / bit-identity (1.21.4) (push) Successful in 5m30s
bit-identity / bit-identity (26.2) (push) Successful in 7m21s
ci / release (linux-arm64) (push) Successful in 3m51s
ci / release (macos-x86_64) (push) Successful in 4m32s
setup-versions / setup (1.12.2) (push) Successful in 1m7s
ci / release (linux-x86_64) (push) Successful in 4m14s
ci / release (windows-x86_64) (push) Successful in 4m21s
setup-versions / setup (1.21.4) (push) Successful in 1m21s
setup-versions / setup (26.2) (push) Successful in 1m11s
|
||
|---|---|---|
| .cargo | ||
| .forgejo/workflows | ||
| .github/workflows | ||
| .vscode | ||
| crates | ||
| java | ||
| Scripts | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
worldclanker
From-scratch Rust reimplementations of Minecraft overworld world generation, built to be bit-identical to the real Java server for the same seed — same blocks, same states, same RNG stream, down to the last block. Every layer is validated against the real server bytecode:
- Beta 1.7.3 (the classic pre-release engine) — bit-identical to the real CraftBukkit Beta
1.7.3 server across the full pipeline: terrain, surface, caves, ravines, and the complete population
pass including the synchronous fluid-flow engine (
WorldGenLiquidssprings). Validated live in CI over an n×n region (the Beta oracle jars aren't on Mojang's manifest, so the run downloads a community archive on demand); far-out chunks (~180k blocks out) match too. Ground truth is the server's controlled chunk generation, the same stance the 1.12.2 oracle takes. - Beta 1.8.1 (the Adventure Update engine — a completely different biome/terrain system than 1.7.3)
— COMPLETE. Rebuilt from scratch against the real CraftBukkit Beta 1.8.1 server and bit-identical
(block id + metadata) across the full pipeline: GenLayer biomes, density terrain, surface, caves,
ravines, the complete population pass (ores, disks, trees incl. big/swamp/taiga, springs with the
synchronous fluid-flow engine, lakes, dungeons), and all three structure families — mineshafts,
strongholds, villages (placement, layout, every piece type, chest loot, spawners, the village
lake-suppression gate). Verified 0-diff on six oracle regions for the 2b2t seed — swamp, spawn,
a 64-chunk mineshaft cluster, a 100-chunk stronghold, a 169-chunk village, and a taiga — and
validated live in CI alongside 1.7.3. Getting here required reproducing some deep engine
behaviour: Java's aliased
BlockFlowingdirection-array field, exact material/opacity/lighting tables,World.randomdraw accounting (torch pops, spawn passes, village reseeds), and Beta's chunk-local lighting-bug quirk. - 1.12.2 (legacy engine) — COMPLETE. A seed-42 region generated end-to-end (terrain + populate) matches the real jar with 0 differences across 1024 chunks (32×32).
- 1.21.4 (the post-1.18 "Caves & Cliffs" density-function engine) — COMPLETE. RNG, noise, density router, terrain/aquifers/ore veins, biomes, surface, carvers, a 129-entry oracle-validated PlacedFeature registry (including decorated trees), Beardifier terrain adaptation, and every overworld structure family (village, mansion, monument, stronghold, mineshaft, shipwreck, igloo, ocean ruin, ruined portal, desert/jungle temple, swamp hut, buried treasure, ancient city, trail ruins, trial chambers, pillager outpost) wired into full cross-chunk region decoration: a seed-42 64×64-chunk region with structures enabled (terrain + surface + carvers + structures + decoration) matches the real 1.21.4 server with 0 differences across all 4096 chunks (402,653,184 blocks).
Installation
Install the mc-worldgencli binary straight from the repository with Cargo (needs a stable Rust
toolchain — nothing else):
cargo install --git https://git.eplg.services/obvtiger/worldgen mc-worldgencli
This builds and drops mc-worldgencli into ~/.cargo/bin (make sure it's on your PATH). To update
later, re-run the same command with --force.
Generating a world
mc-worldgencli generates a region and writes the Anvil region files + level.dat directly — a real,
loadable save, no Java step and no oracle jar. It's resumable: re-running the same command skips
batches already on disk.
# 1.21.4, the 2b2t seed, 64×64 chunks (radius 32), into ./world
mc-worldgencli --version 1.21.4 --seed -4172144997902289642 --radius 32 --out ./world
# 1.12.2 (legacy engine)
mc-worldgencli --version 1.12.2 --seed 42 --radius 32 --out ./world-1122
# Beta 1.7.3 and Beta 1.8.1
mc-worldgencli --version b1.7.3 --seed 42 --radius 16 --out ./world-b173
mc-worldgencli --version b1.8.1 --seed 42 --radius 16 --out ./world-b181
Copy the output folder into your Minecraft saves/ directory and open it in the matching game
version (don't let a newer client convert it). You spawn at the centre of the region.
Chunks are generated in [-radius, radius) on both axes — a 2*radius-chunk square. Beta and 1.21.4
generate the whole square in one pass (bit-identity needs it), so memory scales with the square:
radius 32 (64×64 chunks) peaks around 0.6 GB for beta and ~1 GB for 1.21.4 (also 1.21.4's radius cap
for now). Add --terrain-only for raw terrain + carvers with no ores/trees/structures.
Full flag reference:
$ mc-worldgencli --help
Usage: mc-worldgencli [OPTIONS] --out <OUT> --seed <SEED>
Options:
--out <OUT> Output world directory (created if missing)
--seed <SEED> World seed (accepts negatives)
--radius <RADIUS> Chunks generated in [-radius, radius) on both axes (a 2*radius side square)
--version <VERSION> "1.12.2", "1.21.4", "b1.7.3" or "b1.8.1" [default: 1.12.2]
--batch <BATCH> 1.12.2 only (default 32): resume/halo granularity in chunks per side
--terrain-only Skip population: raw terrain + carvers only
-h, --help Print help
Repository layout
worldclanker/
├── crates/
│ ├── mc-core/ # engine primitives shared across versions (RNG, noise, density, …)
│ ├── mc-worldgen-beta/ # the Beta 1.7.3 generator + its CraftBukkit-oracle fixture suite
│ ├── mc-worldgen-b1_8/ # the Beta 1.8.1 generator + its CraftBukkit-oracle fixture suite
│ ├── mc-worldgen-v1_12_2/ # the 1.12.2 generator + its bit-parity fixture suite
│ ├── mc-worldgen-v1_21_4/ # the 1.21.4 generator + its bit-parity fixture suite
│ ├── mc-version-detector/ # classify stored chunks by worldgen epoch (incl. 1.18 blended); .mca read/write
│ └── mc-worldgencli/ # end-to-end resumable CLI → a real, loadable Minecraft world
├── java/
│ ├── mappings/ # MCP stable_39 mappings for 1.12.2 (community, redistributable)
│ ├── beta_fixtures/ # committed CraftBukkit golden chunks for the Beta 1.7.3 / 1.8.1 suites
│ ├── reference/ # 1.12.2 oracle dumpers + WorldExport (the save packager)
│ └── reference-1.21.4/ # Ref1214.java — the 1.21.4 golden-value dumper (Java 21)
├── Scripts/
│ ├── setup.sh # download + deobfuscate a Mojang jar → the validation oracle
│ ├── dump_reference_1214.sh # run a Ref1214 dump mode (fixtures / regions)
│ ├── generate_java_world.sh # REAL-server region dump (1.12.2 or 1.21.4)
│ └── generate_rust_world.sh # Rust region dump in the same byte format
├── .forgejo/workflows/bit-identity.yml # CI: 64×64 live-oracle compare per version, every push
└── README.md
Mojang's jar is not redistributed. The validation oracle (
java/server-srg.jar) and the decompiled source are produced locally bysetup.sh(see below); they're git-ignored, never committed. The Rust crate + its fixtures are self-contained and need none of this to build or test.
Prerequisites
- Rust (stable, 2021 edition) — for the generators and tests. This is all you need for the crates.
- For the validation oracles / world export only: Java 8 (1.12.2 oracle) and/or Java 21
(1.21.4 oracle), plus
python3,curl/wget, andunzip(used bysetup.sh).
Setting up the validation oracle (setup.sh)
The oracle is the real Minecraft server, deobfuscated. Since the jar can't be shipped, fetch and build it on demand (under Mojang's EULA):
./setup.sh --list 1.12 # list matching release versions
./setup.sh 1.12.2 # download + deobfuscate → java/server-srg.jar (the oracle)
./setup.sh 1.12.2 --decompile # also produce readable source (see below)
setup.sh lists any release, downloads its server jar (handling modern "bundler" jars), pulls the
tools it needs, and deobfuscates: 1.12.2 via the bundled MCP stable_39 SRG mappings; 1.14.4
through 1.21.x via Mojang's own official mappings (e.g. ./setup.sh 1.20.1 → java/1.20.1-mojang.jar).
26.2 and newer already ship readable net/minecraft names and publish no mappings, so the jar is
used as-is (no remap). The worldclanker oracle itself targets 1.12.2.
--decompile decompiles the jar to readable .java (with CFR, which runs on the same Java 8 the
1.12.2 oracle needs) into java/decompiled-<version>/. For 1.12.2 it then auto-substitutes the MCP
stable_39 human-readable names (func_76304_a → generateNoiseOctaves) into java/named-<version>/.
All tools (JAVA env to override) and outputs are git-ignored.
Build & test
cargo test --release --workspace # every bit-parity suite (all versions, committed fixtures only)
End-to-end region compare (either version)
The Scripts/ directory holds the oracle-comparison harnesses used for validation — e.g.
generate_java_world.sh / generate_rust_world.sh (1.12.2 & 1.21.4 region dumps in a common byte
format) and compare_beta.sh (live CraftBukkit oracle vs Rust). The same compares run in CI
(.forgejo/workflows/bit-identity.yml, self-hosted) at full scale on every push: a 64×64-chunk
live-oracle compare for each version — 1.12.2, 1.21.4 (structures on), Beta 1.7.3, and Beta 1.8.1.
(.github/workflows/bit-identity.yml is a GitHub-runner variant with small PR regions and a nightly
schedule, sized for GitHub's 6h job limit.)
Using the library (1.12.2)
use mc_worldgen::WorldGen;
let mut world = WorldGen::new(42); // construct once per seed
let chunk = world.terrain_chunk(0, 0); // generate chunk (0, 0)
let (id, meta) = chunk.block(8, 64, 8); // (block_id, metadata) at local x,y,z
let air = chunk.is_air(8, 100, 8);
let raw = chunk.state(8, 64, 8); // packed (id << 4) | meta
let all = chunk.states(); // &[u16; 65536], index (x*16 + z)*256 + y
let biome = world.biome_at(8, 8); // biome id at world block (x, z)
terrain_chunk returns the per-chunk terrain (stone/water shape + surface builder + cave/ravine
carving). Decoration (ores, trees, lakes, snow) and structures are a separate multi-chunk populate
pass that writes across chunk borders — that wiring lives in the full-world driver
(tests/worldgen_parity.rs). For a ready-to-play save, use mc-worldgencli (see
Generating a world) rather than driving the library directly.
Detecting the worldgen version of an existing world
mc-version-detector classifies the worldgen epoch of already-generated chunks straight from their
.mca region files — including the mixed/blended chunks 1.18 left behind where an older surface sits
over a regenerated modern underground. It ships its own zero-dependency DEFLATE inflate, .mca
reader/writer, and NBT parser, plus several diagnostic binaries (classify, census, betadetect, …).
# per-region epoch map + summary, or point it at a whole world/region dir for an aggregate distribution
cargo run --release -p mc-version-detector --bin classify -- path/to/world/region