README.md (4924B)
1 # comun — base compartida de los juegos 2 3 Todo lo que no es de un juego en particular: dibujo en pixeles, menús, terminal, 4 ventana SDL, red, servidor de partidas y la PicoCalc. Lo usan `catan/` y 5 `ajedrez-c/`. No sabe nada de ningún juego: cada juego lo configura con un 6 `app_config.h` y le enchufa sus reglas. 7 8 ``` 9 base/ C99 sin malloc ni stdio (compila igual para Linux y el RP2040) 10 rng (PCG32), str (texto sin stdio), lang (g_lang es/en), 11 input (teclas K_*, eventos, zonas clickeables, layouts), form (menús) 12 gfx/ renderer de pixeles sobre una Surface abstracta: primitivas, texto, 13 fuente bitmap (font.c, generada), menús en pixeles (gfx_form) 14 linux/ paths (XDG + reloj), netline (cliente de líneas TCP + tokens guardados), 15 tuikit (ncurses: colores opacos, cajas, lienzo de medios bloques, menús, input), 16 guikit (ventana SDL3 con framebuffer escalado) 17 server/ srv: servidor de partidas por turnos; el juego se enchufa con un GameModule 18 pico/ hal.h (la interfaz de hardware) y sus dos implementaciones: 19 hal_rp2040.c (PicoCalc real) y hal_sim.c (simulador SDL, cable por TCP); 20 sdlog (SD: log y partida guardada), link (líneas con checksum por el cable), 21 memmap_sdboot_200k.ld y comun_pico.cmake (arma el .uf2 y el .bin) 22 deploy/ install-vps.sh: instala el servidor de un juego con systemd 23 tools/ mkfont.py (fuente), patch_reset.py (parche del .bin), ansi2png.py (capturas de la TUI) 24 ``` 25 26 ## Cómo lo usa un juego 27 28 **`app_config.h`** en el include path del juego: 29 30 ```c 31 #define APP_NAME "catan" /* ~/.local/share/catan, ~/.config/catan */ 32 #define APP_TITLE "Catan" /* ventanas, arranque de la PicoCalc */ 33 #define APP_SD_LOG "CATAN.LOG" /* archivos pre-creados en la raíz de la SD */ 34 #define APP_SD_SAV "CATAN.SAV" 35 #define APP_SD_LOG83 "CATAN LOG" /* los mismos como entrada FAT 8+3 */ 36 #define APP_SD_SAV83 "CATAN SAV" 37 ``` 38 39 **Makefile**: 40 41 ```make 42 COMUN ?= ../comun 43 include $(COMUN)/comun.mk 44 CPPFLAGS += -I. $(COMUN_INC) 45 # fuentes: $(COMUN_BASE) $(COMUN_GFX) $(COMUN_LINUX) $(COMUN_TUI) $(COMUN_GUI) 46 # $(COMUN_SERVER) $(COMUN_SIM) 47 ``` 48 49 **PicoCalc** (`pico/CMakeLists.txt`, después de `pico_sdk_init()`): 50 51 ```cmake 52 include(${COMUN_DIR}/pico/comun_pico.cmake) 53 comun_picocalc_app(mi_app NAME "MiApp" DESC "..." SOURCES ... INCLUDES ${ROOT}) 54 ``` 55 56 La app define `void app_main(void)` y usa solo `hal.h`, así el mismo código corre 57 en la PicoCalc y en el simulador. 58 59 **Servidor**: el juego implementa un `GameModule` (ver `server/srv.h`): crear 60 partida, aplicar/reproducir movidas, redactar lo privado, cabecera, estado para 61 "mis partidas", bots/relojes (`next_wake`/`wake`). El servidor pone conexiones, 62 códigos de 6 letras, tokens por asiento, persistencia (meta + log) y reanuda las 63 partidas al reiniciar. `srv_main()` es el `main` de un servidor dedicado. 64 65 El servidor acepta en el mismo puerto clientes TCP y **WebSocket** (la versión web del 66 juego en el navegador): si lo primero que llega es un pedido HTTP de upgrade (`GET ` 67 en vez de `HELLO`), `server/ws.c` hace el handshake y desenvuelve/envuelve los frames; 68 el protocolo de líneas es el mismo. Todo el WebSocket vive en `ws.c` (sin sockets, se 69 prueba sobre buffers) y `srv.c` lo llama en tres puntos; `-DSRV_NO_WS` lo saca. Como el 70 navegador exige TLS, delante va Caddy o nginx haciendo `wss://` → `ws://127.0.0.1:puerto`. 71 72 `AGAIN` arma otra partida como la actual (mismas opciones, la misma gente en los mismos 73 asientos, otro reparto si el juego implementa `GameModule.again`). 74 75 `ADMIN <secreto> RESET <código> <llave> <nombre>` cambia la llave de un asiento (para 76 quien se olvidó la contraseña; el nombre va al final porque puede tener espacios); el secreto está en `<datos>/admin.key` (el servidor lo 77 crea la primera vez). `deploy/admin.sh` (instalado como `<juego>-admin` por 78 `install-vps.sh`) lo usa y además lista las partidas desde los `meta`. 79 80 **Menús**: `gfx_form_backdrop` (pixeles) y `tk_form_logo` (terminal) son hooks 81 para que cada juego ponga su fondo y su logo. 82 83 ## Depuración sin mirar la pantalla 84 85 `APP_SHOT=cuadro.ppm` vuelca cada cuadro de la GUI o del simulador a PPM, y 86 `APP_KEYS="..."` alimenta el input (`~` Enter, `<` Esc, `>` Tab, `^ v { }` flechas, 87 `.` pausa de 300 ms, `!` salir). 88 89 ## PicoCalc: reglas de la casa 90 91 - **La flash de la Pico no se escribe.** Todo lo persistente va a la SD, en 92 archivos pre-creados que `sdlog.c` reescribe por dentro (nunca crea archivos ni 93 toca la FAT). La partida usa dos mitades alternadas con checksum. 94 - El cargador de la SD deja interrupciones armadas y el core 1 dibujando: 95 `comun_early_reset` (instalado por `tools/patch_reset.py`) y 96 `multicore_reset_core1()` lo resuelven. 97 98 ## Separar en repos 99 100 Si los juegos se publican por separado, `comun/` va a su propio repo y cada juego 101 lo incluye con `git subtree` en `comun/` (y `COMUN=comun`).