#!/usr/bin/env python3 """Build unpackable Champions of Luneraria demos for Linux and Windows. Run: python3 tools/luneraria/build_luneraria_demo.py [--check-only] Output: ../dist/luneraria/ChampionsOfLuneraria-Linux-x64-.zip ../dist/luneraria/ChampionsOfLuneraria-Windows-x64-.zip Old Saumwacht releases under ../dist/Saumwacht-*.zip stay untouched. """ from pathlib import Path import argparse, zipfile, subprocess, shutil, sys PROJECT = Path(__file__).resolve().parents[2] DIST = PROJECT.parent / "dist" / "luneraria" VERSION = "0.16.0-m4" INTRO = f"""CHAMPIONS OF LUNERARIA · PROTOTYP {VERSION} START Linux: ./ChampionsOfLuneraria.x86_64 Windows: ChampionsOfLuneraria.exe Vulkan-Probleme: --rendering-driver opengl3 Godot und Blender werden zum Spielen nicht benötigt. Das ganze ZIP zuerst entpacken. INHALT Drei Lanes, zwei Teams à drei Rollen, Partieende nur durch einen zerstörten Ancient. Planung → automatischer Kampf → Abrechnung. Helden, Items, Angriffschampions und eine Bossgrotte mit entsandtem Boss. NETZWERK (Direktverbindung, experimentell) Im Setup: Hosten oder Beitreten mit Adresse und Port (Standard 24571). Der Host ist autoritativ. Freie Plätze werden von Bots gespielt. Ein Disconnect übernimmt ein Bot; er ist kein Kernverlust. Kein Matchmaking, keine Hostmigration. Getestet: Protokollchecks und ein lokaler Zwei-Prozess- Loopback – keine Internetpartie auf sechs Rechnern. PLATTFORM Geprüft: Fedora 44, Forward+ (Quellprojekt). Windows-Export vorhanden; ein nativer Windows-11-Test steht aus (keine Hardware in dieser Umgebung). QUELLEN https://github.com/ (lokal) · Doku im Quellrepo unter docs/luneraria/ """ PRESETS = [ ("Luneraria-Linux", "linux", "ChampionsOfLuneraria.x86_64", "ChampionsOfLuneraria-Linux-x64"), ("Luneraria-Windows", "windows", "ChampionsOfLuneraria.exe", "ChampionsOfLuneraria-Windows-x64"), ] def build(preset: str, folder: str, binary: str) -> Path | None: out_dir = DIST / folder out_dir.mkdir(parents=True, exist_ok=True) cmd = ["godot", "--headless", "--path", str(PROJECT), "--export-release", preset, str(out_dir / binary)] print("+", " ".join(cmd)) result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: print(result.stdout[-2000:]) print(result.stderr[-2000:], file=sys.stderr) return None return out_dir / binary def pack(folder: str, binary: str, zip_stem: str) -> Path: out_dir = DIST / folder zip_path = DIST / f"{zip_stem}-{VERSION}.zip" readme = out_dir / "LIESMICH.txt" readme.write_text(INTRO, encoding="utf-8") with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf: for path in sorted(out_dir.iterdir()): if path.suffix == ".zip": continue zf.write(path, path.name) print("PACK", zip_path) return zip_path def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--check-only", action="store_true") args = parser.parse_args() DIST.mkdir(parents=True, exist_ok=True) # Fail early on missing templates / manifests instead of shipping a broken zip. required = [ PROJECT / "assets-source/phase6/export-templates/linux_release.x86_64", PROJECT / "assets-source/phase6/export-templates/windows_release_x86_64.exe", PROJECT / "assets/luneraria/peoples_manifest.json", PROJECT / "assets/luneraria/map_props_manifest.json", PROJECT / "scenes/luneraria.tscn", ] missing = [str(p) for p in required if not p.exists()] if missing: print("MISSING", missing) return 1 if args.check_only: print("CHECK_OK", VERSION) return 0 ok = True for preset, folder, binary, stem in PRESETS: artifact = build(preset, folder, binary) if artifact is None or not artifact.exists(): print("EXPORT_FAIL", preset) ok = False continue pack(folder, binary, stem) return 0 if ok else 1 if __name__ == "__main__": raise SystemExit(main())