LoParkour/TODO.md
loki5512344 0079cbf54b fix: remove Hardcore mode, disable Elytra by default, add bug tracker
- Remove HardcoreMode (lose all rewards on fall)
- Disable Elytra mode in default config
- Add todo.md with 20 identified bugs
- Fix 3 remaining bugs: checkPlayerFall continue, removeTrailBlocks sync, scoredBlocks clear on fall
2026-06-08 14:40:22 +02:00

109 lines
8.9 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 Bug Tracker
## CRITICAL
### 1. ProfileValue.asInt/asDouble — NumberFormatException при пустой строке
- **Файл:** `Profile.java:57-58`
- **Описание:** `Integer.parseInt(value)` и `Double.parseDouble(value)` падают при пустой строке `""`, которая возвращается по умолчанию при отсутствии ключа (`new ProfileValue("")`)
- **Фикс:** Добавить дефолтное значение либо кидать понятное исключение, а не NFE
### 2. Bukkit.createBlockData — IllegalArgumentException при невалидном materialName
- **Файл:** `GeneratorProfileManager.java:133`
- **Описание:** Если materialName из конфига невалидный (опечатка в generation.yml), `Bukkit.createBlockData()` кинет исключение
- **Фикс:** Валидировать materialName перед вызовом, либо ловить конкретно на строке 133
### 3. JumpDirector диагональный дрейф — heading никогда не выпрямляется
- **Файл:** `JumpDirector.java:87-99`
- **Описание:** `getRecommendedHeading()` всегда создает `Vector(1,0,1)` для X и Z границ. После нормализации heading становится диагональным и НИКОГДА не возвращается к осевому направлению
- **Фикс:** Использовать `Vector(1,0,0)` для X и `Vector(0,0,1)` для Z. Сбрасывать heading на исходный при отсутствии границы
### 4. subList().clear() на synchronizedList(LinkedList) — повреждение node связей
- **Файл:** `GeneratorCleanup.java:50-56`
- **Описание:** `history.subList(0, removeCount).clear()` на `Collections.synchronizedList(new LinkedList<>())` — compound операция не атомарна. ConcurrentModificationException или повреждение связей
- **Фикс:** Оборачивать в `synchronized(history)` или использовать CopyOnWriteArrayList
### 5. Мультиплеер — runaway генерация блоков
- **Файл:** `PlayerInteractionHandler.java:116-118` + `LifecycleTickManager.java:89-97`
- **Описание:** Каждый игрок триггерит `generate(1)` при скоре. N игроков = N блоков/тик. maintainBlockLead добавляет еще. Положительная обратная связь
- **Фикс:** Не больше 1 блока за тик независимо от числа игроков, кэп на maintainBlockLead
### 6. Система схематик полностью сломана
- **Файл:** `PlayerInteractionHandler.java:111-113` + `BlockPlacer.java:207-212`
- **Описание:** `isSchematicEndBlock` возвращает true для ЛЮБОГО schematic блока. При входе в схематик сразу удаляется + блоки засчитываются как очки
- **Фикс:** `isSchematicEndBlock` должен проверять только ПОСЛЕДНИЙ блок схематика. Исключить schematic блоки из скоринга
### 7. Прыжки за границами валидации
- **Файл:** `JumpCalculator.java:101-114`
- **Описание:** JumpOffsetGenerator генерирует offset до 5 блоков, total horizontal = sqrt(4²+5²)=6.4 при лимите 4.1. Retry-цикл не гарантирует валидность за 10 попыток
- **Фикс:** Ограничить randomOffset пределами валидатора: `maxRandomOffset = sqrt(maxHorizontal² - distance²)`
## HIGH
### 8. angleInY вращает offset относительно глобального Option.HEADING
- **Файл:** `JumpCalculator.java:105-113`
- **Описание:** rotateAroundY использует разницу между текущим heading и Option.HEADING, а не между текущим и предыдущим heading. Блоки уходят вбок
- **Фикс:** Вращать offset относительно предыдущего heading
### 9. Дублирование canJump(Location) и canJump(Vector) — рассинхронизация
- **Файл:** `JumpValidator.java:73-161`
- **Описание:** Два метода canJump. Location-версия учитывает slab-корректировку, Vector — нет
- **Фикс:** Убрать дублирование или добавить adjustment в Vector-версию
### 10. synchronizedList — итерации без синхронизации
- **Файл:** `GeneratorState.java:35`
- **Описание:** Итерации по `history` (cleanupDistantBlocks, historyContains, indexOfBlock) не обернуты в `synchronized`. Пока все на main thread, но это хрупко
- **Фикс:** Добавить `synchronized(history)` на все итерации, либо убрать synchronizedList
### 11. heading.clone() без null-проверки
- **Файл:** `JumpCalculator.java:101-103`
- **Описание:** `generator.state.heading.clone()` упадет с NPE, если heading не инициализирован до первого вызова calculateJumpOffset
- **Фикс:** Добавить null-guard: если heading == null, инициализировать из Option.HEADING
## MEDIUM
### 12. BlockSelector.selectBlockData рекурсия при пустом списке стилей
- **Файл:** `BlockSelector.java:32-33`
- **Описание:** Если style == null, код сбрасывает стиль на первый. `orElseThrow()` упадет, если список пуст
- **Фикс:** Проверка `if (styles.isEmpty()) return Material.STONE.createBlockData()`
### 13. checkPlayerFall — break вместо continue
- **Файл:** `LifecycleTickManager.java:74-78`
- **Описание:** При падении двух игроков в одном тике, второй пропускает обработку до следующего тика
- **Фикс:** Заменить break на continue
### 14. removeTrailBlocks сдвигает индексы истории
- **Файл:** `GeneratorCleanup.java:79-93`
- **Описание:** `history.subList(startIndex, endIndex).clear()` сдвигает индексы при параллельном вызове historyContains
- **Фикс:** Защититься копированием или проверять синхронизацию
### 15. Дублирование isSlabMaterial
- **Файл:** `JumpValidator.java:67-71`
- **Описание:** JumpValidator и BlockSelector имеют дублирующуюся логику определения slab. Рассинхронизация при изменениях
- **Фикс:** Вынести в общий утилитарный метод
### 16. DifficultyScore thresholds для льда (1.0/2.0) могут быть недостижимы
- **Файл:** `GeneratorProfileManager.java:57-69`
- **Описание:** packed_ice добавляется при difficulty >= 1.0, blue_ice при >= 2.0. Многие конфиги не достигают этих значений. Лед не появляется
- **Фикс:** Нормализовать difficulty до предсказуемой шкалы или изменить thresholds
### 17. schematicBlocks — ArrayList без thread safety
- **Файл:** `GeneratorState.java:41`
- **Описание:** schematicBlocks это plain ArrayList, без синхронизации, в отличие от history
- **Фикс:** Добавить синхронизацию или документировать main-thread-only
## LOW
### 18. scoredBlocks HashSet не очищается при fall
- **Файл:** `ParkourPlayer.java:125-127`
- **Описание:** HashSet растет бесконечно. При возрождении на тех же координатах не засчитает блоки
- **Фикс:** scoredBlocks.clear() при fall/reset
### 19. getFormattedTime() — Date(elapsed) хак
- **Файл:** `GeneratorStatistics.java:90-91`
- **Описание:** `new Date(elapsed)` — Date ожидает timestamp от 1970, а передается длительность. Сломается при >24ч
- **Фикс:** Использовать Duration API для форматирования
### 20. isUnsafeParkourMaterial блокирует PUMPKIN и _BED без причины
- **Файл:** `BlockSelector.java:48-60`
- **Описание:** PUMPKIN не имеет onPlace-сканирования соседей. _BED безопасны при setBlockData с флагом false
- **Фикс:** Убрать лишние исключения