Replace server/pom.xml with Gradle 9.2.1 (Kotlin DSL) + Shadow plugin for fat jar packaging. New files: - server/build.gradle.kts (Kotlin DSL script) - server/settings.gradle.kts - server/gradle/wrapper/ (committed wrapper, pinned to 9.2.1) - server/gradlew, gradlew.bat Deleted: - server/pom.xml Gradle config: - plugins: java, com.gradleup.shadow 8.3.5 - toolchain: JavaLanguageVersion.of(25) (auto-provisions if missing) - deps: netty-all 4.1.115.Final, protobuf-java 3.25.5, gson 2.11.0, junit-bom 5.11.3 + junit-jupiter (test) - compiler: -parameters, UTF-8 - test: useJUnitPlatform() - shadowJar: main class com.miti99.caro.server.SimpleServer, mergeServiceFiles(), append META-INF/io.netty.versions.properties - default assembly depends on shadowJar Output path migration: - server/target/caro-server-0.0.1-beta.jar moves under Gradle output conventions. Infrastructure: - server/Dockerfile: eclipse-temurin:25-jdk + committed wrapper (no Maven image); runtime stage unchanged. COPY order optimized. - .github/workflows/build.yml: setup-java temurin 25 + gradle/actions/setup-gradle, run gradlew with -p server. - .gitignore: add .gradle/, whitelist wrapper jar after *.jar rule. Docs + README fully updated to Gradle commands across: README.md, codebase-summary.md, code-standards.md, deployment-guide.md, project-overview.md, system-architecture.md. Validation: gradlew clean assemble check passes all 37 tests on Java 25.
12 KiB
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, Msg, ClientSide)
│ │ │ ├── enums/ ServerEventCode, ClientEventCode, PieceType, etc.
│ │ │ ├── exception/ LandlordException
│ │ │ ├── features/ Feature flags
│ │ │ ├── handler/ Protocol codec (DefaultDecoder)
│ │ │ ├── helper/ GomokuHelper, MapHelper
│ │ │ ├── print/ SimplePrinter
│ │ │ ├── robot/ AI engine (GomokuAI)
│ │ │ ├── transfer/ Binary serialization (ByteKit, ByteLink, TransferProtocolUtils)
│ │ │ └── utils/ JsonUtils (gson), ListUtils, OptionsUtils, StreamUtils
│ │ └── server/
│ │ ├── event/ ServerEventListener_* handlers
│ │ ├── handler/ Netty pipeline (Protobuf/WS codecs)
│ │ ├── proxy/ ProtobufProxy, WebsocketProxy
│ │ ├── timer/ RoomClearTask
│ │ ├── SimpleServer.java Server entry point
│ │ └── ServerContains.java Global state container
│ ├── src/main/resources/
│ │ └── proto/ .proto files + generate.sh (future proto-over-WS)
│ ├── 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-beta
├── 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)Msg.java— WebSocket JSON envelope (record: code, data, info)ServerTransferData.java/ClientTransferData.java— Protobuf-generated wire typesClientSide.java— Player connection state (nickname, status, role)
Enums:
ServerEventCode— client→server action codesClientEventCode— server→client response codesPieceType— EMPTY, BLACK, WHITEGameResult— IN_PROGRESS, BLACK_WIN, WHITE_WIN, DRAWRoomType,RoomStatus,ClientRole,ClientStatus
Game Logic:
GomokuHelper.java— Win detection (4 directions), board renderingGomokuAI.java— AI move selection (Easy/Medium/Hard)
Utilities:
JsonUtils.java— gson wrapper (toJson,fromJson)ListUtils,OptionsUtils,StreamUtilsMapHelper.java— Fluent map builder (uses gson)
Protocol:
ByteKit,ByteLink— Byte buffer operationsTransferProtocolUtils.java— Protocol framing (#...$delimiters, gson JSON body)DefaultDecoder.java— Protobuf message decoder
com.miti99.caro.server (Server code)
Entry Point:
SimpleServer.java— Bootstrap (-p {port}, default 1024)- Starts TCP proxy on
portand WebSocket proxy onport+1
- Starts TCP proxy on
ServerContains.java— Singleton global state (rooms, client sides, channel map)
Event Handlers (ServerEventListener_*):
CODE_CLIENT_NICKNAME_SET,CODE_ROOM_CREATE,CODE_ROOM_CREATE_PVE,CODE_GET_ROOMSCODE_ROOM_JOIN,CODE_GAME_STARTING,CODE_GAME_READY,CODE_GAME_MOVECODE_GAME_WATCH/CODE_GAME_WATCH_EXIT,CODE_CLIENT_OFFLINE
Network Handlers:
ProtobufTransferHandler— TCP/Protobuf codecWebsocketTransferHandler— WebSocket JSON codec (usesJsonUtils.fromJson(text, Msg.class))SecondProtobufCodec— Second-pass protobuf decoder
Message Proxies:
ProtobufProxy— TCP server bootstrapWebsocketProxy— WebSocket server bootstrap (no static file handler; non-WS HTTP → default Netty 400/403)
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 menuMenuScene— Nickname input, lobby, room list, difficulty selectorGameScene— Board + stones, click handling, move history, turn indicator, game over
Services:
EventBus— Pub/sub decoupling scenes and servicesConnectionService— WebSocket client with heartbeat + auto-reconnectGameStateService— Client-side state container
Game Objects:
Board— 15x15 wood-textured gridStone— Gradient stone sprite with drop animation
UI:
MenuUI— Nickname form, room list, settingsGameUI— 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-beta
Plugins:
java— standard Java plugincom.gradleup.shadow:8.3.5— fat jar packaging
Toolchain: JavaLanguageVersion.of(25) — Gradle auto-provisions Java 25 if missing.
Dependencies:
io.netty:netty-all:4.1.115.Final— async networkingcom.google.protobuf:protobuf-java:3.25.5— binary serializationcom.google.code.gson:gson:2.11.0— JSON (supports records)org.junit:junit-bom:5.11.3(platform) +org.junit.jupiter:junit-jupiter— testing
Shadow jar config:
- Main class:
com.miti99.caro.server.SimpleServer mergeServiceFiles()— preserve Netty SPIsappend("META-INF/io.netty.versions.properties")— merge Netty version file- Excludes signing metadata (
*.SF,*.DSA,*.RSA)
Build Command:
./server/gradlew -p server clean build
# Produces: server/build/libs/caro-server-0.0.1-beta.jar (shaded fat jar)
Vite (JavaScript)
File: client/package.json
Package: caro-client 0.0.1-beta
Scripts:
npm run dev— 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 (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:
server/src/test/java/com/miti99/caro/common/helper/tests/GomokuHelperTest.java— 29 tests (win detection, edges, draw, game flow)server/src/test/java/com/miti99/caro/common/robot/tests/GomokuAITest.java— 8 tests (Easy/Medium/Hard AI)
Run Tests:
./server/gradlew -p server clean test
Coverage: ~100% for game logic (Board, GomokuHelper, GomokuAI)
Dependencies Summary
| Scope | Dependencies |
|---|---|
| server runtime | Netty 4.1.115, Protobuf 3.25.5, gson 2.11.0 |
| server test | JUnit Jupiter 5.11.3 |
| client runtime | Phaser 3.87 |
| client build | Vite 6.3 |
Important Files by Feature
Game Logic
server/src/main/java/com/miti99/caro/common/entity/Board.javaserver/src/main/java/com/miti99/caro/common/helper/GomokuHelper.javaserver/src/main/java/com/miti99/caro/common/robot/GomokuAI.java
Networking
server/src/main/java/com/miti99/caro/server/handler/WebsocketTransferHandler.javaserver/src/main/java/com/miti99/caro/server/handler/ProtobufTransferHandler.javaserver/src/main/java/com/miti99/caro/common/channel/ChannelUtils.javaclient/src/services/connection-service.js
Game Flow
server/src/main/java/com/miti99/caro/server/event/ServerEventListener_CODE_GAME_MOVE.javaserver/src/main/java/com/miti99/caro/server/event/ServerEventListener_CODE_GAME_STARTING.javaclient/src/scenes/game-scene.js
UI
client/src/objects/board.jsclient/src/ui/game-ui.jsclient/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:
recordfor immutable DTOs (Msg)- Switch expressions (
GomokuHelper.getWinnerMessage,GomokuAI.getNextMove) varfor obvious local types
Build Artifacts
| Artifact | Location | Purpose |
|---|---|---|
| Server jar | server/build/libs/caro-server-0.0.1-beta.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
.mdand.gitignore) - Jobs:
build-server— Setup Java 25 (Temurin) +gradle/actions/setup-gradle, run./gradlew -p server --no-daemon clean buildbuild-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-beta (both caro-server and caro-client)
Versioning: Semantic versioning (MAJOR.MINOR.PATCH) with -beta suffix during pre-1.0.