DistroCraft

Distributed computing for Minecraft — let your players contribute their idle CPU cycles to power your server.

Downloads

Get DistroCraft

Select your platform and version to download the right build.

Documentation

What is DistroCraft?

DistroCraft splits CPU-bound work into small tasks and dispatches them to connected player machines. Results are returned asynchronously to the server. Communication uses Minecraft's custom payload system — no extra ports needed for the mod variant.

Components

Server Mod

NeoForge + Fabric 1.21.x server-side mod. Drops into mods/.

Client Mod

NeoForge + Fabric 1.21.x client mod. Drops into .minecraft/mods/.

Standalone App

Pure Java app (GUI + CLI). No Minecraft required. Connect from anywhere.

Paper Plugin

Paper 1.21.x server plugin. Alternative to the server mod — uses TCP port.

Use either the server mod or the Paper plugin — not both. Players use either the client mod or the standalone app.

License

DistroCraft is licensed under GNU GPLv3.

1. Server (mod or plugin)

NeoForge / Fabric mod: Drop the server mod JAR into your server's mods/ folder. The coordinator starts automatically.

Paper plugin: Drop the plugin JAR into plugins/. Configure via plugins/DistrocraftServer/config.yml.

2. Players (mod)

Drop the client mod JAR into .minecraft/mods/. Use /distro start to connect — you'll automatically contribute your spare CPU cycles.

3. Players (standalone app)

GUI mode: java -jar DistroCraft-app-*.jar

CLI mode: java -jar DistroCraft-app-*.jar <host> [port] [threads] [label]

java -jar DistroCraft-app-1.0.0.jar play.myserver.com 25566 4 Steve

Requirements

Java 21 or later. For mods: Minecraft 1.21.x with NeoForge 21.1+ or Fabric Loader 0.16+.

Player In-Game Commands

Type these in chat (prefixed with /distro):

CommandDescription
/distro startConnect to the server's coordinator
/distro stopDisconnect from the coordinator
/distro statusShow connection status and task stats
/distro set threads <n>Set worker thread count
/distro set resources <key>=<value> ...Set resource limits (e.g. ram_mb=2048)

Server Plugin Commands

CommandDescription
/dc statusOverall coordinator stats
/dc listList connected clients with capabilities
/dc submit <KIND> <k>=<v> ...Queue a task of any kind

Server Mod config/distrocraft-server.properties

port=25566
enabled=true
requireInGame=true
maxClientsPerPlayer=1
debugLogging=false
taskTimeoutSec=60
clientTimeoutSec=30

Player Mod .minecraft/config/distrocraft-client.properties

host=localhost
port=25566
threads=2
autoStart=false
showHud=true
# Additional resources:
resource.ram_mb=2048

Paper Plugin plugins/DistrocraftServer/config.yml

YAML config with the same options as the server mod. Created automatically on first run.

Wire Format

All communication is newline-delimited JSON over custom payload packets (mods) or TCP (app/plugin).

SERVER → CLIENT  HELLO      {"type":"HELLO","version":1,"serverId":"<uuid>"}
CLIENT → SERVER  REGISTER   {"type":"REGISTER","clientId":"...","maxThreads":4,"playerName":"Steve","capabilities":{"threads":4,"ram_mb":2048}}
SERVER → CLIENT  TASK       {"type":"TASK","taskId":"<uuid>","kind":"CHUNK_GEN","payload":{...}}
CLIENT → SERVER  RESULT     {"type":"RESULT","taskId":"...","success":true,"data":{...}}
EITHER           PING/PONG  {"type":"PING"} / {"type":"PONG"}
SERVER → CLIENT  DISCONNECT {"type":"DISCONNECT","reason":"..."}

Dynamic Task Kinds

Task kinds are arbitrary strings — there is no enum. Any string is a valid task kind. Register handlers on both sides.

Built-in Examples

KindPayloadResult
CHUNK_GENcx, cz, dimension, seedcx, cz, heightmap
PATHFINDx1,y1,z1, x2,y2,z2, contextfound, estimatedLength, pathJson
STRUCTURE_SCANx1,z1, x2,z2, seed, structureIdcandidateX, candidateZ, confidence
PHYSICS_SIMsimulationType, paramssimulationType, stepsCompleted, energy
CUSTOMany JsonObjectecho + processed:true

Custom Task Handler Example

// Register on the client:
TaskExecutor.getRegistry().register("AERONAUTICS_PHYSICS", payload -> {
    JsonObject result = new JsonObject();
    // your solver here
    return result;
});

// Submit from the server:
DistroTask task = DistroTask.of("AERONAUTICS_PHYSICS", payload);
coordinator.submitTask(task);