slop game oder so

This commit is contained in:
2026-09-24 17:57:54 +02:00
commit 4c997eee21
166 changed files with 14976 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
"""Baut das Upload-Paket für cPanel: nur die Dateien, die der Server braucht.
Aufruf (im Projektordner, beliebiges Betriebssystem)::
python scripts/build_deploy_zip.py # -> dist/glory_defense.zip
python scripts/build_deploy_zip.py -o paket.zip
Warum ein eigenes Skript statt „ZIP-Datei erstellen“: Windows PowerShell 5.1
(`Compress-Archive`) schreibt Pfade mit Backslash ins Archiv. Manche Entpacker unter
Linux erzeugen daraus flache Dateinamen wie ``app\\api.py`` – dann findet Passenger
das Paket ``app`` nicht. Außerdem landen hier garantiert weder ``.env`` (Geheimnisse)
noch ``instance/`` (Datenbank) noch Caches im Paket.
"""
from __future__ import annotations
import argparse
import sys
import zipfile
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
DEFAULT_OUTPUT = PROJECT_ROOT / "dist" / "glory_defense.zip"
#: Einzeldateien und Ordner, die auf den Server gehören.
INCLUDE_FILES = ("passenger_wsgi.py", "requirements.txt", ".env.example")
INCLUDE_DIRS = ("app",)
#: Wird nie mitgepackt, auch wenn es unterhalb von INCLUDE_DIRS liegt.
EXCLUDED_DIR_NAMES = frozenset({"__pycache__", ".pytest_cache", ".ruff_cache", "node_modules"})
EXCLUDED_SUFFIXES = frozenset({".pyc", ".pyo"})
def iter_deploy_files(root: Path = PROJECT_ROOT) -> list[Path]:
"""Alle Dateien des Upload-Pakets, sortiert (für reproduzierbare Archive)."""
files = [root / name for name in INCLUDE_FILES if (root / name).is_file()]
for directory in INCLUDE_DIRS:
for path in (root / directory).rglob("*"):
relative_parts = path.relative_to(root).parts
if not path.is_file() or EXCLUDED_DIR_NAMES.intersection(relative_parts):
continue
if path.suffix in EXCLUDED_SUFFIXES:
continue
files.append(path)
return sorted(files)
def build_zip(target: Path, root: Path = PROJECT_ROOT) -> list[str]:
"""Schreibt das ZIP und gibt die enthaltenen Pfade (mit ``/``) zurück."""
target.parent.mkdir(parents=True, exist_ok=True)
names = []
with zipfile.ZipFile(target, "w", compression=zipfile.ZIP_DEFLATED) as archive:
for path in iter_deploy_files(root):
# as_posix(): immer „/“ als Trenner, unabhängig vom Betriebssystem.
name = path.relative_to(root).as_posix()
archive.write(path, name)
names.append(name)
return names
def main(argv: list[str] | None = None) -> int:
"""Kommandozeilen-Einstieg."""
parser = argparse.ArgumentParser(description="Upload-Paket für cPanel bauen.")
parser.add_argument("-o", "--output", type=Path, default=DEFAULT_OUTPUT, help="Ziel-ZIP")
args = parser.parse_args(argv)
names = build_zip(args.output)
size_kb = args.output.stat().st_size / 1024
print(f"{args.output} erstellt: {len(names)} Dateien, {size_kb:.0f} KB")
return 0
if __name__ == "__main__":
sys.exit(main())
+26
View File
@@ -0,0 +1,26 @@
/**
* Kopiert Phaser aus node_modules nach app/static/js/lib/.
*
* Warum kopieren statt CDN: Das Spiel soll ohne externe Abhängigkeiten laufen
* (Offline-Betrieb, Datenschutz, strikte Content-Security-Policy). Die kopierte
* Datei wird mit ausgeliefert; auf dem Server ist daher kein Node nötig.
*
* Aufruf: npm run vendor:phaser
*/
import { copyFileSync, mkdirSync, readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
const source = join(root, 'node_modules', 'phaser');
const target = join(root, 'app', 'static', 'js', 'lib');
const { version } = JSON.parse(readFileSync(join(source, 'package.json'), 'utf8'));
if (!version.startsWith('3.')) {
throw new Error(`Erwartet wird Phaser 3.x, gefunden: ${version}`);
}
mkdirSync(target, { recursive: true });
copyFileSync(join(source, 'dist', 'phaser.min.js'), join(target, 'phaser.min.js'));
copyFileSync(join(source, 'LICENSE.md'), join(target, 'PHASER_LICENSE.md'));
console.log(`Phaser ${version} nach ${target} kopiert.`);