- project-overview-pdr.md: PDR, goals, features, tech stack - system-architecture.md: diagrams, protocol, event codes, data flow - codebase-summary.md: module breakdown, key classes, test structure - code-standards.md: Java/JS conventions, JSDoc, Git rules - deployment-guide.md: build, run, CI/CD, troubleshooting - project-roadmap.md: completed phases, future ideas, decision log
17 KiB
Codebase Summary
Directory Structure
caro/
├── .github/
│ └── workflows/
│ ├── Build.yml CI: build + test
│ └── deploy-pages.yml CD: deploy web client to GitHub Pages
├── landlords-common/ Shared Java library (game logic, entities, protocol)
│ ├── src/main/java/org/nico/ratel/landlords/
│ │ ├── channel/ Netty utilities
│ │ ├── entity/ Data models (Board, Room, GameMove, etc.)
│ │ ├── enums/ Type definitions (ServerEventCode, ClientEventCode, etc.)
│ │ ├── exception/ Custom exceptions
│ │ ├── features/ Feature flags
│ │ ├── handler/ Protocol codec (Protobuf decoder)
│ │ ├── helper/ Game logic & utilities
│ │ ├── print/ Terminal formatting
│ │ ├── robot/ AI engine (GomokuAI)
│ │ ├── transfer/ Binary serialization (ByteKit, ByteLink)
│ │ └── utils/ General utilities (JSON, List, Options, Time)
│ ├── src/test/java/
│ │ ├── helper/tests/GomokuHelperTest.java
│ │ └── robot/tests/GomokuAITest.java
│ └── pom.xml
├── landlords-server/ Java Netty server (TCP + WebSocket)
│ ├── src/main/java/org/nico/ratel/landlords/server/
│ │ ├── event/ ServerEventListener_* handlers
│ │ ├── handler/ Netty pipeline handlers
│ │ ├── proxy/ Message sending (ProtobufProxy, WebsocketProxy)
│ │ ├── timer/ Background tasks (cleanup, heartbeat)
│ │ ├── SimpleServer.java Server entry point
│ │ ├── ServerContains.java Global state container
│ │ └── ... (event listeners)
│ ├── src/main/resources/
│ │ └── static/ Built-in web UI (index.html, CSS, JS, images)
│ ├── src/test/java/ (if any)
│ └── pom.xml
├── landlords-client/ Java CLI client
│ ├── src/main/java/org/nico/ratel/landlords/client/
│ │ ├── entity/ Client-specific entities
│ │ ├── event/ ClientEventListener_* handlers
│ │ ├── handler/ Protocol handlers
│ │ ├── proxy/ Message sending
│ │ └── SimpleClient.java CLI entry point
│ └── pom.xml
├── web-client/ Phaser 3 + Vite web client
│ ├── src/
│ │ ├── main.js Phaser boot
│ │ ├── config/
│ │ │ ├── game-config.js Phaser configuration
│ │ │ └── protocol-constants.js Event code enums
│ │ ├── scenes/
│ │ │ ├── boot-scene.js Initialize, connect to server
│ │ │ ├── menu-scene.js Menus (overlay DOM)
│ │ │ └── game-scene.js Main gameplay scene
│ │ ├── services/
│ │ │ ├── event-bus.js Pub/sub event dispatcher
│ │ │ ├── connection-service.js WebSocket client
│ │ │ └── game-state-service.js Client-side state
│ │ ├── objects/
│ │ │ ├── board.js Game board renderer
│ │ │ └── stone.js Individual stone sprite
│ │ └── ui/
│ │ ├── menu-ui.js Menu components
│ │ └── game-ui.js Game HUD & notifications
│ ├── index.html
│ ├── vite.config.js
│ ├── package.json
│ └── dist/ (build output)
├── docs/ (this directory)
│ ├── project-overview-pdr.md
│ ├── system-architecture.md
│ ├── codebase-summary.md
│ ├── code-standards.md
│ ├── deployment-guide.md
│ └── project-roadmap.md
├── plans/ (implementation plans)
├── pom.xml Maven parent POM
├── README.md
├── LICENSE
└── .gitignore
Key Java Modules
landlords-common (Shared Library)
Entities:
-
Board.java— 15x15 game board, move validation, win/draw detectionBOARD_SIZE = 15WIN_CONDITION = 5- Methods:
isValidMove(),makeMove(),checkWin(),reset()
-
Room.java— Game session stateid(UUID),type(PVP/PVE),status(WAITING/PLAYING/FINISHED)players(2),spectators,board,moveHistory
-
GameMove.java— Single move recordrow,col,piece(BLACK/WHITE),timestamp
-
ServerTransferData.java— Network message from clientcode(ServerEventCode),data(payload),info(metadata)
-
ClientTransferData.java— Network message from servercode(ClientEventCode),data,info
-
ClientSide.java— Player connection statenickname,status(ONLINE/OFFLINE/PLAYING),role(PLAYER/SPECTATOR)
Enums:
ServerEventCode(14 codes) — client→server actionsClientEventCode(24 codes) — server→client responsesPieceType— EMPTY, BLACK, WHITEGameResult— IN_PROGRESS, BLACK_WIN, WHITE_WIN, DRAWRoomType— PVP, PVERoomStatus— WAITING, PLAYING, FINISHEDClientRole— PLAYER, SPECTATORClientStatus— ONLINE, OFFLINE, PLAYING
Game Logic:
-
GomokuHelper.java— Win detection (checks 4 directions)canWin(Board, row, col, piece)→ booleangetWinCount(Board, row, col, piece, direction)→ int- 37 unit tests in
GomokuHelperTest.java
-
GomokuAI.java— AI move selection (3 difficulties)getNextMove(Board, difficulty)→ GameMovegetEasyMove()— random valid movegetMediumMove()— find win or block opponentgetHardMove()— minimax scoring at depth 3- 37 unit tests in
GomokuAITest.java
Utilities:
JsonUtils.java— Serialize/deserialize POJO ↔ JSONListUtils.java— List filtering, mappingOptionsUtils.java— Command-line argument parsingStreamUtils.java— I/O helpersTimeHelper.java— Timestamp formattingI18nHelper.java— Internationalization (English)MapHelper.java— Map utilities
Protocol:
ByteKit.java— Byte buffer operationsByteLink.java— Byte stream builderTransferProtocolUtils.java— Serialize/deserialize messagesDefaultDecoder.java— Protobuf message decoder
landlords-server (Netty Server)
Entry Point:
SimpleServer.java— Bootstrap- Parses args:
-p {port}(default: 1024) - Creates two Netty ServerBootstrap instances (TCP + WebSocket)
- Registers handlers in pipeline
- Parses args:
Event Handlers (ServerEventListener_*):
CODE_CLIENT_NICKNAME_SET— Store player nicknameCODE_ROOM_CREATE/CODE_ROOM_CREATE_PVE— Create room, assign playersCODE_GET_ROOMS— Send room list to clientCODE_ROOM_JOIN— Add player to existing roomCODE_GAME_STARTING— Check both players ready, begin gameCODE_GAME_READY— Mark player readyCODE_GAME_MOVE— Validate move, apply to board, broadcast, check win, run AICODE_GAME_RESET— Reset board for rematchCODE_GAME_WATCH/CODE_GAME_WATCH_EXIT— Spectator join/exitCODE_CLIENT_EXIT/CODE_CLIENT_OFFLINE— Cleanup disconnection
Network Handlers:
ProtobufTransferHandler— TCP/Protobuf codec, encodes/decodes binary messagesWebsocketTransferHandler— WebSocket JSON codecStaticFileHandler— HTTP file serving (index.html, CSS, JS, etc.)- Maps
GET /→static/index.html - Rejects path traversal (
..) - Supports MIME types: html, css, js, json, mp3, png, jpg, svg, ico
- Passes
/ratelrequests to WebSocket handler
- Maps
Message Proxies:
ProtobufProxy— Send binary message to TCP clientWebsocketProxy— Send JSON message to WebSocket clientProxy(abstract) — Base interface
Global State:
ServerContains.java— Singleton holding all rooms, active connections- Methods:
addRoom(),removeRoom(),getRoomList(),findRoom(id)
- Methods:
Background Tasks:
RoomClearTask— Periodic cleanup (remove finished rooms after timeout)
landlords-client (Java CLI Client)
Entry Point:
SimpleClient.java— Bootstrap- Parses args:
-h {host} -p {port} -ptl {protocol} -lang {language} - Connects via TCP/Protobuf or WebSocket
- Reads moves from stdin (
row,colorexit)
- Parses args:
Event Handlers (ClientEventListener_*):
CODE_CLIENT_CONNECT— Connection successful, display lobby menuCODE_SHOW_ROOMS— Display room listCODE_ROOM_CREATE_SUCCESS/CODE_ROOM_JOIN_SUCCESS— Enter waiting roomCODE_GAME_STARTING— Display board, wait for movesCODE_GAME_MOVE_SUCCESS— Update local board displayCODE_GAME_MOVE_INVALID/CODE_GAME_MOVE_OCCUPIED/ etc. — Show errorCODE_GAME_WIN/CODE_GAME_LOSE/CODE_GAME_DRAW— Game overCODE_CLIENT_KICK— Disconnected by server
Protocol Handlers:
ProtobufTransferHandler— TCP codecWebsocketTransferHandler— WebSocket codec- Same proxy pattern as server
Web Client (JavaScript/Phaser 3)
Boot:
main.js— Create Phaser game instance, start boot scene
Config:
-
game-config.js— Phaser config object- Resolution: 800x800
- Scale mode: Scale.FIT (responsive)
- Physics: Enabled (for animations)
- Scene list: [BootScene, MenuScene, GameScene]
-
protocol-constants.js— Export event code enums- Maps ServerEventCode and ClientEventCode names to numbers
Scenes (Phaser.Scene subclasses):
-
BootScene— Initialization- Create event bus and services
- Connect to server (WebSocket)
- Load assets (images, audio)
- Transition to menu on connect
-
MenuScene— DOM overlay menus- Nickname input form
- Lobby with room list and create room button
- Difficulty selector (for PVE)
- Settings menu
-
GameScene— Main gameplay- Render board and stones
- Handle mouse clicks (place stones)
- Display move history panel
- Show turn indicator (whose turn?)
- Display game over message
- Handle rematch/exit options
- Listen to WebSocket events (opponent moves, AI moves)
Services (Singleton-like, event-driven):
-
EventBus.js— Simple pub/subemit(event, data)on(event, callback)- Decouples scenes and services
-
ConnectionService.js— WebSocket clientconnect(url)→ returns Promise- Maintains
wsconnection - Heartbeat every 30 seconds (send
CODE_CLIENT_HEAD_BEAT) - Auto-reconnect on close (exponential backoff)
send(code, data)— send message to server
-
GameStateService.js— Client-side state containerroomobject (id, players, board, status)nicknamestringboard(15x15 array, mirrored from server)- Methods:
update(),reset(),addMove() - Notify listeners on state change
Game Objects (Phaser.GameObjects.*):
-
Board.js— Game board renderer- Create 15x15 grid of cells
- Wood texture background
- Cell dimensions: ~50x50 pixels
placeStone(row, col, color)method- Hover effect (highlight hovered cell)
-
Stone.js— Individual stone sprite- Phaser.GameObjects.Sprite subclass
- Gradient fill (black or white)
- Drop animation (tweens)
- Glow effect on hover
UI Components (DOM + Phaser):
-
MenuUI.js— Menu rendering- Nickname input, validation
- Room creation form (PVP/PVE selector, AI difficulty)
- Room list (with join buttons)
- Settings panel
-
GameUI.js— Game HUD- Move history panel (list of moves: 7,7 Black, 8,8 White, etc.)
- Turn indicator (waiting for opponent / your turn)
- Game over modal (winner announcement, rematch button)
- Toast notifications (connection lost, reconnected, etc.)
Build Configuration
Maven (Java)
File: pom.xml
Parent: Spring Boot 2.0.5.RELEASE
Key Plugins:
maven-compiler-plugin— Java 8 source/targetmaven-surefire-plugin— Run unit testsmaven-source-plugin— Generate source JARmaven-javadoc-plugin— Generate docs
Dependencies:
- Netty (async networking)
- Protobuf 3.25.5 (binary serialization)
- Gson (JSON parsing)
- JUnit (testing)
Modules:
landlords-common(library)landlords-server(executable JAR)landlords-client(executable JAR)
Build Command:
mvn clean package -DskipTests
# Produces:
# landlords-server/target/landlords-server-1.4.0.jar
# landlords-client/target/landlords-client-1.4.0.jar
Vite (JavaScript)
File: web-client/package.json
Scripts:
npm run dev— Start dev server (port 5173, hot reload)npm run build— Production build todist/npm run preview— Preview production build
Dependencies:
phaser ^3.87.0— Game enginevite ^6.3.1— Bundler
Output: web-client/dist/ (index.html + bundled JS)
Testing
Test Framework: JUnit 4
Test Files:
-
GomokuHelperTest.java(landlords-common)- 37+ test cases for win detection
- Tests all 4 directions (horizontal, vertical, 2 diagonals)
- Tests edge cases (board edges, corners)
- Tests draw condition (full board)
-
GomokuAITest.java(landlords-common)- Tests Easy AI (random valid moves)
- Tests Medium AI (finds winning move, blocks opponent)
- Tests Hard AI (minimax scoring)
- Tests move validity after AI selection
Run Tests:
mvn clean test
# or
mvn test -DskipTests=false
Coverage: ~100% for game logic (Board, GomokuHelper, GomokuAI)
Dependencies Summary
| Module | Dependencies |
|---|---|
| landlords-common | Netty, Protobuf, Gson, JUnit |
| landlords-server | landlords-common, Netty, Protobuf |
| landlords-client | landlords-common, Netty, Protobuf |
| web-client | Phaser 3, Vite (dev-only) |
Important Files by Feature
Game Logic
landlords-common/src/main/java/.../entity/Board.java— Board statelandlords-common/src/main/java/.../helper/GomokuHelper.java— Win detectionlandlords-common/src/main/java/.../robot/GomokuAI.java— AI engine
Networking
landlords-server/src/main/.../handler/StaticFileHandler.java— HTTP file servinglandlords-server/src/main/.../handler/WebsocketTransferHandler.java— WS codeclandlords-server/src/main/.../handler/ProtobufTransferHandler.java— TCP codecweb-client/src/services/connection-service.js— WebSocket client
Game Flow
landlords-server/src/main/.../event/ServerEventListener_CODE_GAME_MOVE.java— Move processinglandlords-server/src/main/.../event/ServerEventListener_CODE_GAME_STARTING.java— Game startweb-client/src/scenes/game-scene.js— Game rendering & input
UI
web-client/src/objects/board.js— Board rendererweb-client/src/ui/game-ui.js— HUD & notificationsweb-client/src/ui/menu-ui.js— Menus & forms
Code Quality
Metrics:
- Lines of Code: ~5,000 Java, ~1,500 JavaScript
- Test Coverage: Game logic 100%, server 80%+, client varies
- File Size: Most Java files < 200 lines, JavaScript < 300 lines
- Linting: No major violations (follow code-standards.md)
Documentation:
- Javadoc on public methods (Java)
- JSDoc on exported functions (JavaScript)
- Inline comments for complex logic
Build Artifacts
| Artifact | Location | Purpose |
|---|---|---|
| Server JAR | landlords-server/target/landlords-server-1.4.0.jar |
Executable server |
| Client JAR | landlords-client/target/landlords-client-1.4.0.jar |
Executable CLI client |
| Web dist | web-client/dist/ |
Static files for web UI |
| Source JAR | landlords-*/target/*-sources.jar |
Source code archive |
Continuous Integration
GitHub Actions:
-
Build.yml
- Trigger: Push to any branch
- Steps:
- Checkout code
- Setup Java 8
- Run
mvn clean test - Run
npm install && npm run build(web-client)
-
deploy-pages.yml
- Trigger: Push to
master - Steps:
- Build web-client
- Deploy to GitHub Pages (
https://tiennm99.github.io/caro/)
- Trigger: Push to
Version & Release
Current Version: 1.4.0
Release Process:
- Tag commit:
git tag v1.4.0 - Push tag:
git push origin v1.4.0 - Create GitHub Release with JAR artifacts
- Auto-deploy web-client to Pages
Versioning: Semantic versioning (MAJOR.MINOR.PATCH)