Commit Graph
14 Commits
Author SHA1 Message Date
tiennm99 501ef1f1d2 docs: rewrite CLAUDE.md, README, architecture; trim historical baggage
The project-level docs described the pre-caro-port architecture (TCP on
9999, JSON {data:base64} wire format, web/ + core/ + api/ + bot/ dirs,
server flags -w/-t/-s, state strings like '1'/'2'/'7,7') and referenced
files that no longer exist. The README also described an owner-controlled
Start button, 5-second heartbeat, 'database/' directory, AuthRequest
handshake, and linked to now-deleted plan files.

CLAUDE.md
- Rewritten for the current architecture: single WS endpoint at
  :1999/gomoku, protobuf binary frames, server/{consts,game,lobby,
  network,state,pkg/log}, client/src/{config,scenes,services,ui,
  objects,generated}, auto-start PVP semantics, heartbeat 50s/deadline
  90s, ClientExit self-vs-peer helper, enum serialization notes, Hard
  AI description, and a "When editing" section covering proto regen,
  state flow tests, and scene cleanup patterns.

README.md
- Features: owner-controlled start → auto-start on 2nd join.
- Heartbeat: 5s → 50s; add server deadline + reconnect back-off.
- Project structure: database/ → lobby/; services list corrected.
- Protocol: replace AuthRequest story with real SetNickname handshake.
- Credits: trimmed from a multi-bullet block to a single attribution
  line ("Based on ratel-online by ainilili"). Removed caro references
  and the link to the deleted plans/ implementation history.

docs/system-architecture.md
- Fully rewritten. Drops old TCP+JSON protocol tables, CLI client box,
  obsolete state flow diagram. Adds: current state registry
  (welcome/setNickname/home/waiting/gamePvp/gamePve/gameover/watching),
  cross-goroutine sync channels (StartCh/GameOverCh/RematchCh), typed
  enum list, kickStaleRoomPeers note, ClientExit self-vs-peer semantics,
  and client module table.

docs/deployment-guide.md
- Remove stale pointer to deleted plans/ directory.

Code comment cleanup (user: "don't mention too much"):
- server/network/handlers_stateless.go handleHeartbeat: drop caro
  reference, explain behavior in terms of the reader loop.
- server/game/ai_eval.go: "ported from caro's GomokuAI scoring" →
  generic "threat-pattern weights used by the Hard AI".
- server/game/ai.go positionScore: drop caro attribution, describe
  the heuristic directly.
- server/lobby/room.go: drop "caro Java domain" annotation, describe
  what Room actually embeds.
- client/src/services/game-state-service.js WATCH_GAME_SUCCESS: drop
  historical rename comment.

go vet + go test ./... + npm run build all green.
2026-04-11 20:16:47 +07:00
tiennm99 9de0f97752 feat(pvp): auto-start game on second player join
The "Start Game" button in the waiting room is gone — as soon as a
second player joins a PVP room, the server flips to Playing and both
clients transition into the game in lockstep.

Server:
- Proto: remove GameStartingRequest message + oneof field (now unused).
- state/home.go handleJoinRoom: after a successful join that fills the
  room, call assignColors, set Status=Playing + CurrentTurn=Black,
  close StartCh, broadcast GameStartingResponse, return StateGamePvp
  for the joining player. If still only one player, return StateWaiting
  as before.
- state/waiting.go: collapse ownerWait + joinerWait into a single
  unified loop. Both roles just select on StartCh (auto-start signal)
  and CmdCh (for ClientExit). No more GameStartingRequest handling or
  PlayerCount checks.
- network/dispatch.go: drop Request_GameStarting from the stateful
  routing list.

Client:
- connection-service.js: remove sendGameStarting() helper.
- menu-ui-rooms.js showWaiting: drop the isOwner parameter + Start Game
  button + owner/joiner branching. Both views show the same passive
  'Waiting for opponent...' message that flips to 'Opponent joined:
  <name> - starting game...' when the second player arrives.
- menu-scene.js: update _onRoomCreateSuccess + _onRoomJoinSuccess to
  call the simpler showWaiting(ownerNickname, playerCount, onLeave)
  signature.

Tests:
- Remove TestWaitingOwnerGameStartingRequiresFullRoom (obsolete).
- Rewrite TestWaitingOwnerStartsWhenFull into TestWaitingOwner
  TransitionsOnStartCh: simulate handleJoinRoom closing StartCh,
  verify owner transitions to StateGamePvp.
- Add TestFlow_JoinAutoStartsGame: end-to-end drive where owner is in
  waitingState, joiner sends JoinRoomRequest from home, and both
  goroutines must land in StateGamePvp with colors assigned and
  GameStartingResponse broadcast.

Regen Go + JS proto stubs. go vet + go test ./... green.
npm --prefix client run build green.
2026-04-11 18:19:05 +07:00
tiennm99 03758b0e90 fix(exit): route ClientExit through state machine, keep WS alive
Bug: after clicking "Leave" on the game-over modal, the client landed
on the nickname entry screen and got stuck — typing a nickname produced
no response for up to 90 seconds.

Root cause chain:
1. Server handleClientExit (stateless) closed SendCh and nilled it but
   did not close the WS connection. Writer goroutine drained + exited
   without closing the conn; reader stayed blocked on ReadMessage; state
   machine stayed blocked on CmdCh. Zombie session.
2. Any subsequent player.Send() returned nil (SendCh was nil), silently
   dropping responses. The setNickname reply never reached the client.
3. Client only unstuck when reader's 90 s readDeadline fired, finally
   closing the WS and triggering the auto-reconnect path.
4. Client MenuScene.create() always called showNicknameScreen() without
   checking gameState.nickname, so even after the reconnect the user
   had to re-type their name.

Fix: "exit" now means "leave current room, return to home lobby" —
not "terminate WS session".

Server:
- dispatch.go: move Request_ClientExit from stateless to stateful path.
- handlers_stateless.go: delete handleClientExit entirely.
- waiting.go leaveRoom: broadcast ClientExitResponse via broadcastResponse
  BEFORE removing the player, so the exiting player also receives their
  own exit confirmation. Removes duplicated self-notification logic.
- waiting/gamePvp/gamePve/gameover/watching: on ClientExitRequest, call
  leaveRoom + return consts.StateHome (was return 0, ErrClientExit).
- home.go: on ClientExitRequest, send bare ClientExitResponse and stay
  in home (no room to leave).
- Update 4 state tests that asserted ErrClientExit → now assert StateHome.
- Rename TestWatching_ClientExitReturnsErrClientExit → ReturnsHome.

Client:
- menu-scene.js create(): if gameState.nickname is set, skip nickname
  screen and call showLobby() directly. Otherwise showNicknameScreen().
- game-scene.js _onClientExit: drop the explicit showLobby() call; let
  MenuScene.create() decide the panel based on nickname state. Remove
  now-unused menu-ui showLobby import.

Result: click Leave → server sends ClientExitResponse, state machine
transitions to StateHome, WS stays open, client transitions to
MenuScene → sees gameState.nickname is set → goes straight to lobby.
No reconnect, no re-typing, no 90-second stall.

go vet + go test ./... green. npm run build green.
2026-04-11 16:51:13 +07:00
tiennm99 4c068849c4 refactor(server): rename database package to lobby, drop ratel legacy files
Rename
- server/database/ → server/lobby/ (17 import sites + qualified references)
- Package was named "database" but there is no database — it's in-memory
  hashmaps for players/rooms/spectators. "lobby" accurately names its role:
  the multiplayer game lobby state (who is in what room, joining/leaving,
  spectating).

Ratel-online legacy cleanup
- Delete server/README.md — 100% Chinese, entirely about ratel card games
  (斗地主/跑得快/德州扑克/麻将/骗子酒馆/Uno). Zero relevance to gomoku.
- Delete server/build.sh + server/build.ps1 — multi-platform ratel-server
  build scripts with mixed Chinese comments, superseded by Makefile +
  Dockerfile.
- Delete server/docs/ — Chinese Docker deployment guide + quickstart,
  superseded by root docs/deployment-guide.md and root README.md.
- Delete server/demo.gif — ratel card-game demo screenshot.

Comment fixes: update "database" references in consts/const.go and
game/board.go package docs to point at "lobby" instead.

go vet + go test ./... green.
2026-04-11 16:08:46 +07:00
tiennm99 d45b1275af refactor: typed proto enums, dead code cleanup, room-join broadcast fix
Protocol type safety
- Add Piece, GameResult, RoomType, RoomStatus proto3 enums; replace
  unsafe string fields in GameMoveSuccessResponse, GameOverResponse,
  RoomCreateSuccessResponse, RoomSummary, WatchGameSuccessResponse.
- Go compiler now rejects typos like "PVP" or "BLACK". protobufjs
  toJSON() serializes enums as UPPERCASE names, so existing client
  comparisons keep working.
- Fixes turn-change bug where lowercase "black"/"white" server strings
  never matched client 'BLACK'/'WHITE' checks, freezing currentTurn
  and blocking the non-starting player's clicks.
- Regenerate Go + JS stubs.

Room-join bug fix
- home.go handleJoinRoom now broadcasts RoomJoinSuccessResponse to all
  players in the room (owner + joiner), not just the joiner. Owner
  can see the player count flip to 2/2 and the Start Game button
  enables. Remove superseded broadcastJoined + GameReadyResponse path.
- client menu-scene _onRoomJoinSuccess: read correct proto camelCase
  field names (roomOwner, roomClientCount, clientNickname).

Dead code removal
- Delete GameReadyRequest/Response proto messages entirely; leaveRoom
  notifies via ClientExitResponse.
- Delete server/network/{network,wss}.go empty stubs.
- Delete server/pkg/consts/ unused re-export package.
- Slim server/consts/const.go from 117 LOC to 24: drop legacy TCP
  constants, duplicated RoomType/RoomStatus enums, Error/NewErr types,
  StateJoin/StateCreate=0 type-unsafe aliases, unused GameTypes maps.
- database/player.go: remove unused IP, Mode, Type, Amount, legacy
  private state field.
- Fix gopls findings: unused forPlayer, gameOverOnce, runAIMove player,
  handleGameReset player params.

go vet + go test ./... green, npm run build green.
2026-04-11 16:03:21 +07:00
tiennm99 530b96d161 refactor: retire legacy database shim, TCP handler, and server/pkg shims
Remove database/legacy.go (legacy hashmap store, Room/Gomoku types).
Remove state/create.go and state/join.go (collapsed into home.go).
Remove state/game/gomoku.go (replaced by game_pvp.go + game_shared.go).
Remove server/pkg/{model,network,protocol,async,json,strings} packages
that are no longer imported after the state machine rewrite.
Stub out network/network.go (legacy TCP handler retired).
Rewrite database/player.go to remove legacy conn/data fields.
2026-04-11 14:28:32 +07:00
tiennm99 43ac04ac79 feat(state): rewrite state machine using cmdCh and typed protobuf requests
Replace legacy AskForString/AskForPacket state machine with channel-based
runner. Each state reads *protocol.Request from player.CmdCh. Adds PVP
waiting (owner/joiner role split with StartCh signal), gamePvp (GameOverCh
for cross-goroutine game-end sync), gamePve (AI alternates with human,
AI-first when human is White), and gameover (reset/rematch support).
2026-04-11 14:28:19 +07:00
tiennm99 5ceb7ef924 test(server): unit tests for dispatch and ws network layer
- codec_test.go: roundtrip encode/decode for Request and Response variants,
  malformed input, empty frame
- handlers_stateless_test.go: nickname validation table (9 cases),
  heartbeat no-op, get_rooms response, set_client_info version store,
  dispatch routing (stateless inline vs stateful CmdCh push),
  CmdCh overflow drop without panic
2026-04-11 13:56:29 +07:00
tiennm99 9e14f3a9b3 feat(server): new ws network layer and protobuf dispatch on :1999/gomoku
- Add server/network/{server,codec,reader,writer,dispatch,handlers_stateless}.go
- Single /gomoku WS endpoint; binary protobuf frames only (no JSON/base64)
- Per-connection reader + writer goroutines; write mutex serialises WS writes
- Dispatch type-switch: stateless (heartbeat, set_nickname, get_rooms,
  set_client_info, client_exit) inline; stateful requests → player.CmdCh
- Add Player.SendCh, CmdCh, LastHeartbeat, ClientVersion, Send() to database.Player
- Rewire main.go: NewServer(":1999").Serve() + database.StartCleanup()
- Empty wss.go (old shim superseded by server.go)
2026-04-11 13:56:22 +07:00
tiennm99 b089e64955 refactor: delete api/, core/, old client/, web/, server/bot/, server/network/tcp.go
Removed legacy Java API, Go shared core lib, Go CLI client, vanilla-JS web
client, QQ bot integration, and TCP listener. Server is now WS-only.
2026-04-11 12:07:18 +07:00
tiennm99 1b9eec5f7d refactor: rename Go module and copy core pkgs into server/pkg
- Module: github.com/ratel-online/server → github.com/tiennm99/gomoku/server
- Copied core/{log,util/async,util/json,util/strings,model,network,protocol,consts}
  into server/pkg/* (temporary shims until phase-05 replaces protocol/network)
- Rewrote all ratel-online import paths across server/**/*.go
- Trimmed main.go: single -p flag, WS-only on :1999, no TCP/bot/static
- Trimmed network/wss.go: endpoint /gomoku, no static file serving
- Updated Makefile: removed TCP/bot references, port 1999
2026-04-11 12:04:03 +07:00
tiennm99 5ccd4e7ce2 feat: add documentation, code comments, and update Docker config
Rewrite README with usage guide, deployment instructions, and protocol
docs. Update CLAUDE.md to reflect gomoku-only architecture. Add English
doc comments to all key server Go files, replacing Chinese comments.

Create docs/system-architecture.md (state machine, protocol, database
schema) and docs/deployment-guide.md (local dev, Docker, production
nginx, resource requirements).

Update Dockerfile to Go 1.22 with repo-root build context to include
web client. Update docker-compose to match.
2026-04-09 23:35:46 +07:00
tiennm99 2635151ce2 feat: add gomoku game type and web client with canvas board engine
Add server-side gomoku (five-in-a-row) as game type 9 with 15x15 board,
2-player rooms, move validation, win detection in 4 directions, and
draw detection. Includes channel-based turn sync with mutex-protected
board access.

Add vanilla JS web client served as static files from the Go server:
WebSocket connection with base64 packet encoding, state machine
navigation, Canvas-based board renderer with gradient stones, hover
ghost, last-move highlight, and game-over overlay.
2026-04-09 22:25:24 +07:00
tiennm99 6e3670aec8 feat: add ratel-online server, core, client, and api sources
Import source files from ratel-online organization repos into monorepo
structure for gomoku game development. Update README with project
structure and credits for original authors.
2026-04-09 17:09:41 +07:00