LoParkour/TODO.md
loki5512344 fd0ba2cc0e refactor: reorganize packages and replace LPSchematic with WorldEdit
Restructure core modules into subpackages (generator, schematic, config, session, etc.); add .schem/.nbt schematic pipeline, commands, adaptive stats skeleton, and bootstrap wiring.
2026-06-01 14:02:48 +02:00

324 lines
15 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.

# LoParkour — TODO (обновлено 2026-06-01)
> Roadmap + **честный аудит** репозитория. Старые галочки «✅» в фазах 1–4 не соответствуют коду — см. раздел **Аудит**.
## Легенда
- 🔴 Критично — блокирует сборку / релиз / основной UX
- 🟡 Важно — заявленная функциональность или i18n
- 🟢 Планово — улучшение, рефакторинг
- ✅ Готово (проверено в коде)
---
## Аудит 2026-06-01 (снимок)
| Область | Факт |
|--------|------|
| **Сборка** | ✅ `./gradlew compileJava` проходит |
| **Адаптивность** | 🟡 Подключено: `AdaptiveServices`, `MetricsCollector` на генераторе, профиль после fall/reset |
| **Elytra** | 🟡 `ElytraMode` + `ElytraGenerator` есть; отдельного `mode/elytra/*` из старого TODO **нет** |
| **Размер файлов** | 🔴 Цель «все < 200 строк» **не выполнена**: 18 файлов > 150, 2 > 200 |
| **i18n** | 🟡 Основные потоки через `Locales`; остаётся Phase 0 split + `MessageKeys` |
| **GUI** | 🟡 Основные меню на LoLib OK; **заглушки** `Menu`/`PagedMenu`, `DynamicMenu` вырезан |
| **TODO.md** | Ранее помечено ✅ то, что не сделано — статусы ниже исправлены |
**Статистика:** ~160 `.java` файлов, средний размер ~85 строк, максимум **252** (`ElytraGenerator.java`).
---
## Фаза 0: Полный рефакторинг (KISS · DRY · SOLID) — приоритет
> Цель: предсказуемая структура, тонкие классы, без «божественных» файлов.
### Правила (жёсткие)
| Правило | Значение |
|--------|----------|
| **Целевой размер** | ~**150** строк на файл |
| **Жёсткий потолок** | **190–200** строк (исключения только с комментом в PR) |
| **Файлов в папке** | ≤ **6** (при росте — новая подпапка) |
| **KISS** | Один публичный сценарий = один класс / use-case |
| **DRY** | Сообщения только через `Locales`; команды — `Messages` / `admin.*` |
| **SOLID** | `generator` не импортирует `adaptive`; связь только через `GeneratorEventListener` + DI в bootstrap |
### Целевая структура пакетов (✅ 2026-06-01)
```
dev.loki.loparkour/
├── LoParkour.java # main plugin class
├── command/
│ ├── LoParkourCommand.java
│ ├── player/ # PlayerCommandHandler
│ ├── admin/ # AdminCommandHandler
│ └── schematic/ # SchematicCommandHandler
├── config/
│ ├── core/ # Config, ConfigLoader, ConfigAccessor, ConfigUpdater
│ ├── locale/ # Locales, LocaleLoader, LocaleCache
│ └── options/ # Option + OptionSQL, OptionGeneral, …
├── generator/
│ ├── core/ # ParkourGenerator, Profile, GeneratorState, …
│ ├── jump/, lifecycle/, profile/, effect/
│ └── core/GeneratorEventListener
├── mode/
│ ├── base/ # Mode, MultiMode, Modes, ModeMessages
│ ├── impl/ # DefaultMode, SpeedrunMode, …
│ └── elytra/ # ElytraGenerator + ring/physics/hud
├── menu/
│ ├── core/ # LPMenu, MainMenu, Menus, ParkourOption
│ └── play/, settings/, community/, lobby/
├── player/
│ ├── core/ # ParkourUser, ParkourPlayer
│ ├── service/ # UserRegistry, hotbar, scoreboard, …
│ ├── spectator/
│ └── data/
├── util/
│ ├── text/, item/, gui/, world/, particle/, misc/
├── storage/
│ ├── Storage.java # фасад
│ ├── sql/ # StorageSQL, SQL*, миграции
│ └── disk/ # StorageDisk (JSON)
├── session/
│ ├── core/Session.java
│ └── manager/ # State, Player, User managers
├── listener/
│ ├── player/, gameplay/, schematic/
├── leaderboard/
│ ├── model/Score, core/, persistence/
├── ghost/
│ ├── model/, core/
├── hook/
│ ├── papi/, holo/, floodgate/, vault/
├── schematic/
│ ├── registry/Schematics.java
│ └── lpschem/
├── api/core/ + api/event/
├── reward/core/, style/core/, world/core/
├── adaptive/bootstrap/AdaptiveServices
├── bootstrap/PluginBootstrap
└── …
```
Скрипт переноса: `scripts/refactor-packages.ps1` (+ `fix-imports-after-refactor.ps1`).
### Очередь разбиения (файлы > 150 строк)
| Приоритет | Файл | Строк | Действие |
|-----------|------|-------|----------|
| ✅ 1 | `ElytraGenerator.java` | 101 | → `elytra/ElytraRingLoop`, `ElytraScoring`, `ElytraHud`, `ElytraPlayerKit`, `ElytraFireworkListener` |
| ✅ 2 | `ParkourPlayer.java` | 166 | → `ParkourHotbar` |
| 🟡 3 | `PAPIHook.java` | 194 | → placeholders по группам |
| 🟡 4 | `LoParkour.java` | 192 | → `bootstrap/PluginBootstrap.java` |
| 🟡 5 | `MetricsCollector.java` | 187 | → session hook + jump hook + flush |
| 🟡 6 | `StorageSQL.java` | 179 | → queries / mapper / connection (уже частично) |
| 🟡 7 | `BlockPlacer.java` | 176 | | |
| 🟡 8 | `JumpValidator.java` | 172 | | |
| 🟡 9 | `LoParkourCommand.java` | 170 | → делегаты только маршрутизация |
| 🟡 10 | `CoopMode.java` | 165 | → `CoopGenerator` отдельный файл |
| 🟢 | остальные 151–159 | 8 файлов | после топ-10 |
### Чек-лист фазы 0
- [ ] Нет файлов > 200 строк (кроме явно согласованных)
- [x] Пакеты разнесены (config/mode/command/generator/menu/player/util)
- [ ] Нет циклических зависимостей `generator` ↔ `adaptive`
- [ ] Единый `MessageService` / `Locales` для player + console + action bar + title
- [ ] Удалить или подключить мёртвый код: `Menu`, `PagedMenu`, `DynamicMenu`, `MenuStub`
- [ ] `Option.java` — только фасад, без роста (делегаты в `options/*`)
- [x] `./gradlew build` зелёный
- [ ] README/TODO не врут про «всё готово»
---
## Баги и долг (найдено при аудите)
### 🔴 Сборка
| # | Проблема | Статус |
|---|----------|--------|
| B1 | `SQLConnectionManager` visibility | ✅ |
| B2 | `AdaptiveConfig` + `Config.CONFIG` | ✅ |
### 🟡 Локализация (i18n) — большинство закрыто
| # | Проблема | Статус |
|---|----------|--------|
| I1 | `LPMenu` back/next | ✅ `other.back`, `other.next` |
| I2 | `other.no_menu_items` | ✅ |
| I3 | joining disabled | ✅ `ModeMessages` + `other.joining_disabled` |
| I4 | Elytra messages | ✅ `modes.elytra.*` |
| I5–I11 | Race, coop, admin, schematic, commands, bungee, GUI stubs | ✅ (см. `locales/*.yml`) |
| I12 | `ghost.saved` в en | ✅ |
| I13 | `%[a-z]` vs `%s` | 🟢 документировать / унифицировать позже |
| I14 | reload NPE с консоли | ✅ `getString(sender, …)` |
| I15 | недостающие ключи | ✅ основной набор добавлен |
### 🟡 Логика / архитектура
| # | Проблема | Где |
|---|----------|-----|
| A1 | `MetricsCollector` на генераторе | ✅ `SessionStateManager` + `AdaptiveServices.attachToGenerator` |
| A2 | Adaptive → профиль генерации | ✅ `GeneratorProfileManager` + `AdaptiveDifficulty` |
| A3 | `adaptive.*` в config.yml | ✅ |
| A4 | SQL таблица stats | ✅ `StorageSQL` + `SQLMigrationManager.createAdaptiveStatsTable` |
| A5 | `DynamicMenu` мёртвый | 🔴 |
| A6 | STONE debug-spam | ✅ только при отсутствии `.material` |
| A7 | Несогласованные пути locale: `play.single.*` vs `modes.*` для режимов | `*Mode.getItem()` |
| A8 | `sendHelp` упоминает `/LoParkour`, игроки используют `/parkour` | `PlayerCommandHandler` |
### 🟢 Мелочи
| # | Проблема |
|---|----------|
| M1 | `SpectatorMode`: MiniMessage `<red>` vs legacy `§c` в других режимах |
| M2 | `HardcoreMode` / др.: смешение `ColorUtil` и сырого `sendMessage` |
| M3 | Unit/integration тесты в TODO помечены ✅ — **фактически** только 2 test-класса |
---
## Фаза 1: Рефакторинг структуры (статус реальный)
### Архитектура
| # | Задача | Статус |
|---|--------|--------|
| 1 | Разбить `ParkourGenerator` | 🟡 Частично (composition), файл 159 строк — ок |
| 2 | `GeneratorProfileManager` | 🟡 Есть, без отдельного `ProfileCalculator` |
| 3 | statistics из generator | 🟡 `GeneratorStatistics` внутри generator, не пакет `statistics/` |
| 4 | Структура пакетов `generator/core`, `jump`, `lifecycle` | 🟡 Частично |
| 5 | `GeneratorEventListener` | ✅ Интерфейс + вызовы в `PlayerInteractionHandler` |
### Большие файлы (цель &lt; 200) — **не выполнено**
| Файл | Строк | Статус |
|------|-------|--------|
| ElytraGenerator.java | 101 | ✅ |
| ParkourPlayer.java | 166 | ✅ |
| PAPIHook, LoParkour, MetricsCollector, … | 151–194 | 🟡 см. Фаза 0 |
---
## Фаза 2: Адаптивная система (статус реальный)
| # | Задача | Статус |
|---|--------|--------|
| 1 | `adaptive/model/` | 🟡 Классы есть |
| 2 | `adaptive/storage/` | ✅ compile + SQL/file repo |
| 3 | SQL таблицы | ✅ CREATE в `StorageSQL` / `SQLMigrationManager` |
| 4 | File JSON storage | ✅ |
| 5 | `MetricsCollector` | ✅ |
| 6 | Calculator / Adjuster в профиле | ✅ через `AdaptiveDifficulty` |
| 7 | `AdaptiveMode`, `StatsService` | 🔴 отдельный режим не нужен пока |
| 8 | `config.yml` → `adaptive.*` | ✅ |
---
## Фаза 3: ElytraMode (статус реальный)
| # | Задача | Статус |
|---|--------|--------|
| 1 | `ElytraMode` | 🟡 Есть |
| 2 | `ElytraGenerator` + helpers | ✅ Разбит на `mode/elytra/*` |
| 3 | `ElytraConfig`, `RingRenderer`, … | ✅ В пакете `mode/elytra/` |
| 4 | `modes/elytra.yml` | 🔴 Нет |
| 5 | i18n для elytra | ✅ |
---
## Фаза 4: Режимы (статус реальный)
| Режим | Меню | i18n join disabled | Примечание |
|-------|------|-------------------|------------|
| default, speedrun, hardcore, gravity-shift | ✅ SingleMenu | 🔴 хардкод EN | |
| elytra, race | ✅ | 🔴 | race — ещё UI хардкод |
| coop | ❌ (null item — ок) | 🔴 | title хардкод |
| spectator | ✅ | 🟡 частично Locales | |
| roguelike | — | — | **Нет в коде** (в старом TODO было ✅ — ошибка) |
---
## Фаза 5: i18n — единая система сообщений
| # | Задача | Статус |
|---|--------|--------|
| 1 | `other.back` / `other.next` | ✅ |
| 2 | Ключи из таблицы I* | ✅ |
| 3 | `MessageKeys` enum или constants class (DRY путей) | 🟢 |
| 4 | `Locales.getString(CommandSender)` — использовать везде для консоли | 🟡 Частично |
| 5 | Убрать debug-spam STONE | ✅ |
| 6 | Синхронизировать `en.yml` ↔ `ru.yml` | 🟡 периодический diff |
| 7 | Проверка CI: скрипт diff ключей locale vs `Locales.getString`/`sendTranslated` | 🟢 |
---
## Технический долг (актуальный)
| # | Задача | Приоритет |
|---|--------|-----------|
| 1 | Compile adaptive | ✅ |
| 2 | Bootstrap MetricsCollector | ✅ |
| 3 | SQL adaptive table | ✅ |
| 4 | Удалить или реализовать `Menu`/`PagedMenu`/`DynamicMenu` | 🟡 |
| 5 | Реальные тесты adaptive + modes | 🟢 |
---
## Чек-лист перед релизом (честный)
- [x] `./gradlew build` без ошибок
- [x] Нет хардкода RU в `LPMenu` / основных режимах и админке
- [ ] Полный diff ключей locale vs Java (CI)
- [ ] Адаптивность: ручной тест на сервере (`adaptive.enabled: true`)
- [ ] ElytraMode протестирован вручную
- [ ] Нет файлов &gt; 200 строк (или исключения задокументированы)
- [ ] README / CHANGELOG соответствуют коду
---
## SQL миграция (без изменений)
```sql
CREATE TABLE IF NOT EXISTS loparkour_player_stats (
player_uuid VARCHAR(36) PRIMARY KEY,
skill_rating DOUBLE DEFAULT 1.0,
sessions_count INT DEFAULT 0,
total_jumps INT DEFAULT 0,
total_falls INT DEFAULT 0,
longest_streak INT DEFAULT 0,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_skill_rating (skill_rating),
INDEX idx_last_updated (last_updated)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
---
## Оценка времени (пересмотр)
| Фаза | Дней | Комментарий |
|------|------|-------------|
| **0: KISS/DRY/SOLID + лимит строк** | 5–8 | Блокирует нормальную поддержку |
| **5: i18n** | 2–3 | Можно параллельно с 0 |
| **2: Adaptive** | 3–4 | После зелёной сборки + bootstrap |
| **3: Elytra split** | 1–2 | После 0 |
| **4: Режимы / тесты** | 2–3 | |
| **Итого** | **13–20** | Старые «8–12 дней» занижены |
---
## Метрики успеха (пересмотр)
### Технические
- [ ] ≥ 90% файлов ≤ 150 строк
- [ ] 0 файлов &gt; 200 строк
- [ ] SOLID: `adaptive` → listener/port, не прямой import generator internals
- [ ] `./gradlew test` — осмысленное покрытие, не «галочка в TODO»
### Функциональные
- [ ] 2+ языка без хардкода в Java (кроме логов debug)
- [ ] Adaptive влияет на профиль после N сессий
- [ ] ElytraMode без монолита 250+ строк
### Производительность
- [ ] TPS стабилен 50+ игроков (профилирование)
- [ ] SQL batch / flush adaptive &lt; 50ms