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>
93 lines
3.9 KiB
Python
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()
|