srv.h (5848B)
1 /* srv.h - servidor de partidas por turnos (VPS o embebido para red local). 2 * El juego se enchufa con un GameModule; el servidor pone conexiones, codigos de 3 * partida, tokens por asiento, persistencia (meta + log de movidas) y bots. 4 * 5 * Protocolo de lineas de texto (UTF-8, terminadas en \n, max SRV_LINE bytes). 6 * 7 * Cliente -> servidor: 8 * HELLO <version> <nombre> saludo (obligatorio primero) 9 * AUTH <clave> opcional: 32 hex que el cliente deriva de nombre + 10 * contrasena; CREATE/JOIN la usan como token del asiento 11 * CREATE <argumentos del juego> crea una partida; el asiento 0 es de quien crea 12 * JOIN <codigo|-> toma el primer asiento humano libre ("-": cualquier partida abierta); 13 * con AUTH, si ya hay un humano con tu nombre y la clave 14 * coincide, volves a ese asiento (desde cualquier compu) 15 * OPEN <codigo> <token> volver a entrar a una partida propia 16 * STATUS <codigo> <token> [...] estado de varias partidas (para "mis partidas") 17 * MINE estado de las partidas donde tu clave (AUTH) tiene asiento 18 * AGAIN otra partida como la actual (mismas opciones y bots, la misma 19 * gente en los mismos asientos, otro reparto): siguen GAME/HDR/... 20 * como en CREATE; a los demas les aparece en MINE 21 * MOVE <movida> movida en el formato del juego 22 * SAY <para> <texto> chat de la partida; para = asiento (privado) o -1 (todos) 23 * LEAVE | PING 24 * 25 * Servidor -> cliente: 26 * WELCOME <version> 27 * GAME <codigo> <asiento> <token> quedaste adentro de una partida; siguen: 28 * HDR <cabecera> opciones y estado inicial (formato del juego) 29 * SEAT <i> <tipo> <conectado> <nombre> tipo: H libre, P humano, B bot, N neutral 30 * EV <movida> historial y despues en vivo (redactado para vos) 31 * CHAT <de> <para> <texto> chat (al entrar, las ultimas lineas que podes ver) 32 * SYNC fin del historial 33 * STAT <codigo> <asiento> <estado del juego> <np> <nombres separados por |> 34 * STATEND 35 * ERR <codigo> <texto> | PONG 36 * 37 * En disco (<dir>/<codigo>/): meta = "<magic>\nSEED n\nOPTS ...\nSEAT i k token nombre\n..." 38 * y log = una movida por linea (sin las automaticas, que se regeneran al reproducir); 39 * chat = "<de> <para> <texto>" por linea; partida.txt = la partida legible (si el juego exporta). */ 40 #ifndef COMUN_SRV_H 41 #define COMUN_SRV_H 42 43 #include <stdbool.h> 44 #include <stddef.h> 45 #include <stdint.h> 46 47 #define PROTO_VERSION 1 48 #define SRV_MAX_CLIENTS 128 49 #define SRV_MAX_SEATS 8 50 #define SRV_LINE 512 51 52 /* movida resuelta que sale de la partida; is_auto: la genera la partida sola (no va al log) */ 53 typedef void (*SrvEmit)(void *ctx, const char *move, bool is_auto); 54 55 typedef struct GameModule { 56 const char *magic; /* primera linea de meta, ej "CATAN-GAME 1" */ 57 size_t state_size; 58 int err_args, err_turn; /* codigos de ERR del juego */ 59 /* CREATE <args>: valida, escribe la linea de opciones (va a meta) y un tipo por 60 * asiento en seats ('H' humano / 'B' bot). Devuelve la cantidad de asientos o -1. */ 61 int (*create)(const char *args, char *opts, int optsn, char *seats); 62 /* Arranca la partida (nueva o al cargar de disco). kinds tiene un tipo por asiento 63 * ('H' 'P' 'B', '-' no existe); puede marcar 'N' (y nombrar) los que maneja sola. */ 64 bool (*start)(void *st, const char *opts, uint64_t seed, char *kinds, char (*names)[20], SrvEmit emit, void *ctx); 65 int (*submit)(void *st, int seat, const char *move); /* 0 ok o codigo de error */ 66 int (*replay)(void *st, const char *move); /* movida del log */ 67 void (*redact)(const char *move, int viewer, char *out, int n); 68 void (*header)(const void *st, char *out, int n); 69 void (*status)(const void *st, int seat, char *out, int n); 70 bool (*is_over)(const void *st); 71 long long (*next_wake)(const void *st); /* ms (srv_now_ms) o -1 */ 72 void (*wake)(void *st, long long now); /* bots, relojes... */ 73 void (*summary)(const void *st, char *out, int n); /* para el log del servidor */ 74 /* Opcional: la partida como texto legible (moves = todas las movidas resueltas, en 75 * orden). El servidor la mantiene al dia en <dir>/<codigo>/partida.txt, con el chat. */ 76 void (*export)(const void *st, const char *code, const char *const *moves, int nmoves, 77 char (*names)[20], const char *kinds, void (*put)(void *ctx, const char *line), void *ctx); 78 /* Opcional (AGAIN): la linea de opciones de la partida nueva a partir de la vieja (por 79 * ejemplo, sin la semilla del tablero para que salga otro reparto). NULL: la misma. */ 80 void (*again)(const char *opts, char *out, int n); 81 } GameModule; 82 83 typedef struct Server Server; 84 85 Server *srv_open(const GameModule *gm, int port, const char *datadir, bool quiet, char *err, int errlen); 86 int srv_fds(Server *s, int *fds, int max); 87 void srv_poll(Server *s, int timeout_ms); /* timeout 0: no bloquea */ 88 int srv_timeout(Server *s); /* ms hasta el proximo evento de una partida */ 89 void srv_close(Server *s); 90 int srv_port(Server *s); 91 long long srv_now_ms(void); 92 93 /* main() de un servidor dedicado: --port, --data, --quiet */ 94 int srv_main(const GameModule *gm, const char *prog, int port, const char *datadir, int argc, char **argv); 95 96 #endif