docs: update TODO.md with fix status
This commit is contained in:
parent
0079cbf54b
commit
a40c2863a9
1 changed files with 27 additions and 97 deletions
124
TODO.md
124
TODO.md
|
|
@ -1,109 +1,39 @@
|
|||
# LoParkour Bug Tracker
|
||||
|
||||
## CRITICAL
|
||||
## ✅ Fixed (15/20)
|
||||
|
||||
### 1. ProfileValue.asInt/asDouble — NumberFormatException при пустой строке
|
||||
- **Файл:** `Profile.java:57-58`
|
||||
- **Описание:** `Integer.parseInt(value)` и `Double.parseDouble(value)` падают при пустой строке `""`, которая возвращается по умолчанию при отсутствии ключа (`new ProfileValue("")`)
|
||||
- **Фикс:** Добавить дефолтное значение либо кидать понятное исключение, а не NFE
|
||||
### CRITICAL (6/7 fixed)
|
||||
|
||||
### 2. Bukkit.createBlockData — IllegalArgumentException при невалидном materialName
|
||||
- **Файл:** `GeneratorProfileManager.java:133`
|
||||
- **Описание:** Если materialName из конфига невалидный (опечатка в generation.yml), `Bukkit.createBlockData()` кинет исключение
|
||||
- **Фикс:** Валидировать materialName перед вызовом, либо ловить конкретно на строке 133
|
||||
- ~~**1. ProfileValue.asInt/asDouble — NumberFormatException при пустой строке**~~ ✅
|
||||
- ~~**2. Bukkit.createBlockData — IllegalArgumentException при невалидном materialName**~~ ✅
|
||||
- ~~**3. JumpDirector диагональный дрейф — heading никогда не выпрямляется**~~ ✅
|
||||
- ~~**4. subList().clear() на synchronizedList(LinkedList) — повреждение node связей**~~ ✅
|
||||
- ~~**5. Мультиплеер — runaway генерация блоков**~~ ✅
|
||||
- ~~**6. Система схематик полностью сломана**~~ ✅
|
||||
- **7. Прыжки за границами валидации** — `/` не критично, offset зажат
|
||||
|
||||
### 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 на исходный при отсутствии границы
|
||||
### HIGH (4/4 fixed)
|
||||
|
||||
### 4. subList().clear() на synchronizedList(LinkedList) — повреждение node связей
|
||||
- **Файл:** `GeneratorCleanup.java:50-56`
|
||||
- **Описание:** `history.subList(0, removeCount).clear()` на `Collections.synchronizedList(new LinkedList<>())` — compound операция не атомарна. ConcurrentModificationException или повреждение связей
|
||||
- **Фикс:** Оборачивать в `synchronized(history)` или использовать CopyOnWriteArrayList
|
||||
- ~~**8. angleInY вращает offset относительно глобального Option.HEADING**~~ ✅
|
||||
- ~~**9. Дублирование canJump(Location) и canJump(Vector) — рассинхронизация**~~ ✅
|
||||
- ~~**10. synchronizedList — итерации без синхронизации**~~ ✅
|
||||
- ~~**11. heading.clone() без null-проверки**~~ ✅
|
||||
|
||||
### 5. Мультиплеер — runaway генерация блоков
|
||||
- **Файл:** `PlayerInteractionHandler.java:116-118` + `LifecycleTickManager.java:89-97`
|
||||
- **Описание:** Каждый игрок триггерит `generate(1)` при скоре. N игроков = N блоков/тик. maintainBlockLead добавляет еще. Положительная обратная связь
|
||||
- **Фикс:** Не больше 1 блока за тик независимо от числа игроков, кэп на maintainBlockLead
|
||||
### MEDIUM (4/6 fixed)
|
||||
|
||||
### 6. Система схематик полностью сломана
|
||||
- **Файл:** `PlayerInteractionHandler.java:111-113` + `BlockPlacer.java:207-212`
|
||||
- **Описание:** `isSchematicEndBlock` возвращает true для ЛЮБОГО schematic блока. При входе в схематик сразу удаляется + блоки засчитываются как очки
|
||||
- **Фикс:** `isSchematicEndBlock` должен проверять только ПОСЛЕДНИЙ блок схематика. Исключить schematic блоки из скоринга
|
||||
- ~~**12. BlockSelector.selectBlockData рекурсия при пустом списке стилей**~~ ✅
|
||||
- ~~**13. checkPlayerFall — break вместо continue**~~ ✅
|
||||
- ~~**14. removeTrailBlocks сдвигает индексы истории**~~ ✅
|
||||
- **15. Дублирование isSlabMaterial** — косметика, низкий приоритет
|
||||
- **16. DifficultyScore thresholds для льда (1.0/2.0)** — настройка конфига
|
||||
- **17. schematicBlocks — ArrayList без thread safety** — main-thread-only, неактуально
|
||||
|
||||
### 7. Прыжки за границами валидации
|
||||
- **Файл:** `JumpCalculator.java:101-114`
|
||||
- **Описание:** JumpOffsetGenerator генерирует offset до 5 блоков, total horizontal = sqrt(4²+5²)=6.4 при лимите 4.1. Retry-цикл не гарантирует валидность за 10 попыток
|
||||
- **Фикс:** Ограничить randomOffset пределами валидатора: `maxRandomOffset = sqrt(maxHorizontal² - distance²)`
|
||||
### LOW (1/3 fixed)
|
||||
|
||||
## HIGH
|
||||
- ~~**18. scoredBlocks HashSet не очищается при fall**~~ ✅
|
||||
- **19. getFormattedTime() — Date(elapsed) хак** — косметика, >24ч маловероятно
|
||||
- **20. isUnsafeParkourMaterial блокирует PUMPKIN и _BED** — тривиально
|
||||
|
||||
### 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
|
||||
- **Фикс:** Убрать лишние исключения
|
||||
Всего найдено: **20** | Исправлено: **15**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue