mdbd/PLAN.md
loki5512344 53f3f6e9da Complete Stage 0: Project scaffold
- Fix build.gradle.kts: Java 21, Paper 1.20.6, ProtocolLib 5.3.0
- Add permissions to paper-plugin.yml
- Add ConfigManager with safe yaml loading (no overwrite)
- Add LocationsConfig for all game object coordinates
- Add GameConfig with all balance values
- Update mdbd.java with onEnable/onDisable + ConfigManager
- Mark Stage 0 complete in PLAN.md
2026-05-31 20:37:36 +02:00

16 KiB
Raw Blame History

DBD Plugin — План разработки

Архитектурные принципы

  • KISS: Нет абстракций ради абстракций. Простые классы с одной ответственностью.
  • DRY: Общая логика в утилитах, не копипаста.
  • SOLID:
    • SRP: Один класс = одна задача (StateManager только состояния, DamageHandler только урон)
    • OCP: Перки через интерфейс, не if-else везде
    • LSP: KillerController и SurvivorController наследуются от PlayerController корректно
    • ISP: Маленькие интерфейсы (IRepairable, IHealable, IHookable)
    • DIP: Высокоуровневые модули зависят от абстракций, не от имплементаций
    • max 150 строк/файл

Структура папок (max 150 строк/файл)

src/main/java/com/dbd/plugin/
├── DBDPlugin.java                    # Точка входа (max 50 строк)
├── config/
│   ├── ConfigManager.java            # Загрузка всех yaml
│   ├── LocationsConfig.java          # Координаты объектов
│   └── GameConfig.java               # Балансные цифры
├── core/
│   ├── GameManager.java               # Главный контроллер игр
│   ├── GameSession.java               # Одна игра (lobby -> end)
│   ├── GameState.java                 # Enum: LOBBY, IN_GAME, ENDING
│   └── GameEventBus.java              # Внутренние события игры
├── phase/
│   ├── Phase.java                     # Interface: enter(), tick(), exit()
│   ├── LobbyPhase.java                # Ожидание игроков
│   ├── RoleAssignPhase.java           # Назначение ролей, таймер 5сек
│   ├── GameplayPhase.java             # Основная игра
│   └── EndgamePhase.java              # Эндгейм коллапс + результаты
├── player/
│   ├── BasePlayer.java                # UUID, Player объект
│   ├── Survivor.java                  # Данные выжившего
│   ├── Killer.java                    # Данные киллера
│   ├── PlayerState.java               # Enum: HEALTHY, INJURED, DOWNED...
│   └── PlayerManager.java             # Map<UUID, BasePlayer>
├── state/
│   ├── StateMachine.java              # Машина состояний игрока
│   ├── StateTransition.java           # Проверка можно ли перейти
│   └── StateHandler.java              # Обработчик изменений
├── role/
│   ├── RoleAssigner.java              # Логика выбора кто киллер
│   ├── RoleQueue.java                 # Очередь на киллера
│   └── SpawnPosition.java             # Спавн-точки из конфига
├── survivor/
│   ├── SurvivorController.java          # Действия выжившего
│   ├── SurvivorMovement.java          # Sprint, Exhaustion
│   ├── SurvivorHealing.java           # Лечение себя/других
│   └── SurvivorInventory.java         # Предметы в руках
├── killer/
│   ├── KillerController.java          # Действия киллера
│   ├── KillerAttack.java              # ЛКМ, кулдаун, hit detection
│   ├── KillerCarry.java               # Подъём, перенос, wiggle
│   └── KillerVision.java              # Terror radius, red stain
├── damage/
│   ├── DamageHandler.java             # Нанесение урона (Healthy->Injured...)
│   ├── AttackListener.java            # Слушатель ЛКМ киллера
│   └── HitValidator.java              # Line of sight, range check
├── objective/
│   ├── Generator.java                 # Один генератор
│   ├── GeneratorManager.java          # Все 7 генераторов
│   ├── GeneratorRepair.java           # Логика починки
│   ├── GeneratorRegression.java       # Откат прогресса
│   ├── SkillCheck.java                # QTE система
│   └── SkillCheckUI.java              # Title-анимация
├── hook/
│   ├── Hook.java                      # Один крюк
│   ├── HookManager.java               # Все крюки
│   ├── HookStage.java                 # Stage 1, Stage 2
│   ├── HookStruggle.java              # Skill checks на Stage 2
│   ├── HookRescue.java                # Спасание с крюка
│   └── HookSacrifice.java             # Смерть после Stage 2
├── pallet/
│   ├── Pallet.java                    # Один паллет
│   ├── PalletManager.java             # Все паллеты
│   ├── PalletDrop.java                # Выживший бросает
│   ├── PalletStun.java                # Стан киллера
│   └── PalletBreak.java               # Киллер ломает
├── window/
│   ├── Window.java                    # Одно окно
│   ├── WindowManager.java             # Все окна
│   ├── WindowVault.java               # Прыжок через окно
│   └── WindowFastVault.java           # Быстрый/медленный волт
├── gate/
│   ├── ExitGate.java                  # Одни ворота
│   ├── GateManager.java               # 2 ворота
│   └── GateOpening.java               # 20 сек открытие
├── hatch/
│   ├── Hatch.java                     # Люк
│   ├── HatchCondition.java            # Условие появления
│   └── HatchEscape.java               # Прыжок в люк
├── item/
│   ├── ItemType.java                  # Enum: MEDKIT, FLASHLIGHT...
│   ├── BaseItem.java                  # Interface предмета
│   ├── ItemMedkit.java                # Аптечка
│   ├── ItemFlashlight.java            # Фонарик
│   ├── ItemToolbox.java               # Ящик инструментов
│   ├── ItemKey.java                   # Ключ от люка
│   ├── ItemMap.java                   # Карта
│   └── ChestLoot.java                 # Лут из сундуков
├── chest/
│   ├── Chest.java                     # Сундук
│   ├── ChestManager.java              # Все сундуки
│   └── ChestOpening.java              # 3 сек открытие
├── totem/
│   ├── Totem.java                     # Тотем
│   ├── TotemManager.java              # 5 тотемов
│   ├── DullTotem.java                 # Обычный тотем
│   └── HexTotem.java                  # Проклятый (с перком)
├── perk/
│   ├── IPerk.java                     # Интерфейс перка
│   ├── PerkType.java                  # Enum: SURVIVOR, KILLER
│   ├── PerkRegistry.java              # Map всех перков
│   ├── survivor/
│   │   ├── SelfCarePerk.java
│   │   ├── DeadHardPerk.java
│   │   ├── SprintBurstPerk.java
│   │   └── BorrowedTimePerk.java
│   └── killer/
│       ├── HexRuinPerk.java
│       ├── CorruptInterventionPerk.java
│       └── BBQChiliPerk.java
├── ui/
│   ├── ActionBar.java                 # Нижняя полоска
│   ├── Sidebar.java                   # Scoreboard
│   ├── TitleUI.java                   # Title/Subtitle
│   ├── ProgressBar.java               # [████░░░░░░] 40%
│   └── StatusIcons.java               # ❤ 🩸 💀
├── sound/
│   ├── SoundManager.java              # Воспроизведение звуков
│   ├── TerrorRadiusSound.java         # Сердцебиение
│   ├── GeneratorSound.java            # Звуки генератора
│   └── SoundLevels.java               # 3 уровня громкости
├── util/
│   ├── LocationUtil.java              # Dist, line of sight
│   ├── PlayerUtil.java                # Is sneaking, sprinting
│   ├── TimeUtil.java                  # Форматирование секунд
│   ├── MathUtil.java                  # Clamp, lerp
│   └── ParticleUtil.java              # Спавн частиц
├── command/
│   ├── DBDCommand.java                # /dbd главная
│   ├── JoinSubcommand.java            # /dbd join
│   ├── LeaveSubcommand.java           # /dbd leave
│   ├── SetupSubcommand.java           # /dbd setgen, sethook...
│   ├── AdminSubcommand.java           # /dbd forcestart, stop
│   └── StatsSubcommand.java           # /dbd stats
├── listener/
│   ├── PlayerQuitListener.java        # Дисконнект во время игры
│   ├── PlayerInteractListener.java    # ПКМ, ЛКМ
│   ├── PlayerMoveListener.java        # Движение, ползание
│   └── DamageListener.java            # Отмена ванильного урона
├── data/
│   ├── DataStorage.java               # Interface: save(), load()
│   ├── YamlStorage.java               # YAML реализация
│   ├── SQLiteStorage.java             # SQLite реализация (позже)
│   ├── PlayerStats.java               # Статистика игрока
│   └── MatchResult.java               # Результат матча
└── exception/
    ├── DBDException.java              # Базовое исключение
    ├── InvalidLocationException.java
    └── InvalidStateException.java

TODO (по порядку)

Этап 0: Скелет проекта

  • Создать build.gradle (Paper 1.20.6, Java 21, ProtocolLib)
  • plugin.yml с пермишнами
  • DBDPlugin.java — onEnable/onDisable
  • ConfigManager — загрузка yaml без перезаписи
  • LocationsConfig — структура для всех координат
  • GameConfig — балансные цифры

Этап 1: Core Game Loop

  • GameState enum
  • GameSession — хранит игроков, фазу, таймер
  • Phase interface
  • LobbyPhase — ожидание, минимум 5 игроков, таймер 60сек
  • RoleAssigner + RoleQueue — кто киллер
  • RoleAssignPhase — телепорты, задержка 5сек
  • GameplayPhase — заглушка
  • /dbd join, /dbd leave, /dbd forcestart

Этап 2: Игроки и состояния

  • BasePlayer, Survivor, Killer
  • PlayerState enum: HEALTHY, INJURED, DOWNED, HOOKED, DEAD, ESCAPED
  • StateMachine — переходы с валидацией
  • PlayerManager — map UUID -> BasePlayer
  • SpawnPosition — телепорт из конфига

Этап 3: Киллер (базовый)

  • KillerController — основной класс
  • KillerAttack — ЛКМ, кулдаун 2.5с, hitbox
  • HitValidator — line of sight, расстояние
  • DamageHandler — Healthy->Injured, Injured->Downed
  • KillerCarry — подъём, перенос, wiggle progress
  • KillerMovement — скорость 115%, замедление после удара

Этап 4: Выживший (базовый)

  • SurvivorController
  • SurvivorMovement — sprint, exhaustion 3сек/5сек кулдаун
  • SurvivorHealing — аптечка 10сек, другие 16сек, прогресс-бар
  • Downed movement — crawl 30% скорости

Этап 5: Генераторы

  • Generator класс — прогресс, статус
  • GeneratorManager — 7 штук, 5 нужно
  • GeneratorRepair — зажать ПКМ, прогресс в ActionBar
  • SkillCheck — логика QTE, успех/провал
  • SkillCheckUI — Title-анимация, круг (текстом или картинкой)
  • GeneratorRegression — откат 0.25%/сек, Kick 2.5%/сек 30сек

Этап 6: Крюки

  • Hook класс
  • HookManager — все крюки, подвал
  • HookStage — Stage 1 (60с), Stage 2 (60с)
  • HookStruggle — skill check каждые 2с
  • HookRescue — снятие 2сек
  • HookSacrifice — смерть
  • Счётчик крюков — 3 раза макс

Этап 7: UI

  • ActionBar — статус, прогресс-бары
  • ProgressBar — [████░░░░░░] формат
  • Sidebar — генераторы, живые
  • TitleUI — начало игры, skill check, победа/поражение
  • StatusIcons — ❤ 🩸 💀

Этап 8: Паллеты и окна

  • Pallet — standing/dropped/broken
  • PalletDrop — ПКМ выжившим
  • PalletStun — 2.5сек стан киллеру
  • PalletBreak — зажать ПКМ 3сек
  • Window — класс
  • WindowVault — 1сек выживший, 1.5сек киллер

Этап 9: Эндгейм

  • ExitGate — открытие 20сек
  • GateManager — 2 ворота
  • Hatch — условие появления
  • HatchCondition — формула: живые < починенные гены
  • HatchEscape — прыжок = побег
  • EndgamePhase — коллапс 120сек

Этап 10: Предметы

  • ItemType enum
  • BaseItem interface
  • ItemMedkit, ItemFlashlight, ItemToolbox, ItemKey, ItemMap
  • Chest — 3сек открытие
  • ChestLoot — весовая таблица

Этап 11: Звуки и Terror Radius

  • SoundManager
  • TerrorRadiusSound — 3 уровня по расстоянию
  • KillerVision — red stain частицы
  • Звуки генераторов, взрывы

Этап 12: Data (YAML -> SQLite)

  • DataStorage interface
  • YamlStorage — реализация
  • PlayerStats — сохранение BP, матчей
  • Статистика после матча

Этап 13: Перки (отложено до стабильности)

  • IPerk interface: onEquip, onTrigger, onRemove
  • PerkRegistry — фабрика перков
  • 4 перка выжившего (Self-Care, Dead Hard, Sprint Burst, Borrowed Time)
  • 3 перка киллера (Hex: Ruin, Corrupt Intervention, BBQ)
  • Totem + TotemManager — только с Hex

Этап 14: Полировка

  • Обработка дисконнекта
  • Баланс скоростей
  • Тест-раунды
  • Оптимизация (проверка не каждый тик)

Правила <150 строк на файл

// ✅ Правильно: Controller делегирует
public class KillerController {
    private final KillerAttack attack;
    private final KillerCarry carry;
    private final KillerMovement movement;
    
    public void onLeftClick(Player target) {
        attack.tryAttack(target);
    }
}

// ❌ Неправильно: всё в одном классе
public class KillerController {
    // 500 строк логики атаки, переноса, движения...
}

Ключевые интерфейсы

IPerk

public interface IPerk {
    String getId();
    String getName();
    PerkType getType(); // SURVIVOR or KILLER
    
    void onEquip(BasePlayer player);
    void onTrigger(BasePlayer player, PerkTrigger trigger);
    void onRemove(BasePlayer player);
}

Phase

public interface Phase {
    void enter(GameSession session);
    void tick(GameSession session); // каждую секунду
    void exit(GameSession session);
    boolean isComplete();
}

DataStorage

public interface DataStorage {
    void saveStats(UUID player, PlayerStats stats);
    PlayerStats loadStats(UUID player);
    void saveMatch(MatchResult result);
}