First-boot server provisioner. Named by Holly. Architecture per Gemini 4-round
consultation. Drops a provision.json in server root, mod runs once on
ServerStartedEvent: pastes spawn schematic, places TP command blocks pointing
at the original level.dat spawn, sets worldspawn, gamerules, YAWP region file,
self-destructs by renaming jar to .jar.disabled.
Files (services/bitch-bot/1.21.1/):
- build.gradle / settings.gradle / gradle.properties / gradle wrapper (mirrors rules-mod 1.21.1)
- META-INF/neoforge.mods.toml
- BitchBot.java — @Mod entry, ServerStartedEvent listener, Throwable net
- Provisioner.java — sequenced step runner, per-step try/catch, success tracking gates self-destruct
- ProvisionConfig.java — Gson POJO matching provision.json schema verbatim
- SchematicLoader.java — HTTP download + SHA-256 verify + Sponge v2 .schem parser (NbtIo + varint + BlockStateParser palette)
- CommandBlockPlacer.java — impulse command blocks with /tp @p baked into CommandBlockEntity
- SignPlacer.java — oak signs, 4-line front text via SignBlockEntity#setText
- YawpConfigWriter.java — drops region JSON to world/serverconfig/yawp/regions/{name}.json
- SelfDestruct.java — ProtectionDomain → CodeSource → jar rename, Windows fallback to deleteOnExit
Plus services/bitch-bot/CLAUDE.md (project doc) and sample-provision.json.
NOT COMPILED — no Java/Gradle on Nitro per repo CLAUDE.md. Compile on Dev Panel:
cd /opt/mod-builds/firefrost-services/services/bitch-bot/1.21.1
source use-java 21
/opt/gradle-8.8/bin/gradle build --no-daemon
Risk areas flagged in CLAUDE.md for first compile: schematic parser (untested
against real WorldEdit output), YAWP file format (best-guess schema).
30 lines
1.1 KiB
JSON
30 lines
1.1 KiB
JSON
{
|
|
"version": "1.0",
|
|
"schematic_name": "firefrost-spawn-v1.schem",
|
|
"schematic_url": "https://downloads.firefrostgaming.com/Firefrost-Schematics/firefrost-spawn-v1.schem",
|
|
"schematic_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
|
"spawn_type": "standard",
|
|
"spawn_coords": { "x": -5000, "y": 64, "z": -5000 },
|
|
"paste_origin": "center",
|
|
"worldspawn_offset": { "x": 0, "y": 1, "z": 0 },
|
|
"command_blocks": [
|
|
{ "position": { "x": -4998, "y": 65, "z": -4998 }, "facing": "up" },
|
|
{ "position": { "x": -5002, "y": 65, "z": -4998 }, "facing": "up" },
|
|
{ "position": { "x": -4998, "y": 65, "z": -5002 }, "facing": "up" },
|
|
{ "position": { "x": -5002, "y": 65, "z": -5002 }, "facing": "up" }
|
|
],
|
|
"rules_signs": [
|
|
{
|
|
"position": { "x": -4999, "y": 65, "z": -5005 },
|
|
"lines": ["Welcome to", "Firefrost", "Read /rules", "Have fun!"]
|
|
}
|
|
],
|
|
"yawp_region": {
|
|
"name": "spawn",
|
|
"min": { "x": -5050, "y": 0, "z": -5050 },
|
|
"max": { "x": -4950, "y": 255, "z": -4950 },
|
|
"flags": ["no-pvp", "no-mob-spawning", "break-blocks", "place-blocks"]
|
|
},
|
|
"self_destruct_on_success": true
|
|
}
|