diff --git a/docs/BUILD-RASPBERRY-PI.md b/docs/BUILD-RASPBERRY-PI.md new file mode 100644 index 0000000..91e7380 --- /dev/null +++ b/docs/BUILD-RASPBERRY-PI.md @@ -0,0 +1,95 @@ +# Build standalone per Raspberry Pi 5 (arm64) + +Stato: **procedura verificata sulla generazione del binario** (export reale prodotto e +validato); la prova di esecuzione va fatta sul Pi 5, che non è questa macchina. + +Artefatto prodotto il 2026-10-24 con Godot 4.7.1.stable (a13da4feb), commit `4af402f8` +(tag `v1.0.0-kiosk`). + +## Esito + +| Voce | Valore | +| --- | --- | +| File | `build/linux-arm64/work_death_balance.arm64` | +| Tipo | ELF 64-bit LSB, ARM aarch64, interpreter `/lib/ld-linux-aarch64.so.1` | +| Dimensione | 74.094.536 byte (≈70,7 MiB) = template 67.046.672 + PCK 7.047.864 | +| PCK | incorporato (`embed_pck=true`), magic `GDPC` a offset 67.046.672, pack_version 4 | +| Texture | `etc2_astc=true`, `s3tc_bptc=false` (v3d/V3D 7.1 non supporta S3TC/BPTC) | +| Addon nativo | non incluso: il preset esclude `addons/*`; nessun `.so` arm64 necessario | + +## Perché serve poco lavoro + +- I **template ufficiali Godot includono Linux arm64** (le architetture ufficiali sono + x86_32, x86_64, arm32, arm64). L'export è un **cross-export**: si esegue su x86_64, + non serve toolchain aarch64 né compilare il motore. +- La **GDExtension `goldsrc` non è nel gioco esportato**: `export_presets.cfg` ha + `exclude_filter="addons/*"` e l'unico riferimento nel codice è un commento in + `scripts/grenade_explosion.gd:3`. I modelli sono già `.scn` pre-estratti. + (Nel repository i binari dell'addon sono solo x86_64: irrilevante per l'export.) + +## Procedura riproducibile + +```bash +# 1. Godot 4.7.1 editor (x86_64) in ~/.local/opt/godot-4.7.1/ +# https://github.com/godotengine/godot-builds/releases/tag/4.7.1-stable +# (solo il template che serve: templates/linux_release.arm64 dal tpz) + +# 2. template installati in: +# ~/.local/share/godot/export_templates/4.7.1.stable/{linux_release.arm64,version.txt} +# version.txt deve contenere esattamente: 4.7.1.stable + +# 3. import del progetto (genera .godot/), una volta sola +godot --headless --path . --import + +# 4. export +godot --headless --path . --export-release "Linux ARM64" \ + build/linux-arm64/work_death_balance.arm64 +``` + +Il preset `Linux ARM64` è in `export_presets.cfg` (`[preset.2]`) ed è identico a +`Linux` tranne per: `binary_format/architecture="arm64"`, +`texture_format/etc2_astc=true`, `texture_format/s3tc_bptc=false`, +`export_path="build/linux-arm64/work_death_balance.arm64"`. + +### Scaricare solo il template che serve (1,28 GB → 27 MB) + +Il `tpz` dei template è uno zip: `tools/zipfetch.py` legge EOCD e central directory +via HTTP Range e scarica il solo membro richiesto. Comodo su connessioni lente. + +## Sul Pi 5: aspettative e leve + +GPU: Broadcom VideoCore VII (V3D 7.1). Mesa espone **OpenGL 3.1 desktop + OpenGL ES 3.1** +(v3d) e **Vulkan 1.2/1.3 conformante** (v3dv). + +- Il progetto è `forward_plus`. Su Vulkan il Forward+ **viene declassato automaticamente + a Mobile** ("Platform supports less than 48 textures per stage … Defaulting to Mobile + renderer"): è il comportamento atteso, non un errore. +- Con `--rendering-driver opengl3` il driver desktop GL 3.3 non è disponibile su V3D e + Godot **ripiega su OpenGL ES 3.1**: per questo servono le texture ETC2 (già abilitate + nel preset arm64). +- Nessuna aspettativa da 1080p: il target realistico è 960x540 (o 640x360) con + `--max-fps 30`. Da misurare sul campo con `--print-fps` se compilato in debug. + +Avvio consigliato (script fornito: `build/linux-arm64/run-arm64.sh`): + +```bash +./run-arm64.sh # GL/GLES3, 960x540, 30 fps, classifica attiva +WDB_MODE=vulkan ./run-arm64.sh # percorso Vulkan (Mobile) +WDB_RES=640x360 ./run-arm64.sh # se non regge +WDB_API= ./run-arm64.sh # senza classifica +``` + +## Insidie verificate + +1. **`--api=` solo dopo `--`**: `leaderboard.gd` legge `OS.get_cmdline_user_args()`. + Senza separatore il gioco stampa "Classifica disattivata". +2. **`curl -C -` senza `-L`** su GitHub scarica il corpo del 302 (0 byte) e sembra + "riuscito": il download resta fermo per sempre. Serve `-L`. +3. **Resume fragile**: la CDN può restituire 206 anche dopo uno stallo; con + `--speed-time 30 --speed-limit 20000` si riprende senza perdere i byte già scaricati. +4. **L'addon `goldsrc` non si carica su host con glibc più vecchia del build** + (`GLIBC_2.43 not found`): errore cosmetico in import/export, non incide sul PCK + perché `addons/*` è escluso. +5. **Verifica del PCK**: la controprova x86_64 esportata dallo stesso clone si avvia e + gira senza risorse mancanti; per l'arm64 l'unica verifica possibile qui è strutturale + (`file`, offset/size del PCK). La prova reale richiede il Pi. diff --git a/export_presets.cfg b/export_presets.cfg index 743fc14..2e129e4 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -54,3 +54,31 @@ binary_format/architecture="x86_64" texture_format/s3tc_bptc=true texture_format/etc2_astc=false ssh_remote_deploy/enabled=false + +[preset.2] + +name="Linux ARM64" +platform="Linux" +runnable=true +advanced_options=true +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="addons/*,tools/*,docs/*,build/*,assets/**/*.mdl,assets/half_life_manifest.json" +export_path="build/linux-arm64/work_death_balance.arm64" +patches=PackedStringArray() +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.2.options] + +custom_template/release="" +custom_template/debug="" +debug/export_console_wrapper=0 +binary_format/embed_pck=true +binary_format/architecture="arm64" +texture_format/s3tc_bptc=false +texture_format/etc2_astc=true +ssh_remote_deploy/enabled=false diff --git a/tools/zipfetch.py b/tools/zipfetch.py new file mode 100755 index 0000000..236d28c --- /dev/null +++ b/tools/zipfetch.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +"""Estrae singoli file da uno ZIP remoto via HTTP Range (senza scaricare 1,28 GB). + +Il tpz dei template Godot e' uno zip: serve solo templates/linux_release.arm64. +Legge EOCD + central directory con Range, poi scarica solo il membro richiesto. +""" +import binascii +import struct +import sys +import urllib.request +import zlib + +URL = ("https://github.com/godotengine/godot-builds/releases/download/" + "4.7.1-stable/Godot_v4.7.1-stable_export_templates.tpz") + + +def get_range(url, start, end=None): + if end is None: + rng = f"bytes={start}-" + else: + rng = f"bytes={start}-{end}" + req = urllib.request.Request(url, headers={"Range": rng}) + with urllib.request.urlopen(req, timeout=90) as r: + return r.read(), r.status + + +def main(wanted, dest_dir): + # 1. dimensione totale + req = urllib.request.Request(URL, method="HEAD") + with urllib.request.urlopen(req, timeout=60) as r: + total = int(r.headers["Content-Length"]) + print(f"zip remoto: {total} byte") + + # 2. EOCD negli ultimi 64 KiB + tail_len = min(65536, total) + tail, _ = get_range(URL, total - tail_len) + pos = tail.rfind(b"PK\x05\x06") + if pos < 0: + sys.exit("EOCD non trovato (zip64?)") + (_, _, _, _, n_entries, cd_size, cd_off, _) = struct.unpack( + " 1 else "templates/linux_release.arm64" + dest = sys.argv[2] if len(sys.argv) > 2 else "/tmp/godot-dl" + main(target, dest)