diff --git a/REFACTORING_SUMMARY.md b/REFACTORING_SUMMARY.md deleted file mode 100644 index 972b084..0000000 --- a/REFACTORING_SUMMARY.md +++ /dev/null @@ -1,91 +0,0 @@ -# Рефакторинг - Краткое описание - -## Выполненные изменения - -### 1. StorageSQL.java (248 → ~150 строк) - -**Проблемы:** -- Смешивание логики подключения, миграций и CRUD операций -- Дублирование кода в методах sendUpdate/sendUpdateSuppressed -- Отсутствие разделения ответственностей - -**Решение:** -Разделен на 3 класса: -- `SQLConnectionManager` - управление подключением к БД -- `SQLQueryExecutor` - выполнение SQL запросов -- `SQLMigrationManager` - управление миграциями схемы БД - -**Преимущества:** -- Каждый класс отвечает за одну задачу (Single Responsibility Principle) -- Легче тестировать и поддерживать -- Упрощена логика переподключения - -### 2. Session.java (236 → ~120 строк) - -**Проблемы:** -- Слишком много ответственностей (игроки, спектаторы, видимость, мут) -- Дублирование логики в add/remove методах -- Сложная логика уведомлений - -**Решение:** -Создан класс `SessionUserManager` для управления пользователями - -**Преимущества:** -- Session теперь делегирует управление пользователями -- Логика уведомлений инкапсулирована -- Проще добавлять новые типы пользователей - -### 3. ParkourUser.java (220 → ~100 строк) - -**Проблемы:** -- Смешивание статических методов регистрации и instance методов -- Сложная логика scoreboard встроена в класс -- Запутанные методы register/unregister/leave - -**Решение:** -Разделен на 3 класса: -- `UserRegistry` - регистрация и управление пользователями -- `ScoreboardManager` - управление scoreboard -- `BungeeUtil` - утилиты для BungeeCord - -**Преимущества:** -- Четкое разделение статической и instance логики -- Scoreboard логика изолирована и переиспользуема -- Упрощена логика регистрации/выхода - -### 4. ParkourPlayer.java (202 → ~150 строк) - -**Проблемы:** -- Огромная статическая инициализация PLAYER_COLUMNS -- Дублирование логики с ParkourUser -- Сложный метод setSettings - -**Решение:** -Создан класс `PlayerSettingsManager` для управления настройками - -**Преимущества:** -- Настройки и их маппинг инкапсулированы -- Легче добавлять новые настройки -- Упрощена логика применения настроек - -## Итоговая статистика - -| Файл | Было строк | Стало строк | Новых классов | -|------|------------|-------------|---------------| -| StorageSQL.java | 248 | ~150 | 3 | -| Session.java | 236 | ~120 | 1 | -| ParkourUser.java | 220 | ~100 | 3 | -| ParkourPlayer.java | 202 | ~150 | 1 | -| **ИТОГО** | **906** | **~520** | **8** | - -## Принципы, примененные в рефакторинге - -1. **Single Responsibility Principle (SRP)** - каждый класс отвечает за одну задачу -2. **Separation of Concerns** - разделение логики по разным классам -3. **DRY (Don't Repeat Yourself)** - устранение дублирования кода -4. **Encapsulation** - инкапсуляция сложной логики в отдельные классы -5. **Delegation** - делегирование задач специализированным классам - -## Обратная совместимость - -Все публичные API остались без изменений. Рефакторинг затронул только внутреннюю структуру классов. diff --git a/TODO.md b/TODO.md index 1041cd5..132df1c 100644 --- a/TODO.md +++ b/TODO.md @@ -14,6 +14,12 @@ | # | Баг | Файл | Что сделать | |---|-----|------|-------------| +| ✅ | ~~BOM в `ParkourGenerator.java` ломает компиляцию~~ | `ParkourGenerator.java` | ✅ Удалён через Python | +| ✅ | ~~`generator.score` → `generator.state.score`~~ | `PAPIHook.java`, `ParkourSettingsMenu.java` | ✅ Исправлено | +| ✅ | ~~`ParkourUser.joinCount` удалён~~ | `LoParkour.java` | ✅ Использован `UserRegistry.getJoinCount()` | +| ✅ | ~~`PlayerSettingsManager.OptionContainer` не public~~ | `PlayerSettingsManager.java` | ✅ Сделан public | +| ✅ | ~~`Option.PARTICLE_DATA.data()` не существует~~ | `EffectManager.java` | ✅ Убран `.data()` | +| ✅ | ~~`ParticleUtil.circle()` неправильные параметры~~ | `EffectManager.java` | ✅ Исправлено на (Location, Particle, int, int) | | 1 | `PotionEffectType.JUMP` и `SLOW` удалены в Paper 1.20.5+ | `GravityShiftMode.java` | Заменить на `JUMP_BOOST` и `SLOWNESS` | | 2 | `ElytraMode` создаёт обычный `ParkourGenerator` → `getMode()` возвращает DEFAULT | `ElytraMode.java` | Создать `ElytraGenerator extends ParkourGenerator` | | 3 | `SpeedrunMode`: таймеры `runLater` продолжают тикать после `reset()` — гонка с генератором | `SpeedrunMode.java` | Хранить `ScheduledTask`, отменять в `reset()` | @@ -27,21 +33,72 @@ | 4 | `HardcoreMode`: `collectedRewards` не очищается при падении | `HardcoreMode.java` | Добавить `player.collectedRewards.clear()` в `fall()` | | 5 | `JumpValidator` создан но нигде не вызывается | `BlockPlacer.java` | Добавить retry-loop в `selectNext()` (до 10 попыток) | | 6 | `JumpType` enum создан но не интегрирован в генератор | `BlockPlacer.java` | Добавить выбор JumpType по шансу из конфига | -| 7 | `ConfigUpdater` закомментирован | `Config.java` | Раскомментировать, проверить `ignoredSections` | +| 7 | ~~`ConfigUpdater` закомментирован~~ | `Config.java` | ✅ Написан `ConfigUpdater.java`, подключён в `Config.update()` | | 8 | `GravityShiftMode`: нет визуала при смене эффекта | `GravityShiftMode.java` | Добавить Title + Sound + партиклы `PORTAL` | --- +## 🟢 Планово — дуэли + +### DuelMode +- [ ] `DuelMode implements Mode` — режим дуэли +- [ ] `DuelSession extends Session` — два игрока, отдельные острова +- [ ] `/lp duel <игрок>` — вызов на дуэль, запрос истекает через 30 сек +- [ ] Форматы: **Race** (кто первый до N очков), **Survival** (3 жизни), **Time Attack** (60 сек кто больше) +- [ ] Scoreboard показывает счёт обоих в реальном времени +- [ ] ActionBar: `Opponent: 34 pts` во время игры +- [ ] При падении противника — уведомление +- [ ] Победитель получает награды через систему `Rewards` +- [ ] Лидерборд дуэлей (W/L) +- [ ] Кнопка реванша после окончания + +--- + ## 🟢 Планово | # | Фича | Файл | Что сделать | |---|------|------|-------------| | 9 | Ghost система не интегрирована | `ghost/` | Подключить `GhostRecorder` к `GeneratorLifecycle` | -| 10 | Удалить мёртвые stub-файлы | `generator/`, корень | `Command.java`, `Events.java`, `BlockSelector.java`, `ScoreManager.java`, `GeneratorTick.java` | +| ✅ | ~~Удалить мёртвые stub-файлы~~ | `generator/`, корень | ✅ Удалены: `Command.java`, `Events.java`, `BlockSelector.java`, `ScoreManager.java`, `GeneratorTick.java` | | 11 | ElytraMode: кольца из партиклов + детекция пролёта | `ElytraMode.java` | BoundingBox check в `tick()` | | 12 | ElytraMode: cooldown на фейерверки | `ElytraMode.java` | Счётчик + сообщение | | 13 | RaceMode | новый файл | Кто первый наберёт N очков | | 14 | CoopMode | новый файл | Общий счёт нескольких игроков | +| ✅ | ~~Реорганизация `generator/` по подпакетам~~ | `generator/` | ✅ Создана структура: `jump/`, `lifecycle/`, `effect/` | + +--- + +## 🏗️ ✅ Реорганизация generator/ — ГОТОВО + +Новая структура по логическим группам: + +``` +generator/ +├── ParkourGenerator.java ← главный класс (183 строки) +├── GeneratorState.java ← данные генератора +├── GeneratorOption.java ← enum опций +├── Profile.java ← профиль настроек +├── Island.java ← остров спавна +│ +├── jump/ ← всё про прыжки и размещение блоков +│ ├── BlockPlacer.java (166 строк) +│ ├── JumpDirector.java +│ ├── JumpOffsetGenerator.java +│ ├── JumpValidator.java +│ └── JumpType.java +│ +├── lifecycle/ ← жизненный цикл: тик, падение, очистка +│ └── GeneratorLifecycle.java +│ +└── effect/ ← визуальные эффекты + └── EffectManager.java +``` + +**Результат:** +- ✅ Все файлы перемещены через `smartRelocate` (импорты обновлены автоматически) +- ✅ Удалены мёртвые stub-файлы +- ✅ Проект компилируется без ошибок +- ✅ Структура стала логичнее и понятнее --- @@ -55,12 +112,13 @@ - `LoParkourCommand` разбит на `PlayerCommandHandler` + `AdminCommandHandler` + `SchematicCommandHandler` - `Events` разбит на 3 listener'а - `StorageSQL` разбит на `SQLConnectionManager` + `SQLQueryExecutor` + `SQLMigrationManager` +- ✅ **Проект компилируется без ошибок** (исправлены все баги после рефакторинга) --- ## 🎮 Чек-лист перед релизом -- [ ] `./gradlew build` без ошибок +- [x] `./gradlew build` без ошибок - [ ] Запуск сервера без ошибок в консоли - [ ] Паркур: прыжки, счёт, рекорд работают - [ ] Scoreboard обновляется diff --git a/src/main/java/dev/loki/loparkour/Command.java b/src/main/java/dev/loki/loparkour/Command.java deleted file mode 100644 index 93fc411..0000000 --- a/src/main/java/dev/loki/loparkour/Command.java +++ /dev/null @@ -1,7 +0,0 @@ -package dev.loki.loparkour; - -/** - * @deprecated Replaced by {@link LoParkourCommand}. Delete this file. - */ -@Deprecated -class Command extends LoParkourCommand {} diff --git a/src/main/java/dev/loki/loparkour/Events.java b/src/main/java/dev/loki/loparkour/Events.java deleted file mode 100644 index 6ff8a2e..0000000 --- a/src/main/java/dev/loki/loparkour/Events.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.loki.loparkour; - -/** - * @deprecated Split into: - * - {@link dev.loki.loparkour.listener.PlayerConnectionListener} - * - {@link dev.loki.loparkour.listener.ParkourRestrictionListener} - * - {@link dev.loki.loparkour.listener.SchematicWandListener} - * - * Delete this file after verifying compilation. - */ -@Deprecated -class Events {} diff --git a/src/main/java/dev/loki/loparkour/LoParkour.java b/src/main/java/dev/loki/loparkour/LoParkour.java index c61d470..565e3fd 100644 --- a/src/main/java/dev/loki/loparkour/LoParkour.java +++ b/src/main/java/dev/loki/loparkour/LoParkour.java @@ -14,6 +14,7 @@ import dev.loki.loparkour.mode.Modes; import dev.loki.loparkour.mode.SpectatorMode; import dev.loki.loparkour.mode.SpeedrunMode; import dev.loki.loparkour.player.ParkourUser; +import dev.loki.loparkour.player.UserRegistry; import dev.loki.loparkour.reward.Rewards; import dev.loki.loparkour.schematic.lpschem.LPSchematicManager; import dev.loki.loparkour.storage.Storage; @@ -243,8 +244,7 @@ public final class LoParkour extends LoPlugin { metrics.addCustomChart(new SimplePie("using_rewards", () -> Boolean.toString(Rewards.REWARDS_ENABLED))); metrics.addCustomChart(new SimplePie("locale_count", () -> Integer.toString(Locales.locales.size()))); metrics.addCustomChart(new SingleLineChart("player_joins", () -> { - int joins = ParkourUser.joinCount; - ParkourUser.joinCount = 0; + int joins = UserRegistry.getJoinCount(); return joins; })); } diff --git a/src/main/java/dev/loki/loparkour/config/Config.java b/src/main/java/dev/loki/loparkour/config/Config.java index 1609077..d6aa0b1 100644 --- a/src/main/java/dev/loki/loparkour/config/Config.java +++ b/src/main/java/dev/loki/loparkour/config/Config.java @@ -87,10 +87,12 @@ public enum Config { /** * Updates the file so all keys are present. + * Any key that exists in the bundled default but is missing on disk + * will be appended to the correct section automatically. */ public void update() { try { - // TODO: ConfigUpdater.update(LoParkour.getPlugin(), fileName, path, ignoredSections); + ConfigUpdater.update(LoParkour.getPlugin(), fileName, path, ignoredSections); } catch (Exception ex) { LoParkour.getPlugin().getLogger().log(java.util.logging.Level.SEVERE, "Error while trying to update config file: " + fileName, ex); diff --git a/src/main/java/dev/loki/loparkour/config/ConfigUpdater.java b/src/main/java/dev/loki/loparkour/config/ConfigUpdater.java new file mode 100644 index 0000000..0e24566 --- /dev/null +++ b/src/main/java/dev/loki/loparkour/config/ConfigUpdater.java @@ -0,0 +1,287 @@ +package dev.loki.loparkour.config; + +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.logging.Level; + +/** + * Automatically adds missing keys from the default (bundled) config + * into the player's config file on disk, preserving all existing values, + * comments, and blank lines. + * + *
Algorithm: + *
Strategy: walk disk lines first, emit them as-is. Then walk default
+ * lines; for each key block (comment + key line) whose key is absent on
+ * disk and not ignored, append it at the correct indentation level.
+ */
+ private static List