- Java 76.2%
- Shell 13.3%
- Python 9.9%
- Makefile 0.4%
- Dockerfile 0.2%
|
Some checks failed
Build MultiFolia / build (push) Failing after 35s
4 batches of NMS hooks applied to ShreddedPaper 26.1.2: Batch 1 (critical infrastructure): - Chunk load/save through MultiPaper Master - Player data sync on join/quit - Level.dat sync, FileSyncer initialization Batch 2 (game state sync): - Time, weather, hunger, XP, entity IDs, block updates - Combat (damage forwarding, attack strength, projectiles) - Portals, scoreboards, advancements, gamerules - Potion effects, respawn/spawn positions Batch 3 (data sync): - Inventory, ender chest, mob navigation, sign editing - Statistics, beacons, difficulty, POIs - Entity velocity, chat signing Batch 4 (player/entity/chunk management): - External player lifecycle (create/remove/login guard) - Entity sync (add/remove/update on external servers) - Entity tracking filters, inactive tracker - Chunk management (lock, mustNotSave, event-based IO) - Player list filtering (local vs all) - Persistent entity IDs, PersistentDataContainer sync All 5 workers deployed and running. Master shows active connections from all regions. 0 compilation errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| docker | ||
| gradle/wrapper | ||
| infra | ||
| multifolia-master | ||
| multifolia-protocol | ||
| multifolia-server | ||
| multifolia-velocity | ||
| scripts | ||
| testing | ||
| .gitignore | ||
| ARCHITECTURE.md | ||
| build.gradle.kts | ||
| CODEBASE_ANALYSIS.md | ||
| CONTRIBUTING.md | ||
| deploy-config.yml | ||
| DEPLOYMENT.md | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| LESSONS_LEARNED.md | ||
| NMS_PATCH_PLAN.md | ||
| PERFORMANCE_PATCHES.md | ||
| README.md | ||
| settings.gradle.kts | ||
MultiFolia
Distributed multi-server Minecraft 26.1.2 combining MultiPaper's distributed coordination with ShreddedPaper's multithreaded chunk processing. One seamless world, many servers, many threads per server.
Version: 1.0.0-SNAPSHOT MC Version: 26.1.2 Java: 25 (server module / NMS patches), 21+ (master/protocol/velocity) Build: Gradle 8.14 + Foojay toolchain resolver 0.9.0 Velocity: 3.5.0-b595 (protocol 775, MC 26.1.2 native support) License: GPLv3 (inherited from Paper/MultiPaper)
Why MultiFolia?
Vanilla Minecraft is single-threaded and single-server. When player count exceeds what one core can handle, performance degrades for everyone. Existing solutions solve part of the problem:
- Folia/ShreddedPaper add multithreading to a single server but cannot scale horizontally.
- MultiPaper distributes a world across multiple servers but each server is single-threaded, and development stalled at MC 1.20.1.
MultiFolia combines both: multiple servers, each running ShreddedPaper's multithreaded tick engine, coordinated by a lightweight Master process. The result is a Minecraft infrastructure that scales both vertically (more cores per server) and horizontally (more servers per world).
Architecture
play.mc.ekaii.fr (regional DNS)
|
+------------+-----------+-----------+-----------+
| | | | |
Velocity-EU Vel-Nordic Vel-US-E Vel-US-W Vel-SG
(FSN) (HEL) (ASH) (HIL) (SIN)
| | | | |
Worker-EU1 Worker-HEL1 Worker-ASH Worker-HIL Worker-SIN
(FSN,4c/16G)(HEL,4c/16G)(ASH,4c/16G)(HIL,4c/16G)(SIN,4c/16G)
| | | | |
+------+-----+-----+----+-----+-----+-----------+
| | |
MultiFolia-Master Redis P2P mesh
(FSN, 10.0.1.1) (EU1) (all workers)
All 5 Velocity proxies are cross-connected to all 5 backend MC servers. Each worker runs ShreddedPaper 26.1.2 with MultiFolia distributed patches + 9 NMS performance patches.
Each component is a separate module:
- Master -- Standalone JVM coordinator. Manages chunk ownership, stores world data, routes cross-server messages. Not a Minecraft server.
- Workers -- ShreddedPaper servers with MultiFolia distributed patches. Tick chunks they own, subscribe to remote chunks for rendering.
- Velocity Plugin -- GeoIP-based player routing, health-aware load balancing, cross-proxy session state via Redis.
- Protocol -- Shared Netty codec library used by Master, Workers, and Velocity.
For the full technical design (1600+ lines), see ARCHITECTURE.md. For the upstream codebase analysis, see CODEBASE_ANALYSIS.md.
Modules
| Module | Description | Artifact | Status |
|---|---|---|---|
multifolia-protocol |
Shared Netty protocol library (80+ message types) | multifolia-protocol.jar |
Compiling + Running |
multifolia-master |
Chunk ownership coordinator + world storage | multifolia-master-all.jar |
Compiling + Running |
multifolia-server |
ShreddedPaper distributed plugin (Paper plugin) | multifolia-server.jar |
Compiling + Running |
multifolia-velocity |
Velocity 3.5.0 geo-routing + load balancing plugin | multifolia-velocity.jar |
Compiling + Running |
testing/bot-swarm |
MCProtocolLib-based load testing framework | bot-swarm-all.jar |
Compiling + Running |
testing/mc-bot |
Python MC 26.1.2 bot client | bot.py / swarm.py |
Working |
Codebase stats: 284 Java files, ~26k lines of code, 85 unit tests passing, Forgejo CI green.
Quick Start
Prerequisites
- Java 25 (Eclipse Temurin 25 -- required by the server module via Foojay toolchain resolver; master/protocol/velocity build with Java 21+)
- Gradle 8.14+ (wrapper included)
- Docker + Docker Compose (for deployment)
- Git
Build All Modules
git clone https://forgejo.ekaii.fr/exo/multifolia.git
cd multifolia
./gradlew clean build shadowJar
Artifacts land in each module's build/libs/ directory.
Build Individual Modules
# Master only
./gradlew :multifolia-master:shadowJar
# Server plugin only
./gradlew :multifolia-server:shadowJar
# Velocity plugin only
./gradlew :multifolia-velocity:shadowJar
# Bot testing framework
cd testing/bot-swarm && ./gradlew shadowJar
Build NMS-Patched Server JAR
The performance-patched ShreddedPaper server JAR is built separately from the MultiFolia modules. See scripts/ for the full toolchain:
# Full build: clone ShreddedPaper + apply upstream patches + apply MultiFolia NMS patches + compile
cd scripts && make build
# Or step by step
make clone # Clone/update ShreddedPaper
make apply-upstream # Run paperweight-patcher applyAllPatches
make apply-patches # Apply MultiFolia performance patches
make build-jar # Build the final server JAR
# Validate patches without modifying anything
make dry-run
Output: build-output/multifolia-shreddedpaper-latest.jar (~56 MB). 9 of 10 NMS patches apply cleanly; 1 skipped (Purpur native). See PERFORMANCE_PATCHES.md for details.
Deploy
For deployment instructions covering all 6 nodes across 5 regions, see DEPLOYMENT.md.
Configuration
Master (multifolia-master.yml)
bind:
host: "0.0.0.0"
port: 35353
storage:
type: "filesystem" # "filesystem" for dev, "postgresql" for production
path: "/app/data"
ownership:
timeout-ms: 5000 # Worker considered dead after this
max-chunks-per-request: 256
idle-release-seconds: 300
health:
check-interval-ms: 10000
timeout-ms: 30000
Worker (plugins/multifolia.yml)
master-connection:
my-name: "worker-eu1"
master-address: "10.0.1.1:35353"
standby-address: "10.0.1.1:35353" # HA standby (Phase 2+)
peer-connection:
port: 35354
compression-threshold: 1024
sync-settings:
batch-ownership-requests: true
remote-chunk-cache-size: 4096
sync-entity-ids: true
sync-scoreboards: true
redstone:
cross-server-mode: "sync" # "sync", "break", or "off"
lock-timeout-ms: 100
combat:
p2p-latency-threshold: 50
latency-compensation-ms: 200
hit-registration: "attacker"
Velocity (plugins/multifolia/config.yml)
routing:
geoip-database: "plugins/multifolia/GeoLite2-City.mmdb"
regions:
eu: ["worker-eu1", "worker-eu2"]
us: ["worker-us1"]
sg: ["worker-sg1"]
geo-mapping:
default: "eu"
NA: "us"
SA: "us"
AS: "sg"
OC: "sg"
redis:
host: "127.0.0.1"
port: 6379
health-check:
interval-ms: 5000
min-tps: 15.0
max-mspt: 45.0
Testing
Current Test Results
| Test | Target | Result |
|---|---|---|
| 100 bots walking on EU1 | play-eu.mc.ekaii.fr |
PASS -- 0 crashes, 0 disconnects |
| 20 bots walking on ASH | play-us.mc.ekaii.fr |
PASS -- 0 crashes, 0 disconnects |
| Cross-server chunk transfer | EU <-> US | PASS -- chunks transfer correctly |
| Unit tests | All modules | 85/85 passing |
| Flying kick fix | All workers | PASS -- allow-flight + spigot thresholds applied |
Bot Swarm Load Tests (Java)
The bot-swarm framework connects configurable numbers of bots via MCProtocolLib and measures TPS, MSPT, disconnect rates, and cross-server sync latency.
cd testing/bot-swarm
# Run default stress test
./run-test.sh
# Run a specific scenario
./run-test.sh stress-test.yml
./run-test.sh cross-server.yml
./run-test.sh combat-test.yml
./run-test.sh stability-24h.yml
# Ad-hoc test with CLI arguments
./run-test.sh --host 78.46.225.179 --port 25577 --count 50 --duration 300
Available bot behaviors: walk-around, cross-server-walk, combat, build, idle.
Test results are written to testing/bot-swarm/results/ as JSON and CSV. Tests output a verdict (PASS/WARN/FAIL) based on configurable thresholds. See testing/scenarios/README.md for scenario format details.
Python MC Bot (testing/mc-bot)
A lightweight Python MC 26.1.2 protocol client for quick ad-hoc testing:
cd testing/mc-bot
pip install -r requirements.txt
python swarm.py --host play-eu.mc.ekaii.fr --port 25577 --count 10 --duration 120
Results stored in testing/mc-bot/results/.
Infrastructure
Hetzner Cloud Layout (6 nodes, 5 regions)
| Server | Type | Region | Public IP | Private IP | Role | Status |
|---|---|---|---|---|---|---|
mf-master |
CCX13 (2c/8G) | FSN (Falkenstein) | 178.105.108.80 |
10.0.1.1 |
Master coordinator | Live |
mf-worker-eu1 |
CCX23 (4c/16G) | FSN (Falkenstein) | 78.46.225.179 |
10.0.1.2 |
Worker + Velocity + Redis + CI runner | Live |
mf-worker-hel1 |
CCX23 (4c/16G) | HEL (Helsinki) | 89.167.30.40 |
10.0.1.3 |
Worker + Velocity | Live |
mf-worker-ash |
CCX23 (4c/16G) | ASH (Ashburn) | 178.156.161.254 |
-- | Worker + Velocity | Live |
mf-worker-hil |
CCX23 (4c/16G) | HIL (Hillsboro) | 5.78.96.50 |
-- | Worker + Velocity | Live |
mf-worker-sin |
CCX23 (4c/16G) | SIN (Singapore) | 5.223.89.219 |
-- | Worker + Velocity | Live |
Total (6 servers): ~238 EUR/month. Redis runs on EU1 only (cross-proxy sync limited to EU).
Network Topology
Hetzner Private Network: 10.0.0.0/16 (eu-central zone)
+-------------------------------------------------------+
| FSN (10.0.1.0/24) |
| mf-master 10.0.1.1 :35353 (Master protocol) |
| mf-worker-eu1 10.0.1.2 :25565 (MC) :35354 (P2P) |
| :25577 (Velocity) |
| :6379 (Redis, local) |
+-------------------------------------------------------+
| HEL (10.0.1.0/24 -- same eu-central zone) |
| mf-worker-hel1 10.0.1.3 :25565 :35354 :25577 |
+-------------------------------------------------------+
Non-EU workers (public IP only, no Hetzner private net):
mf-worker-ash 178.156.161.254 :25565 :35354 :25577
mf-worker-hil 5.78.96.50 :25565 :35354 :25577
mf-worker-sin 5.223.89.219 :25565 :35354 :25577
Cross-region P2P: MULTIFOLIA_PUBLIC_HOST env var per worker.
Inter-DC latency (measured):
FSN <-> FSN: <1ms FSN <-> HEL: 25ms FSN <-> ASH: 102ms
FSN <-> HIL: 167ms FSN <-> SIN: 164ms
ASH <-> HIL: 65ms ASH <-> SIN: 210ms
HEL <-> SIN: 170ms
Firewall multifolia-fw allows: SSH/22, MC/25565, Velocity/25577, Master/35353, Peer/35354, WireGuard/51820, ICMP.
All 5 Velocity proxies are cross-connected to all 5 backend MC servers. See infra/INVENTORY.md for full resource IDs, cost breakdown, and provisioning details.
DNS (Cloudflare)
Players connect via regional subdomains. SRV records handle port 25577 redirection so players just type the hostname:
| Region | Server Address | Backend |
|---|---|---|
| Auto (EU default) | play.mc.ekaii.fr |
mf-worker-eu1 |
| Europe | play-eu.mc.ekaii.fr |
mf-worker-eu1 |
| Nordics | play-nordic.mc.ekaii.fr |
mf-worker-hel1 |
| US East | play-us.mc.ekaii.fr |
mf-worker-ash |
| US West | play-usw.mc.ekaii.fr |
mf-worker-hil |
| Singapore / APAC | play-sg.mc.ekaii.fr |
mf-worker-sin |
Currently manual region selection. Automatic geo-routing is possible via Cloudflare Load Balancer (Phase 6). See infra/dns/README.md for full record listing and management.
JVM Flags
Worker (CCX23: 4 vCPU, 16 GB RAM)
java -Xms12G -Xmx12G \
-XX:+UseZGC -XX:+ZGenerational \
-XX:+AlwaysPreTouch -XX:+DisableExplicitGC \
-XX:+UnlockExperimentalVMOptions \
-XX:AllocatePrefetchStyle=1 -XX:-ZProactive \
-Dcom.mojang.eula.agree=true \
-jar shreddedpaper.jar --nogui
Master (CCX13: 2 vCPU, 8 GB RAM)
java -Xms1G -Xmx2G \
-XX:+UseG1GC \
-jar multifolia-master.jar
ZGC Generational is recommended for workers because ShreddedPaper's multi-threaded tick engine generates short-lived objects across many threads. G1GC is sufficient for the Master since it is a lightweight coordinator with minimal allocation pressure.
Roadmap
- Phase 0: Upstream analysis + architecture design
- Phase 1: Single-region PoC (Master + Worker in Falkenstein)
- Phase 2: Helsinki worker (mf-worker-hel1 live, eu-central private net)
- Phase 3: Ashburn worker (mf-worker-ash live, cross-region P2P fix deployed)
- Phase 4: Hillsboro + Singapore workers (both live, 5 workers across 5 regions)
- Phase 5: Bot load testing at scale (in progress -- 100 bots EU1, 20 bots ASH confirmed stable; targeting 500+ all regions)
- Phase 6: Production hardening (TLS, monitoring, backups, Cloudflare geo-routing LB, runbook)
Performance Patches
96 performance patches cataloged from 6 upstream forks, with 10 reference NMS patch implementations. 9 of 10 patches apply cleanly and are built into the patched server JAR (56 MB). 1 patch skipped (Purpur native). See PERFORMANCE_PATCHES.md for the full catalog and build instructions.
CI/CD
- Forgejo CI runner on mf-worker-eu1, CI green
- Build workflow (
.forgejo/workflows/build.yml): builds all modules + bot-swarm on push to main or dev/* branches - Release workflow (
.forgejo/workflows/release.yml): triggered by version tags (v*), produces release artifacts - Scheduled 2-hour code quality routine for ongoing maintenance
Project Structure
multifolia/
build.gradle.kts Root build (Shadow 9.2.2, Foojay toolchain)
settings.gradle.kts Module includes + Foojay resolver 0.9.0
gradle.properties MC version, upstream refs, dependency versions
multifolia-protocol/ Shared Netty protocol library
multifolia-master/ Standalone coordination server
multifolia-server/ ShreddedPaper distributed plugin (Paper plugin)
patches/server/performance/ 10 NMS performance patches (0001-0010)
multifolia-velocity/ Velocity 3.5.0 geo-routing plugin
scripts/ NMS patched server build toolchain
build-patched-server.sh Full build script (clone + patch + compile)
apply-multifolia-patches.py Patch applier (handles decompiled var names)
generate-minecraft-patches.py Patch generator from pseudo-patches
Makefile Convenience targets (build, dry-run, clean, etc.)
testing/
bot-swarm/ Java MCProtocolLib load testing framework
mc-bot/ Python MC 26.1.2 bot client
scenarios/ Test scenario YAML files
run-test.sh Test runner
docker/ Per-region Docker Compose stacks
master/
worker-eu/
worker-hel/
worker-us-east/
worker-us-west/
worker-sg/
velocity/
infra/ Infrastructure documentation + scripts
INVENTORY.md Full 6-node Hetzner resource inventory
cluster-status.sh Cluster health check script
deploy.sh Deployment automation script
dns/ Cloudflare DNS setup + docs
setup-geodns.sh DNS record creation script
README.md DNS record reference
ARCHITECTURE.md Full technical architecture (1600+ lines)
CODEBASE_ANALYSIS.md Upstream codebase analysis
DEPLOYMENT.md Deployment guide (all 6 nodes, 5 regions)
CONTRIBUTING.md Contributor guide
PERFORMANCE_PATCHES.md 96-patch catalog + 10 NMS implementations
Contributing
See CONTRIBUTING.md for development setup, code style, and PR process.
License
MultiFolia is licensed under GPLv3, inherited from Paper and MultiPaper.
The MultiFolia-Master and MultiFolia-Protocol modules are licensed under MIT, inherited from MultiPaper-Master.
Acknowledgements
MultiFolia builds on the work of:
- Paper -- High-performance Minecraft server fork
- Purpur -- Extended Paper fork with additional features
- Folia -- Regionized multithreading for Paper
- ShreddedPaper -- Chunk-radius multithreaded ticking
- MultiPaper -- Distributed multi-server Minecraft
- Luminol -- Folia fork with additional optimizations