Files
cobblemon-survival-pack/tools/biome_layout.py
T
claudeandClaude Opus 5.5 398301f0be Cobblemon Survival Pack: phases 0-2 and Phase 3 zones and hazards
Free NeoForge 1.21.1 modpack on Cobblemon 1.8.4 built with packwiz, plus
the Kotlin companion mod (cobblesurvival) and its built-in data pack.

- Phase 0: packwiz pack with Modrinth/CurseForge cross-links, build and
  export tooling, Prism instance sync, test server with smoke checks.
- Phase 1: Poke Ball shaped island (WorldGen Editor preset, seed isle-26),
  Adrian's biome list, no natural ore, structures without ore or vanilla
  mobs, no Nether portals, world template builder and world report.
- Phase 2: permadeath (CobbleHardcoreMon plus the companion mod's gap
  fixes), Revival Charm, expensive Healing Machine, Lootr refreshing
  loot, in-game self-tests on Minecraft's GameTest framework.
- Phase 3 so far: 14 zones with their own spawn pools and level bands
  (tools/zone_layout.py, tools/zone_spawns.py, "zone" spawn condition),
  Cold Sweat heat and cold as gates with boss-drop insulation recipes,
  spawn survey and hazard self-tests in tools/quick_check.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 19:01:21 +01:00

93 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""Write the island world type from world/biomes.json.
Vanilla's overworld biome parameters come from Minecraft's own data generator
(run on the vanilla server jar that the NeoForge installer put in
build/server; no server is started). Every entry is sent to its target biome
from world/biomes.json, the extra entries are appended, and the result becomes
the inline biome list of WorldGen Editor's delegate in
datapacks/core/data/cobblesurvival/worldgen/world_preset/island.json.
The world type has no Nether dimension.
Usage: tools/biome_layout.py (run tools/smoke_test.py once first so build/server exists)
"""
import json
import subprocess
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from mcserver import CACHE, PACK, ROOT, SERVER # noqa: E402
from packwiz_sync import java # noqa: E402
PRESET = ROOT / "datapacks/core/data/cobblesurvival/worldgen/world_preset/island.json"
def vanilla_parameters():
version = PACK["versions"]["minecraft"]
report = CACHE / f"datagen-{version}" / "reports/biome_parameters/minecraft/overworld.json"
if not report.exists():
jar = SERVER / "libraries/net/minecraft/server" / version / f"server-{version}.jar"
if not jar.exists():
sys.exit(f"{jar} is missing; run tools/smoke_test.py once so the NeoForge installer fetches it")
work = CACHE / f"datagen-{version}"
work.mkdir(parents=True, exist_ok=True)
subprocess.run([java(), "-DbundlerMainClass=net.minecraft.data.Main", "-jar", str(jar),
"--reports", "--output", str(work)], cwd=work, check=True, stdout=subprocess.DEVNULL)
return json.loads(report.read_text())["biomes"]
def main():
spec = json.loads((ROOT / "world/biomes.json").read_text())
targets = set(spec["allowed"]) | set(spec["water"])
entries, unmapped = [], set()
for entry in vanilla_parameters():
target = spec["remap"].get(entry["biome"])
if target is None:
unmapped.add(entry["biome"])
continue
entries.append({"biome": target, "parameters": entry["parameters"]})
for extra in spec["add"]:
entries.append({"biome": extra["biome"], "parameters": extra["parameters"]})
bad_targets = {e["biome"] for e in entries} - targets
if unmapped or bad_targets:
sys.exit(f"vanilla biomes without a target: {sorted(unmapped)}; targets outside the list: {sorted(bad_targets)}")
preset = {
"dimensions": {
"minecraft:overworld": {
"type": "minecraft:overworld",
"generator": {
"type": "minecraft:noise",
"biome_source": {
"type": "worldgen_editor:island_biome_source",
"preset": "cobblesurvival_island",
"delegate": {"type": "minecraft:multi_noise", "biomes": "@BIOMES@"},
},
"settings": "worldgen_editor:island_overworld",
},
},
"minecraft:the_end": {
"type": "minecraft:the_end",
"generator": {"type": "minecraft:noise", "biome_source": {"type": "minecraft:the_end"},
"settings": "minecraft:end"},
},
}
}
# One biome entry per line keeps the 7,600-entry file diffable.
body = ",\n".join(" " + json.dumps(e, separators=(",", ":")) for e in entries)
text = json.dumps(preset, indent=2).replace('"@BIOMES@"', "[\n" + body + "\n ]")
json.loads(text)
PRESET.write_text(text + "\n")
counts = {}
for e in entries:
counts[e["biome"]] = counts.get(e["biome"], 0) + 1
print(f"wrote {PRESET.relative_to(ROOT)}: {len(entries)} entries")
for biome, n in sorted(counts.items(), key=lambda kv: -kv[1]):
print(f" {n:5} {biome}")
if __name__ == "__main__":
main()