mirror of
https://github.com/tiennm99/caro.git
synced 2026-05-14 02:57:42 +00:00
cbad690565
Phase 05 — sync infrastructure and documentation with the typed-protobuf refactor: - docker-compose.yml: drop 1024/1025 mappings, single "1999:1999" - server/Dockerfile: EXPOSE 1999, -p 1999 entrypoint - README.md: rewrite transport description, architecture diagram, protocol section, server options, project structure, add proto:gen script note - docs/project-overview.md: update transport + dependencies sections - docs/system-architecture.md: rewrite diagrams + pipeline + file inventory for the WebSocket-only typed-dispatch path - docs/codebase-summary.md: refresh file tree, java package inventory, gradle deps, vite deps, networking and game-flow sections - docs/deployment-guide.md: single-port walkthrough for local / docker / systemd / nginx; remove all 1024/1025 firewall and troubleshooting - docs/code-standards.md: replace dead ServerEventListener_CODE_* class-name example, fix sample ws:// URL to port 1999
322 lines
13 KiB
Markdown
322 lines
13 KiB
Markdown
# Codebase Summary
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
caro/
|
|
├── .github/
|
|
│ └── workflows/
|
|
│ └── build.yml CI: build + test (Java 25 + Node 22)
|
|
├── server/ Standalone Netty server (Java 25, Gradle)
|
|
│ ├── src/main/java/com/miti99/caro/
|
|
│ │ ├── common/
|
|
│ │ │ ├── channel/ Netty utilities (ChannelUtils)
|
|
│ │ │ ├── entity/ Data models (Board, Room, GameMove, ClientSide)
|
|
│ │ │ ├── enums/ ClientEventCode, PieceType, GameResult, RoomType, etc.
|
|
│ │ │ ├── exception/ LandlordException
|
|
│ │ │ ├── features/ Feature flags
|
|
│ │ │ ├── helper/ GomokuHelper (win detection)
|
|
│ │ │ ├── print/ SimplePrinter
|
|
│ │ │ ├── robot/ AI engine (GomokuAI)
|
|
│ │ │ └── utils/ ListUtils, OptionsUtils, StreamUtils
|
|
│ │ └── server/
|
|
│ │ ├── event/
|
|
│ │ │ ├── request/ ClientRequest sealed interface + record variants (14 types)
|
|
│ │ │ ├── handler/ 14 typed request handlers (*Handler.java)
|
|
│ │ │ ├── RequestConverter.java Protobuf→ClientRequest conversion
|
|
│ │ │ └── RequestDispatcher.java Pattern-match dispatch logic
|
|
│ │ ├── handler/ Netty pipeline (WebsocketTransferHandler)
|
|
│ │ ├── timer/ RoomClearTask
|
|
│ │ ├── SimpleServer.java Server entry point
|
|
│ │ └── ServerContains.java Global state container
|
|
│ ├── src/main/proto/
|
|
│ │ ├── request.proto Client→server typed message definitions
|
|
│ │ └── response.proto Server→client typed message definitions
|
|
│ ├── src/test/java/com/miti99/caro/common/
|
|
│ │ ├── helper/tests/GomokuHelperTest.java 29 JUnit 5 tests
|
|
│ │ └── robot/tests/GomokuAITest.java 8 JUnit 5 tests
|
|
│ ├── gradle/wrapper/ Gradle wrapper (9.2.1)
|
|
│ ├── gradlew, gradlew.bat Wrapper launchers
|
|
│ ├── settings.gradle.kts Root project name
|
|
│ ├── build.gradle.kts Standalone build (Kotlin DSL) with Shadow plugin
|
|
│ └── Dockerfile Multi-stage (eclipse-temurin:25-jdk, eclipse-temurin:25-jre-alpine)
|
|
├── client/ Phaser 3 + Vite 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
|
|
│ ├── Dockerfile Nginx-based static server
|
|
│ ├── index.html
|
|
│ ├── vite.config.js
|
|
│ └── package.json caro-client 0.0.1
|
|
├── docs/ (this directory)
|
|
│ ├── project-overview.md
|
|
│ ├── system-architecture.md
|
|
│ ├── codebase-summary.md
|
|
│ ├── code-standards.md
|
|
│ └── deployment-guide.md
|
|
├── plans/ Implementation plans
|
|
├── docker-compose.yml services: server, client
|
|
├── README.md
|
|
├── LICENSE
|
|
└── .gitignore
|
|
```
|
|
|
|
---
|
|
|
|
## Key Java Packages
|
|
|
|
### `com.miti99.caro.common` (Shared code)
|
|
|
|
**Entities:**
|
|
- `Board.java` — 15x15 game board, move validation, win/draw detection (`BOARD_SIZE=15`, `WIN_CONDITION=5`)
|
|
- `Room.java` — Game session state (id, type, status, players, board, moveHistory)
|
|
- `GameMove.java` — Single move (row, col, piece, playerId, timestamp)
|
|
- `ClientSide.java` — Player connection state (nickname, status, role)
|
|
- Generated proto messages — `Request`, `Response` oneof wrappers (in `server/build/generated/sources/proto/main/java/`)
|
|
|
|
**Enums:**
|
|
- `ServerEventCode` — client→server action codes
|
|
- `ClientEventCode` — server→client response codes
|
|
- `PieceType` — EMPTY, BLACK, WHITE
|
|
- `GameResult` — IN_PROGRESS, BLACK_WIN, WHITE_WIN, DRAW
|
|
- `RoomType`, `RoomStatus`, `ClientRole`, `ClientStatus`
|
|
|
|
**Game Logic:**
|
|
- `GomokuHelper.java` — Win detection (4 directions), board rendering
|
|
- `GomokuAI.java` — AI move selection (Easy/Medium/Hard)
|
|
|
|
**Utilities:**
|
|
- `ListUtils`, `OptionsUtils`, `StreamUtils`
|
|
|
|
**Dispatch (typed records):**
|
|
- `ClientRequest` — Sealed interface representing all possible client requests (14 variants)
|
|
- Record types: `SetNicknameRequest`, `CreateRoomRequest`, `CreatePveRoomRequest`, `GetRoomsRequest`, `JoinRoomRequest`, `GameStartingRequest`, `GameReadyRequest`, `GameMoveRequest`, `GameResetRequest`, `WatchGameRequest`, `WatchGameExitRequest`, `ClientExitRequest`, `ClientOfflineRequest`, `SetClientInfoRequest`
|
|
|
|
---
|
|
|
|
### `com.miti99.caro.server` (Server code)
|
|
|
|
**Entry Point:**
|
|
- `SimpleServer.java` — Bootstrap (WebSocket server defaults to port 1999 at `/ratel`)
|
|
- `ServerContains.java` — Singleton global state (rooms, client sides, channel map)
|
|
|
|
**Event Handlers (14 *Handler classes):**
|
|
- `SetNicknameHandler`, `CreateRoomHandler`, `CreatePveRoomHandler`, `GetRoomsHandler`, `JoinRoomHandler`
|
|
- `GameStartingHandler`, `GameReadyHandler`, `GameMoveHandler`, `GameResetHandler`
|
|
- `WatchGameHandler`, `WatchGameExitHandler`, `ClientExitHandler`, `ClientOfflineHandler`, `SetClientInfoHandler`
|
|
|
|
**Request Processing:**
|
|
- `RequestConverter` — Decodes `Request` oneof from binary wire format → typed `ClientRequest` variant
|
|
- `RequestDispatcher` — Pattern-matches `ClientRequest` variant → dispatches to corresponding handler
|
|
|
|
**Network Handler:**
|
|
- `WebsocketTransferHandler` — Netty pipeline handler: decodes binary frame to `Request` protobuf message
|
|
|
|
**Background Tasks:**
|
|
- `RoomClearTask` — Periodic cleanup
|
|
|
|
---
|
|
|
|
## Client (JavaScript/Phaser 3)
|
|
|
|
**Boot:**
|
|
- `main.js` — Create Phaser game instance, start boot scene
|
|
|
|
**Config:**
|
|
- `game-config.js` — Phaser config (800x800, Scale.FIT, scenes: [BootScene, MenuScene, GameScene])
|
|
- `protocol-constants.js` — Export event code enums matching server
|
|
|
|
**Scenes:**
|
|
- `BootScene` — Create services, connect WebSocket, load assets, transition to menu
|
|
- `MenuScene` — Nickname input, lobby, room list, difficulty selector
|
|
- `GameScene` — Board + stones, click handling, move history, turn indicator, game over
|
|
|
|
**Services:**
|
|
- `EventBus` — Pub/sub decoupling scenes and services
|
|
- `ConnectionService` — WebSocket client with heartbeat + auto-reconnect
|
|
- `GameStateService` — Client-side state container
|
|
|
|
**Game Objects:**
|
|
- `Board` — 15x15 wood-textured grid
|
|
- `Stone` — Gradient stone sprite with drop animation
|
|
|
|
**UI:**
|
|
- `MenuUI` — Nickname form, room list, settings
|
|
- `GameUI` — HUD, move history, game over modal, toasts
|
|
|
|
---
|
|
|
|
## Build Configuration
|
|
|
|
### Gradle (Java)
|
|
|
|
**Files:**
|
|
- `server/build.gradle.kts` — standalone Gradle build script (Kotlin DSL)
|
|
- `server/settings.gradle.kts` — root project name (`caro-server`)
|
|
- `server/gradle/wrapper/` — committed wrapper (Gradle 9.2.1)
|
|
- `server/gradlew` / `server/gradlew.bat` — wrapper launchers
|
|
|
|
**Coordinates:** `com.miti99.caro:caro-server:0.0.1`
|
|
|
|
**Plugins:**
|
|
- `java` — standard Java plugin
|
|
- `com.google.protobuf:0.9.6` — protobuf code generation
|
|
- `com.gradleup.shadow:8.3.8` — fat jar packaging
|
|
|
|
**Toolchain:** `JavaLanguageVersion.of(25)` — Gradle auto-provisions Java 25 if missing.
|
|
|
|
**Dependencies:**
|
|
- `io.netty:netty-all:4.1.128.Final` — async networking
|
|
- `com.google.protobuf:protobuf-java:3.25.5` — binary serialization, generated code
|
|
- `com.google.protobuf:protoc:3.25.5` — protobuf compiler (build time)
|
|
- `org.junit:junit-bom:5.11.4` (platform) + `org.junit.jupiter:junit-jupiter` — testing
|
|
|
|
**Shadow jar config:**
|
|
- Main class: `com.miti99.caro.server.SimpleServer`
|
|
- No special command-line args (server defaults to port 1999)
|
|
- `mergeServiceFiles()` — preserve Netty SPIs
|
|
- Excludes signing metadata (`*.SF`, `*.DSA`, `*.RSA`)
|
|
|
|
**Build Command:**
|
|
```bash
|
|
./server/gradlew -p server clean build
|
|
# Produces: server/build/libs/caro-server-0.0.1.jar (shaded fat jar)
|
|
```
|
|
|
|
### Vite (JavaScript)
|
|
|
|
**File:** `client/package.json`
|
|
|
|
**Package:** `caro-client` 0.0.1
|
|
|
|
**Scripts:**
|
|
- `npm run dev` — Dev server (port 5173, hot reload)
|
|
- `npm run build` — Production build to `dist/`
|
|
- `npm run preview` — Preview production build
|
|
- `npm run proto:gen` — Regenerate protobuf code from server `.proto` files (uses `pbjs` + `pbts`)
|
|
|
|
**Dependencies:**
|
|
- `phaser ^3.87.0` — Game engine
|
|
- `protobufjs ^7.5.4` — JavaScript protobuf codec
|
|
- `vite ^6.3.1` — Bundler (dev-only)
|
|
- `@protobufjs/cli ^1.1.3` — Protobuf code generator (dev-only)
|
|
|
|
**Output:** `client/dist/` (index.html + bundled JS, ~1.5 MB / 346 KB gzipped)
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
**Test Framework:** JUnit 5 (`org.junit.jupiter.api`)
|
|
|
|
**Test Files:**
|
|
1. `server/src/test/java/com/miti99/caro/common/helper/tests/GomokuHelperTest.java` — 29 tests (win detection, edges, draw, game flow)
|
|
2. `server/src/test/java/com/miti99/caro/common/robot/tests/GomokuAITest.java` — 8 tests (Easy/Medium/Hard AI)
|
|
|
|
**Run Tests:**
|
|
```bash
|
|
./server/gradlew -p server clean test
|
|
```
|
|
|
|
**Coverage:** ~100% for game logic (Board, GomokuHelper, GomokuAI)
|
|
|
|
---
|
|
|
|
## Dependencies Summary
|
|
|
|
| Scope | Dependencies |
|
|
|-------|--------------|
|
|
| **server runtime** | Netty 4.1.128, Protobuf 3.25.5 (generated code) |
|
|
| **server test** | JUnit Jupiter 5.11.4 |
|
|
| **server build** | Gradle 9.2.1, Protobuf Gradle plugin 0.9.6, Shadow 8.3.8 |
|
|
| **client runtime** | Phaser 3.87, protobufjs 7.5.4 |
|
|
| **client build** | Vite 6.3, protobufjs-cli 1.1.3 |
|
|
|
|
---
|
|
|
|
## Important Files by Feature
|
|
|
|
### Game Logic
|
|
- `server/src/main/java/com/miti99/caro/common/entity/Board.java`
|
|
- `server/src/main/java/com/miti99/caro/common/helper/GomokuHelper.java`
|
|
- `server/src/main/java/com/miti99/caro/common/robot/GomokuAI.java`
|
|
|
|
### Networking
|
|
- `server/src/main/java/com/miti99/caro/server/handler/WebsocketTransferHandler.java` — Binary decoder
|
|
- `server/src/main/java/com/miti99/caro/server/event/RequestConverter.java` — Protobuf→record conversion
|
|
- `server/src/main/java/com/miti99/caro/server/event/RequestDispatcher.java` — Dispatch logic
|
|
- `server/src/main/java/com/miti99/caro/common/channel/ChannelUtils.java` — Response encoder/sender
|
|
- `client/src/services/connection-service.js` — WebSocket client (binary mode)
|
|
- `server/src/main/proto/*.proto` — Message definitions
|
|
|
|
### Game Flow
|
|
- `server/src/main/java/com/miti99/caro/server/event/handler/GameMoveHandler.java`
|
|
- `server/src/main/java/com/miti99/caro/server/event/handler/GameStartingHandler.java`
|
|
- `client/src/scenes/game-scene.js`
|
|
|
|
### UI
|
|
- `client/src/objects/board.js`
|
|
- `client/src/ui/game-ui.js`
|
|
- `client/src/ui/menu-ui.js`
|
|
|
|
---
|
|
|
|
## Code Quality
|
|
|
|
**Metrics:**
|
|
- **Lines of Code:** ~5,000 Java, ~1,500 JavaScript
|
|
- **Test Coverage:** Game logic ~100%, server flow ~80%, client varies
|
|
- **File Size:** Most Java files < 200 lines, JavaScript < 300 lines
|
|
|
|
**Java 25 features in use:**
|
|
- `record` for immutable DTOs (`Msg`)
|
|
- Switch expressions (`GomokuHelper.getWinnerMessage`, `GomokuAI.getNextMove`)
|
|
- `var` for obvious local types
|
|
|
|
---
|
|
|
|
## Build Artifacts
|
|
|
|
| Artifact | Location | Purpose |
|
|
|----------|----------|---------|
|
|
| Server jar | `server/build/libs/caro-server-0.0.1.jar` | Shaded executable fat jar |
|
|
| Client dist | `client/dist/` | Static files for web UI |
|
|
|
|
---
|
|
|
|
## Continuous Integration
|
|
|
|
**GitHub Actions:**
|
|
|
|
**build.yml**
|
|
- Trigger: push/PR on master (ignores `.md` and `.gitignore`)
|
|
- Jobs:
|
|
- `build-server` — Setup Java 25 (Temurin) + `gradle/actions/setup-gradle`, run `./gradlew -p server --no-daemon clean build`
|
|
- `build-client` — Setup Node 22, `npm ci`, `npm run build`
|
|
|
|
Deployment is handled via Docker Compose from this repo; there is no hosted deployment pipeline.
|
|
|
|
---
|
|
|
|
## Version & Release
|
|
|
|
**Current Version:** 0.0.1 (both `caro-server` and `caro-client`)
|
|
|
|
**Versioning:** Semantic versioning (MAJOR.MINOR.PATCH).
|