summaryrefslogtreecommitdiff
path: root/website/src/docs/developers
diff options
context:
space:
mode:
Diffstat (limited to 'website/src/docs/developers')
-rw-r--r--website/src/docs/developers/engine.md11
-rw-r--r--website/src/docs/developers/platform-paper.md6
-rw-r--r--website/src/docs/developers/resource.md22
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)