diff options
Diffstat (limited to 'website/src/docs/developers')
| -rw-r--r-- | website/src/docs/developers/engine.md | 11 | ||||
| -rw-r--r-- | website/src/docs/developers/platform-paper.md | 6 | ||||
| -rw-r--r-- | website/src/docs/developers/resource.md | 22 |
3 files changed, 29 insertions, 10 deletions
diff --git a/website/src/docs/developers/engine.md b/website/src/docs/developers/engine.md index a65a3f6..1f8956a 100644 --- a/website/src/docs/developers/engine.md +++ b/website/src/docs/developers/engine.md @@ -79,6 +79,17 @@ There are two UUID serializers because they serve different purposes. `UUIDSeria So that Paper and Velocity can handle domain errors as the same types, exceptions are centralized in `engine`. There is no common sealed base — it is a flat structure that directly extends `Exception`. They fall into existence/reference, state, limit, and permission/BAN/KICK categories, and many take `playerId` / `channelId` / `limit` in the constructor and build their own messages. Because there is no base type, callers are expected to catch each individually. +## debug — One switch both platforms read + +Debug logging is a contract before it is an implementation: `config.yml` and the proxy's system property must mean the same thing by `velocity,protocol`, and a category added on one side must exist on the other. So the vocabulary lives here and only the writing is left to the platforms. + +- `DebugCategory` — the areas that can be logged, each carrying the `key` operators write +- `DebugCategories.parse` / `resolve` — the one reading of a debug switch, shared by `DebugConfigSerializer` on Paper and `VelocityDebugSwitch` on Velocity. An unknown name is collected rather than thrown, so a typo costs only itself +- `DebugLogger` — `log(category) { message }`. The lambda is the point: the chat path is instrumented once per message, and while debugging is off the string is never built +- `DebugState` — the categories currently on, replaceable at runtime by `/lc reload` and `/lc debug` + +`JulDebugLogger` (Paper) and `Slf4jDebugLogger` (Velocity) both write at `INFO`, because neither platform's stock logging configuration prints anything below it. + ## permission / command — Neutral abstractions Permissions and command results are placed in `engine` as neutral representations that can be passed to either the Bukkit or Velocity API. diff --git a/website/src/docs/developers/platform-paper.md b/website/src/docs/developers/platform-paper.md index dbba4f1..6e6b7f4 100644 --- a/website/src/docs/developers/platform-paper.md +++ b/website/src/docs/developers/platform-paper.md @@ -23,7 +23,7 @@ Features are assembled via manual DI, without an external DI framework. The key The `onEnable` flow: -1. `saveDefaultConfig()` → build `LunaticChatConfiguration` via `ConfigManager` +1. `saveDefaultConfig()` → build `LunaticChatConfiguration` via `ConfigManager`, then create the `MessageFormatHolder` and the `ConfigurationReloader` over it 2. Initialize `HttpClient(CIO)` and `PluginCoroutineScope` 3. `ServiceInitializer.initialize()` → receive a `ServiceContainer` 4. Move services into the public properties used by commands @@ -146,6 +146,9 @@ Channel state itself is managed by the `chat/channel` package. - `ConfigManager` — deserializes `config.yml` into `LunaticChatConfiguration` with **KAML**, so each default lives in exactly one place: on the data class. It replaced a hand-written dotted-key mapper that repeated every default a second time, and they had already drifted — `checkForUpdates` disagreed with both `config.yml` and the data class, and the whole `messageLogging` block was documented but never read - Failure is handled per setting, not per file: on a `YamlException` the offending key is pruned from the document and decoding is retried, so one unreadable value costs only itself. Only a document that is not YAML at all falls back to defaults wholesale, and neither case is allowed to throw out of `onEnable` +- `ConfigManager.loadStrictly` — the reading `/lc reload` uses. It shares the pruning loop with `loadConfiguration` but reads the outcome the other way round: any setting that had to be pruned means the whole file is refused, with every unreadable setting named at once. A document holding no settings is refused too, because a reload cannot tell a comments-only file apart from one caught mid-write, and resetting every format over that is worse than doing nothing +- `MessageFormatHolder` — the one part of the configuration that is live. Deliberately narrower than `LunaticChatConfiguration`: taking this type says the value can change under you, taking `LunaticChatConfiguration` says it was frozen at startup. A holder over the whole configuration would produce a tree matching no version of the file, since only `messageFormat` is ever swapped +- `ConfigurationReloader` — re-reads the file and swaps the holder. It classifies every setting into applied (leaf by leaf, from `MessageFormatConfig`) or restart-required (block by block, riding on the data class `equals`), and a test over `memberProperties` fails when `config.yml` grows a setting neither table covers. The two lists are measured against different baselines: applied against the formats currently in effect, restart-required against the configuration the server actually started on. Nothing beyond `messageFormat` can be applied, because Paper registers commands only through its `COMMANDS` lifecycle event, Bukkit cannot unregister a listener, and the cache saver keeps no task handle to cancel - `LenientBoolean` — a `Boolean` typealias with a serializer that still accepts `yes` / `no` / `on` / `off`. Bukkit read `config.yml` as YAML 1.1, where those are booleans; kaml reads YAML 1.2, where they are plain strings, and silently resetting them would have flipped `checkForUpdates: no` to its opposite default - Feature defaults: `quickReplies=true`, `japaneseConversion=false`, `channelChat=false`, `velocityIntegration=false` - Under `config/key`: `FeaturesConfig` / `ChannelChatFeatureConfig` / `JapaneseConversionFeatureConfig` / `VelocityIntegrationConfig` / `QuickRepliesFeatureConfig` / `MessageFormatConfig` / `ChannelMessageLoggingConfig` @@ -155,6 +158,7 @@ Channel state itself is managed by the `chat/channel` package. - `Language` (enum) — `EN` / `JA`; unknown codes fall back to EN - `LanguageManager` — loads `resources/languages/` with KAML at startup and flattens the nested YAML into dotted keys (`toggle.on`, etc.). `getMessage(key, placeholders)` resolves with selected-language → EN fallback and substitutes `{placeholder}`, returning the key itself if not found. A missing EN is a fatal error - `MessageFormatter` (`object`) — produces an Adventure `Component` with a `[LC]` prefix and highlights `{braces}` placeholders detected by regex +- `ChatPlaceholder` / `ChatFormat.kt` — the placeholder vocabulary of `messageFormat` and its one renderer: entry points per format (`directMessage` / `channelMessage` / `crossServerGlobalChat`) substitute in a single pass and hand the result to `LegacyComponentSerializer`, then splice in Component values such as `{display_name}` so their styles and events stay scoped to them. Handlers never spell a placeholder name ## converter — Romaji-to-Japanese conversion diff --git a/website/src/docs/developers/resource.md b/website/src/docs/developers/resource.md index 543365d..614597a 100644 --- a/website/src/docs/developers/resource.md +++ b/website/src/docs/developers/resource.md @@ -14,7 +14,9 @@ A Gradle multi-module setup shares `engine` while building and releasing Paper / - `platform-velocity` — `version = velocityVersion`. `api(project(":engine"))`. velocity-api as `compileOnly`. Output is **`LunaticChat-<ver>-velocity.jar`** (distinguished by classifier) - `dokka` — aggregates engine/paper/velocity and includes the README in the HTML -Both platforms' `processResources` compute `version` / `gitCommitHash` / `channel` from the git short hash and `isNightly`, and token-expand them into `paper-plugin.yml` / `velocity-plugin.json` and `build-info.properties`. +Both platforms derive their version from `isNightly`: with `-PisNightly=true` the base version gains a `-nightly.<git short hash>` suffix, so a development build is never mistakable for the release of the same base version (`LunaticChat-1.3.0-nightly.44132f3.jar`). Without the flag the version stays the bare `paperVersion` / `velocityVersion`, which is what the release workflows build. + +`processResources` then token-expands `version` / `gitCommitHash` / `channel` into `paper-plugin.yml` / `velocity-plugin.json` and `build-info.properties`. ## Independent versioning @@ -28,23 +30,25 @@ Paper and Velocity carry separate version numbers and can be released independen ## Release workflows -The release target switches based on the tag pattern. +One tag releases exactly one platform. The tag pattern selects which. | Workflow | Trigger tag | Build target | Version validation | |----------|-------------|--------------|--------------------| -| `release.yaml` | `v*` | Both Paper + Velocity | extract both versions from gradle.properties | -| `release-paper.yaml` | `paper/v*` | Paper only | requires the tag to match `paperVersion` | -| `release-velocity.yaml` | `velocity/v*` | Velocity only | requires the tag to match `velocityVersion` | +| `release-paper.yaml` | `vX.Y.Z` | Paper only | requires the tag to match `paperVersion` | +| `release-velocity.yaml` | `velocity/vX.Y.Z` | Velocity only | requires the tag to match `velocityVersion` | -- Common flow: `validate` (check for a duplicate existing release) → `build` (mise + Gradle setup, `shadowJar`) → `release` (`gh release create --draft` + publish to Modrinth) -- The per-platform workflows (paper / velocity) differ from `release.yaml` in requiring a strict match between the tag and `gradle.properties` -- Modrinth game-versions are Paper=`26.2.x` (loaders: paper, folia) and Velocity=`1.21.x` + `26.1.x` + `26.2.x` (loader: velocity) +- Releasing both at once means pushing both tags together (`git push origin v1.5.0 velocity/v1.4.0`). Each produces its own GitHub Release +- Paper keeps the bare `vX.Y.Z` tag because the update checker in already-deployed Paper builds only understands that form +- Up to v1.4.0, a `vX.Y.Z` tag released both platforms (`v1.0.0`, `v1.3.0`, `v1.4.0`), and some Paper-only releases used `paper/vX.Y.Z`. Those tags are kept as they are +- Both workflows call the shared `_release.yaml`: `validate` (tag format, match with `gradle.properties`, duplicate release check) → `build` (mise + Gradle setup, `shadowJar`) → `release` (`gh release create --draft` + publish to Modrinth) +- The GitHub Release is created as a draft. Publish a Velocity release with `--latest=false`, so that the repository's latest release stays the Paper one +- Modrinth game-versions are Paper=`26.2.x` (loaders: paper, folia) and Velocity=`1.21.x` + `26.1.x` + `26.2.x` (loader: velocity), set in each caller workflow ## CI `ci.yaml` runs on push to main / PR / manual dispatch. -- `build_plugin` — ktlintCheck → test + jacocoTestReport → upload to Codecov → nightly shadowJar (`-PisNightly=true`) → retain artifacts +- `build_plugin` — ktlintCheck → test + jacocoTestReport → upload to Codecov → nightly shadowJar (`-PisNightly=true`) → retain artifacts as `LunaticChat-paper-<sha>` / `LunaticChat-velocity-<sha>` (one per platform, each holding the JAR at the archive root) - `build_dokka` / `deploy_dokka` — generate Dokka → deploy to GitHub Pages (main push only) - `build_docs` — format/lint/build `website/` with bun → deploy to Cloudflare Workers (wrangler) (main push only) |
