diff options
| author | Sho Sakuma <me@m1sk9.dev> | 2026-08-05 04:36:50 +0900 |
|---|---|---|
| committer | Sho Sakuma <me@m1sk9.dev> | 2026-08-05 04:36:50 +0900 |
| commit | 418be2d127ce2d6a3ed5e9c876deb9c2aafc089b (patch) | |
| tree | db800a91ac8fb05ae870b50014dc7fe06f274c47 /website/src/docs/developers/engine.md | |
| parent | 048932276d0c1e11d463f8b9aea872e498b04743 (diff) | |
| download | LunaticChat-418be2d127ce2d6a3ed5e9c876deb9c2aafc089b.tar.gz LunaticChat-418be2d127ce2d6a3ed5e9c876deb9c2aafc089b.tar.bz2 LunaticChat-418be2d127ce2d6a3ed5e9c876deb9c2aafc089b.zip | |
docs: correct the website where it had drifted from the implementation
Several statements were wrong rather than merely thin, and each would have set
the wrong expectation:
- the conversion example implied romaji replaces the input, when the result is
appended in parentheses and both are sent
- the handshake was described as happening at startup, when it waits for the
first player to join, so a DISCONNECTED status on an empty server read as a
fault
- cache eviction was called oldest-first, which the unordered in-memory map
cannot provide
- the Velocity settings table omitted crossServerDirectMessage
- ConfigManager was described as reading Bukkit's FileConfiguration, and the
settings storage as recovering from a backup that does not exist
It also documents behaviour that had no mention anywhere: the `!` force-global
prefix, that spy sees channel messages and not only DMs, the nightly build
warnings, the overall 1000ms conversion budget that makes api.timeout above it
ineffective, and the data files the plugin writes.
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'website/src/docs/developers/engine.md')
| -rw-r--r-- | website/src/docs/developers/engine.md | 12 |
1 files changed, 5 insertions, 7 deletions
diff --git a/website/src/docs/developers/engine.md b/website/src/docs/developers/engine.md index ee3a2c1..a65a3f6 100644 --- a/website/src/docs/developers/engine.md +++ b/website/src/docs/developers/engine.md @@ -48,13 +48,11 @@ The compatibility check is "**MAJOR matches exactly, the remote MINOR is within As a consequence of this design, Paper and Velocity can be released independently. See [Build, Release & Versioning](/docs/developers/resource#independent-versioning). -## converter — Romaji-to-Japanese conversion +## Romaji conversion is no longer here -`converter` is not a Paper↔Velocity contract (Velocity does no romaji conversion); it lives in `engine` **because it is platform-independent pure logic**. It has three layers. +Romaji conversion used to live in `engine` on the grounds that it was platform-independent pure logic. It now lives in [platform-paper](/docs/developers/platform-paper), which is its only caller. -- `KanaConverter` (`object`) — converts romaji to hiragana with a **Trie**. An immutable structure of `sealed class TrieNode { Leaf, Branch }` covers mappings from 4 characters (`xtsu`→っ) down to 1 (`a`→あ). `isValidRomaji()` validates before conversion; `toHiragana()` is a pure algorithm using longest-match plus sokuon handling -- `GoogleIMEClient` — receives a Ktor `HttpClient` via DI and converts hiragana to kanji-kana via Google IME (`langpair=ja-Hira|ja`), concatenating the top candidate of each segment of the response -- `CacheData` (`@Serializable`) — the persistence schema for conversion results (`version` plus `entries: Map`). It is a container for caching the expensive IME conversions; the caching logic itself lives on the paper side +Being platform-independent turned out not to be reason enough: keeping it here made `engine` depend on Ktor, and because both platforms depend on `engine`, the **Velocity** artifact shipped an HTTP client it never called. Moving it out is what let `engine` narrow its dependencies to `kotlinx-serialization-json` alone. ## chat/channel — Channel domain model @@ -79,14 +77,14 @@ There are two UUID serializers because they serve different purposes. `UUIDSeria ## exception — Shared error vocabulary -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 (23 types) 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. +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. ## 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. - `LunaticChatPermissionNode` — permissions enumerated type-safely as `sealed class` + `object` subclasses. The string node can be passed to either platform's permission API, and `when` also gives exhaustiveness checking -- `CommandResult` — a `sealed class` (`Success` / `SuccessWithMessage` / `Failure` / `InvalidUsage`). The message is an Adventure `Component`, and `toBrigadierResult()` expresses only "the meaning of the return value" (success=1/failure=0) without depending on Brigadier itself +- `CommandResult` — a `sealed class` (`Success` / `SuccessWithMessage` / `Failure` / `InvalidUsage`). Messages travel as plain `String`, so no Adventure type reaches `engine`; turning them into styled output is the platform's job. `toBrigadierResult()` expresses only "the meaning of the return value" (success=1/failure=0) without depending on Brigadier itself ## Related |
