Build: every tool pinned (JDK, packwiz, Gradle plugins, Python packages), exports normalised, tools/check_reproducible.py proves two clean builds are byte-identical. Server-side balance: a server can load config/cobblesurvival/datapack.zip in place of the jar's data, /reload applies it, tools/server_update.py packages it and refuses when a client change is needed. JEI drop pages are sent by the server. Code-held balance numbers moved to tuning/server.json. Performance: spark in the pack (server only), tools/perf_test.py with fake players whose chunks really are active, docs/performance.md. Adrian's feedback: default keys R, U, J, §; drop pages link to Cobblemon Info and show real chances; bosses only hurt in battles; battle XP halved; channels between the islands low level; temperature ×3 with insulation doubled; hazards start at once; no item dots on the map; a wild attack starts a battle; the starter only faints; quest book on join with a basics page and an HMs page; regional forms obtainable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
77 lines
2.9 KiB
Python
Executable File
77 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Check on the test server that a balance change goes live with tools/server_update.py alone (Adrian, 2026-11-09):
|
|
the server loads the update's data instead of the copy in its jar, `/reload` picks up a changed file while it runs,
|
|
and without the update the jar's copy is used again.
|
|
|
|
Usage: tools/check_server_update.py (needs eula.txt from tools/selftest.py --accept-eula)
|
|
"""
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import zipfile
|
|
from io import BytesIO
|
|
from pathlib import Path
|
|
|
|
from mcserver import ROOT, SERVER, Server, eula_accepted, prepare
|
|
|
|
ZIP = SERVER / "config/cobblesurvival/datapack.zip"
|
|
TUNING = "data/cobblesurvival/tuning/server.json"
|
|
LEVEL = "world-update-check"
|
|
FLAT = {"level-name": LEVEL, "level-type": "minecraft:flat",
|
|
"generator-settings": '{"layers":[{"block":"minecraft:stone","height":4}],"biome":"minecraft:plains"}'}
|
|
|
|
|
|
def expect(line, *parts):
|
|
missing = [p for p in parts if p not in line]
|
|
if missing:
|
|
sys.exit(f"expected {missing} in: {line}")
|
|
print(f"ok: {line.strip()}")
|
|
|
|
|
|
def set_boss_evs(value):
|
|
with zipfile.ZipFile(ZIP) as z:
|
|
items = [(i, z.read(i.filename)) for i in z.infolist()]
|
|
out = BytesIO()
|
|
with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED) as z:
|
|
for info, content in items:
|
|
if info.filename == TUNING:
|
|
content = json.dumps(json.loads(content) | {"boss_evs": value}).encode()
|
|
z.writestr(info, content)
|
|
part = ZIP.with_name(ZIP.name + ".part")
|
|
part.write_bytes(out.getvalue())
|
|
part.replace(ZIP) # as an update does, with the server running
|
|
|
|
|
|
def main():
|
|
if not eula_accepted():
|
|
sys.exit("build/server/eula.txt does not accept the Minecraft EULA yet (see tools/selftest.py --accept-eula).")
|
|
args_file = prepare()
|
|
subprocess.run([sys.executable, str(ROOT / "tools/server_update.py"), "--install", str(SERVER), "--level", LEVEL, "--force"], check=True)
|
|
try:
|
|
with Server(args_file, FLAT, stdout_name="update-check-stdout.log") as server:
|
|
server.wait_ready()
|
|
first = server.command("cobblesurvival data")
|
|
expect(first, "data server;", "boss_evs 170;")
|
|
set_boss_evs(150)
|
|
server.command("reload")
|
|
for _ in range(60):
|
|
time.sleep(2)
|
|
line = server.command("cobblesurvival data")
|
|
if "boss_evs 150" in line:
|
|
break
|
|
expect(line, "data server;", "boss_evs 150;")
|
|
server.stop()
|
|
ZIP.unlink()
|
|
with Server(args_file, FLAT, stdout_name="update-check-stdout.log") as server:
|
|
server.wait_ready()
|
|
expect(server.command("cobblesurvival data"), "data jar;", "boss_evs 170;")
|
|
server.stop()
|
|
finally:
|
|
ZIP.unlink(missing_ok=True)
|
|
print("SERVER UPDATE CHECK PASSED")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|