fix(lint,command,scheduler): lpk alias, ReturnCount/IllegalCatch triage, scheduler facade
- command: replace /lp alias with /lpk (LuckPerms conflict, p.144);
parkour alias kept; docs/changelog/javadoc updated
- lint p.169: restructure last 69 void early-returns into if-blocks and
helpers; ReturnCount is now an error gate (0 violations)
- lint p.170: Throwable->RuntimeException on 3 boundaries; narrow 5
catches to concrete types; document 14 intentional boundary catches
- scheduler p.21: add runTimerAsync to the facade (Bukkit + Folia
backends); MetricsCacheStore and duels go through the facade, no
BukkitRunnable/Bukkit.getScheduler outside scheduler/ (archunit
freeze-store emptied); drop the unverified Folia badge from README
- tracker: mark p.26-29/32-33 done (fixed in fea15e6, verified)
This commit is contained in:
parent
8ff02cff18
commit
b6712391fd
79 changed files with 696 additions and 800 deletions
52
TODO.md
52
TODO.md
|
|
@ -46,19 +46,32 @@
|
|||
|
||||
### Функциональность, которая не работает
|
||||
|
||||
- **21. Folia-поддержка — фикция.** Нет `folia-plugin.yml` (Folia не загрузит плагин). `MetricsCollector` использует удалённое API `BukkitRunnable.runTaskTimerAsynchronously` (MetricsCollector.java:73). `SessionStateManager.runTimer` → GlobalRegionScheduler, но тик мутирует блоки/entities (SessionStateManager.java:76, LifecycleTickManager.java:75, BlockPlacer.java:158, teleport в ParkourUser.java:93-95). → Либо выпилить бейдж Folia из README, либо: добавить folia-plugin.yml, перевести тик на runTimerAtLocation/runAtEntity, заменить BukkitRunnable.
|
||||
- **21. Folia-поддержка — фикция.** ✅ **ЧАСТИЧНО (2026-10-10):** все вызовы планировщика идут через фасад `scheduler/`
|
||||
(добавлен `runTimerAsync`: Bukkit → `runTaskTimerAsynchronously`, Folia → `AsyncScheduler.runAtFixedRate` рефлексией);
|
||||
`MetricsCacheStore` переведён с `BukkitRunnable` на фасад, прямые `Bukkit.getScheduler()` из `DuelsCountdown`/`DuelsGenerator`
|
||||
убраны — вне `scheduler/` их больше нет. Бейдж Folia из README убран (поддержка не проверена на Folia-сервере).
|
||||
❌ Осталось: тик идёт через global scheduler, но мутирует блоки/entities (`SessionStateManager`, `LifecycleTickManager`,
|
||||
`BlockPlacer`, teleport) → нужен region/entity-tick + `folia-plugin.yml`; без Folia-стенда не верифицируется (см. п.143).
|
||||
- **22. Ghost-система — 100% мёртвый код.** `GhostManager`/`GhostRecorder`/`GhostPlayer` нигде не инстанцируются (grep: только само-ссылки). Конфиг `ghost-mode.*` не потребляется. → Подключить к lifecycle (запись в saveGhost/спавн в spawnGhosts) ИЛИ удалить подсистему и конфиг.
|
||||
- **23. Coop-режим нерабочий.** Ни одно `Session.create` не строит `CoopGenerator` (CoopMode.java:134). `/parkour join <игрок>` ведёт в спектаторы. → Реализовать создание coop-сессии (лобби/инвайты) или выпилить режим из меню и регистрации.
|
||||
- **24. Coop: латентный StackOverflow.** `ParkourPlayer.unregister()` → `CoopMode.leave()` → `ParkourUser.leave()` → `UserRegistry.unregister()` → `user.unregister()` — бесконечная рекурсия (ParkourPlayer.java:102-107, CoopMode.java:115-121, UserRegistry.java:58-67). Нет guard-флага. → Добавить in-flight guard в unregister (например, reentrancy flag в ParkourUser).
|
||||
- **25. Лидерборд: тайминги сломаны.** `Score.getTimeMillis()` ждёт ровно 3 части через `:` (Score.java:36-55), но генератор пишет `mm:ss.SSS` (2 части) и `HH:mm:ss.SSS` (третья `02.123` → NFE). Итог: TIME-сортировка и тай-брейк мёртвые, Race-лидерборд не обновляется. Плюс переполнение `int` в m*60*1000+... (Score.java:51). → Унифицировать формат времени; парсить `mm:ss.SSS` и `HH:mm:ss.SSS`; перейти на `long`.
|
||||
- **26. ConfigUpdater уничтожает пользовательские данные.** `merge()` перегенерирует весь файл из шаблона при каждом старте (ConfigUpdater.java:85-127): теряются листы (`options.leads.amount`, стили), кастомные ключи, комментарии; алгоритм отступов (`prevIndent -= 2`) ошибочен; `ignoredSections` не защищают. → Точечный merge только отсутствующих ключей, сохранять листы/комментарии, либо заменить на библиотеку (e.g. `me.mattstudios` / SimpleConfig) или `Bukkit's config addDefaults`.
|
||||
- **27. SQL: утечка Hikari-пулов.** `StorageSQL.init(mode)` вызывается на каждый режим (6 лидербордов), каждый раз пересоздаёт `connectionManager` (StorageSQL.java:66-77, LeaderboardStorage.java:35) → до ~10 соединений висят навсегда. → Один пул на плагин, инициализация один раз.
|
||||
- **28. SQL: блокирующий connect на main thread** (SQLConnectionManager.java:34-56) — при лежащей БД включение висит до 5с×режимы. → `setInitializationFailTimeout(-1)` + асинхронный connect.
|
||||
- **29. SQL: адаптив не стартует.** `AdaptiveServices.init` вызывается до создания лидербордов, а `StorageSQL.runWhenConnected` выбрасывает колбэк при не-подключении (StorageSQL.java:45-51). → Очередь колбэков в SQLConnectionManager.onConnectCallbacks; порядок init: лидерборды → storage → adaptive.
|
||||
- **26. ConfigUpdater уничтожает пользовательские данные.** ✅ **СДЕЛАНО (ещё в fea15e6, подтверждено 2026-10-10):**
|
||||
точечный merge (`ConfigMergeProcessor` + `ConfigMergeParser`): block-sequence листы и `ignoredSections` сохраняются,
|
||||
есть `ConfigMergeProcessorTest` (249 строк). `performUpdate` ловит только `IOException`, runtime уходит на границу `ConfigLoader`.
|
||||
- **27. SQL: утечка Hikari-пулов.** ✅ **СДЕЛАНО (ещё в fea15e6, подтверждено 2026-10-10):**
|
||||
`StorageSQL.init(mode)` создаёт пул один раз (`if (connectionManager == null)`).
|
||||
- **28. SQL: блокирующий connect на main thread** ✅ **СДЕЛАНО (ещё в fea15e6, подтверждено 2026-10-10):**
|
||||
`setInitializationFailTimeout(-1)` — пул стартует, не дожидаясь БД.
|
||||
- **29. SQL: адаптив не стартует.** ✅ **СДЕЛАНО (ещё в fea15e6, подтверждено 2026-10-10):**
|
||||
`SQLConnectionManager.runWhenConnected` складывает колбэки в `onConnectCallbacks` вместо выбрасывания.
|
||||
- **30. SQL: настройки игрока не сохраняются.** ✅ **СДЕЛАНО**: `SQLDataMapper.serializeSettings` пишет `PlayerSettingsManager.toSettingsMap(player)` (12 ключей) в JSON-колонку, `deserializeSettings` читает её тем же словарём (`normalizeNumericSettings` + `applySettings`) и падает на `applyDefaults` при пустоте/битости → `schematicDifficulty`/`blockLead` больше не null при входе (NPE в `updateGeneratorSettings`/`PAPIHook` не стало). Диск и SQL теперь используют **один и тот же** набор ключей.
|
||||
- **31. Схематики: креш на main thread от битых файлов.** `LPSchematicLegacy`/`SchemLoader` парсят без валидации; NPE/AIOOBE мимо `catch(IOException)` (SchematicManager.java:109-133, LpschemConverter.java:44-54). Битый файл = отказ включения плагина. → Валидация dimensions/palette/frameCount + `catch(RuntimeException)` + лимиты размера файла/блоков.
|
||||
- **32. JumpCalculator: возврат невалидного прыжка.** После 10 неудач валидация сдаётся и возвращает заведомо невалидный блок (JumpCalculator.java:125-136). → Пере-роллить offset/направление, а не только уменьшать distance/height; при исчерпании — safety-fallback (простой допустимый шаг).
|
||||
- **33. JumpCalculator: диагональный heading залипает.** `JumpDirector.getRecommendedHeading` в безопасной зоне возвращает current без изменений (JumpDirector.java:105-107), а `calculateJumpOffset` при `offset.getX()!=0` перезаписывает Z (JumpCalculator.java:110-115) → курс зигзагом и не выпрямляется. → При диагонали аппендикс не перезаписывать случайным; корректный поворот-домножитель.
|
||||
- **32. JumpCalculator: возврат невалидного прыжка.** ✅ **СДЕЛАНО (ещё в fea15e6, подтверждено 2026-10-10):**
|
||||
`validateAndRetryJump` + `safetyFallback` (3 ре-ролла шага 1/0, затем прямой шаг без джиттера, в крайнем случае `current`);
|
||||
покрыто `JumpCalculatorTest` (`safetyFallbackReturnsValidStepForUnitHeading`, `...ReturnsCurrentWhenStraightStepImpossible`).
|
||||
- **33. JumpCalculator: диагональный heading залипает.** ✅ **СДЕЛАНО (ещё в fea15e6, подтверждено 2026-10-10):**
|
||||
`offsetFor` считает перпендикулярный джиттер без перезаписи Z; покрыто `JumpCalculatorTest`.
|
||||
|
||||
### Генерация / lifecycle
|
||||
|
||||
|
|
@ -317,18 +330,17 @@ Checkstyle отработал `0 errors` (error-уровневые legacy-нар
|
|||
- **136. [M] Починить `IllegalCatch` (legacy, 22 / 19 файлов).** catch(Exception/Throwable/RuntimeException)→сужение до конкретных исключений либо переименовать в `expected|ignore`.
|
||||
- **137. [M] Починить все нарушения PMD (45):** `CognitiveComplexity(17)` + `CyclomaticComplexity(7)` — декомпозиция; `GodClass(4)` + `TooManyMethods(8)` — декомпозиция; `AvoidReassigningParameters(7)` — переименование параметров; `EmptyCatchBlock(2)` — комментарий/конкретный тип.
|
||||
- **138. [S] Перевести PMD из report-only в жёсткий гейт.** После зачистки убрать `isIgnoreFailures=true` в `build.gradle.kts` (pmd-блок). ✅ сделано в `b771cc1`.
|
||||
- **169. [M] Починить `ReturnCount` (69 warning / 52 файла) — ПЕРЕСТРУКТУРИРОВАНИЕМ, не порогом.** Все 69 — это половина
|
||||
правила про void (`maxForVoid` по умолчанию = 1 ⇒ запрещена любая guard-клауза `if (x) { return; }`); для value-методов
|
||||
при `max=5` нарушений 0. Владелец запретил поднимать порог → в каждом из 69 void-методов убираем ранний `return`
|
||||
(условие становится обычным `if`-блоком) либо выносим тело в helper-метод. Следить за `NestedIfDepth` (error, max=2)
|
||||
и `NPathComplexity`. После обнуления — перевести `ReturnCount` в `error`.
|
||||
- **170. [M] Починить `IllegalCatch` (23 warning / 18 файлов).** 19× `catch (Exception)`, 3× `catch (Throwable)`,
|
||||
1× `catch (RuntimeException)`. Там, где конкретика реальна, — сужать до `IOException`/`NumberFormatException`/
|
||||
`SQLException`/`YAMLException` и т. п. На истинных границах (диспетчер команд `LoParkourCommand:36`, `session-state:84`,
|
||||
`LoParkour:128`) `Throwable` **обязан** стать `RuntimeException`: `Throwable` глотает `Error` (OOM, StackOverflow) —
|
||||
это баг, а не стиль. Пограничные `catch (Exception)` в `onEnable/onDisable`, загрузчиках конфигов/схематчей и
|
||||
`SchematicManager` — оставляем широкими осознанно (релоад плагина не должен ронять сервер), но каждый такой site
|
||||
требует комментария «почему именно Exception»; после разбора правило остаётся в warning на незачищенном остатке.
|
||||
- **169. [M] Починить `ReturnCount` (69 warning / 52 файла) — ПЕРЕСТРУКТУРИРОВАНИЕМ, не порогом.** ✅ **ВЫПОЛНЕНО (2026-10-10):** все 69 void-методов переструктурированы (guard-`return` → `if`-блок или helper: `placePlayer`/`tickPlayer`/`boostIfValid`/`applyCommand`/`firstNonNull`), порог не поднимался, `NestedIfDepth` ≤ 2 соблюдён; правило переведено в `error`. Попутно `NPathComplexity` 12 → 9. Checkstyle: **0 errors / 61 warning**, тесты 96/0 fail.
|
||||
- **170. [M] Починить `IllegalCatch` (23 warning / 18 файлов).** ✅ **ЧАСТИЧНО (2026-10-10, остаток 18 — осознанные границы, правило остаётся в warning):**
|
||||
3× `catch (Throwable)` → `catch (RuntimeException)` (диспетчер команд, session-tick, shutdown — `Error` больше не глотается);
|
||||
сужено 5: `HoloHook` → `ClassNotFoundException | LinkageError`, `OptionGeneral` → `NumberFormatException` и
|
||||
`IllegalArgumentException | IndexOutOfBoundsException`, `GeneratorProfileManager` → `IllegalArgumentException`,
|
||||
`ConfigUpdater` → `IOException` (runtime уходит на границу `ConfigLoader`).
|
||||
Не сужено осознанно (у каждого — комментарий «почему»): границы enable/reload/shutdown (`PluginBootstrap`,
|
||||
`ConfigLoader`, `LocaleLoader`, `LoParkour:106`, `SQLConnectionManager:59` — таксономия ошибок HikariCP не публична),
|
||||
порча данных (`InventoryData`, `PreviousData`, `SchematicManager` ×2), внешние API (`ScoreboardManager`/PAPI),
|
||||
leave-путь (`UserRegistry`), изоляция колбэков (`SQLConnectionManager:106`), хот-путь генерации
|
||||
(`JumpValidator`, `BlockSelector`), кэш сообщений (`LocaleCache`).
|
||||
|
||||
После зачистки п.132–137 — удалить соответствующие записи из `config/checkstyle/suppressions.xml` (супрессии остаются только для ещё незачищенных legacy-файлов).
|
||||
|
||||
|
|
@ -600,7 +612,7 @@ Checkstyle отработал `0 errors` (error-уровневые legacy-нар
|
|||
- **142. [P1] Убрать API, которых нет в старых/новых версиях.** Известно: `GameRule.*` и `Particle.*` разные (см. п.129: `Particle.FIREWORK` нет в 1.20.4), `Material.STONE_SLAB` (п.100), `BukkitRunnable.runTaskTimerAsynchronously` (п.21), `registerNewObjective(String,String,String)`. В 5.4.0-paper26 IP-Reborn заменял «removed Paper and Adventure API calls» — просмотреть их список как чек-лист.
|
||||
→ Вынести версионно-зависимое в один слой `compat/` (определение версии по `Bukkit.getVersion()` — как `ref/ajParkour/.../utils/VersionSupport.java`; для 26+ учесть смену схемы версий: major ≥ 26).
|
||||
- **143. [P1] Folia (п.21, issue #1).** `World.create()` уже не вызывает `createWorld` для загруженного мира (коммит «reuse already loaded world…»). Остаётся: `folia-plugin.yml`/`folia-supported: true`, region-scheduler вместо BukkitRunnable, настройки мира из global region. IP-Reborn сознательно *не* поддерживает Folia — честнее убрать бейдж, если не успеваем.
|
||||
- **144. [P1] Заменить команду `/lp` — конфликт с LuckPerms.** LuckPerms использует `/lp`; у нас `plugin.yml`: `loparkour` с `aliases: [parkour, lp]`. Оба плагина борются за алиас, при загрузке в разном порядке один из них теряет команду. Заодно `parkour` конфликтует с плагином A5H73Y Parkour и с IP.
|
||||
- **144. [P1] Заменить команду `/lp` — конфликт с LuckPerms.** ✅ **ВЫПОЛНЕНО (2026-10-10, решение владельца: `lp`→`lpk`, `parkour` оставить).** `plugin.yml`: `aliases: [parkour, lpk]`; `/lp` → `/lpk` в `README.md`, `docs/SCHEMATICS.md`, `src/main/resources/docs/SCHEMATICS.md`, `schematics.yml`, `CHANGELOG.md`, javadoc `ReplayCommandExecutor`. Права (`loparkour.*`) не менялись.
|
||||
→ Убрать `lp` (и, вероятно, `parkour`) из `aliases`; оставить `loparkour` + короткий алиас без конфликтов (предложение: **`lpk`**; *имя ждёт решения владельца*).
|
||||
→ Править: `src/main/resources/plugin.yml`; все `/lp …` в `README.md` (15), `docs/SCHEMATICS.md` (16), `src/main/resources/docs/SCHEMATICS.md`, `schematics/schematics.yml`, `docs/ARCHITECTURE.md`, локали, тексты сообщений/usage; `ReplayCommandExecutor` (javadoc `/lp replay`).
|
||||
→ Права (`loparkour.*`) не менять. Добавить в CHANGELOG пометку о breaking-изменении алиаса; рассмотреть deprecation-сообщение при вызове старого алиаса, если он останется.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue