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>
This commit is contained in:
claudeandClaude Opus 5.5 committed 2026-10-29 19:01:21 +01:00
commit 398301f0be
232 files changed
+72665

No files matched your search

+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env python3
"""Install or update a packwiz pack into a folder with packwiz-installer.
packwiz-installer wants a URL, so the pack folder is served on 127.0.0.1 for
the duration of the sync. It downloads Modrinth and CurseForge files from
their own CDNs and removes files that left the pack since the last sync.
Usage: tools/packwiz_sync.py <client|server> <target_dir> [pack_dir]
(pack_dir defaults to build/stage/full)
"""
import functools
import http.server
import shutil
import subprocess
import sys
import threading
import urllib.request
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
CACHE = ROOT / "build" / ".cache"
# Pinned; the bootstrap runs with --bootstrap-no-update so neither self-updates.
TOOLS = {
"packwiz-installer-0.5.14.jar":
"https://github.com/packwiz/packwiz-installer/releases/download/v0.5.14/packwiz-installer.jar",
"packwiz-installer-bootstrap-0.0.3.jar":
"https://github.com/packwiz/packwiz-installer-bootstrap/releases/download/v0.0.3/packwiz-installer-bootstrap.jar",
}
def cached(name):
jar = CACHE / name
if not jar.exists():
CACHE.mkdir(parents=True, exist_ok=True)
with urllib.request.urlopen(TOOLS[name], timeout=120) as r, open(jar, "wb") as f:
shutil.copyfileobj(r, f)
return jar
def java():
for candidate in (Path.home() / ".var/app/org.prismlauncher.PrismLauncher/data/PrismLauncher/java/java-runtime-delta/bin/java",):
if candidate.exists():
return str(candidate)
return shutil.which("java")
class QuietHandler(http.server.SimpleHTTPRequestHandler):
def log_message(self, *args):
pass
def sync(side, target, pack_dir):
target.mkdir(parents=True, exist_ok=True)
handler = functools.partial(QuietHandler, directory=str(pack_dir))
server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), handler)
threading.Thread(target=server.serve_forever, daemon=True).start()
try:
url = f"http://127.0.0.1:{server.server_port}/pack.toml"
subprocess.run([java(), "-jar", str(cached("packwiz-installer-bootstrap-0.0.3.jar")),
"--bootstrap-no-update",
"--bootstrap-main-jar", str(cached("packwiz-installer-0.5.14.jar")),
"-g", "-s", side, url],
cwd=target, check=True)
finally:
server.shutdown()
def main():
if len(sys.argv) < 3 or sys.argv[1] not in ("client", "server"):
sys.exit(__doc__)
pack_dir = Path(sys.argv[3]) if len(sys.argv) > 3 else ROOT / "build" / "stage" / "full"
sync(sys.argv[1], Path(sys.argv[2]).resolve(), pack_dir.resolve())
if __name__ == "__main__":
main()