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

8.9 KiB
Raw Blame History

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
  • Фикс: Убрать лишние исключения