LoVisual/TODO.md

99 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## Фаза 11: Серверный плагин — сервер может отключать функции мода (дизайн 2026-09-30)
> Идея владельца 2026-09-29. Решения владельца 2026-09-30: **Velocity (прокси)** —
> целевой софт v1; **политика — локальный YAML плагина** (наш бэкенд не участвует);
> **дизайн → сразу код**. Статус: дизайн написан, код — в этом же заходе.
**Что это.** Отдельный плагин для Velocity-прокси, который публикует подключившимся
игрокам «политику»: какие возможности LoVisual на этом прокси запрещены. Мод применяет
её автоматически — честный игрок не может включить запрещённое, пока находится за этим
прокси. Работает без интернета и без нашего бэкенда.
### Канал и формат (v1)
Канал: plugin message `lovisual:policy` (`MinecraftChannelIdentifier`), payload — UTF-8 JSON.
- **S→C (push)** — прокси шлёт при `PostLoginEvent` и при `ServerConnectedEvent`
(смена backend-сервера), плюс в ответ на запрос клиента:
```json
{ "type": "policy", "deny": ["esp", "freecam", "hitboxes"],
"mode": "lock", "reason": "правила сервера", "server": "lobby-1" }
```
- **C→S (request)** — клиент просит политику (шлёт при входе в play-состояние и после
каждой смены сервера; это страховка, если push не дошёл из-за регистрации канала):
```json
{ "type": "request" }
```
- `mode: lock` — запрещённые модули выключаются и не включаются, ClickGui показывает
замок с подписью «отключено сервером» (reason из политики);
- `mode: suggest` — при попытке включить: предупреждение в чат, игрок сам решает;
- поле `server` — имя backend-сервера (для логов и будущей per-server политики;
v1 политика одна на весь прокси).
### Velocity-плагин (`server-plugin/`)
Отдельный Gradle-проект в корне репо (серверная Java, не Fabric-клиент; в `mod/`-сборку
не входит). Velocity API 4.2.0 (release, papermc-repo), Java 21; gson + snakeyaml
shaded в jar; JUnit 5 для тестов логики.
- `PolicyConfig` — YAML из `plugins/lovisual-policy/config.yml`:
```yaml
enabled: true
mode: lock # lock | suggest
reason: "Правила сервера"
deny: [esp, freecam, hitboxes, fullbright]
```
при первом запуске пишется дефолтный; `/lvpolicy reload` — перечитать,
`/lvpolicy status` — режим/счётчик/версию конфига.
- `PolicyMessage` — кодирование policy-JSON и разбор `request` (gson).
- `LoVisualPolicyPlugin` — тонкий вiring: `ProxyInitializeEvent` (регистрация канала),
`PostLoginEvent`/`ServerConnectedEvent` (push), `PluginMessageEvent` (ответ на
request), команда `/lvpolicy`. Вся логика — в `PolicyConfig`/`PolicyMessage`
(тестируются без Velocity-сервера).
- Если конфиг `enabled: false` — плагин молчит (канал зарегистрирован, сообщений нет).
### Клиент в моде (`features/platform/serverpolicy/`)
- `ServerPolicy` — record: `mode` (`LOCK`/`SUGGEST`), `deny` (set), `reason`, `server`;
- `ServerPolicyCodec` — Gson parse/encode (тот же gson, что у `PlatformHttpClient`);
- `ServerPolicyState` — синглтон-состояние: текущая политика, `allows(moduleId)`,
`isLocked()`, `clear()` при дисконнекте; при получении — принудительное выключение
запрещённых включённых модулей (source INTERNAL) + одно chat-уведомление;
- `ServerPolicyPayload` + регистрация через Fabric networking
(`PayloadTypeRegistry` playS2C/playC2S) — S2C receiver пишет в State и отвечает
ничего (push-модель), C2S `request` шлётся клиентом при входе; авторегистрация
`minecraft:register` — на стороне Fabric API;
- применимый шлюз один: `ModuleLifecycleHelper.setEnabled` — при `state==true` и
`!ServerPolicyState.allows(id)` → отказ (+ chat-сообщение в `lock`, просто
предупреждение в `suggest`); то же правило в `loadAndApply` (загрузка конфига не
включает запрещённое);
- ClickGui: на строке запрещённого модуля — замок и подпись reason (по образцу
setting-level unavailable);
- `%policy` — команда (`features/command/impl/platform/PolicyCommand`): текущий режим,
список запрещённых, источник (сервер), время получения.
### Честные ограничения (записаны заранее)
Применение политики — на клиенте: читер может её игнорировать. Это не античит —
цель: правила сервера и удобство честных игроков. Настоящая защита — серверный
античит, он отдельно. Подсистема 2 не конфликтует: там realtime-слой (RPC/друзья),
здесь — один payload при входе, каналы разные.
### Тесты и приёмка
- плагин: `PolicyConfigTest` (парс YAML: режимы, дефолты, кривой mode → исключение),
`PolicyMessageTest` (encode policy / decode request / экранирование reason);
- мод: `ServerPolicyCodecTest` (round-trip, мусорный JSON → пустая политика),
`ServerPolicyStateTest` (allows/lock/suggest, force-disable, clear на дисконнекте);
- `./gradlew build` + `test` в обоих проектах; ручная приёмка на стенде владельца:
поднять Velocity с плагином → зайти клиентом → `%policy` показывает политику →
запрещённый модуль не включается (lock).
### Риски / известное
- версия протокола клиента (MC 26.2) должна поддерживаться версией прокси —
проверяется на стенде владельца (плагин от версии протокола не зависит);
- push S→C может не дойти, пока клиент не зарегистрировал канал — поэтому есть
C→S `request` и повторный push при `ServerConnectedEvent`;
- пер-server политика (у каждого backend свой набор) — backlog: формат поля `server`
для неё зарезервирован.