nx_game_chat.nx
buildroot/runtime/nx_game_chat.nx
about
nx_game_chat.nx -- C12 of the comms lane: TURN-BASED MULTIPLAYER + CHAT over the C1 store. Contract
symbol gc_room_wire == the /compare/comms C12 watch (milestone M5: comms visible in the games).
DONE-RULE (comms.plan): a game opens a room per session and two clients exchange moves and chat
through the C1 store; the gate proves order and delivery with the game's own rules as the referee.
REFEREE: nx_game_chat_gate.
THE DESIGN: THE LOG IS THE GAME. A match is an ordinary nx_chat_store room; moves are TEXT rows
with the reserved body prefix mv:<n>; the CURRENT STATE is a DETERMINISTIC REPLAY of the log.
The move verb validates against the replayed state before appending, and the replay validates
AGAIN on every read -- so a row that slipped in out of turn (a race, or a client that lied) is
counted and IGNORED by every reader identically: replay is the referee, the wire is untrusted.
Store-and-forward multiplayer follows free: an offline player fetches-since-cursor and the same
replay produces the same board on every device (C2 sync moves whole matches between roots).
GAME DEFINITIONS ARE DATA (knowledge/comms/games.conf): id, cols, rows, winlen, mode
(drop = gravity, connect-four class; place = direct cell, tic-tac-toe class). A new grid game is a
conf row. WRITES go through the ONE ruler -- this organ forks the nx_chat_store elf named in the
conf, so budgets/refusals/announcements stay with C1; READS are direct plane reads (the same split
C2 established). Chat rides the same room (say verb); a chat body may not start with the reserved
mv: prefix (refused by name). Tombstones hide CHAT from display but NEVER hide moves: a game's
history is its state, so replay ignores del: keys for move rows by design (stated, not accidental).
The emitted HTML artifact stamps itself from the LAST ROW's epoch, never the wall clock, so two
emits of the same log are byte-identical (deterministic artifacts).
license_tier: ORIGINAL No hw writes (Rule 26).
dependencies 5 imports · 0 importers
imports: nx_syscalls.nxnx_itoa_lib.nxnx_store_seed_lib.nxnx_seg_store.nxnx_tool_run.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 31 | const GC_EXIT_OK: i64 = 0 |
| 32 | const GC_EXIT_USAGE: i64 = 2 |
| 33 | const GC_EXIT_REFUSED: i64 = 3 |
| 34 | const GC_EXIT_RETRY: i64 = 4 |
| 35 | const GC_EXIT_CORRUPT: i64 = 5 |
| 37 | const GC_NAME_MAX: i64 = 64 |
| 38 | const GC_PFX_CAP: i64 = 256 |
| 39 | const GC_CONF_CAP: i64 = 192 |
| 40 | const GC_BOARD_MAX: i64 = 4096 // conf sanity: cols*rows above this is a conf mistake, refused by name |
| 41 | const GC_OUT_CAP: i64 = 65536 // fork-capture buffer |
| 42 | const GC_HTML_CAP: i64 = 262144 // emit buffer |
| 43 | const GC_NL: i64 = 10 |
| 44 | const GC_PIPE: i64 = 124 |
| 45 | const GC_ST_ONGOING: i64 = 0 |
| 46 | const GC_ST_WIN: i64 = 2 |
| 47 | const GC_ST_DRAW: i64 = 3 |
| 48 | const GC_MODE_DROP: i64 = 1 |
| 49 | const GC_MODE_PLACE: i64 = 2 |
functions
| 51 | func gc_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 52 | func gc_n(v: i64) -> i64 { nxi_out(v); return 0 } |
| 53 | func gc_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 54 | func gc_eq(a: *u8, b: *u8) -> i64 |
| 60 | func gc_tok_ok(s: *u8) -> i64 |
| 76 | func gc_atoi(b: *u8, n: i64) -> i64 |
| 88 | func gc_hexv(c: i64) -> i64 called by 1: gc_hexd |
| 94 | func gc_hexd(src: *u8, n: i64, dst: *u8) -> i64 |
| 108 | func gc_confs(confpath: *u8, key: *u8, out: *u8, cap: i64) -> i64 |
| 144 | func gc_game(gconf: *u8, id: *u8, g: *i64) -> i64 |
| 209 | func gc_prefix(chatconf: *u8, room: *u8, out: *u8) -> i64 |
| 221 | func gc_field(p: *u8, l: i64, idx: i64, op: *i64) -> i64 called by 1: gc_replay |
| 237 | func gc_chat(chatelf: *u8, av: *i64, out: *u8, ol: *i64) -> i64 |
| 246 | func gc_replay(pfx: *u8, gconf: *u8, board: *u8, st: *i64, p1: *u8, p2: *u8, gid: *u8) -> i64 |
| 419 | func gc_replay_err(rr: i64) -> i64 |
| 430 | func gc_room_wire(game: *u8, session: *u8, p1: *u8, p2: *u8, gconf: *u8) -> i64 |
| 498 | func gc_move(room: *u8, player: *u8, mv: *u8, gconf: *u8) -> i64 |
| 591 | func gc_say(room: *u8, player: *u8, text: *u8, gconf: *u8) -> i64 |
| 623 | func gc_board_print(board: *u8, st: *i64) -> i64 |
| 641 | func gc_board(room: *u8, gconf: *u8) -> i64 |
| 684 | func gc_emit(room: *u8, outpath: *u8, gconf: *u8) -> i64 |
| 765 | func gc_usage() -> i64 |
| 769 | func gc_confpick(argc: i64, argv: *i64, idx: i64) -> *u8 called by 1: main |
| 773 | func main(argc: i64, argv: *i64) -> i64 |