Sun, 23 Aug 2026 12:19:05 +0200
fix byte-order problem in GameInfo and change decline reason to one byte
relates to #976
| PROTOCOL.md | file | annotate | diff | comparison | revisions | |
| src/chess/rules.h | file | annotate | diff | comparison | revisions | |
| src/main.c | file | annotate | diff | comparison | revisions | |
| src/network.h | file | annotate | diff | comparison | revisions |
--- a/PROTOCOL.md Sun Aug 23 11:38:27 2026 +0200 +++ b/PROTOCOL.md Sun Aug 23 12:19:05 2026 +0200 @@ -97,8 +97,12 @@ When the server wants to continue a game, they SHALL send a `NETCODE_PGNDATA` message. The payload of this message is as follows: -* the same two BYTES and three WORDS as in `NETCODE_GAMEINFO`, followed by -* +* the same two BYTEs and three WORDs as in `NETCODE_GAMEINFO`, followed by +* one WORD for the number `n` of moves that will follow +* the `n` MOVEs that have been played already + +The server SHOULD NOT send a game that cannot be continued because it already +has reached a checkmate, stalemate, or forced draw position. ### Clock Setup @@ -110,6 +114,10 @@ * when the used time for a move is less than the delay, the move costs no time * the delay is always subtracted from the actual move time +## Playing the Game + +TODO: describe + ## Message Code Table The following table shows the definitions of the network codes.
--- a/src/chess/rules.h Sun Aug 23 11:38:27 2026 +0200 +++ b/src/chess/rules.h Sun Aug 23 12:19:05 2026 +0200 @@ -106,14 +106,14 @@ } Move; typedef struct { - uint8_t servercolor; - /** 1: play with timecontrol, 0: play without time control */ - uint8_t timecontrol; - /** If timecontrol is 1, initial clock time in seconds */ + Color servercolor; + /** play with timecontrol? */ + bool timecontrol; + /** If timecontrol is true, initial clock time in seconds */ uint16_t time; - /** If timecontrol is 1, time added per move in seconds */ + /** If timecontrol is true, time added per move in seconds */ uint16_t addtime; - /** If timecontrol is 1, delay before the clock starts ticking down */ + /** If timecontrol is true, delay before the clock starts ticking down */ uint16_t delay; } GameInfo;
--- a/src/main.c Sun Aug 23 11:38:27 2026 +0200 +++ b/src/main.c Sun Aug 23 12:19:05 2026 +0200 @@ -355,7 +355,7 @@ } } -static void eval_move_failed_msg(uint32_t code) { +static void eval_move_failed_msg(int code) { switch (code) { case AMBIGUOUS_MOVE: printw("Ambiguous move - please specify the piece to move."); @@ -496,27 +496,50 @@ } } -static NetMove hton_move(const Move *move) { - return (NetMove) { - .mtime_sec = net_htonl(move->movetime / 1000000ull), - .mtime_usec = net_htonl(move->movetime % 1000000ull), - .piece = move->piece, - .fromfile = move->fromfile, .fromrow = move->fromrow, - .tofile = move->tofile, .torow = move->torow, - .promotion = move->promotion +#define NETMOVE_LEN 14 +#define NETGI_LEN 8 + +static NetGameInfo hton_gi(GameInfo gi) { + return (NetGameInfo) { + .servercolor = gi.servercolor, + .timecontrol = gi.timecontrol ? 1 : 0, + .time = net_htons(gi.time), + .addtime = net_htons(gi.addtime), + .delay = net_htons(gi.delay) }; } -static Move ntoh_move(const NetMove *move) { +static GameInfo ntoh_gi(NetGameInfo gi) { + return (GameInfo) { + .servercolor = gi.servercolor, + .timecontrol = gi.timecontrol, + .time = net_ntohs(gi.time), + .addtime = net_ntohs(gi.addtime), + .delay = net_ntohs(gi.delay) + }; +} + +static NetMove hton_move(Move move) { + return (NetMove) { + .mtime_sec = net_htonl(move.movetime / 1000000ull), + .mtime_usec = net_htonl(move.movetime % 1000000ull), + .piece = move.piece, + .fromfile = move.fromfile, .fromrow = move.fromrow, + .tofile = move.tofile, .torow = move.torow, + .promotion = move.promotion + }; +} + +static Move ntoh_move(NetMove move) { return (Move) { .string = {0}, /* calculated before applying the move */ .timestamp = {0}, /* planned to be removed */ - .movetime = (uint64_t)net_ntohl(move->mtime_sec) - * 1000000ull + net_ntohl(move->mtime_usec), - .piece = move->piece, - .fromfile = move->fromfile, .fromrow = move->fromrow, - .tofile = move->tofile, .torow = move->torow, - .promotion = move->promotion, + .movetime = (uint64_t)net_ntohl(move.mtime_sec) + * 1000000ull + net_ntohl(move.mtime_usec), + .piece = move.piece, + .fromfile = move.fromfile, .fromrow = move.fromrow, + .tofile = move.tofile, .torow = move.torow, + .promotion = move.promotion, /* flags are also calculated before applying the move */ 0 }; @@ -637,7 +660,7 @@ movestr, mycolor, &move); switch (eval_result) { case VALID_MOVE_SYNTAX: - NetMove nmove = hton_move(&move); + NetMove nmove = hton_move(move); net_send_data(opponent, NETCODE_MOVE, &nmove, NETMOVE_LEN); code = net_recieve_code(opponent); /* we could validate the move's check/checkmate flag with @@ -645,9 +668,8 @@ gamestate->checkmate = code == NETCODE_CHECKMATE; gamestate->stalemate = code == NETCODE_STALEMATE; if (code == NETCODE_DECLINE_MOVE) { - uint32_t reason; - net_recieve_data(opponent, &reason, sizeof(uint32_t)); - reason = net_ntohl(reason); + uint8_t reason; + net_recieve_data(opponent, &reason, 1); eval_move_failed_msg(reason); } else if (code == NETCODE_ACCEPT || code == NETCODE_CHECK @@ -789,7 +811,7 @@ case NETCODE_MOVE: { NetMove nmove; net_recieve_data(opponent, &nmove, NETMOVE_LEN); - Move move = ntoh_move(&nmove); + Move move = ntoh_move(nmove); format_move(gamestate, &move); code = validate_move(gamestate, &move); if (code == VALID_MOVE_SEMANTICS) { @@ -832,9 +854,7 @@ return 0; } } else { - uint32_t reason = net_htonl(code); - net_send_data(opponent, NETCODE_DECLINE_MOVE, - &reason, sizeof(uint32_t)); + net_send_data(opponent, NETCODE_DECLINE_MOVE, &code, 1); } break; } @@ -1075,18 +1095,19 @@ } int fd = server.client->fd; + NetGameInfo gi = hton_gi(gamestate->info); if (settings.continuepgn) { /* Continue game, send PGN data */ uint16_t mc = gamestate->movecount; - size_t pgndata_size = sizeof(GameInfo) + 2 + mc * NETMOVE_LEN; + size_t pgndata_size = NETGI_LEN + 2 + mc * NETMOVE_LEN; char *pgndata = malloc(pgndata_size); - memcpy(pgndata, &(gamestate->info), sizeof(GameInfo)); - unsigned offset = sizeof(GameInfo); + memcpy(pgndata, &gi, NETGI_LEN); + unsigned offset = NETGI_LEN; uint16_t mcn = net_htons(mc); memcpy(pgndata+offset, &mcn, 2); offset += 2; for (unsigned i = 0 ; i < mc ; i++) { - NetMove nmove = hton_move(gamestate->moves + i); + NetMove nmove = hton_move(gamestate->moves[i]); memcpy(pgndata+offset, &nmove, NETMOVE_LEN); offset += NETMOVE_LEN; } @@ -1094,8 +1115,7 @@ free(pgndata); } else { /* Start new game */ - net_send_data(fd, NETCODE_GAMEINFO, - &(gamestate->info), sizeof(GameInfo)); + net_send_data(fd, NETCODE_GAMEINFO, &gi, NETGI_LEN); } addstr("\rClient connected - awaiting challenge acceptance..."); refresh(); @@ -1171,7 +1191,9 @@ bool played = false; if (code == NETCODE_GAMEINFO) { /* Start new game */ - net_recieve_data(server.fd, &(gamestate->info), sizeof(GameInfo)); + NetGameInfo gi; + net_recieve_data(server.fd, &gi, NETGI_LEN); + gamestate->info = ntoh_gi(gi); dump_gameinfo(gamestate); if (prompt_yesno("Accept challenge")) { net_send_code(server.fd, NETCODE_ACCEPT); @@ -1181,9 +1203,11 @@ net_send_code(server.fd, NETCODE_DECLINE); } } else if (code == NETCODE_PGNDATA) { - net_recieve_data(server.fd, &(gamestate->info), sizeof(GameInfo)); + NetGameInfo gi; + net_recieve_data(server.fd, &gi, NETGI_LEN); + gamestate->info = ntoh_gi(gi); uint16_t mc; - net_recieve_data(server.fd, &mc, sizeof(mc)); + net_recieve_data(server.fd, &mc, 2); mc = net_ntohs(mc); char *movedata = malloc(mc * NETMOVE_LEN); net_recieve_data(server.fd, movedata, mc*NETMOVE_LEN); @@ -1192,7 +1216,7 @@ NetMove nmove; memcpy(&nmove, movedata+offset, NETMOVE_LEN); offset += NETMOVE_LEN; - Move move = ntoh_move(&nmove); + Move move = ntoh_move(nmove); format_move(gamestate, &move); apply_move(gamestate, &move); }
--- a/src/network.h Sun Aug 23 11:38:27 2026 +0200 +++ b/src/network.h Sun Aug 23 12:19:05 2026 +0200 @@ -71,6 +71,14 @@ } Server; typedef struct { + uint8_t servercolor; + uint8_t timecontrol; + uint16_t time; + uint16_t addtime; + uint16_t delay; +} NetGameInfo; + +typedef struct { uint32_t mtime_sec; uint32_t mtime_usec; uint8_t piece; @@ -81,8 +89,6 @@ uint8_t promotion; } NetMove; -#define NETMOVE_LEN 14 - int net_create_tcp(Server *server, short port); int net_find_tcp(Server *server, char* host, short port);