A Minecraft-style multiplayer building game that rebuilds a real landscape from open topography data. This is a fork of BuildCraft that ships with the real elevation raster of the Rursee area in the Eifel (NRW, Germany, DGM1 open data) — so the world you walk into is the actual terrain, not procedural noise.
Three.js voxel client, Python WebSocket game server, nginx in front for production. No build step, no asset files — textures and sounds are generated procedurally at runtime; the heightmap is the only bundled data.
It just works after cloning.
server/data/map.bin+map.json(the Rursee heightmap) are committed, so./run.shboots straight into the real-world terrain. Delete those two files to fall back to seed-based procedural worlds — see Real-world terrain below.
In-game captures of the bundled Rursee terrain (real DGM1 elevation; biomes, trees, caves and ores are layered on top procedurally):
![]() |
![]() |
| The Rursee valley and surrounding hills at midday | Low evening sun over the lake |
![]() |
![]() |
| Lakeshore at ground level with the hotbar HUD | Night falls — stars, moonlight and clouds |
./run.sh
# open http://localhost:8080 in one or more browser tabsThe script creates a venv and installs the single dependency (websockets)
on first run.
- Infinite procedural terrain (hills, lakes, beaches, trees, snowy peaks, coal and iron ore underground) from a shared seed
- Multiplayer: see other players move and build in real time, chat
- Survival loop: mine blocks (timed, tool-dependent) for drops, craft tools, place workbenches and furnaces for advanced recipes; tools have durability; three tool tiers (wood → stone → iron)
- Mobs: chickens, dogs, sheep and cows by day; zombies, skeletons and spiders at night — zombies and skeletons burn at sunrise, spiders turn passive
- Inventory (E): 36 slots, stacking to 64, right-click splits stacks; persisted per player name on the server
- Crafting menu: recipe book with have/need counts; Blocks tab: creative palette with free stacks of every block (tools must be crafted)
- Physics: gravity, jumping, swimming, sprinting, sneaking, flying
- Health with hearts HUD, knockback, regeneration, respawn
- Rebindable controls via in-game menu (F5), persisted per browser
- Admin console (F6) — type
/helpfor the command list - Day/night cycle, ambient occlusion, block highlight, hotbar, debug overlay (F3)
- World persists across server restarts (
server/data/world.json)
| Key | Action |
|---|---|
| WASD / Space | move / jump |
| Shift | sprint |
| Ctrl | sneak (slower, lowered camera; fly down while flying) |
| F or double-Space | toggle fly (Space/Ctrl = up/down) |
| Left click | mine block (hold) / attack mob |
| Right click | place block |
| E | inventory · crafting · block palette |
| 1–9 or mouse wheel | select hotbar slot |
| T or Enter | chat |
| F3 | debug overlay |
| F5 | key bindings menu |
| F6 | admin console |
| Esc | release cursor |
- Punch a tree (logs break by hand in ~2.5 s) → craft planks → sticks
- 4 planks → workbench; place it — tool recipes need one within 4 blocks
- Craft wooden tools: pickaxe (mining stone requires one), axe (wood faster), shovel (dirt/sand faster), sword (more damage vs. mobs)
- Mine stone → cobblestone → stone tools + a furnace (8 cobble)
- Dig for ore: coal in the upper stone layers, iron below y≈28 (iron ore needs at least a stone pickaxe)
- Smelt at the furnace: 1 iron ore + 1 coal → iron ingot; also 4 cobble + 1 coal → 4 bricks for fancy building
- Iron tools: fastest mining, 250 durability, iron sword does 10 damage
Blocks won't drop without the required tool/tier. Tool stats live in
client/js/items.js, recipes in client/js/crafting.js.
/help lists everything: /time day|night|0..1, /tp x y z or /tp player,
/players, /spawn chicken|dog|zombie [n], /mobs on|off, /butcher,
/clear (wipe all edits), /kick player, /say msg, /seed, /save.
Every player may use the console — fine for a friends server, lock it down
before hosting strangers.
browser ── static files ── nginx (prod) or python (dev)
│
└─ /ws (WebSocket) ── python game server ── data/world.json
- The server is authoritative for block edits, player presence, chat and mob simulation.
- Terrain is generated client-side from the server's seed (deterministic
integer-hash noise), so the server only stores the diff (player edits) and
the protocol stays tiny.
server/terrain.pyis a bit-exact Python port of the same noise so mobs walk on the ground clients actually render. - Positions and mob snapshots are relayed at 10 Hz; clients interpolate.
| Direction | Message |
|---|---|
| C→S | hello {name}, move {p,r}, block {x,y,z,id}, chat {text}, hit {id,item}, cmd {text}, inv {s} |
| S→C | init {id,seed,time,edits,inv,players}, join {player}, leave {id}, moves {pl}, block, chat {from,text}, sys {text}, mobs {l}, mob_die {id}, hurt {dmg,from}, con {text}, time {time}, teleport {p}, wipe |
-
Run the game server as a service, e.g. with systemd:
# /etc/systemd/system/buildcraft.service [Unit] Description=BuildCraft game server After=network.target [Service] User=www-data WorkingDirectory=/opt/buildcraft ExecStart=/opt/buildcraft/server/.venv/bin/python /opt/buildcraft/server/main.py Environment=BUILDCRAFT_HOST=127.0.0.1 BUILDCRAFT_PORT=8080 Restart=on-failure [Install] WantedBy=multi-user.target
-
Install the nginx site from
nginx/buildcraft.conf(adjust therootpath), thennginx -t && systemctl reload nginx.
nginx serves the static client and proxies only /ws to Python. For TLS,
put certbot/LE on the server block as usual — the client automatically uses
wss: when served over https.
| Env var | Default | Meaning |
|---|---|---|
BUILDCRAFT_HOST |
0.0.0.0 |
bind address |
BUILDCRAFT_PORT |
8080 |
HTTP + WebSocket port |
World data lives in server/data/world.json (saved every 30 s when dirty and
on shutdown). Delete it to regenerate a fresh world with a new seed.
This edition ships with the Rursee heightmap already built into
server/data/map.bin + map.json, so it is active out of the box — both server
and client replace the noise heightAt with lookups into that raster (outside
the map it's open sea). Biomes, caves, ores and trees still layer on top.
To go back to seed-based procedural worlds, simply delete the two files:
rm server/data/map.bin server/data/map.jsontools/build_map.py regenerates the raster from real elevation data. The
bundled map is the Rursee area in the Eifel from NRW open data
(opengeodata.nrw.de, DGM1, licence DL-DE Zero):
server/.venv/bin/pip install tifffile imagecodecs numpy
# download some 1 km tiles (UTM32 E314-316 / N5610-5612 = Rursee):
curl -O https://www.opengeodata.nrw.de/produkte/geobasis/hm/dgm1_tiff/dgm1_tiff/dgm1_32_315_5611_1_nw_2021.tif
server/.venv/bin/python tools/build_map.py dgm1_32_*.tif
# restart the server — it logs "heightmap loaded"Scaling is 4 m per block (true proportions); the lowest terrain (a lake
surface) lands just below the water line, so real lakes become water.
Delete server/data/map.bin and map.json to go back to seed terrain.
BuildCraft is free to use under two complementary licenses:
- Source code — MIT License. Covers
client/,server/,tools/,tests/,nginx/, and the build/run scripts. Maximally permissive and compatible with the wider open-source ecosystem. - Documentation & assets — CC BY 4.0. Covers the prose
docs (this README,
CLAUDE.md), the procedurally generated textures and sounds, and any bundled world/map data. Free to share and adapt, even commercially, as long as you give attribution.
The optional real-world terrain uses NRW open data (DGM1 elevation, ALKIS), published under DL-DE Zero 2.0. That data is downloaded by the user, not redistributed here.
Creative Commons recommends against using CC licenses for software, so the code is MIT and only the non-code material is CC BY.



