saumwacht-godot/tools/luneraria/build_luneraria_demo.py
Martin Stickelbroeck 214ed5a1cc M4: autoritative Host/Join-Sitzung, Protokolltests, Loopback und Demos
LuneSession hält den autoritativen Matchzustand; Clients senden nur
Absichten. Fremde Sitze, veraltete Befehle und Doppelkäufe sind geprüft,
Disconnect führt zur Bot-Übernahme statt zum Kernverlust. Exporte und
entpackbare Demos 0.16.0-m4 für Linux und Windows.
2026-09-28 00:57:02 +02:00

112 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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-<ver>.zip
../dist/luneraria/ChampionsOfLuneraria-Windows-x64-<ver>.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())