|
| 1 | +# Copilot Instructions for surf-cloud |
| 2 | + |
| 3 | +## Repository Overview |
| 4 | + |
| 5 | +surf-cloud is a Minecraft cloud/networking system that facilitates communication between Minecraft servers (Paper/Bukkit, Velocity proxy) and a standalone server. It's a multi-module Gradle project written primarily in Kotlin with some Java, totaling ~50,000 lines of code. The system uses Netty for network communication, Spring Boot for the server components, and provides APIs for client-server packet-based communication. |
| 6 | + |
| 7 | +**Project Type**: Multi-module Gradle project (Kotlin/Java) |
| 8 | +**Primary Languages**: Kotlin (95%), Java (5%) |
| 9 | +**Target Runtime**: JDK 21 (configured in CI), local development works with JDK 17+ |
| 10 | +**Gradle Version**: 8.14.3 |
| 11 | +**Key Frameworks**: Spring Boot 3.5.6, Netty 4.2.6, Ktor 3.3.0, Exposed ORM 0.61.0 |
| 12 | + |
| 13 | +## Build and Validation |
| 14 | + |
| 15 | +### Prerequisites |
| 16 | + |
| 17 | +- **Java 17 or higher** (JDK 21 preferred for CI compatibility) |
| 18 | +- **Network access to `https://repo.slne.dev/repository/maven-public/`** - This is a **required** private Maven repository for the custom `surf-api-gradle-plugin`. Builds will fail without this access. |
| 19 | + |
| 20 | +### Core Build Commands |
| 21 | + |
| 22 | +**IMPORTANT**: Always run builds from the repository root (`/home/runner/work/surf-cloud/surf-cloud`). |
| 23 | + |
| 24 | +#### Standard Build |
| 25 | +```bash |
| 26 | +./gradlew build |
| 27 | +``` |
| 28 | +- **Expected duration**: 5-10 minutes on first run (downloads dependencies) |
| 29 | +- **Expected duration**: 2-5 minutes on subsequent runs (with Gradle daemon) |
| 30 | +- **What it does**: Compiles all modules, runs tests, generates artifacts |
| 31 | +- **Timeout setting**: Use `timeout: 300` seconds minimum for bash tool |
| 32 | +- **Cache location**: `.gradle/` and `build/` directories |
| 33 | + |
| 34 | +#### Clean Build |
| 35 | +```bash |
| 36 | +./gradlew clean build |
| 37 | +``` |
| 38 | +- **When to use**: After major dependency changes or when builds behave unexpectedly |
| 39 | +- **Expected duration**: 5-10 minutes |
| 40 | + |
| 41 | +#### Build Specific Module |
| 42 | +```bash |
| 43 | +./gradlew :surf-cloud-api:surf-cloud-api-common:build |
| 44 | +``` |
| 45 | + |
| 46 | +#### Run Tests |
| 47 | +```bash |
| 48 | +./gradlew test |
| 49 | +``` |
| 50 | +- **Expected duration**: 1-3 minutes |
| 51 | +- **Test locations**: `*/src/test/` directories (limited test coverage exists) |
| 52 | + |
| 53 | +#### Code Quality Check (Qodana) |
| 54 | +- Runs automatically on PRs and master branch via GitHub Actions |
| 55 | +- Uses JetBrains Qodana with profile `qodana.starter` |
| 56 | +- Configuration: `qodana.yaml` in root |
| 57 | +- Target JDK: 21 (as configured in qodana.yaml) |
| 58 | + |
| 59 | +### Build Troubleshooting |
| 60 | + |
| 61 | +**Network Dependency Issue**: If you see `Could not GET 'https://repo.slne.dev/repository/maven-public/...'`, the private Maven repository is inaccessible. This is a blocker for builds and cannot be worked around without repository access. |
| 62 | + |
| 63 | +**Gradle Daemon Issues**: If builds hang or behave strangely: |
| 64 | +```bash |
| 65 | +./gradlew --stop |
| 66 | +./gradlew clean build |
| 67 | +``` |
| 68 | + |
| 69 | +**Out of Memory**: The project is configured with `org.gradle.jvmargs=-Xmx4G` in `gradle.properties`. If you encounter OOM errors, this may need to be increased. |
| 70 | + |
| 71 | +## Project Architecture |
| 72 | + |
| 73 | +### Module Structure |
| 74 | + |
| 75 | +The project follows a layered architecture with clear separation between API, implementation, and platform-specific code: |
| 76 | + |
| 77 | +``` |
| 78 | +surf-cloud/ |
| 79 | +├── surf-cloud-api/ # Public APIs (client & server) |
| 80 | +│ ├── surf-cloud-api-common/ # Common API (packets, networking, player) |
| 81 | +│ ├── surf-cloud-api-server/ # Server-side API (commands, JPA, Ktor) |
| 82 | +│ └── surf-cloud-api-client/ # Client-side API |
| 83 | +│ ├── surf-cloud-api-client-common/ |
| 84 | +│ ├── surf-cloud-api-client-paper/ # Paper-specific API |
| 85 | +│ └── surf-cloud-api-client-velocity/ # Velocity-specific API |
| 86 | +├── surf-cloud-core/ # Core implementations |
| 87 | +│ ├── surf-cloud-core-common/ # Common core logic |
| 88 | +│ └── surf-cloud-core-client/ # Client-side core |
| 89 | +├── surf-cloud-bukkit/ # Paper/Bukkit plugin implementation |
| 90 | +├── surf-cloud-velocity/ # Velocity proxy plugin implementation |
| 91 | +├── surf-cloud-standalone/ # Standalone server (Spring Boot app) |
| 92 | +├── surf-cloud-standalone-launcher/ # Launcher for standalone (Java) |
| 93 | +├── surf-cloud-bom/ # Bill of Materials (dependency versions) |
| 94 | +└── surf-cloud-test-plugin/ # Test plugins (excluded from CI) |
| 95 | +``` |
| 96 | + |
| 97 | +### Key Configuration Files |
| 98 | + |
| 99 | +- **Root `build.gradle.kts`**: Configures all subprojects, shadow JAR settings, API validation |
| 100 | +- **`settings.gradle.kts`**: Defines module structure and CI-specific includes |
| 101 | +- **`gradle.properties`**: Gradle daemon settings, JVM args, Kotlin config, project version |
| 102 | +- **`buildSrc/`**: Custom Gradle convention plugins |
| 103 | + - `core-convention.gradle.kts`: Common dependencies (Spring Boot, Ktor, Kotlin wrappers) |
| 104 | + - `dokka-convention.gradle.kts`: Documentation generation |
| 105 | + - `exclude-kotlin.gradle.kts`: Kotlin stdlib exclusion |
| 106 | +- **`gradle/libs.versions.toml`**: Version catalog for all dependencies |
| 107 | +- **`.gitlab-ci.yml`**: CI pipeline (build → test → deploy → docs) |
| 108 | +- **`.github/workflows/qodana_code_quality.yml`**: Code quality checks |
| 109 | +- **`qodana.yaml`**: Qodana configuration (JDK 21, linter: jetbrains/qodana-jvm:2024.3) |
| 110 | + |
| 111 | +### Entry Points |
| 112 | + |
| 113 | +- **Bukkit/Paper Plugin**: `dev.slne.surf.cloud.bukkit.PaperMain` (main) and `PaperBootstrap` (bootstrapper) |
| 114 | +- **Velocity Plugin**: `dev.slne.surf.cloud.velocity.VelocityMain` |
| 115 | +- **Standalone Server**: `dev.slne.surf.cloud.standalone.Bootstrap` (Spring Boot application) |
| 116 | +- **Standalone Launcher**: `dev.slne.surf.cloud.launcher.Main` (Java application) |
| 117 | + |
| 118 | +### Dependencies Not Obvious from Structure |
| 119 | + |
| 120 | +1. **Custom Gradle Plugin**: The project depends on a private Gradle plugin (`dev.slne.surf:surf-api-gradle-plugin:1.21.10+`) hosted at `https://repo.slne.dev/`. This plugin provides tasks for Paper/Velocity plugin configuration and standalone server setup. |
| 121 | + |
| 122 | +2. **Generated Code**: `surf-cloud-api-common` generates `StreamCodecComposites.kt` during build (arity 2-20 composite codecs). This runs via the `generateStreamCodecComposites` task. |
| 123 | + |
| 124 | +3. **Version Resource**: `surf-cloud-api-common` writes the project version to `src/main/resources/cloud.version` during `processResources`. |
| 125 | + |
| 126 | +4. **Spring Boot Configuration Processor**: Used across modules but only as `compileOnly` dependency. |
| 127 | + |
| 128 | +5. **LuckPerms API**: Required server dependency for the Bukkit plugin. |
| 129 | + |
| 130 | +6. **Voicechat API**: Optional (soft) dependency for voice chat mute functionality. |
| 131 | + |
| 132 | +## Coding Standards |
| 133 | + |
| 134 | +From `AGENTS.md`: |
| 135 | + |
| 136 | +- **Style**: Kotlin standard style with 4-space indentation, no trailing whitespace, files end with newline |
| 137 | +- **Build Requirement**: **ALWAYS run `./gradlew build` after modifying code.** The build must succeed before committing. |
| 138 | +- **Commit Messages**: Short (50 chars max), imperative mood |
| 139 | +- **PR Description**: Summarize changes and mention build results |
| 140 | + |
| 141 | +Additional conventions observed in codebase: |
| 142 | + |
| 143 | +- **Package Structure**: `dev.slne.surf.cloud.{module}.{feature}` |
| 144 | +- **Packet Classes**: Annotated with `@SurfNettyPacket`, extend `NettyPacket`, have packet codec |
| 145 | +- **Packet Listeners**: Methods annotated with `@SurfPacketListener`, must be in Spring components |
| 146 | +- **API Annotations**: Internal APIs marked with `@InternalApi` annotation |
| 147 | +- **TODO Comments**: Many TODOs exist in code (see surf-cloud-standalone especially) - these are known and not errors |
| 148 | + |
| 149 | +## Common Workflows |
| 150 | + |
| 151 | +### Adding a New Packet |
| 152 | + |
| 153 | +1. Create packet class in appropriate API module extending `NettyPacket` |
| 154 | +2. Annotate with `@SurfNettyPacket` |
| 155 | +3. Implement packet codec with `StreamCodec` |
| 156 | +4. Add constructor with `SurfByteBuf` parameter |
| 157 | +5. Add `write(buf: SurfByteBuf)` method |
| 158 | +6. Build and test: `./gradlew build` |
| 159 | + |
| 160 | +### Adding a New Module Dependency |
| 161 | + |
| 162 | +1. Add dependency to module's `build.gradle.kts` |
| 163 | +2. If it's a new library, add version to `gradle/libs.versions.toml` first |
| 164 | +3. Run `./gradlew build` to verify dependency resolution |
| 165 | +4. Check for dependency conflicts in output |
| 166 | + |
| 167 | +### Running Locally |
| 168 | + |
| 169 | +**Standalone Server**: |
| 170 | +```bash |
| 171 | +./gradlew :surf-cloud-standalone:bootJar |
| 172 | +java -jar surf-cloud-standalone/build/libs/surf-cloud-standalone-*.jar |
| 173 | +``` |
| 174 | + |
| 175 | +**Bukkit Plugin**: |
| 176 | +```bash |
| 177 | +./gradlew :surf-cloud-bukkit:runServer |
| 178 | +``` |
| 179 | +(Configured with JVM arg: `-Dsurf.cloud.serverName=test-server01`) |
| 180 | + |
| 181 | +### Certificate Generation |
| 182 | + |
| 183 | +The system uses TLS certificates for secure communication. Initial setup requires: |
| 184 | + |
| 185 | +1. Run standalone server to generate server keys |
| 186 | +2. Run client (will fail) to generate folder structure |
| 187 | +3. Copy `ca.pem` from standalone to client's `certificates/` folder |
| 188 | +4. Restart client |
| 189 | + |
| 190 | +Use `cert_generation/generate_keys.sh` for generating certificates. |
| 191 | + |
| 192 | +## CI/CD Pipeline |
| 193 | + |
| 194 | +**GitLab CI** (`.gitlab-ci.yml`): |
| 195 | +- **Stages**: build → test → deploy → build_docs → test_docs → deploy_docs |
| 196 | +- **Java Image**: `eclipse-temurin:21-jdk-alpine` |
| 197 | +- **Build Cache**: Enabled for `gradle/wrapper/` and `cache/` directories |
| 198 | +- **Test Stage**: Runs `./gradlew test` |
| 199 | +- **Deploy Stage**: Runs `./gradlew publish` (publishes to Maven repository) |
| 200 | +- **Docs**: Uses Writerside for documentation generation and deployment |
| 201 | + |
| 202 | +**GitHub Actions**: |
| 203 | +- **Qodana**: Runs on PRs and master branch pushes |
| 204 | +- **JDK**: Uses JDK 21 for Qodana analysis |
| 205 | +- **Environment**: Production environment with Qodana token |
| 206 | + |
| 207 | +## Important Notes for Coding Agents |
| 208 | + |
| 209 | +1. **Trust Build System**: The Gradle configuration is complex but complete. Don't add build workarounds unless absolutely necessary. |
| 210 | + |
| 211 | +2. **Module Dependencies**: Respect the dependency hierarchy: |
| 212 | + - API modules should NOT depend on core/implementation modules |
| 213 | + - Client modules should NOT depend on server modules |
| 214 | + - BOM module defines platform dependencies |
| 215 | + |
| 216 | +3. **Spring Boot Logging**: The project uses Log4j2, NOT Logback. Logback is explicitly excluded in multiple places. |
| 217 | + |
| 218 | +4. **Kotlin Stdlib**: Some modules exclude kotlin-stdlib-default dependency via `exclude-kotlin` plugin. |
| 219 | + |
| 220 | +5. **Binary Compatibility**: The project uses `kotlinx.binary-compatibility-validator` with specific modules ignored (see `apiValidation` block in root `build.gradle.kts`). |
| 221 | + |
| 222 | +6. **Test Plugin Exclusion**: The `surf-cloud-test-plugin` is excluded from CI builds (see `settings.gradle.kts` CI check). |
| 223 | + |
| 224 | +7. **Migration Generation**: There's a custom task `generateExposedMigrationScript` in surf-cloud-standalone that requires `migration.properties` file with database credentials. |
| 225 | + |
| 226 | +## Root Directory File List |
| 227 | + |
| 228 | +``` |
| 229 | +.gitattributes - Git attributes configuration |
| 230 | +.gitignore - Ignores build/, .gradle/, .idea/, IDE files |
| 231 | +.gitlab-ci.yml - GitLab CI/CD pipeline |
| 232 | +.github/ - GitHub configuration (workflows, copilot instructions) |
| 233 | +AGENTS.md - Coding guidelines for agents (referenced above) |
| 234 | +LICENSE - Project license |
| 235 | +README.md - Basic project info and setup instructions |
| 236 | +build.gradle.kts - Root Gradle build configuration |
| 237 | +buildSrc/ - Custom Gradle plugins and conventions |
| 238 | +cert_generation/ - Certificate generation scripts |
| 239 | +cert_new/ - Certificate documentation |
| 240 | +gradle/ - Gradle wrapper and version catalog |
| 241 | +gradle.properties - Gradle configuration (JVM args, versions) |
| 242 | +gradlew / gradlew.bat - Gradle wrapper scripts |
| 243 | +logo-styles.css - Logo styling for documentation |
| 244 | +netlify.toml - Netlify deployment configuration |
| 245 | +qodana.yaml - Qodana code quality configuration |
| 246 | +settings.gradle.kts - Gradle multi-module settings |
| 247 | +Writerside/ - Documentation source files |
| 248 | +[module directories] - See Module Structure section |
| 249 | +``` |
| 250 | + |
| 251 | +## Search Strategy |
| 252 | + |
| 253 | +Before exploring the codebase with grep/find: |
| 254 | + |
| 255 | +1. **Check this file first** - Most structural information is documented here |
| 256 | +2. **Check `gradle/libs.versions.toml`** - For dependency versions |
| 257 | +3. **Check module's `build.gradle.kts`** - For module-specific configuration |
| 258 | +4. **Check `buildSrc/src/main/kotlin/`** - For convention plugin details |
| 259 | + |
| 260 | +Only search if the above don't contain the needed information or if looking for specific code patterns. |
| 261 | + |
| 262 | +## Final Reminders |
| 263 | + |
| 264 | +- **Always build before committing**: `./gradlew build` must succeed |
| 265 | +- **Repository access required**: Builds fail without access to `repo.slne.dev` |
| 266 | +- **Use appropriate timeout**: Gradle tasks can take 2-10 minutes |
| 267 | +- **Check CI configuration**: Both GitLab and GitHub workflows must pass |
| 268 | +- **Respect module boundaries**: API vs. Core vs. Implementation separation |
0 commit comments