summaryrefslogtreecommitdiff
path: root/website/src
diff options
context:
space:
mode:
Diffstat (limited to 'website/src')
-rw-r--r--website/src/assets/changelog-default.md26
-rw-r--r--website/src/changelog/overview.md53
-rw-r--r--website/src/changelog/paper/v1.3.0.md60
-rw-r--r--website/src/changelog/velocity/v1.2.0.md23
-rw-r--r--website/src/docs/configuration.md30
-rw-r--r--website/src/docs/developers/architecture.md10
-rw-r--r--website/src/docs/developers/engine.md12
-rw-r--r--website/src/docs/developers/platform-paper.md24
-rw-r--r--website/src/docs/features/admin.md17
-rw-r--r--website/src/docs/features/channel-chat.md17
-rw-r--r--website/src/docs/features/direct-message.md11
-rw-r--r--website/src/docs/features/japanese-conversion.md12
-rw-r--r--website/src/docs/features/velocity.md5
-rw-r--r--website/src/docs/permissions.md2
-rw-r--r--website/src/docs/reference/commands.md3
-rw-r--r--website/src/docs/reference/compatibility.md4
-rw-r--r--website/src/ja/changelog/overview.md55
-rw-r--r--website/src/ja/changelog/paper/v1.3.0.md60
-rw-r--r--website/src/ja/changelog/velocity/v1.2.0.md23
-rw-r--r--website/src/ja/docs/configuration.md30
-rw-r--r--website/src/ja/docs/developers/architecture.md8
-rw-r--r--website/src/ja/docs/developers/engine.md12
-rw-r--r--website/src/ja/docs/developers/platform-paper.md24
-rw-r--r--website/src/ja/docs/features/admin.md17
-rw-r--r--website/src/ja/docs/features/channel-chat.md17
-rw-r--r--website/src/ja/docs/features/direct-message.md11
-rw-r--r--website/src/ja/docs/features/japanese-conversion.md12
-rw-r--r--website/src/ja/docs/features/velocity.md5
-rw-r--r--website/src/ja/docs/permissions.md2
-rw-r--r--website/src/ja/docs/reference/commands.md3
-rw-r--r--website/src/ja/docs/reference/compatibility.md4
31 files changed, 524 insertions, 68 deletions
diff --git a/website/src/assets/changelog-default.md b/website/src/assets/changelog-default.md
new file mode 100644
index 0000000..1e9be22
--- /dev/null
+++ b/website/src/assets/changelog-default.md
@@ -0,0 +1,26 @@
+---
+layout: doc
+---
+
+# vX.Y.Z
+
+<!--
+- Download:
+ - [GitHub](https://github.com/m1sk9/LunaticChat/releases/tag/paper/vX.Y.Z)
+ - [Modrinth](https://modrinth.com/plugin/lunaticchat/version/X.Y.Z)
+
+- Download:
+ - [GitHub](https://github.com/m1sk9/LunaticChat/releases/tag/velocity/vX.Y.Z)
+ - [Modrinth (Velocity)](https://modrinth.com/plugin/lunaticchat/version/X.Y.Z-velocity)
+
+-->
+
+## New Features
+
+## Improvements
+
+## Changes
+
+## Bug Fixes
+
+## Notes
diff --git a/website/src/changelog/overview.md b/website/src/changelog/overview.md
new file mode 100644
index 0000000..b0e4a97
--- /dev/null
+++ b/website/src/changelog/overview.md
@@ -0,0 +1,53 @@
+---
+layout: doc
+---
+
+# Changelog
+
+The release history of LunaticChat.
+
+## Versioning
+
+::: tip
+
+For the details of independent versioning in LunaticChat, see [Build, Release & Versioning](/docs/developers/resource).
+
+:::
+
+LunaticChat follows semantic versioning. A version number consists of the three numbers `MAJOR.MINOR.PATCH`, each raised on the following basis.
+
+| Position | Raised when | Example |
+|----------|-------------|---------|
+| **MAJOR** | Used for the move from the pre-release (v0) line to the first stable release. It has not been raised since entering the stable line | `v0.11.0` → `v1.0.0` |
+| **MINOR** | A feature is added or changed, and **when a supported platform is dropped** | `v1.2.2` → `v1.3.0` (cross-server DM added, Paper 26.1 dropped) |
+| **PATCH** | Bug fixes and dependency updates only. No functional changes | `v1.2.0` → `v1.2.1` (dependency updates only) |
+
+::: warning Dropping support is done in a MINOR bump
+
+Cutting a runtime environment loose — "support for Paper 26.1 has ended", "support for Velocity 3.5.x has ended" — **is done in a MINOR bump**. MAJOR is not raised for it, so there can be combinations that stop working across nothing more than a minor version update. Check the changelog for the target version before updating.
+
+:::
+
+### The Paper and Velocity builds have separate version numbers
+
+The plugin for Paper / Folia and the plugin for Velocity are released independently, so their version numbers advance separately. Numbers that do not line up are the normal state of affairs.
+
+Releases are cut with a tag naming the target.
+
+| Tag | Released target |
+|-----|-----------------|
+| `paper/vX.Y.Z` | The Paper / Folia build only |
+| `velocity/vX.Y.Z` | The Velocity build only |
+| `vX.Y.Z` | Both at once, for a change that affects them both — such as one in the shared `engine` module |
+
+### The plugin version does not express compatibility
+
+Whether a Paper build and a Velocity build can talk to each other is decided by the **protocol version** embedded in both, not by the plugin version. Builds with distant version numbers may be combinable, and conversely builds with adjacent numbers may not be.
+
+For details, see [Paper / Velocity Compatibility](/docs/reference/compatibility).
+
+### Supported versions
+
+Only **the latest release of each platform** is supported. Fixes are not backported to older versions unless it is unavoidable.
+
+Nightly builds are generated automatically from in-development commits. They are not formal releases and are therefore not supported. When a nightly build is in use, a warning is shown on join and when `/lc status` is run.
diff --git a/website/src/changelog/paper/v1.3.0.md b/website/src/changelog/paper/v1.3.0.md
new file mode 100644
index 0000000..599a59a
--- /dev/null
+++ b/website/src/changelog/paper/v1.3.0.md
@@ -0,0 +1,60 @@
+---
+layout: doc
+---
+
+# v1.3.0
+
+- Download:
+ - [GitHub](https://github.com/m1sk9/LunaticChat/releases/tag/paper/v1.3.0)
+ - [Modrinth](https://modrinth.com/plugin/lunaticchat/version/1.3.0)
+
+## New Features
+
+- Added support for Paper 26.2 (Minecraft 26.2)
+ - Support for Paper 26.1 has ended at the same time.
+ - Paper 26.2 bundles Adventure 5.2.0, which is not binary compatible with 26.1.
+ - Builds from v1.3.0 onward therefore no longer run on Paper 26.1.
+- `/tell <player>@<server>` can now message a player on a server connected through Velocity
+ - Disabled by default.
+ - Enable it with `features.velocityIntegration.crossServerDirectMessage`.
+- Raised the protocol version to `1.0.1`.
+ - Paper and Velocity can be updated in either order.
+ - Cross-server direct messages do, however, require both sides to be updated.
+
+## Improvements
+
+- A failed player data save no longer aborts the remaining shutdown steps, so channel logs and the Velocity connection are always closed.
+- File persistence has been consolidated behind a single storage layer.
+ - As a result, a crash or a concurrent save can no longer leave a file in a half-written state.
+- Each player's messages are now delivered in the order they were sent.
+ - Work still queued when a player disconnects is discarded rather than delivered to a player who has already logged out.
+- Direct message delivery and channel message logging no longer run on the tick thread.
+- Cached romaji conversion results no longer wait for a permit from the shared API concurrency limiter.
+ - Previously, even a message whose every word was already cached could exhaust its conversion budget waiting for a permit it did not need, and be sent unconverted.
+- The words in a message are now converted concurrently.
+- Player settings are only rewritten when something has changed.
+ - Previously, every player quit re-serialized every player stored in the file, even when the bytes were identical.
+- When a player quits without an active channel, clearing their active channel no longer takes a snapshot of the channel caches.
+ - Previously, a mass disconnect produced one full snapshot per disconnecting player within a single tick.
+- Spy notification for direct messages and channel messages no longer builds its translation lookup and member set when no recipient is online.
+- Channel data writes are now batched instead of rewriting the whole file on every change.
+- Performed internal cleanup.
+
+## Changes
+
+- `config.yml` is now read with KAML, which changes how a broken file is treated.
+ - An unreadable configuration file no longer disables the plugin; it starts on its default settings instead.
+ - When a single value cannot be read, the other settings in the file are no longer all discarded: only that value falls back to its default, with a warning.
+- Per-player delivery queues are now bounded.
+ - A player who sends faster than delivery drains is refused with a warning, rather than building an unbounded backlog that arrives all at once minutes later.
+
+## Bug Fixes
+
+- Fixed the player argument of `/tell` matching partially
+ - This came from the switch away from the old Bukkit API.
+- Fixed `features.channelChat.messageLogging` never actually being read and falling back to its default values
+ - The loading was never implemented despite being documented, so it stayed at its defaults regardless of what the file said.
+- Fixed a slow Google IME reply silently stopping every subsequent message delivery for that player's session
+- Fixed a single conversion timeout permanently pinning a word to its hiragana form
+- Fixed `/reply` not recognizing a reply target that had just been recorded
+- Fixed reply target entries that had already been cleared on disconnect being recorded again
diff --git a/website/src/changelog/velocity/v1.2.0.md b/website/src/changelog/velocity/v1.2.0.md
new file mode 100644
index 0000000..272fb50
--- /dev/null
+++ b/website/src/changelog/velocity/v1.2.0.md
@@ -0,0 +1,23 @@
+---
+layout: doc
+---
+
+# v1.2.0
+
+- Download:
+ - [GitHub](https://github.com/m1sk9/LunaticChat/releases/tag/velocity/v1.2.0)
+ - [Modrinth (Velocity)](https://modrinth.com/plugin/lunaticchat/version/1.2.0-velocity)
+
+## New Features
+
+- Added support for Velocity 4.0.0
+ - Support for the Velocity 3.5.x line has ended.
+- Added cross-server direct message relay and player presence tracking.
+- Raised the protocol version to `1.0.1`.
+ - Paper and Velocity can be updated in either order.
+ - Cross-server direct messages do, however, require both sides to be updated.
+
+## Improvements
+
+- The Velocity JAR shrank from about 8.2 MiB to about 2.6 MiB.
+ - Paper-only dependencies (Ktor and the romaji conversion module) were separated out of the shared module and are no longer bundled into the Velocity build.
diff --git a/website/src/docs/configuration.md b/website/src/docs/configuration.md
index 78430f3..f2cfe5b 100644
--- a/website/src/docs/configuration.md
+++ b/website/src/docs/configuration.md
@@ -6,6 +6,22 @@ layout: doc
LunaticChat's configuration is managed in `plugins/LunaticChat/config.yml`. A default configuration file is generated on the server's first startup.
+## Applying Changes
+
+There is no reload command. Edit `config.yml` and **restart the server** to apply a change.
+
+Boolean settings accept `true` / `false`, and also the `yes` / `no` / `on` / `off` spellings that Bukkit accepted historically, so a file written for an older release keeps working as it did.
+
+## Recovery From an Invalid File <Badge type="tip" text="v1.3.0~" />
+
+A `config.yml` the plugin cannot use never stops the plugin from starting.
+
+- If a **single value** cannot be read, only that setting falls back to its default, and a warning naming the key is logged. Every other setting in the file is still honoured.
+- If the file is **not valid YAML at all**, or cannot be read from disk, every setting falls back to its default and an error is logged.
+- A file containing only comments is a valid way of saying "use the defaults" and is not reported as a problem.
+
+Check the server log after editing `config.yml`: a setting that quietly reverted to its default was reported there.
+
## Global Settings
| Key | Type | Default | Description |
@@ -68,6 +84,20 @@ LunaticChat's configuration is managed in `plugins/LunaticChat/config.yml`. A de
| `channelMessageFormat` | `§7[§b#{channel}§7] §e{sender}: §f{message}` | `{sender}`, `{message}`, `{channel}` |
| `crossServerGlobalChatFormat` | `§7[§6{server}§7] §e{sender}: §f{message}` | `{sender}`, `{message}`, `{server}` |
+## Data Files
+
+Everything the plugin writes lives under `plugins/LunaticChat/`.
+
+| File | Written when | Notes |
+|------|--------------|-------|
+| `config.yml` | Generated on first startup | Never rewritten by the plugin |
+| `player-settings.yaml` | A player changes a setting with `/lc settings` | Path configurable via `userSettingsFilePath`. If it cannot be read at startup, **every player's settings fall back to their defaults** |
+| `channels.json` | Channels or memberships change | Only when channel chat is enabled |
+| `conversion_cache.json` | Periodically, per `cache.saveIntervalSeconds` | Only when Japanese conversion is enabled. Path configurable via `cache.filePath` |
+| `logs/channelchat/` | Per channel message | Only when message logging is enabled. See [Message Logging](/docs/features/message-logging) |
+
+Saves are coalesced rather than written on every change, and every file is written atomically, so nothing ever reads a half-written file. All of them are also flushed when the server stops.
+
## Default Configuration File
[View on GitHub](https://github.com/m1sk9/LunaticChat/blob/main/platform-paper/src/main/resources/config.yml)
diff --git a/website/src/docs/developers/architecture.md b/website/src/docs/developers/architecture.md
index 4ba88d1..0532594 100644
--- a/website/src/docs/developers/architecture.md
+++ b/website/src/docs/developers/architecture.md
@@ -34,15 +34,11 @@ Things that break unless Paper and Velocity share the exact same definition.
- `exception` — the shared vocabulary of domain errors
- `permission`, `command` — neutral abstractions for permission node strings and command results
-#### (b) Platform-independent pure logic
-
-Logic that could live anywhere, but is pulled into the neutral core because it is pure and reusable.
-
-- `converter` — the pure romaji-conversion algorithm (Trie) plus an external API client
+Everything in `engine` falls into this category. Logic that merely *could* live anywhere is not pulled in for that reason alone: romaji conversion used to sit here as "platform-independent pure logic", and moving it into `platform-paper` — where its only caller is — let `engine` shed its Ktor dependency, which the Velocity build had been paying for in JAR size for nothing.
The primary goal of centralizing (a) in `engine` is to create a **single source of truth for the wire contract**. Paper and Velocity are two artifacts built, deployed, and versioned separately; duplicating the protocol in both modules would inevitably drift. With a single definition in `engine`, a contract mismatch surfaces early as a compile error or a snapshot-test failure rather than a runtime mismatch in production.
-`engine` depends on no Bukkit / Velocity API, and borrows only the "meaning of types and values" from Adventure / Brigadier to avoid depending on their runtimes (`compileOnly` Adventure, and `toBrigadierResult()` returning an `Int` without depending on Brigadier itself). This lets `engine` be tested on a pure JVM without spinning up a Minecraft server, while platform concerns (the Folia scheduler, etc.) stay isolated in the platform modules.
+`engine` depends on no Bukkit / Velocity / Adventure / Brigadier API at all — its single dependency is `kotlinx-serialization-json`. Rendering was pushed out to the platform modules (`CommandResult` carries a message key, and `toBrigadierResult()` returns an `Int` without depending on Brigadier), so `engine` borrows nothing from a platform runtime. This lets `engine` be tested on a pure JVM without spinning up a Minecraft server, while platform concerns (the Folia scheduler, HTTP, Adventure components) stay isolated in the platform modules.
## Compatibility via the protocol version
@@ -77,7 +73,7 @@ For details, see [platform-paper - Paper / Folia Plugin](/docs/developers/platfo
4. **Annotation-driven commands** — `@Command` / `@Permission` / `@PlayerOnly` are read via Kotlin reflection and mapped onto the Brigadier tree. A command's definition and its metadata (permission, aliases) are declared together in one place.
5. **Folia compatibility** — asynchronous work runs on `asyncScheduler` and `PluginCoroutineScope` (SupervisorJob), and Bukkit API calls are moved back to the main thread via `scheduler.runTask`. Thread boundaries are handled explicitly so it also works on region-threaded Folia.
6. **Persistence chosen per purpose** — languages / player settings = KAML (YAML), channels / conversion cache = kotlinx.serialization JSON, channel logs = NDJSON. All follow the same pattern: in-memory cache + asynchronous save (debounce/queue) + synchronous save on shutdown.
-7. **DM/channel = local, global = via the proxy** — routing differs by chat type; only global chat goes through Velocity. The relay prevents loops in two stages: "exclude the source server" + "deduplicate by messageId".
+7. **Channel = local, global and DM = optionally via the proxy** — routing differs by chat type. Channel chat is always server-local; global chat crosses the proxy when `crossServerGlobalChat` is on, and direct messages do when `crossServerDirectMessage` is on. The relay prevents loops in two stages: "exclude the source server" + "deduplicate by messageId".
## Module details
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
diff --git a/website/src/docs/developers/platform-paper.md b/website/src/docs/developers/platform-paper.md
index 19437c1..dbba4f1 100644
--- a/website/src/docs/developers/platform-paper.md
+++ b/website/src/docs/developers/platform-paper.md
@@ -121,7 +121,7 @@ Branches:
### Direct messages (DirectMessageHandler)
-Manages `/tell`・`/reply` state. Two `ConcurrentHashMap`s, `lastMessager` / `lastRecipient`, track reply targets, and `getReplyTarget()` returns an online player in the order "whoever messaged me → whoever I messaged".
+Manages `/tell`・`/reply` state. Two `ConcurrentHashMap`s, `lastMessager` / `lastRecipient`, track reply targets as a `sealed interface ReplyTarget` of `Local` (a UUID) or `Remote` (a player name plus server name). `getReplyTarget()` resolves in the order "whoever messaged me → whoever I messaged", validating as it goes: a `Local` target must be online, and a `Remote` target must still be reported on that server by `RemotePlayerRegistry`.
`sendDirectMessage()` applies romaji conversion per the sender's settings → delivers a hover-annotated copy to spy players (excluding sender and recipient) → sends the formatted message to sender and recipient plus a notification sound (settings-dependent). The message carries a `ClickEvent.suggestCommand` that fills in `/tell <sender>`.
@@ -144,27 +144,27 @@ Channel state itself is managed by the `chat/channel` package.
## config
-- `ConfigManager` — reads the main `config.yml` from **Bukkit's `FileConfiguration`** by dotted keys and hand-assembles `LunaticChatConfiguration` (note: this path is not KAML)
+- `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`
+- `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`
-::: warning Implementation note
-`ChannelChatFeatureConfig.messageLogging` is not loaded by `ConfigManager` and stays at its default values (enabled=true, retention=30, 100MB). Whether this is intentional needs confirmation — decide whether to fix it or document it as intended behavior.
-:::
-
## i18n
- `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
-## converter (paper side) — engine integration
+## converter — Romaji-to-Japanese conversion
-The paper side handles the platform concerns of "cache management, timeouts, Bukkit scheduling", and delegates the conversion algorithm and API calls to `engine`.
+Romaji conversion lives here in full: the algorithm, the API client, the cache, and the platform concerns (timeouts, scheduling). It used to sit in `engine` as platform-independent pure logic, but `platform-paper` is its only caller, and keeping it in `engine` made the Velocity artifact carry Ktor for nothing.
-- `RomanjiConverter` — the two-stage conversion orchestrator. Per word: cache lookup → engine `KanaConverter` for romaji→hiragana → engine `GoogleIMEClient` for hiragana→kanji. Falls back to hiragana on API failure
-- `ConversionCache` — persists engine `CacheData` as JSON. In-memory cache plus debounced save (a FIXME notes that eviction on `maxEntries` overflow is effectively random due to `ConcurrentHashMap` ordering)
-- `RomajiConversionHelper` — `convertWithRomaji()`. Calls synchronously via `runBlocking` + `withTimeoutOrNull` (default 1000ms), returning `"original §e(converted)"` on success and the original text on failure/timeout
+- `KanaConverter` (`object`) — romaji to hiragana with a **Trie**. An immutable `sealed class TrieNode { Leaf, Branch }` covers mappings from 4 characters (`xtsu`→っ) down to 1 (`a`→あ). `isValidRomaji()` validates before conversion; `toHiragana()` is a pure longest-match algorithm with 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
+- `RomanjiConverter` — the two-stage orchestrator. Per word: cache lookup → `KanaConverter` → `GoogleIMEClient`. Words are converted concurrently, and an API failure degrades to hiragana rather than failing the message
+- `ConversionCache` — persists `CacheData` as JSON. In-memory cache plus debounced save (a FIXME notes that eviction on `maxEntries` overflow drops an arbitrary 10%, not the oldest, because `ConcurrentHashMap` is unordered)
+- `RomajiConversionHelper` — `convertWithRomaji()` is `suspend` and bounded by `withTimeoutOrNull` (default 1000ms), returning `"original §e(converted)"` on success and the original text on failure or timeout. `convertWithRomajiBlocking()` wraps it in `runBlocking` for `AsyncChatEvent`, the one caller that must decide whether to cancel the event before returning; command handlers run on the tick thread and must use the suspending form
## Velocity integration (Paper side)
@@ -177,7 +177,7 @@ Using the engine's protocol, it communicates with the proxy over Bukkit's Plugin
## settings / common
- `PlayerSettingsManager` — manages three boolean settings in `ConcurrentHashMap`s. Uses the engine DTOs; unset values default to true
-- `YamlPlayerSettingsStorage` — reads/writes `player-settings.yaml` with KAML. Recovers from a backup on load failure; debounced save (5s)
+- `YamlPlayerSettingsStorage` — reads/writes `player-settings.yaml` with KAML; debounced save (5s). There is no backup file: a load failure is logged and falls back to **empty settings**, which means every player silently returns to defaults
- `UpdateChecker` — hits the GitHub Releases API via Ktor and compares semver. The result is a sealed `UpdateCheckResult`
- `SoundCollector` — Adventure `Sound` constants for notifications plus Player extension functions
- `PermissionCollector` — a DSL that collects permissions via `@PermissionDsl` + the `+LunaticChatPermissionNode` operator. `requirePermission` throws the engine's `RequirePermissionException`
diff --git a/website/src/docs/features/admin.md b/website/src/docs/features/admin.md
index c3a3d2f..3f71dcc 100644
--- a/website/src/docs/features/admin.md
+++ b/website/src/docs/features/admin.md
@@ -24,9 +24,11 @@ Displayed information:
## Spy Mode
-Players with the `lunaticchat.spy` permission (default: op) can view all direct messages sent and received on the server.
+Players with the `lunaticchat.spy` permission (default: op) can view both the direct messages and the channel messages sent on the server.
-- Spy players see the original message before romaji conversion
+- Direct messages are delivered to spies, excluding the sender and the recipient
+- Channel messages are delivered to spies, excluding the sender and the channel's own members
+- For direct messages, spies see the original text before romaji conversion. Channel messages reach spies in the same converted form the members see
- Hover text indicates the message is a spy message
- Spy players themselves are not included in the normal sender/recipient list
@@ -46,6 +48,15 @@ When `checkForUpdates` is `true` (default), the plugin checks for new versions a
checkForUpdates: true
```
+## Nightly Builds
+
+Builds produced from the `main` branch outside of a release are marked as nightly, and the plugin says so rather than letting it go unnoticed.
+
+- Every player is warned on join that the build may be unstable, along with a pointer to GitHub Issues
+- `/lc status` shows the same warning, and displays the release channel in yellow instead of green
+
+Nightly builds are not covered by the [security policy](https://github.com/m1sk9/LunaticChat/blob/main/.github/SECURITY.md); use a release build on a production server.
+
## Debug Mode
Setting `debug` to `true` enables verbose plugin logging. This is useful for troubleshooting issues or submitting bug reports.
@@ -68,7 +79,7 @@ language: "ja" # "en" or "ja"
| Permission | Default | Description |
|-----------|---------|-------------|
-| `lunaticchat.spy` | op | View all direct messages |
+| `lunaticchat.spy` | op | View all direct and channel messages |
| `lunaticchat.channelbypass` | op | Bypass channel restrictions |
| `lunaticchat.noticeupdate` | op | Receive update notifications |
| `lunaticchat.command.lcv.status` | op | Use the `/lcv status` command |
diff --git a/website/src/docs/features/channel-chat.md b/website/src/docs/features/channel-chat.md
index c06ea39..ff6bab0 100644
--- a/website/src/docs/features/channel-chat.md
+++ b/website/src/docs/features/channel-chat.md
@@ -37,6 +37,19 @@ Players can join multiple channels, but only one channel can be active at a time
/lc channel status # Display the current active channel and list of joined channels
```
+## Sending to Global Chat (`!` Prefix)
+
+While a channel is active, your chat goes to that channel. Prefixing a message with `!` sends that one message to global chat instead, without leaving or switching the channel.
+
+```
+!Hello everyone # Goes to global chat even while a channel is active
+```
+
+The `!` and any space following it are stripped before the message is sent, so it never appears in the message itself. A message consisting of only `!` is discarded and nothing is sent.
+
+> [!NOTE]
+> The prefix is handled by the chat listener, which is only registered when channel chat, cross-server global chat, or Japanese conversion is enabled. If all three are disabled, a leading `!` stays in the message exactly as typed.
+
## Roles and Permissions
Channels have three roles.
@@ -87,6 +100,10 @@ See the `features.channelChat.messageLogging` section on the [Configuration page
Players with the `lunaticchat.channelbypass` permission (default: op) are protected from kicks and bans, and can force-delete channels.
+## Spy Mode
+
+Channel messages are not private from administrators. Players with the `lunaticchat.spy` permission (default: op) also receive channel messages, excluding the sender and the channel's own members. See [Spy Mode](/docs/features/admin#spy-mode) for details.
+
## Message Format
The display format for channel messages can be customized via `messageFormat.channelMessageFormat` in `config.yml`. See [Message Format](/docs/reference/message-format) for details.
diff --git a/website/src/docs/features/direct-message.md b/website/src/docs/features/direct-message.md
index 07f6cdb..ec0f24e 100644
--- a/website/src/docs/features/direct-message.md
+++ b/website/src/docs/features/direct-message.md
@@ -42,6 +42,17 @@ To message a player on another server, specify the player argument as `playerNam
/tell <player>@<server> <message>
```
+`serverName` is the name of the destination server **as registered in your Velocity configuration** (`velocity.toml`), which is what the proxy resolves the target against. Tab completion offers the names and players it currently knows about.
+
+Set `features.velocityIntegration.serverName` on each backend to that same name. It does not affect routing, but it fills `{server}` in cross-server chat and is how a server recognises which players are its own — if it disagrees with the Velocity name, local players are treated as remote in tab completion.
+
+Delivery can fail in two ways, and the sender is told which:
+
+| Reason | Meaning |
+|--------|---------|
+| `SERVER_NOT_FOUND` | No server registered on the proxy has that name |
+| `TARGET_OFFLINE` | The server exists, but that player is not on it — including when they are online on a different server |
+
## Notification Settings
Players can individually control the sound notification when receiving direct messages.
diff --git a/website/src/docs/features/japanese-conversion.md b/website/src/docs/features/japanese-conversion.md
index ec1df1b..d98ac87 100644
--- a/website/src/docs/features/japanese-conversion.md
+++ b/website/src/docs/features/japanese-conversion.md
@@ -19,8 +19,11 @@ Conversion is performed in two stages.
Input: konnichiha sekai
Stage 1: こんにちは せかい
Stage 2: こんにちは 世界
+Sent: konnichiha sekai §e(こんにちは 世界)
```
+The original text is **not** replaced. What you typed is kept, and the conversion result is appended in parentheses, so both are visible to everyone who receives the message.
+
## Conversion Targets
- Normal chat
@@ -48,7 +51,7 @@ Conversion results are cached per word. When the same word is converted again, t
| `cache.saveIntervalSeconds` | `300` | Interval for saving to disk (seconds) |
| `cache.filePath` | `"conversion_cache.json"` | Path to the cache file |
-When the cache reaches its limit, the oldest 10% of entries are automatically removed.
+When the cache reaches its limit, 10% of the entries are removed. Which entries are dropped is not defined: the in-memory cache is unordered, so eviction is effectively arbitrary rather than oldest-first.
## API Settings
@@ -56,6 +59,11 @@ Settings related to the connection to the Google IME API.
| Setting Key | Default | Description |
|-------------|---------|-------------|
-| `api.timeout` | `3000` | Request timeout (milliseconds) |
+| `api.timeout` | `3000` | Timeout for a single API request (milliseconds) |
If the API times out or fails, the message is sent in hiragana as-is.
+
+> [!WARNING]
+> Independently of `api.timeout`, converting one message is given an overall budget of **1000 ms**. When that budget runs out the conversion is abandoned and the message is sent exactly as typed, with nothing appended.
+>
+> Because the overall budget is shorter than the default `api.timeout`, raising `api.timeout` above `1000` has no practical effect.
diff --git a/website/src/docs/features/velocity.md b/website/src/docs/features/velocity.md
index 8bc1b70..7842a24 100644
--- a/website/src/docs/features/velocity.md
+++ b/website/src/docs/features/velocity.md
@@ -51,6 +51,8 @@ When `crossServerGlobalChat` is set to `true`, player chat messages are relayed
Each message is assigned a unique ID, and a cache prevents the same message from being displayed more than once. The cache size can be configured with `messageDeduplicationCacheSize` (default: `100`).
+Entries expire 60 seconds after they are recorded. If the cache is still over its configured size after expired entries are cleared, the oldest remaining entries are dropped.
+
## Cross-Server Direct Messages <Badge type="tip" text="v1.3.0~" />
Setting `crossServerDirectMessage` to `true` lets players exchange direct messages with players on other servers connected to the same proxy.
@@ -80,7 +82,8 @@ The handshake timeout is 5 seconds. If the handshake times out, the state become
|-------------|---------|-------------|
| `enabled` | `false` | Enable Velocity integration |
| `crossServerGlobalChat` | `false` | Enable cross-server global chat |
-| `serverName` | `"Unknown"` | Server name displayed in cross-server chat |
+| `crossServerDirectMessage` | `false` | Enable cross-server direct messages |
+| `serverName` | `"Unknown"` | This server's own name. Fills `{server}` in cross-server chat and is how the server recognises its own players. Set it to the name registered in `velocity.toml` |
| `messageDeduplicationCacheSize` | `100` | Size of the message deduplication cache |
## Message Format
diff --git a/website/src/docs/permissions.md b/website/src/docs/permissions.md
index d059bba..caada8b 100644
--- a/website/src/docs/permissions.md
+++ b/website/src/docs/permissions.md
@@ -44,7 +44,7 @@ The following permissions are granted to OPs only by default.
| Permission | Default | Description |
|------------|---------|-------------|
-| `lunaticchat.spy` | op | View all direct messages on the server |
+| `lunaticchat.spy` | op | View all direct and channel messages on the server |
| `lunaticchat.noticeupdate` | op | Receive update notifications |
| `lunaticchat.channelbypass` | op | Bypass channel restrictions (kick/ban protection, force deletion) |
| `lunaticchat.command.lcv.status` | op | Use the `/lcv status` command |
diff --git a/website/src/docs/reference/commands.md b/website/src/docs/reference/commands.md
index a039f7a..28627bc 100644
--- a/website/src/docs/reference/commands.md
+++ b/website/src/docs/reference/commands.md
@@ -58,7 +58,8 @@ Creates a new channel. The creator becomes the owner.
- **Aliases**: `new`
- **Permission**: `lunaticchat.command.lc.channel.create`
-- `channelId`: Only alphanumeric characters, underscores, and hyphens are allowed
+- `channelId`: 3-30 characters; only alphanumeric characters, underscores, and hyphens are allowed
+- `name`: Cannot be blank
- `isPrivate`: `true` / `false` (default: `false`)
#### `/lc channel list [page]`
diff --git a/website/src/docs/reference/compatibility.md b/website/src/docs/reference/compatibility.md
index e0e341c..23274ab 100644
--- a/website/src/docs/reference/compatibility.md
+++ b/website/src/docs/reference/compatibility.md
@@ -57,9 +57,11 @@ The rules (from Velocity's perspective) are:
Compatibility is checked at connection time:
-1. The Paper server sends a handshake to Velocity at startup
+1. The Paper server sends a handshake to Velocity one second after the **first player joins**
2. Velocity validates Paper's protocol version against its own
3. On mismatch, Velocity rejects the connection and Paper's state becomes `FAILED`
4. The handshake timeout is 5 seconds
+The handshake is sent once per server start, and it is triggered by a player joining rather than by startup itself — the plugin messaging channel needs a player connection to send on. Until the first player joins, `/lcv status` reports `DISCONNECTED`, which is normal and not a sign of a problem.
+
Live connection state is available via `/lcv status`. See [Velocity Integration](/docs/features/velocity#connection-states) for details.
diff --git a/website/src/ja/changelog/overview.md b/website/src/ja/changelog/overview.md
new file mode 100644
index 0000000..3b03477
--- /dev/null
+++ b/website/src/ja/changelog/overview.md
@@ -0,0 +1,55 @@
+---
+layout: doc
+---
+
+# 更新履歴
+
+LunaticChat に関する更新履歴です.
+
+## バージョニング
+
+::: tip
+
+LunaticChat における独立バージョニングの詳細は [ビルド・リリース・バージョニング](../docs/developers/resource.md) を参照してください.
+
+:::
+
+LunaticChat ではセマンティックバージョニングを採用しています.バージョン番号は `MAJOR.MINOR.PATCH` の 3 つの数字で構成され,それぞれ次の基準で上がります.
+
+| 位置 | 上がる条件 | 例 |
+|------|-----------|-----|
+| **MAJOR** | プレリリース (v0 系) から最初の安定版へ移行する際に使用しました.安定版に入って以降は使用していません | `v0.11.0` → `v1.0.0` |
+| **MINOR** | 機能の追加・変更,および**サポート対象プラットフォームの打ち切り** | `v1.2.2` → `v1.3.0` (サーバー間 DM の追加,Paper 26.1 の打ち切り) |
+| **PATCH** | 不具合修正と依存関係の更新のみ.機能の変更を含みません | `v1.2.0` → `v1.2.1` (依存更新のみ) |
+
+::: warning サポート打ち切りは MINOR で行います
+
+「Paper 26.1 のサポートを終了」「Velocity 3.5.x のサポートを終了」のような**動作環境の切り捨ては MINOR バンプで行います**.MAJOR は上がらないため,マイナーバージョンの更新であっても動作しなくなる組み合わせがありえます.更新の前に対象バージョンの更新履歴を確認してください.
+
+:::
+
+### Paper 版と Velocity 版は別のバージョン番号を持ちます
+
+Paper / Folia 向けプラグインと Velocity 向けプラグインは独立してリリースされるため,バージョン番号も別々に進みます.番号が揃っていないのは正常な状態です.
+
+リリースは対象を示すタグで行います.
+
+| タグ | リリース対象 |
+|------|-------------|
+| `paper/vX.Y.Z` | Paper / Folia 版のみ |
+| `velocity/vX.Y.Z` | Velocity 版のみ |
+| `vX.Y.Z` | 両方同時.共有モジュール `engine` の変更など,双方に影響する変更で使用します |
+
+### プラグインバージョンは互換性を表しません
+
+Paper 版と Velocity 版が通信できるかどうかは,プラグインバージョンではなく両者に埋め込まれた**プロトコルバージョン**で決まります.バージョン番号が離れていても組み合わせられる場合があり,逆に近い番号同士でも組み合わせられない場合があります.
+
+詳しくは [Paper / Velocity 互換性](/ja/docs/reference/compatibility) を参照してください.
+
+### サポート対象
+
+サポート対象は**各プラットフォームの最新リリースのみ**です.古いバージョンへの修正の backport は,どうしても必要な場合を除いて行いません.
+
+nightly ビルドは開発中のコミットから自動生成されるビルドであり,正式なリリースではないためサポート対象外です.nightly を使用している場合は,ログイン時と `/lc status` の実行時に警告が表示されます.
+
+
diff --git a/website/src/ja/changelog/paper/v1.3.0.md b/website/src/ja/changelog/paper/v1.3.0.md
new file mode 100644
index 0000000..78e241a
--- /dev/null
+++ b/website/src/ja/changelog/paper/v1.3.0.md
@@ -0,0 +1,60 @@
+---
+layout: doc
+---
+
+# v1.3.0
+
+- Download:
+ - [GitHub](https://github.com/m1sk9/LunaticChat/releases/tag/paper/v1.3.0)
+ - [Modrinth](https://modrinth.com/plugin/lunaticchat/version/1.3.0)
+
+## New Features
+
+- Paper 26.2 (Minecraft 26.2) をサポートしました
+ - 同時にPaper 26.1 のサポートは終了しました.
+ - Paper 26.2 では Adventure 5.2.0 を同梱しているため,26.1 とはバイナリ互換性が失われています.
+ - そのため, v1.3.0 以降のビルドは Paper 26.1 では使用できなくなりました.
+- `/tell <player>@<server>` で Velocity 間で接続しているサーバのプレイヤーにメッセージを送信できるように
+ - デフォルトでは無効化されています.
+ - `features.velocityIntegration.crossServerDirectMessage` で有効化できます.
+- プロトコルバージョンを `1.0.1` に引き上げました.
+ - Paper 側と Velocity 側はどちらを先に更新しても問題ありません.
+ - ただし,サーバー間ダイレクトメッセージ機能を使うには両側の更新が必要です.
+
+## Improvements
+
+- プレイヤーデータの保存に失敗しても,残りのシャットダウン処理が中断されなくなり,チャンネルログと Velocity 接続は必ずクローズされるようになりました.
+- ファイルの永続化処理が単一のストレージレイヤーの背後に統合されました.
+ - これにより,クラッシュや同時保存によってファイルが中途半端な状態のまま残ることがなくなりました.
+- 各プレイヤーのメッセージは送信順に配信されるようになりました.
+ - 切断時にまだキューに残っている作業は,既にログアウトしたプレイヤーに配信されるのではなく破棄されます.
+- ダイレクトメッセージ配信とチャンネルメッセージのロギングが,tick スレッド上で実行されなくなりました.
+- キャッシュ済みのローマ字変換結果が,共有 API 同時実行数リミッターの許可待ちをしなくなりました.
+ - これまでは,全ての単語がキャッシュ済みであるメッセージでも,不要な permit の取得待ちで変換予算を使い切ってしまい,未変換のまま送信されることがありました.
+- メッセージ中の単語の変換が並行して行われるようになりました.
+- プレイヤー設定は,変更があった場合のみ書き直されるようになりました.
+ - これまでは,プレイヤーが退出するたびに,同一バイト列であっても保存済みの全プレイヤーが再シリアライズされていました.
+- プレイヤーがアクティブなチャンネルを持たない状態で退出した際,そのプレイヤーのアクティブチャンネルをクリアする処理でチャンネルキャッシュのスナップショットが取られなくなりました.
+ - これまでは,大量切断時に 1 tick 内で切断人数分のフルスナップショットが発生していました.
+- ダイレクトメッセージおよびチャンネルメッセージのスパイ通知は,対象者がオンラインでない場合,翻訳ルックアップとメンバーセットの構築を行わなくなりました.
+- チャンネルデータの書き込みは,変更のたびにファイル全体を書き直すのではなく,まとめて行われるようになりました.
+- 内部的なクリーンアップを行いました.
+
+## Changes
+
+- 設定ファイルの読み込みに KAML を使用するようになりました.これにより壊れたファイルの扱いが変わります.
+ - 読み込み不能な設定ファイルがあっても,プラグインは無効化されず,デフォルト設定で起動するようになりました.
+ - 単一の値が読み込めない場合も,ファイル内の他の設定が全て破棄されることはなくなり,警告付きでその値のみデフォルトにフォールバックするようになりました.
+- プレイヤーごとの配信キューに上限が設けられました.
+ - 配信のドレイン速度を超えて送信するプレイヤーは,無制限にバックログを溜め込んで数分後にまとめて届くのではなく,警告と共に拒否されるようになりました.
+
+## Bug Fixes
+
+- `/tell` のプレイヤー引数が部分一致になっていた不具合を修正
+ - 旧 Bukkit API からの切り替えによるものです.
+- `features.channelChat.messageLogging` が実際には読み込まれず,デフォルト値としてフォールバックされる不具合を修正
+ - これまではドキュメントに記載があるにもかかわらず読み込み処理が実装されておらず,ファイルの記述に関わらず常にデフォルト値のままでした.
+- Google IME の応答が遅い場合に,そのプレイヤーのセッション中のメッセージ配信が以降すべて無言で止まってしまう不具合を修正
+- 一度の変換タイムアウトが原因で,ある単語が恒久的にひらがな表示に固定されてしまう不具合を修正
+- `/reply` が記録されたばかりの返信先を認識できない不具合を修正
+- `/reply` の対象者がログアウトした際,クリアされたはずのエントリが重複してチャットに挿入されてしまう不具合を修正
diff --git a/website/src/ja/changelog/velocity/v1.2.0.md b/website/src/ja/changelog/velocity/v1.2.0.md
new file mode 100644
index 0000000..18249c9
--- /dev/null
+++ b/website/src/ja/changelog/velocity/v1.2.0.md
@@ -0,0 +1,23 @@
+---
+layout: doc
+---
+
+# v1.2.0
+
+- Download:
+ - [GitHub](https://github.com/m1sk9/LunaticChat/releases/tag/velocity/v1.2.0)
+ - [Modrinth (Velocity)](https://modrinth.com/plugin/lunaticchat/version/1.2.0-velocity)
+
+## New Features
+
+- Velocity 4.0.0 をサポートしました
+ - Velocity 3.5.x 系統のサポートは終了しました.
+- サーバー間ダイレクトメッセージのリレー機能とプレイヤーのプレゼンス追跡機能を追加しました.
+- プロトコルバージョンを `1.0.1` に引き上げました.
+ - Paper 側と Velocity 側はどちらを先に更新しても問題ありません.
+ - ただし,サーバー間ダイレクトメッセージ機能を使うには両側の更新が必要です.
+
+## Improvements
+
+- Velocity 用 JAR のサイズが,約 8.2 MiB から約 2.6 MiB に縮小されました.
+ - Paper 専用の依存関係(Ktor とローマ字変換モジュール)が共有モジュールから分離され,Velocity ビルドに同梱されなくなったためです.
diff --git a/website/src/ja/docs/configuration.md b/website/src/ja/docs/configuration.md
index c2c8c12..3324940 100644
--- a/website/src/ja/docs/configuration.md
+++ b/website/src/ja/docs/configuration.md
@@ -6,6 +6,22 @@ layout: doc
LunaticChat の設定は `plugins/LunaticChat/config.yml` で管理されます.サーバーの初回起動時にデフォルトの設定ファイルが生成されます.
+## 設定の反映
+
+リロードコマンドはありません.`config.yml` を編集したら**サーバーを再起動**してください.
+
+真偽値の設定は `true` / `false` のほか,Bukkit が従来受け付けていた `yes` / `no` / `on` / `off` の表記も使用できます.古いリリース向けに書かれたファイルもそのまま動作します.
+
+## 不正なファイルからの復帰 <Badge type="tip" text="v1.3.0~" />
+
+`config.yml` が使用できない状態であっても,プラグインの起動が止まることはありません.
+
+- **1つの値**が読めない場合,その設定だけがデフォルトにフォールバックし,該当キーを示す警告がログに出力されます.ファイル内のほかの設定はそのまま反映されます
+- ファイルが **YAML として不正**な場合やディスクから読み取れない場合は,すべての設定がデフォルトにフォールバックし,エラーがログに出力されます
+- コメントのみのファイルは「デフォルトを使う」という有効な指定として扱われ,問題として報告されません
+
+`config.yml` を編集したあとはサーバーログを確認してください.デフォルトに戻された設定があれば,そこに報告されています.
+
## グローバル設定
| キー | 型 | デフォルト | 説明 |
@@ -68,6 +84,20 @@ LunaticChat の設定は `plugins/LunaticChat/config.yml` で管理されます
| `channelMessageFormat` | `§7[§b#{channel}§7] §e{sender}: §f{message}` | `{sender}`, `{message}`, `{channel}` |
| `crossServerGlobalChatFormat` | `§7[§6{server}§7] §e{sender}: §f{message}` | `{sender}`, `{message}`, `{server}` |
+## データファイル
+
+プラグインが書き込むファイルはすべて `plugins/LunaticChat/` 配下に置かれます.
+
+| ファイル | 書き込まれるタイミング | 備考 |
+|----------|----------------------|------|
+| `config.yml` | 初回起動時に生成 | プラグインが書き換えることはない |
+| `player-settings.yaml` | プレイヤーが `/lc settings` で設定を変更したとき | パスは `userSettingsFilePath` で変更可能.起動時に読み取れなかった場合,**全プレイヤーの設定がデフォルトに戻る** |
+| `channels.json` | チャンネルまたはメンバーシップが変化したとき | チャンネルチャットが有効な場合のみ |
+| `conversion_cache.json` | `cache.saveIntervalSeconds` ごとに定期保存 | ローマ字変換が有効な場合のみ.パスは `cache.filePath` で変更可能 |
+| `logs/channelchat/` | チャンネルメッセージごと | メッセージログが有効な場合のみ.[メッセージログ](/ja/docs/features/message-logging)を参照 |
+
+保存は変更ごとではなくまとめて行われ,またすべてのファイルはアトミックに書き込まれるため,書き込み途中のファイルが読まれることはありません.いずれもサーバー停止時にも書き出されます.
+
## デフォルト設定ファイル
[GitHub で確認する](https://github.com/m1sk9/LunaticChat/blob/main/platform-paper/src/main/resources/config.yml)
diff --git a/website/src/ja/docs/developers/architecture.md b/website/src/ja/docs/developers/architecture.md
index cd3965a..5e3c513 100644
--- a/website/src/ja/docs/developers/architecture.md
+++ b/website/src/ja/docs/developers/architecture.md
@@ -36,13 +36,11 @@ Paper と Velocity が同一定義でないと壊れるもの.
#### (b) プラットフォーム非依存の純ロジック
-どこに置いてもよいが,純粋な再利用可能のロジックを中立コアに寄せたもの.
-
-- `converter` — ローマ字変換の純アルゴリズム (Trie) +外部 API クライアント
+engine の中身はすべて (a) に該当します.「どこに置いてもよい純ロジック」であることは,それだけでは engine に置く理由になりません.ローマ字変換はかつて「プラットフォーム非依存の純ロジック」としてここにありましたが,唯一の呼び出し元である `platform-paper` へ移したことで engine は Ktor 依存を落とせました.Velocity 側のビルドはそれまで,呼ばない HTTP クライアントの分だけ JAR サイズを払っていたためです.
(a) を engine に一元化する最大の狙いは,**ワイヤ契約の「単一の真実源」を作ること**です.Paper と Velocity は別々にビルド・デプロイ・バージョニングされる 2 つの成果物であり,protocol を両モジュールに複製すれば必ず drift します.engine に 1 つだけ置けば,契約の不一致が「本番での実行時ミスマッチ」ではなく「コンパイルエラー / スナップショットテスト失敗」として早期に顕在化します.
-engine は Bukkit / Velocity API に依存せず,Adventure / Brigadier も「型・値の意味」だけを借りて本体依存を避けています (`compileOnly` の Adventure,Brigadier に依存せず `Int` を返す `toBrigadierResult()`).これにより engine は Minecraft サーバーを立てずに pure-JVM でテストでき,プラットフォーム都合 (Folia のスケジューラ等) は platform 側に隔離されます.
+engine は Bukkit / Velocity / Adventure / Brigadier のいずれの API にも依存せず,唯一の依存は `kotlinx-serialization-json` です.描画は platform 側へ押し出されており (`CommandResult` はメッセージを文字列で運び,`toBrigadierResult()` は Brigadier に依存せず `Int` を返す),プラットフォームのランタイムから何も借りていません.これにより engine は Minecraft サーバーを立てずに pure-JVM でテストでき,プラットフォーム都合 (Folia のスケジューラ,HTTP,Adventure コンポーネント等) は platform 側に隔離されます.
## プロトコルバージョンによる互換管理
@@ -77,7 +75,7 @@ Paper–Velocity 間の互換性は,プラグインのバージョンではな
4. **アノテーション駆動コマンド** — `@Command` / `@Permission` / `@PlayerOnly` を Kotlin リフレクションで読み Brigadier ツリーへマッピングします.コマンドの定義とメタデータ (権限・エイリアス) が同じ場所に宣言的に並びます.
5. **Folia 互換性** — 非同期処理は `asyncScheduler` と `PluginCoroutineScope` (SupervisorJob) で行い,Bukkit API 呼び出しは `scheduler.runTask` でメインスレッドへ戻します.リージョンスレッド化された Folia でも壊れないよう,スレッド境界を明示的に扱います.
6. **永続化の使い分け** — 言語/プレイヤー設定=KAML(YAML),チャンネル/変換キャッシュ=kotlinx.serialization JSON,チャンネルログ=NDJSON.いずれも「メモリキャッシュ+非同期保存 (デバウンス/キュー)+shutdown 同期保存」の共通パターンに従います.
-7. **DM/チャンネル=ローカル,グローバル=プロキシ経由** — チャットの種類でルーティングが分かれ,グローバルチャットだけが Velocity を経由します.中継は「送信元サーバー除外」+「messageId による重複排除」の二段でループを防ぎます.
+7. **チャンネル=ローカル,グローバルと DM=任意でプロキシ経由** — チャットの種類でルーティングが分かれます.チャンネルチャットは常にサーバーローカルで,グローバルチャットは `crossServerGlobalChat` が有効なとき,ダイレクトメッセージは `crossServerDirectMessage` が有効なときにプロキシを経由します.中継は「送信元サーバー除外」+「messageId による重複排除」の二段でループを防ぎます.
## 各モジュールの詳細についてはこちら
diff --git a/website/src/ja/docs/developers/engine.md b/website/src/ja/docs/developers/engine.md
index fb9ee9e..f798335 100644
--- a/website/src/ja/docs/developers/engine.md
+++ b/website/src/ja/docs/developers/engine.md
@@ -48,13 +48,11 @@ Paper–Velocity の互換性は,プラグインバージョンではなく `P
この設計の帰結として Paper と Velocity を独立にリリースできます.詳しくは [ビルド・リリース・バージョニング](/ja/docs/developers/resource#独立バージョニング) を参照してください.
-## converter — ローマ字→日本語変換
+## ローマ字変換はここにはない
-converter は Paper↔Velocity の契約ではなく (Velocity はローマ字変換をしない),**プラットフォームに依存しない純ロジックだから** engine に置かれています.3 段構成です.
+ローマ字変換は「プラットフォームに依存しない純ロジックだから」という理由で engine に置かれていましたが,現在は唯一の呼び出し元である [platform-paper](/ja/docs/developers/platform-paper) にあります.
-- `KanaConverter` (`object`) — **Trie** でローマ字→ひらがなに変換.`sealed class TrieNode { Leaf, Branch }` の不変構造で,4 文字 (`xtsu`→っ) 〜1 文字 (`a`→あ) を網羅.`isValidRomaji()` で変換前検証,`toHiragana()` は最長一致+促音処理を行う純アルゴリズム
-- `GoogleIMEClient` — Ktor `HttpClient` を DI で受け取り,Google IME (`langpair=ja-Hira|ja`) でひらがな→漢字仮名交じりに変換.レスポンスの各セグメント第 1 候補を連結する
-- `CacheData` (`@Serializable`) — 変換結果 (`version` + `entries: Map`) の永続化スキーマ.コストの高い IME 変換をキャッシュするための器で,キャッシュ本体のロジックは paper 側にある
+プラットフォーム非依存であることは,engine に置く理由としては不十分でした.ここに置くと engine が Ktor に依存し,両プラットフォームが engine に依存する構図上,**Velocity** の成果物が呼ばれることのない HTTP クライアントを同梱してしまうためです.これを外したことで engine の依存を `kotlinx-serialization-json` だけに絞れました.
## chat/channel — チャンネルのドメインモデル
@@ -81,14 +79,14 @@ UUID シリアライザが 2 つあるのは用途が違うためです.
## exception — 共通の例外語彙
-ドメインエラーを Paper / Velocity 双方で同じ型として扱えるよう,例外を engine に集約しています.共通の封印基底は持たず,`Exception` を直接継承するフラット構造 (23 種) です.存在/参照系・状態系・制限系・権限/BAN・KICK 系に分類でき,多くが `playerId` / `channelId` / `limit` をコンストラクタで受けてメッセージを自前生成します.基底を持たないため,呼び出し側は個別に catch する前提です.
+ドメインエラーを Paper / Velocity 双方で同じ型として扱えるよう,例外を engine に集約しています.共通の封印基底は持たず,`Exception` を直接継承するフラット構造です.存在/参照系・状態系・制限系・権限/BAN・KICK 系に分類でき,多くが `playerId` / `channelId` / `limit` をコンストラクタで受けてメッセージを自前生成します.基底を持たないため,呼び出し側は個別に catch する前提です.
## permission / command — 中立抽象
Bukkit / Velocity どちらの API にも渡せる中立表現として,権限とコマンド結果を engine に置いています.
- `LunaticChatPermissionNode` — `sealed class` + `object` サブクラスで権限を型安全に列挙.文字列ノードは両プラットフォームの permission API に渡せ,`when` で網羅性チェックも効く
-- `CommandResult` — `sealed class` (`Success` / `SuccessWithMessage` / `Failure` / `InvalidUsage`).メッセージは Adventure `Component`,`toBrigadierResult()` は Brigadier 本体に依存せず成功=1/失敗=0 という「戻り値の意味」だけを表現する
+- `CommandResult` — `sealed class` (`Success` / `SuccessWithMessage` / `Failure` / `InvalidUsage`).メッセージは平文の `String` として運ばれ,engine に Adventure の型は入らない (装飾は platform 側の責務).`toBrigadierResult()` は Brigadier 本体に依存せず成功=1/失敗=0 という「戻り値の意味」だけを表現する
## 関連
diff --git a/website/src/ja/docs/developers/platform-paper.md b/website/src/ja/docs/developers/platform-paper.md
index bbbeb0c..26a9ad7 100644
--- a/website/src/ja/docs/developers/platform-paper.md
+++ b/website/src/ja/docs/developers/platform-paper.md
@@ -121,7 +121,7 @@ config フラグ
### ダイレクトメッセージ (DirectMessageHandler)
-`/tell`・`/reply` の状態を管理します.`lastMessager` / `lastRecipient` の 2 つの `ConcurrentHashMap` で返信先を追跡し,`getReplyTarget()` は「自分に送ってきた人 → 自分が送った人」の優先順でオンラインのプレイヤーを返します.
+`/tell`・`/reply` の状態を管理します.`lastMessager` / `lastRecipient` の 2 つの `ConcurrentHashMap` が返信先を `sealed interface ReplyTarget` (`Local` = UUID / `Remote` = プレイヤー名+サーバー名) として追跡し,`getReplyTarget()` は「自分に送ってきた人 → 自分が送った人」の優先順で解決しながら検証します.`Local` はオンラインであること,`Remote` は `RemotePlayerRegistry` がそのサーバーに在席を報告していることが条件です.
`sendDirectMessage()` は,送信者設定に応じたローマ字変換 → spy プレイヤーへの hover 付き配信 (送受信者は除外) → 送受信者への整形メッセージ送信+通知音 (設定依存) を行います.メッセージには `/tell <sender>` を補完する `ClickEvent.suggestCommand` が付きます.
@@ -144,27 +144,27 @@ config フラグ
## config
-- `ConfigManager` — メイン `config.yml` を **Bukkit の `FileConfiguration`** からドット記法で読み,`LunaticChatConfiguration` を手組みする (この経路は KAML ではない点に注意)
+- `ConfigManager` — `config.yml` を **KAML** で `LunaticChatConfiguration` にデシリアライズする.デフォルト値の定義箇所をデータクラス 1 箇所に限定するためで,以前のドット記法の手組みマッパーは同じデフォルトを二重に持っており,実際に乖離していた (`checkForUpdates` が `config.yml` とデータクラスの双方と食い違い,`messageLogging` ブロックはドキュメント化されていながら一度も読まれていなかった)
+- 失敗はファイル単位ではなく設定単位で処理する.`YamlException` が出た場合は該当キーをドキュメントから取り除いてデコードを再試行するため,読めない値 1 つの影響はその値だけに留まる.全体をデフォルトに落とすのは「YAML として成立していない」場合だけで,いずれのケースも `onEnable` の外へ例外を投げない
+- `LenientBoolean` — `yes` / `no` / `on` / `off` も受け付けるシリアライザ付きの `Boolean` typealias.Bukkit は `config.yml` を YAML 1.1 として読んでいたためこれらは真偽値だったが,kaml が読む YAML 1.2 では単なる文字列であり,黙ってリセットすると `checkForUpdates: no` がデフォルトの逆の値に反転してしまう
- 機能デフォルト: `quickReplies=true`, `japaneseConversion=false`, `channelChat=false`, `velocityIntegration=false`
- `config/key` 以下に `FeaturesConfig` / `ChannelChatFeatureConfig` / `JapaneseConversionFeatureConfig` / `VelocityIntegrationConfig` / `QuickRepliesFeatureConfig` / `MessageFormatConfig` / `ChannelMessageLoggingConfig`
-::: warning 実装ノート
-`ChannelChatFeatureConfig.messageLogging` は `ConfigManager` でロードされず,デフォルト値 (enabled=true, retention=30, 100MB) 固定になっています.意図的な仕様か要確認 — 修正するか,仕様として明記するかを決める必要があります.
-:::
-
## i18n
- `Language` (enum) — `EN` / `JA`.未知コードは EN にフォールバック
- `LanguageManager` — 起動時に `resources/languages/` を KAML でロードし,ネストした YAML をドット記法 (`toggle.on` 等) にフラット化する.`getMessage(key, placeholders)` は 選択言語 → EN フォールバック で解決し `{placeholder}` を置換,未発見はキー自身を返す.EN が無ければ致命エラー
- `MessageFormatter` (`object`) — `[LC]` プレフィックス付きの Adventure `Component` を生成し,`{braces}` プレースホルダを正規表現で検出して色分けする
-## converter (paper 側) — engine 連携
+## converter — ローマ字→日本語変換
-paper 側は「キャッシュ管理・タイムアウト・Bukkit スケジューリング」というプラットフォーム都合を担い,変換アルゴリズムと API 通信は engine に委譲します.
+ローマ字変換はアルゴリズム・API クライアント・キャッシュ・プラットフォーム都合 (タイムアウト,スケジューリング) のすべてがここにあります.かつては「プラットフォーム非依存の純ロジック」として engine にありましたが,呼び出し元は `platform-paper` だけであり,engine に置いたままでは Velocity の成果物が使わない Ktor を同梱することになるため移されました.
-- `RomanjiConverter` — 2 段変換のオーケストレータ.単語ごとに キャッシュ確認 → engine `KanaConverter` でローマ字→ひらがな → engine `GoogleIMEClient` でひらがな→漢字.API 失敗時はひらがなにフォールバック
-- `ConversionCache` — engine `CacheData` を JSON 永続化.メモリキャッシュ+デバウンス保存 (`maxEntries` 超過時の退避は ConcurrentHashMap の順不同により実質ランダム,との FIXME あり)
-- `RomajiConversionHelper` — `convertWithRomaji()`.`runBlocking` + `withTimeoutOrNull` (既定 1000ms) で同期呼び出しし,成功時 `"元文 §e(変換)"`,失敗/タイムアウト時は原文を返す
+- `KanaConverter` (`object`) — **Trie** でローマ字→ひらがなに変換.`sealed class TrieNode { Leaf, Branch }` の不変構造で,4 文字 (`xtsu`→っ) 〜1 文字 (`a`→あ) を網羅.`isValidRomaji()` で変換前検証,`toHiragana()` は最長一致+促音処理を行う純アルゴリズム
+- `GoogleIMEClient` — Ktor `HttpClient` を DI で受け取り,Google IME (`langpair=ja-Hira|ja`) でひらがな→漢字仮名交じりに変換.レスポンスの各セグメント第 1 候補を連結する
+- `RomanjiConverter` — 2 段変換のオーケストレータ.単語ごとに キャッシュ確認 → `KanaConverter` → `GoogleIMEClient`.単語は並行して変換され,API 失敗時はメッセージ全体を失敗させずひらがなにフォールバックする
+- `ConversionCache` — `CacheData` を JSON 永続化.メモリキャッシュ+デバウンス保存 (`maxEntries` 超過時に削除されるのは古い順ではなく任意の 10%,ConcurrentHashMap が順不同であるため,との FIXME あり)
+- `RomajiConversionHelper` — `convertWithRomaji()` は `suspend` 関数で `withTimeoutOrNull` (既定 1000ms) により上限が設けられ,成功時 `"元文 §e(変換)"`,失敗/タイムアウト時は原文を返す.`convertWithRomajiBlocking()` はこれを `runBlocking` で包んだもので,イベントをキャンセルするか否かを return 前に決めなければならない `AsyncChatEvent` だけが使う.コマンドハンドラは tick スレッドで動くため suspend 版を使う必要がある
## velocity 連携 (Paper 側視点)
@@ -177,7 +177,7 @@ engine の protocol を使い,Bukkit の Plugin Messaging Channel (`lunaticcha
## settings / common
- `PlayerSettingsManager` — 3 種のブール設定を `ConcurrentHashMap` で管理.engine の DTO を使い,未設定はデフォルト true
-- `YamlPlayerSettingsStorage` — KAML で `player-settings.yaml` を read/write.読み込み失敗時はバックアップから復旧,5 秒デバウンス保存
+- `YamlPlayerSettingsStorage` — KAML で `player-settings.yaml` を read/write.5 秒デバウンス保存.バックアップファイルは存在せず,読み込み失敗時はログを出して**空の設定**にフォールバックするため,全プレイヤーの設定が黙ってデフォルトに戻る
- `UpdateChecker` — GitHub Releases API を Ktor で叩き semver 比較.結果は sealed `UpdateCheckResult`
- `SoundCollector` — 通知音の Adventure `Sound` 定数と Player 拡張関数
- `PermissionCollector` — `@PermissionDsl` + `+LunaticChatPermissionNode` 演算子で権限を集める DSL.`requirePermission` は engine の `RequirePermissionException` を投げる
diff --git a/website/src/ja/docs/features/admin.md b/website/src/ja/docs/features/admin.md
index 57d38c0..a29be09 100644
--- a/website/src/ja/docs/features/admin.md
+++ b/website/src/ja/docs/features/admin.md
@@ -24,9 +24,11 @@ layout: doc
## スパイモード
-`lunaticchat.spy` パーミッション (デフォルト: op) を持つプレイヤーは,サーバー上で送受信されるすべてのダイレクトメッセージを閲覧できます.
+`lunaticchat.spy` パーミッション (デフォルト: op) を持つプレイヤーは,サーバー上で送信されるダイレクトメッセージとチャンネルメッセージの両方を閲覧できます.
-- スパイプレイヤーにはローマ字変換前の元のメッセージが表示されます
+- ダイレクトメッセージは,送信者と受信者を除いてスパイプレイヤーに配信されます
+- チャンネルメッセージは,送信者とそのチャンネルのメンバーを除いてスパイプレイヤーに配信されます
+- ダイレクトメッセージについては,ローマ字変換前の元のテキストがスパイプレイヤーに表示されます.チャンネルメッセージはメンバーと同じ変換後の形で届きます
- ホバーテキストでスパイメッセージであることが示されます
- スパイプレイヤー自身は通常の送受信者リストには含まれません
@@ -46,6 +48,15 @@ layout: doc
checkForUpdates: true
```
+## Nightly ビルド
+
+リリース以外で `main` ブランチから作られたビルドは nightly として扱われ,プラグインがその旨を明示します.
+
+- すべてのプレイヤーに対して,ログイン時に不安定な可能性があることと GitHub Issues への案内が警告として表示されます
+- `/lc status` にも同じ警告が表示され,リリースチャンネルが緑ではなく黄色で表示されます
+
+nightly ビルドは[セキュリティポリシー](https://github.com/m1sk9/LunaticChat/blob/main/.github/SECURITY.md)のサポート対象外です.本番サーバーではリリースビルドを使用してください.
+
## デバッグモード
`debug` を `true` にすると,プラグインの詳細なログが出力されます.問題の調査やバグ報告時に有用です.
@@ -68,7 +79,7 @@ language: "ja" # "en" または "ja"
| パーミッション | デフォルト | 説明 |
|---------------|-----------|------|
-| `lunaticchat.spy` | op | 全ダイレクトメッセージの閲覧 |
+| `lunaticchat.spy` | op | 全ダイレクトメッセージ・チャンネルメッセージの閲覧 |
| `lunaticchat.channelbypass` | op | チャンネル制限のバイパス |
| `lunaticchat.noticeupdate` | op | アップデート通知の受信 |
| `lunaticchat.command.lcv.status` | op | `/lcv status` コマンドの使用 |
diff --git a/website/src/ja/docs/features/channel-chat.md b/website/src/ja/docs/features/channel-chat.md
index dce3c85..b9723ee 100644
--- a/website/src/ja/docs/features/channel-chat.md
+++ b/website/src/ja/docs/features/channel-chat.md
@@ -37,6 +37,19 @@ layout: doc
/lc channel status # 現在のアクティブチャンネルと参加チャンネル一覧を表示
```
+## グローバルチャットへの送信 (`!` プレフィックス)
+
+アクティブチャンネルがある間,チャットはそのチャンネルに送信されます.メッセージの先頭に `!` を付けると,チャンネルから退出したり切り替えたりせずに,そのメッセージだけをグローバルチャットへ送信できます.
+
+```
+!みんなこんにちは # アクティブチャンネルがあってもグローバルチャットへ送信される
+```
+
+`!` とその直後の空白は送信前に除去されるため,メッセージ本文には残りません.`!` のみのメッセージは破棄され,何も送信されません.
+
+> [!NOTE]
+> このプレフィックスはチャットリスナーが処理します.リスナーはチャンネルチャット・クロスサーバーグローバルチャット・ローマ字変換のいずれかが有効なときのみ登録されるため,3つすべてが無効な場合は先頭の `!` は入力したまま残ります.
+
## ロールと権限
チャンネルには3つのロールがあります.
@@ -87,6 +100,10 @@ layout: doc
`lunaticchat.channelbypass` パーミッション (デフォルト: op) を持つプレイヤーは,キック・BAN の保護やチャンネルの強制削除が可能です.
+## スパイモード
+
+チャンネルメッセージは管理者に対して非公開ではありません.`lunaticchat.spy` パーミッション (デフォルト: op) を持つプレイヤーには,送信者とそのチャンネルのメンバーを除いてチャンネルメッセージが配信されます.詳細は[スパイモード](/ja/docs/features/admin#スパイモード)を参照してください.
+
## メッセージフォーマット
チャンネルメッセージの表示形式は `config.yml` の `messageFormat.channelMessageFormat` でカスタマイズできます.詳細は[メッセージフォーマット](/ja/docs/reference/message-format)を参照してください.
diff --git a/website/src/ja/docs/features/direct-message.md b/website/src/ja/docs/features/direct-message.md
index 945a2db..736a257 100644
--- a/website/src/ja/docs/features/direct-message.md
+++ b/website/src/ja/docs/features/direct-message.md
@@ -42,6 +42,17 @@ layout: doc
/tell <player>@<server> <message>
```
+ここでのサーバー名は,**Velocity の設定 (`velocity.toml`) に登録されている**宛先サーバーの名前です.プロキシはこの名前で宛先を解決します.タブ補完では,その時点で判明しているサーバー名とプレイヤーが提示されます.
+
+各バックエンドの `features.velocityIntegration.serverName` にも同じ名前を設定してください.この設定値はルーティングには使われませんが,クロスサーバーチャットの `{server}` に入る値であり,またサーバーが自分のプレイヤーを識別するために使われます.Velocity 側の名前と食い違っていると,ローカルのプレイヤーがタブ補完でリモート扱いになります.
+
+送信が失敗する場合は次の2種類があり,送信者にどちらであるかが通知されます.
+
+| 理由 | 意味 |
+|------|------|
+| `SERVER_NOT_FOUND` | その名前で登録されているサーバーがプロキシ上に存在しない |
+| `TARGET_OFFLINE` | サーバーは存在するが,そのプレイヤーがそこにいない (別のサーバーでオンラインである場合も含む) |
+
## 通知設定
プレイヤーはダイレクトメッセージ受信時のサウンド通知を個別に制御できます.
diff --git a/website/src/ja/docs/features/japanese-conversion.md b/website/src/ja/docs/features/japanese-conversion.md
index b94542e..1cc7d6b 100644
--- a/website/src/ja/docs/features/japanese-conversion.md
+++ b/website/src/ja/docs/features/japanese-conversion.md
@@ -19,8 +19,11 @@ layout: doc
入力: konnichiha sekai
変換1: こんにちは せかい
変換2: こんにちは 世界
+送信: konnichiha sekai §e(こんにちは 世界)
```
+入力した文字列は**置き換えられません**.入力したそのままの文字列を残し,その後ろに変換結果を括弧付きで併記するため,受信側には両方が表示されます.
+
## 変換対象
- 通常チャット
@@ -48,7 +51,7 @@ layout: doc
| `cache.saveIntervalSeconds` | `300` | ディスク保存の間隔 (秒) |
| `cache.filePath` | `"conversion_cache.json"` | キャッシュファイルのパス |
-キャッシュが上限に達すると,古いエントリの10%が自動的に削除されます.
+キャッシュが上限に達すると,エントリの10%が削除されます.どのエントリが削除されるかは規定されていません.メモリ上のキャッシュは順序を持たないため,古い順ではなく実質的に任意のエントリが対象になります.
## API 設定
@@ -56,6 +59,11 @@ Google IME API への接続に関する設定です.
| 設定キー | デフォルト | 説明 |
|----------|-----------|------|
-| `api.timeout` | `3000` | リクエストタイムアウト (ミリ秒) |
+| `api.timeout` | `3000` | API リクエスト1回あたりのタイムアウト (ミリ秒) |
API がタイムアウトまたは失敗した場合,ひらがなのまま送信されます.
+
+> [!WARNING]
+> `api.timeout` とは別に,1メッセージの変換処理全体に **1000ミリ秒**の上限があります.この上限に達すると変換は中断され,入力したそのままの文字列が (何も併記されずに) 送信されます.
+>
+> 変換全体の上限が `api.timeout` のデフォルト値より短いため,`api.timeout` を `1000` より大きくしても実質的な効果はありません.
diff --git a/website/src/ja/docs/features/velocity.md b/website/src/ja/docs/features/velocity.md
index 55ee653..9020ea1 100644
--- a/website/src/ja/docs/features/velocity.md
+++ b/website/src/ja/docs/features/velocity.md
@@ -51,6 +51,8 @@ features:
各メッセージに一意な ID が付与され,キャッシュにより同じメッセージが重複して表示されることを防ぎます.キャッシュサイズは `messageDeduplicationCacheSize` (デフォルト: `100`) で設定できます.
+エントリは記録から 60 秒で期限切れになります.期限切れエントリを削除してもなお設定サイズを超えている場合は,残りのうち古いものから削除されます.
+
## クロスサーバーダイレクトメッセージ <Badge type="tip" text="v1.3.0~" />
`crossServerDirectMessage` を `true` にすると,同プロキシ内で接続しているサーバーのプレイヤー同士でメッセージのやり取りができるようになります.
@@ -80,7 +82,8 @@ features:
|----------|-----------|------|
| `enabled` | `false` | Velocity 連携を有効にする |
| `crossServerGlobalChat` | `false` | クロスサーバーグローバルチャットを有効にする |
-| `serverName` | `"Unknown"` | クロスサーバーチャットで表示されるサーバー名 |
+| `crossServerDirectMessage` | `false` | クロスサーバーダイレクトメッセージを有効にする |
+| `serverName` | `"Unknown"` | このサーバー自身の名前.クロスサーバーチャットの `{server}` に入り,自分のプレイヤーを識別するために使われる.`velocity.toml` に登録した名前を設定する |
| `messageDeduplicationCacheSize` | `100` | メッセージ重複排除キャッシュのサイズ |
## メッセージフォーマット
diff --git a/website/src/ja/docs/permissions.md b/website/src/ja/docs/permissions.md
index 3fb20f5..b2726dd 100644
--- a/website/src/ja/docs/permissions.md
+++ b/website/src/ja/docs/permissions.md
@@ -44,7 +44,7 @@ LunaticChat のすべてのパーミッションノードの一覧です.
| パーミッション | デフォルト | 説明 |
|---------------|-----------|------|
-| `lunaticchat.spy` | op | サーバー上の全ダイレクトメッセージを閲覧 |
+| `lunaticchat.spy` | op | サーバー上の全ダイレクトメッセージ・チャンネルメッセージを閲覧 |
| `lunaticchat.noticeupdate` | op | アップデート通知の受信 |
| `lunaticchat.channelbypass` | op | チャンネル制限のバイパス(キック・BAN 保護,強制削除) |
| `lunaticchat.command.lcv.status` | op | `/lcv status` コマンドの使用 |
diff --git a/website/src/ja/docs/reference/commands.md b/website/src/ja/docs/reference/commands.md
index 7250ddd..8102a75 100644
--- a/website/src/ja/docs/reference/commands.md
+++ b/website/src/ja/docs/reference/commands.md
@@ -58,7 +58,8 @@ LunaticChat で使用できるすべてのコマンドのリファレンスで
- **エイリアス**: `new`
- **パーミッション**: `lunaticchat.command.lc.channel.create`
-- `channelId`: 英数字,アンダースコア,ハイフンのみ使用可能
+- `channelId`: 3〜30文字.英数字,アンダースコア,ハイフンのみ使用可能
+- `name`: 空文字は不可
- `isPrivate`: `true` / `false`(デフォルト: `false`)
#### `/lc channel list [page]`
diff --git a/website/src/ja/docs/reference/compatibility.md b/website/src/ja/docs/reference/compatibility.md
index 587261e..781dbf6 100644
--- a/website/src/ja/docs/reference/compatibility.md
+++ b/website/src/ja/docs/reference/compatibility.md
@@ -57,9 +57,11 @@ Paper / Velocity 間の通信は LunaticChat 独自のプラグインメッセ
接続時は以下の流れで互換性が確認されます:
-1. Paper サーバー起動時に Velocity に対してハンドシェイクを送信
+1. **最初のプレイヤーがログインした 1 秒後**に,Paper サーバーが Velocity に対してハンドシェイクを送信
2. Velocity が Paper のプロトコルバージョンを自身のものと照合
3. 不一致の場合は Velocity が接続を拒否し,Paper 側の状態が `FAILED` になる
4. ハンドシェイクのタイムアウトは 5 秒
+ハンドシェイクはサーバー起動ごとに1回だけ送信されます.起動時ではなくプレイヤーのログインが契機になるのは,送信に使う plugin messaging チャネルがプレイヤーの接続を必要とするためです.最初のプレイヤーがログインするまで `/lcv status` は `DISCONNECTED` を報告しますが,これは正常であり異常の兆候ではありません.
+
接続状態は `/lcv status` で確認できます.詳細は [Velocity 連携](/ja/docs/features/velocity#接続状態) を参照してください.