Arcade/kiosk name flow, free cursor in menu and portable Linux export

Every game over unlocks the profile and frees the name, so the menu always asks
for a new player name: the field is empty at every boot, restart or game over and
the game does not start without a name (no anonymous scores). The player identity
is derived from the entered name (deterministic FNV-1a, 16 hex chars valid for the
public API) and the profile keeps the best score per name. Backend untouched.

Mouse: player._ready() captured the pointer before the menu existed, so the start
screen was not clickable. The cursor now always starts visible; the capture happens
only in player.begin_play(), called by start_game(). New `playing` flag gates Esc
and the Web click capture to the actual match.

Linux export preset: single-file x86_64 binary with the PCK embedded, no
libstdc++ dependency, official 4.7.1 template (glibc >= 2.28). Notes and the
export_presets.cfg `#`-is-not-a-comment trap documented in docs/KIOSK-ARCADE.md.

Tests: profile 30/30, start screen 15/15 (cursor free at menu, captured only in
game), boss 50/50, rebalance 14/14, touch 14 PASS, API 42/42, all other suites pass.
This commit is contained in:
enne2
2026-10-24 12:50:03 +02:00
parent 21a1d5bf79
commit cb14fd5400
9 changed files with 397 additions and 106 deletions
+17 -12
View File
@@ -27,11 +27,11 @@ File coinvolti:
| `services/scores-api/docker-compose.yml` | compose (volume, limiti, log rotation) |
| `tools/nginx-zombie-fps-api.conf` | snippet nginx del reverse proxy |
| `scripts/leaderboard.gd` | client HTTP Godot (lettura + invio, retry) |
| `scripts/player_profile.gd` | profilo locale: nome scelto, id giocatore, miglior punteggio |
| `scripts/player_profile.gd` | profilo locale: nome dell'ultima partita, id giocatore, miglior punteggio per nome |
| `scripts/start_screen.gd` | menu: nome, pulsante GIOCA, classifica |
| `tools/test_scores_api.py` | 42 controlli sul servizio (funzionalità, validazione, limiti) |
| `tools/test_leaderboard.gd` + `.sh` | 14 controlli sul client, contro un'API locale usa e getta |
| `tools/test_player_profile.gd` | 26 controlli sul profilo (nome, id, riparazioni, migrazione dopo rinomina) |
| `tools/test_player_profile.gd` | 30 controlli sul profilo (campo del nome sempre libero, id derivato dal nome, record per nome, riparazioni, migrazione dopo rinomina) |
| `tools/test_start_screen.gd` | 10 controlli sulle regole del menu |
## 2. Contratto dell'API
@@ -148,19 +148,24 @@ sudo nginx -t && sudo systemctl reload nginx # se -t fallisce: ripristinar
| Chiave | Contenuto |
| --- | --- |
| `zombie_fps_name` | nome scelto |
| `zombie_fps_player_id` | id anonimo, 32 caratteri esadecimali |
| `zombie_fps_best` | miglior punteggio locale |
| `zombie_fps_locked` | `1` se il nome è già stato scelto |
| `zombie_fps_name` | nome dell'ultima partita (solo come chiave del suo record) |
| `zombie_fps_player_id` | id anonimo, 32 caratteri esadecimali, o 16 derivato dal nome |
| `zombie_fps_best` | miglior punteggio del nome salvato |
| `bests` (sezione del file `.cfg`) | miglior punteggio **per nome** |
| `zombie_fps_locked` | sempre `0` in modalità arcade/kiosk |
* Sul Web si scrive **anche** in `localStorage` perché è la memoria del browser che
sopravvive davvero alla ricarica della pagina (l'IndexedDB di Godot può non essere
sincronizzata). Alla lettura i due archivi si fondono: l'id del giocatore resta
stabile, così i punteggi vecchi restano collegati.
* **Il nome, una volta scelto, non viene più richiesto**: se `locked` è attivo il menu
mostra `giocatore: Mat` e il campo di testo non esiste proprio.
* Un nome diverso da quello predefinito (`Giocatore`) vale come nome scelto, anche per
i profili salvati dalle versioni precedenti.
* **Modalità arcade/kiosk (`ALWAYS_ASK_NAME`)**: il nome non viene mai dato per scontato.
Il campo del menu è sempre presente e arriva vuoto a ogni avvio, riavvio o game over;
senza nome scritto la partita non parte (nessun punteggio anonimo in classifica).
Il profilo conserva solo il **miglior punteggio per nome**. Dettagli: `docs/KIOSK-ARCADE.md`.
* L'identità della partita nasce dal nome inserito: `player_id_for_name()` è un FNV-1a
deterministico (16 caratteri esadecimali, valido per il server). Stesso nome = stesso id
anche dopo un riavvio del kiosk, nomi diversi = identità diverse. Il backend non cambia.
* Un `locked` arrivato da profili o dal browser di versioni precedenti viene ignorato.
* **Riparazione automatica**: `str(null)` in GDScript produce la stringa `"null"`, e
una versione precedente l'ha salvata come nome. Alla lettura i valori `null`,
`undefined` e vuoti vengono scartati, il nome torna al predefinito e il blocco si
@@ -198,9 +203,9 @@ sh tools/test_leaderboard.sh # 14 controlli
# profilo e menu (menu: serve un display)
$HOME/.local/opt/godot-4.7.1/Godot_v4.7.1-stable_linux.x86_64 --headless --path . \
--script res://tools/test_player_profile.gd # 26 controlli
--script res://tools/test_player_profile.gd # 30 controlli
$HOME/.local/opt/godot-4.7.1/Godot_v4.7.1-stable_linux.x86_64 --path . \
--rendering-method gl_compatibility --script res://tools/test_start_screen.gd # 10 controlli
--rendering-method gl_compatibility --script res://tools/test_start_screen.gd # 11 controlli
```
In produzione si verifica a mano, con `curl`: