Initial project setup: Paper plugin scaffold
This commit is contained in:
commit
32da611c63
15 changed files with 1325 additions and 0 deletions
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#
|
||||||
|
# https://help.github.com/articles/dealing-with-line-endings/
|
||||||
|
#
|
||||||
|
# Linux start script should use lf
|
||||||
|
/gradlew text eol=lf
|
||||||
|
|
||||||
|
# These are Windows script files and should use crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
|
||||||
|
# Binary files should be left untouched
|
||||||
|
*.jar binary
|
||||||
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
# MacOS DS_Store files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Gradle cache folder
|
||||||
|
.gradle
|
||||||
|
|
||||||
|
# Gradle build folder
|
||||||
|
build
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
# Common working directory
|
||||||
|
run
|
||||||
523
DBD_Plugin_TZ.md
Normal file
523
DBD_Plugin_TZ.md
Normal file
|
|
@ -0,0 +1,523 @@
|
||||||
|
# DEAD BY DAYLIGHT — Minecraft Plugin
|
||||||
|
## Техническое Задание (ТЗ)
|
||||||
|
> Полная реализация механик оригинальной игры 4v1
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Содержание
|
||||||
|
|
||||||
|
1. [Общее описание проекта](#1-общее-описание-проекта)
|
||||||
|
2. [Распределение ролей и старт игры](#2-распределение-ролей-и-старт-игры)
|
||||||
|
3. [Механики выжившего](#3-механики-выжившего-survivor)
|
||||||
|
4. [Генераторы](#4-генераторы-generators)
|
||||||
|
5. [Механики киллера](#5-механики-киллера-killer)
|
||||||
|
6. [Паллеты и окна](#6-паллеты-pallets-и-окна-windows)
|
||||||
|
7. [Выходные ворота и люк](#7-выходные-ворота-exit-gates-и-люк-hatch)
|
||||||
|
8. [Предметы для выживших](#8-предметы-items-для-выживших)
|
||||||
|
9. [Bloodpoints и прогрессия](#9-bloodpoints-и-прогрессия)
|
||||||
|
10. [Система перков](#10-система-перков-perks)
|
||||||
|
11. [Эндгейм и итоги матча](#11-эндгейм-и-итоги-матча)
|
||||||
|
12. [Пользовательский интерфейс](#12-пользовательский-интерфейс-hud)
|
||||||
|
13. [Конфигурация](#13-конфигурация-configyml)
|
||||||
|
14. [Команды и права](#14-команды-и-права)
|
||||||
|
15. [Архитектура плагина](#15-архитектура-плагина)
|
||||||
|
16. [Приоритет разработки](#16-приоритет-разработки)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Общее описание проекта
|
||||||
|
|
||||||
|
### 1.1 Цель плагина
|
||||||
|
|
||||||
|
Плагин реализует полноценную мини-игру Dead by Daylight (4v1) на Minecraft-сервере. Используется готовая карта, предоставленная заказчиком. Плагин управляет всем игровым процессом: распределением ролей, механиками выживших и киллера, победными условиями, интерфейсом и звуками.
|
||||||
|
|
||||||
|
### 1.2 Технические требования
|
||||||
|
|
||||||
|
| Параметр | Значение |
|
||||||
|
|---|---|
|
||||||
|
| Платформа | Paper / Spigot 1.20.x+ |
|
||||||
|
| Язык | Java 17+ |
|
||||||
|
| Зависимости | ProtocolLib, Citizens2 (опционально), PacketEvents |
|
||||||
|
| Кол-во игроков | 5 (1 киллер + 4 выживших) |
|
||||||
|
| Карта | Предоставляется отдельно (worldname задаётся в `config.yml`) |
|
||||||
|
| Gamemode | Adventure mode на протяжении всей игры |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Распределение ролей и старт игры
|
||||||
|
|
||||||
|
### 2.1 Лобби и ожидание
|
||||||
|
|
||||||
|
- Лобби-мир отдельный от игровой карты.
|
||||||
|
- Минимум для старта: 5 игроков (настраивается: `min_players`, `max_players`).
|
||||||
|
- Таймер ожидания: 60 секунд после набора минимума (`countdown_seconds`).
|
||||||
|
- Если игроков < минимума — таймер сбрасывается.
|
||||||
|
- В лобби показывается статус: сколько игроков зашло / нужно.
|
||||||
|
|
||||||
|
### 2.2 Назначение ролей
|
||||||
|
|
||||||
|
- Один игрок случайно становится **Киллером (Killer)**.
|
||||||
|
- Остальные 4 становятся **Выжившими (Survivors)**.
|
||||||
|
- Реализовать систему очереди: если игрок давно не был киллером — шанс повышается.
|
||||||
|
- Роли объявляются через Title + Subtitle (красный текст для киллера, белый для выжившего).
|
||||||
|
- Роль киллера не раскрывается другим выжившим до спавна (5-секундная задержка перед телепортом киллера).
|
||||||
|
|
||||||
|
### 2.3 Спавн
|
||||||
|
|
||||||
|
- Спавн-точки прописаны в `config.yml` (4 точки для выживших + 1 для киллера).
|
||||||
|
- Выжившие телепортируются одновременно.
|
||||||
|
- Киллер телепортируется через **5 секунд** после выживших (grace period).
|
||||||
|
- Во время grace period киллер видит таймер в ActionBar.
|
||||||
|
- Генераторы, хуки, выходы и другие объекты расставляются при старте игры по координатам из `config.yml`.
|
||||||
|
|
||||||
|
> ⚠ Все координаты (спавны, хуки, генераторы, выходы, подвал) задаются в `config.yml` — не хардкодятся в коде.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Механики выжившего (Survivor)
|
||||||
|
|
||||||
|
### 3.1 Состояния здоровья
|
||||||
|
|
||||||
|
Выживший имеет три состояния — переходы строго последовательные:
|
||||||
|
|
||||||
|
| Состояние | Описание | Визуал в Minecraft |
|
||||||
|
|---|---|---|
|
||||||
|
| **Healthy** (здоров) | Может бежать, прыгать, взаимодействовать | Полное здоровье, без эффектов |
|
||||||
|
| **Injured** (ранен) | Оставляет следы крови, издаёт стоны, скорость чуть снижена | Частицы крови, звук боли каждые 3 сек |
|
||||||
|
| **Downed** (повален) | Ползёт по полу, не может бежать или взаимодействовать | Crawl-анимация (Sneak + замедление), скорость 30% |
|
||||||
|
| **Hooked** (на крюке) | Привязан к крюку, ждёт спасения | Заморожен, анимация качания на крюке |
|
||||||
|
| **Dead** (мёртв) | Выбывает из игры | Spectator mode |
|
||||||
|
|
||||||
|
### 3.2 Переходы состояний
|
||||||
|
|
||||||
|
- **Healthy → Injured:** одно попадание от киллера.
|
||||||
|
- **Injured → Downed:** второе попадание от киллера.
|
||||||
|
- **Downed → Hooked:** киллер подбирает (ПКМ) и несёт к крюку.
|
||||||
|
- **Hooked → Dead:** истекло 2 стадии крюка, никто не спас.
|
||||||
|
- **Injured → Healthy:** использование аптечки или спасение с крюка.
|
||||||
|
|
||||||
|
### 3.3 Передвижение
|
||||||
|
|
||||||
|
- **Healthy:** обычная скорость + возможность спринта.
|
||||||
|
- **Injured:** скорость снижена на 5% (speed effect).
|
||||||
|
- **Downed:** только ползти — отрицательный Speed, принудительный Sneak, без прыжков.
|
||||||
|
- **Спринт (Exhaustion):** можно спринтовать конечное время (`exhaustion_seconds`, по умолчанию 3 сек спринта, затем 5 сек кулдауна).
|
||||||
|
|
||||||
|
> ⚠ Спринт — ключевая механика для чейса. Реализовать через `isSprinting()` + кастомный кулдаун.
|
||||||
|
|
||||||
|
### 3.4 Исцеление (Healing)
|
||||||
|
|
||||||
|
- **Аптечка (Med-Kit):** зажать ПКМ 10 секунд, прогресс-бар в ActionBar.
|
||||||
|
- **Исцеление другим выжившим:** подойти вплотную, зажать ПКМ 16 секунд (медленнее, чем аптечкой).
|
||||||
|
- Если движение прервалось (игрок отошёл, получил удар) — прогресс сбрасывается.
|
||||||
|
- Иконка прогресса в ActionBar: `[████░░░░░░] Исцеление 40%`
|
||||||
|
|
||||||
|
### 3.5 Механика крюка (Hook)
|
||||||
|
|
||||||
|
После того как киллер повесил выжившего на крюк:
|
||||||
|
|
||||||
|
| Стадия | Длительность | Событие |
|
||||||
|
|---|---|---|
|
||||||
|
| Stage 1 | 60 секунд | Выживший висит. Можно спасти. В ActionBar — таймер. |
|
||||||
|
| Stage 1 → 2 | Автоматически | Если не спасли за 60 сек — переход на Stage 2. |
|
||||||
|
| Stage 2 | 60 секунд | Выживший борется с Сущностью. Каждые 2 сек — Skill Check (QTE). |
|
||||||
|
| Stage 2 провален | Мгновенно | Выживший умирает — переход в Spectator. |
|
||||||
|
| Спасение с крюка | 2 секунды | Другой выживший снимает с крюка (прогресс-бар). Стадия запоминается. |
|
||||||
|
|
||||||
|
- Один и тот же выживший может быть повешен максимум **3 раза** (`hook_count`). На 3-й раз — мгновенная смерть.
|
||||||
|
- Крюки в подвале (Basement) не уничтожаются и дают бонусные Bloodpoints.
|
||||||
|
|
||||||
|
> ⚠ Skill Check на Stage 2 — случайное появление индикатора в Title. Игрок должен нажать Shift или Drop в нужный момент. Промах — мгновенная смерть.
|
||||||
|
|
||||||
|
### 3.6 Спасение с крюка
|
||||||
|
|
||||||
|
- Выживший подходит к крюку с союзником на расстояние 2 блока.
|
||||||
|
- Зажимает ПКМ (или Sneak) в течение 2 секунд — прогресс в ActionBar.
|
||||||
|
- Спасённый получает статус Injured (или остаётся Injured).
|
||||||
|
- Спасатель не получает защиты — может быть немедленно атакован.
|
||||||
|
- **Borrowed Time:** если киллер стоит рядом с крюком в момент спасения — спасённый получает 10 сек защиты Endurance (не переходит в Downed с первого удара).
|
||||||
|
|
||||||
|
### 3.7 Ползание (Dying State)
|
||||||
|
|
||||||
|
- Повалённый выживший ползёт со скоростью 30% от нормальной.
|
||||||
|
- Может ползти к другому выжившему — тот может его поднять (Recovery, 4 секунды).
|
||||||
|
- После Recovery выживший встаёт в статусе Injured.
|
||||||
|
- Самовосстановление невозможно без специального перка.
|
||||||
|
- Повалённый выживший издаёт стоны (слышимые киллеру).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Генераторы (Generators)
|
||||||
|
|
||||||
|
### 4.1 Общие правила
|
||||||
|
|
||||||
|
- На карте спавнится **7 генераторов**, нужно починить **5**.
|
||||||
|
- Количество настраивается: `total_generators`, `required_generators` в `config.yml`.
|
||||||
|
- Починённые генераторы светятся (частицы + звук).
|
||||||
|
- Киллер видит ауру всех непочиненных генераторов (через частицы или Sidebar).
|
||||||
|
|
||||||
|
### 4.2 Процесс починки
|
||||||
|
|
||||||
|
- Выживший подходит к генератору и зажимает ПКМ — начинается починка.
|
||||||
|
- Прогресс отображается в ActionBar.
|
||||||
|
- Базовое время починки: **80 секунд** (один выживший).
|
||||||
|
- Два выжившего на генераторе: скорость ×1.5 (`gen_coop_multiplier`).
|
||||||
|
- Три и более: скорость ×2.0 (ограничено).
|
||||||
|
- Если выживший отошёл или получил удар — прогресс частично откатывается (regression).
|
||||||
|
|
||||||
|
### 4.3 Skill Checks (Проверки навыка)
|
||||||
|
|
||||||
|
- В Title показывается круговой индикатор (симулируется через Title-анимации).
|
||||||
|
- Игрок должен нажать **Drop (Q)** в нужный момент (попасть в зелёную зону).
|
||||||
|
- **Успешный Skill Check:** +5% к прогрессу генератора + бонусные Bloodpoints.
|
||||||
|
- **Провальный Skill Check:** взрыв — генератор теряет 10% прогресса, громкий звук (слышен киллеру в радиусе 40 блоков).
|
||||||
|
- Частота skill check: раз в 20–40 секунд (рандомно).
|
||||||
|
|
||||||
|
> ⚠ Звук провального skill check — важнейший инструмент для киллера. Реализовать через `playSound()` с большим радиусом.
|
||||||
|
|
||||||
|
### 4.4 Регрессия генератора
|
||||||
|
|
||||||
|
- Если все выжившие отошли от работающего генератора — он начинает откатываться (0.25% в секунду).
|
||||||
|
- Киллер может ударить по генератору (ПКМ) — **Kick:** мощная регрессия 2.5% в секунду на 30 секунд.
|
||||||
|
- Регрессию можно остановить — выживший подходит и нажимает ПКМ.
|
||||||
|
- Взорванный генератор издаёт звук и выбрасывает частицы взрыва.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Механики киллера (Killer)
|
||||||
|
|
||||||
|
### 5.1 Базовые характеристики
|
||||||
|
|
||||||
|
| Параметр | Значение | Настройка |
|
||||||
|
|---|---|---|
|
||||||
|
| Скорость | 115% от скорости выжившего | `killer_speed` |
|
||||||
|
| Terror Radius | 32 блока | `terror_radius` |
|
||||||
|
| Урон атаки | Переводит в Injured / Downed | Не числовой — по состоянию |
|
||||||
|
| Кулдаун атаки | 2.5 секунды | `attack_cooldown` |
|
||||||
|
| Перенос выжившего | 92% скорости | `carry_speed` |
|
||||||
|
|
||||||
|
### 5.2 Terror Radius и Red Stain
|
||||||
|
|
||||||
|
- **Terror Radius** — зона 32 блока вокруг киллера. Выжившие в этой зоне слышат сердцебиение.
|
||||||
|
- Интенсивность звука увеличивается при сближении (3 уровня: далеко / близко / рядом).
|
||||||
|
- **Red Stain** — красное свечение на земле за киллером (частицы). Показывает направление взгляда.
|
||||||
|
- Реализация Red Stain: каждые 0.5 сек спавнить Dust-частицы красного цвета позади головы киллера.
|
||||||
|
|
||||||
|
### 5.3 Атака и удар
|
||||||
|
|
||||||
|
- **Базовая атака:** ЛКМ по выжившему. Урон по состояниям (Healthy→Injured или Injured→Downed).
|
||||||
|
- После удара — кулдаун 2.5 сек (замедление на 0.5 сек).
|
||||||
|
- Нельзя атаковать сквозь окна / паллеты (проверка LineOfSight).
|
||||||
|
- **Bloodlust:** если киллер преследует выжившего >15 секунд без попадания — бонус скорости:
|
||||||
|
- Тир 1: +3%
|
||||||
|
- Тир 2: +5%
|
||||||
|
- Тир 3: +8%
|
||||||
|
- Тиры сбрасываются при ударе или смене цели.
|
||||||
|
|
||||||
|
### 5.4 Подъём и перенос выжившего
|
||||||
|
|
||||||
|
- Когда выживший Downed — киллер нажимает ПКМ для подъёма (2.5 сек анимации).
|
||||||
|
- Во время переноса: киллер замедлен до 92% скорости, не может атаковать.
|
||||||
|
- Выживший сидит на киллере (через ArmorStand или Mount).
|
||||||
|
- Чтобы повесить: киллер подходит к хуку и нажимает ПКМ.
|
||||||
|
- **Wiggle (вырывание):** выживший нажимает Sneak/Jump быстро — прогресс побега в ActionBar. При 100% — выживший падает рядом в Downed статусе.
|
||||||
|
- Время вырывания: **16 секунд** (`wiggle_duration`).
|
||||||
|
|
||||||
|
### 5.5 Взаимодействие с генераторами
|
||||||
|
|
||||||
|
- Киллер нажимает ПКМ на генератор — **Kick** (регрессия, см. раздел 4.4).
|
||||||
|
- Киллер видит ауру всех незаконченных генераторов в Sidebar (иконки + расстояние).
|
||||||
|
|
||||||
|
### 5.6 Подвал (Basement)
|
||||||
|
|
||||||
|
- Специальная зона на карте с 4 крюками.
|
||||||
|
- Крюки в подвале **нельзя саботировать**.
|
||||||
|
- Перевод выжившего в подвал засчитывается быстрее + бонус Bloodpoints.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Паллеты (Pallets) и Окна (Windows)
|
||||||
|
|
||||||
|
### 6.1 Паллеты
|
||||||
|
|
||||||
|
- Паллеты — деревянные барьеры на карте (блоки, отмеченные в конфиге).
|
||||||
|
- Выживший подходит к паллете и нажимает ПКМ — паллета падает (standing → dropped).
|
||||||
|
- Если киллер коснулся упавшей паллеты — **Stun 2.5 сек** (звук, частицы).
|
||||||
|
- Киллер может **сломать паллету**: зажать ПКМ на 3 секунды. Паллета исчезает навсегда.
|
||||||
|
- Количество паллет на карте конечно. Статус каждой хранится в памяти.
|
||||||
|
- Выживший может пробежать через упавшую паллету (Vault, 0.6 сек).
|
||||||
|
|
||||||
|
### 6.2 Окна (Windows)
|
||||||
|
|
||||||
|
- Окна — прыжковые зоны в стенах карты (координаты в конфиге).
|
||||||
|
- Выживший запрыгивает в окно: **1 секунда** анимации Vault (замедление → ускорение).
|
||||||
|
- Киллер тоже может прыгнуть в окно, но медленнее (1.5 сек).
|
||||||
|
- **Fake Vault (Mindgame):** игрок может зайти в начало вота и выйти обратно.
|
||||||
|
|
||||||
|
> ⚠ Паллеты и окна — основа loop-механики чейса. Без правильного расположения на карте игра будет несбалансированной.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Выходные ворота (Exit Gates) и Люк (Hatch)
|
||||||
|
|
||||||
|
### 7.1 Выходные ворота
|
||||||
|
|
||||||
|
- После починки 5 генераторов активируются **2 выходных ворот** (`gate_locations`).
|
||||||
|
- Рубильник ворот загорается (смена блока, звук).
|
||||||
|
- Выживший взаимодействует с рубильником **20 секунд** (прогресс в ActionBar).
|
||||||
|
- Если прервать — прогресс **не откатывается** (в отличие от генераторов).
|
||||||
|
- Открытые ворота остаются открытыми навсегда.
|
||||||
|
- Выживший пересекает границу выхода → **ESCAPED!** (Title).
|
||||||
|
- **Эндгейм-коллапс:** через 2 минуты после открытия первых ворот — все оставшиеся выжившие умирают.
|
||||||
|
|
||||||
|
### 7.2 Люк (Hatch)
|
||||||
|
|
||||||
|
- Люк появляется, когда выживших меньше, чем непочиненных генераторов.
|
||||||
|
- Правило: если X выживших живы и < X генераторов починено — люк открыт.
|
||||||
|
- Последний выживший **всегда** видит открытый люк.
|
||||||
|
- Координата люка — `hatch_location` в конфиге.
|
||||||
|
- Прыжок в люк = Escape (побег через люк).
|
||||||
|
- Киллер может **закрыть люк** (ПКМ). После этого активируется End Game Collapse.
|
||||||
|
- Закрытый люк можно открыть выжившим с **Ключом (Key)** за 2.5 секунды.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Предметы (Items) для выживших
|
||||||
|
|
||||||
|
Предметы выдаются игрокам перед игрой или находятся в Сундуках (Chests) на карте. Максимум **1 предмет** в руках.
|
||||||
|
|
||||||
|
| Предмет | Действие | MC-предмет | Ограничение |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Med-Kit** | Лечит Injured → Healthy за 10 сек | Red Dye / Custom | 1 заряд |
|
||||||
|
| **Flashlight** | Слепит киллера (Blindness 2 сек) | Glowstone Dust / Custom | 8 использований |
|
||||||
|
| **Toolbox** | Ускоряет починку гена на 30% | Iron Pickaxe / Custom | 1 генератор |
|
||||||
|
| **Key** | Открывает закрытый люк | Gold Nugget / Custom | 1 использование |
|
||||||
|
| **Map** | Показывает ауру генераторов выжившим | Paper / Custom | Пассивно |
|
||||||
|
|
||||||
|
### 8.1 Сундуки
|
||||||
|
|
||||||
|
- На карте расставлено N сундуков (`chest_locations` в конфиге).
|
||||||
|
- Каждый сундук при открытии выдаёт случайный предмет (весовая таблица в `loot_table.yml`).
|
||||||
|
- Открытие: **3 секунды** (прогресс-бар). Один сундук — один предмет навсегда.
|
||||||
|
- Киллер может видеть ауры сундуков (опционально, через перк).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Bloodpoints и прогрессия
|
||||||
|
|
||||||
|
Bloodpoints — внутриигровая валюта, начисляется за действия в раунде. Хранятся в базе данных (SQLite или YAML).
|
||||||
|
|
||||||
|
| Действие | Выживший (BP) | Киллер (BP) |
|
||||||
|
|---|---|---|
|
||||||
|
| Починить генератор (полностью) | +1000 | — |
|
||||||
|
| Успешный Skill Check | +150 | — |
|
||||||
|
| Спасти с крюка | +800 | — |
|
||||||
|
| Исцелить союзника | +600 | — |
|
||||||
|
| Сбежать | +5000 | — |
|
||||||
|
| Повесить выжившего на крюк | — | +800 |
|
||||||
|
| Повалить выжившего | — | +500 |
|
||||||
|
| Пожертвовать выжившего (3 стадии) | — | +2000 |
|
||||||
|
| Сломать паллету | — | +200 |
|
||||||
|
| Ударить по генератору (Kick) | — | +100 |
|
||||||
|
|
||||||
|
- Bloodpoints отображаются в Title после окончания матча.
|
||||||
|
- Статистика сохраняется в базе данных.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Система перков (Perks)
|
||||||
|
|
||||||
|
Перки — пассивные и активные способности. Каждый игрок берёт **4 перка** перед матчем (в GUI-меню выбора).
|
||||||
|
|
||||||
|
### 10.1 Перки Выживших (минимум 10)
|
||||||
|
|
||||||
|
| Перк | Эффект |
|
||||||
|
|---|---|
|
||||||
|
| **Self-Care** | Позволяет лечить себя без аптечки (вдвое медленнее) |
|
||||||
|
| **Dead Hard** | При нажатии Sneak во время спринта — кратковременный рывок (0.5 сек неуязвимости) |
|
||||||
|
| **Borrowed Time** | После спасения с крюка — 10 сек защита Endurance |
|
||||||
|
| **Sprint Burst** | При начале спринта — ускорение ×1.5 на 3 сек (кулдаун 40 сек) |
|
||||||
|
| **Iron Will** | Убирает звуки стонов в Injured состоянии |
|
||||||
|
| **Spine Chill** | Предупреждение (иконка + звук), если киллер смотрит на выжившего с 36 блоков |
|
||||||
|
| **Resilience** | В Injured/Downed — скорость починки +9%, скорость вота +9% |
|
||||||
|
| **Kindred** | После повешения на крюк — все союзники видят ауру киллера |
|
||||||
|
| **Prove Thyself** | За каждого выжившего на генераторе — скорость +15% (стакается) |
|
||||||
|
| **Adrenaline** | При открытии 5-го генератора — мгновенно Healthy + Sprint Burst 5 сек |
|
||||||
|
|
||||||
|
### 10.2 Перки Киллера (минимум 10)
|
||||||
|
|
||||||
|
| Перк | Эффект |
|
||||||
|
|---|---|
|
||||||
|
| **Hex: Ruin** | Все генераторы регрессируют вдвое быстрее (пока горит тотем) |
|
||||||
|
| **Corrupt Intervention** | 3 самых дальних генератора заблокированы 2 минуты в начале игры |
|
||||||
|
| **Pop Goes the Weasel** | После повешения — следующий Kick откатывает 25% прогресса гена |
|
||||||
|
| **Deadlock** | После починки любого гена — самый прогрессивный ген блокируется на 30 сек |
|
||||||
|
| **No Way Out** | После повешения — добавляется задержка при открытии ворот (+12/24/36 сек) |
|
||||||
|
| **Scourge Hook: Pain Resonance** | Повешение на Scourge Hook взрывает ближайший ген (−25%) |
|
||||||
|
| **Nowhere to Hide** | После Kick гена — ауры выживших видны 4 сек в радиусе 24 блоков |
|
||||||
|
| **Lethal Pursuer** | В начале игры — видеть ауры всех выживших 7 секунд |
|
||||||
|
| **BBQ & Chili** | После повешения — видеть ауры выживших >40 блоков на 4 сек |
|
||||||
|
| **Tinkerer** | Когда ген достигает 70% — уведомление + Undetectable на 12 сек |
|
||||||
|
|
||||||
|
> ⚠ Перки реализовать через EventListener. Каждый перк — отдельный класс, реализующий интерфейс `IPerk` с методами `onEquip()`, `onTrigger()`, `onRemove()`.
|
||||||
|
|
||||||
|
### 10.3 Тотемы (Totems)
|
||||||
|
|
||||||
|
- На карте **5 тотемов** (`totem_locations` в конфиге).
|
||||||
|
- **Dull Totem:** выживший ломает за 14 секунд — начисляются Bloodpoints.
|
||||||
|
- **Hex Totem:** активируется при использовании Hex-перка. Пока горит — перк активен.
|
||||||
|
- При уничтожении Hex Totema — связанный перк деактивируется навсегда.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Эндгейм и итоги матча
|
||||||
|
|
||||||
|
### 11.1 Условия победы
|
||||||
|
|
||||||
|
| Сторона | Победа | Поражение |
|
||||||
|
|---|---|---|
|
||||||
|
| **Выжившие** | Минимум 2 выживших сбежали (ворота или люк) | Все выжившие мертвы до побега |
|
||||||
|
| **Киллер** | Все 4 выжившие принесены в жертву / умерли | 2+ выжившие сбежали |
|
||||||
|
|
||||||
|
### 11.2 Экран результатов
|
||||||
|
|
||||||
|
- Все игроки телепортируются в лобби.
|
||||||
|
- В Chat выводится таблица: игрок, роль, Bloodpoints, статус (Escaped / Sacrificed).
|
||||||
|
- Title на 5 секунд: **ПОБЕДА / ПОРАЖЕНИЕ**.
|
||||||
|
- Личная статистика матча: генераторы, спасения, хуки, урон.
|
||||||
|
|
||||||
|
### 11.3 Эндгейм Коллапс (End Game Collapse)
|
||||||
|
|
||||||
|
- Активируется при: открытии ворот ИЛИ закрытии люка.
|
||||||
|
- Таймер **120 секунд** показывается всем в ActionBar красным текстом.
|
||||||
|
- По истечении — все оставшиеся выжившие мгновенно умирают.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Пользовательский интерфейс (HUD)
|
||||||
|
|
||||||
|
### 12.1 ActionBar
|
||||||
|
|
||||||
|
- Постоянно: статус игрока (`❤ Healthy` / `🩸 Injured` / `💀 Downed`).
|
||||||
|
- При взаимодействии: прогресс-бар починки / лечения / спасения.
|
||||||
|
- Эндгейм Коллапс: красный таймер обратного отсчёта.
|
||||||
|
|
||||||
|
### 12.2 Sidebar (Scoreboard)
|
||||||
|
|
||||||
|
- **Выжившие:** количество починенных генераторов (`⚡ 2/5`), сколько выживших живо (`👥 3/4`).
|
||||||
|
- **Киллер:** сколько выживших на крюке / мертво, прогресс генераторов.
|
||||||
|
|
||||||
|
### 12.3 Title / Subtitle
|
||||||
|
|
||||||
|
- Оповещения: генератор починен, выживший на крюке, ворота открыты.
|
||||||
|
- Начало игры: роль + краткая инструкция.
|
||||||
|
- Skill Check: вспышка в Title с таймером.
|
||||||
|
|
||||||
|
### 12.4 Звуки
|
||||||
|
|
||||||
|
- **Terror Radius:** нарастающее сердцебиение по мере приближения киллера (3 уровня).
|
||||||
|
- **Генератор:** звук работы при починке, взрыв при провале skill check или Kick.
|
||||||
|
- **Спасение с крюка:** звук успеха.
|
||||||
|
- **Люк:** звук открытия / закрытия.
|
||||||
|
- **Ворота:** звук активации, гудение.
|
||||||
|
|
||||||
|
> ⚠ Рекомендуется базовый Resource Pack для кастомных звуков. Без него — стандартные MC-звуки как замена.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Конфигурация (config.yml)
|
||||||
|
|
||||||
|
| Секция | Ключ | Тип | По умолчанию |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `game` | `min_players` | int | 5 |
|
||||||
|
| `game` | `max_players` | int | 5 |
|
||||||
|
| `game` | `countdown_seconds` | int | 60 |
|
||||||
|
| `game` | `world_name` | string | `dbd_map` |
|
||||||
|
| `game` | `lobby_world` | string | `lobby` |
|
||||||
|
| `killer` | `killer_speed` | double | 1.15 |
|
||||||
|
| `killer` | `terror_radius` | int | 32 |
|
||||||
|
| `killer` | `attack_cooldown` | double | 2.5 |
|
||||||
|
| `killer` | `carry_speed` | double | 0.92 |
|
||||||
|
| `killer` | `wiggle_duration` | double | 16.0 |
|
||||||
|
| `survivor` | `sprint_duration` | double | 3.0 |
|
||||||
|
| `survivor` | `sprint_cooldown` | double | 5.0 |
|
||||||
|
| `survivor` | `heal_self_time` | double | 10.0 |
|
||||||
|
| `survivor` | `heal_other_time` | double | 16.0 |
|
||||||
|
| `generator` | `total_generators` | int | 7 |
|
||||||
|
| `generator` | `required_generators` | int | 5 |
|
||||||
|
| `generator` | `repair_time` | double | 80.0 |
|
||||||
|
| `generator` | `gen_coop_multiplier` | double | 1.5 |
|
||||||
|
| `generator` | `regression_rate` | double | 0.25 |
|
||||||
|
| `hook` | `stage1_duration` | int | 60 |
|
||||||
|
| `hook` | `stage2_duration` | int | 60 |
|
||||||
|
| `hook` | `max_hook_count` | int | 3 |
|
||||||
|
| `endgame` | `collapse_duration` | int | 120 |
|
||||||
|
|
||||||
|
**Дополнительные файлы конфигурации:**
|
||||||
|
- `locations.yml` — все спавн-точки, координаты генераторов, хуков, тотемов, сундуков, ворот, люка.
|
||||||
|
- `loot_table.yml` — весовая таблица предметов в сундуках.
|
||||||
|
- `perks.yml` — настройки перков (кулдауны, длительности).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Команды и права
|
||||||
|
|
||||||
|
| Команда | Описание | Право |
|
||||||
|
|---|---|---|
|
||||||
|
| `/dbd join` | Войти в очередь на игру | `dbd.play` |
|
||||||
|
| `/dbd leave` | Выйти из очереди / матча | `dbd.play` |
|
||||||
|
| `/dbd forcestart` | Принудительно запустить игру | `dbd.admin` |
|
||||||
|
| `/dbd stop` | Принудительно остановить игру | `dbd.admin` |
|
||||||
|
| `/dbd setkiller <игрок>` | Назначить игрока киллером | `dbd.admin` |
|
||||||
|
| `/dbd setspawn <killer\|survivor1..4>` | Установить спавн-точку (по курсору) | `dbd.admin` |
|
||||||
|
| `/dbd setgen <id>` | Отметить блок как генератор | `dbd.admin` |
|
||||||
|
| `/dbd sethook <id>` | Отметить блок как крюк | `dbd.admin` |
|
||||||
|
| `/dbd setgate <1\|2>` | Отметить зону ворот | `dbd.admin` |
|
||||||
|
| `/dbd sethatch` | Отметить блок как люк | `dbd.admin` |
|
||||||
|
| `/dbd reload` | Перезагрузить конфиг | `dbd.admin` |
|
||||||
|
| `/dbd stats [игрок]` | Посмотреть статистику | `dbd.play` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Архитектура плагина
|
||||||
|
|
||||||
|
### 15.1 Структура пакетов
|
||||||
|
|
||||||
|
| Пакет | Назначение |
|
||||||
|
|---|---|
|
||||||
|
| `com.dbd.plugin.core` | Главный класс, GameManager, EventBus |
|
||||||
|
| `com.dbd.plugin.game` | GameSession, GameState, RoleAssigner, RoundTimer |
|
||||||
|
| `com.dbd.plugin.roles` | KillerController, SurvivorController, PlayerState |
|
||||||
|
| `com.dbd.plugin.mechanics` | GeneratorManager, HookManager, PalletManager, HatchManager, GateManager |
|
||||||
|
| `com.dbd.plugin.perks` | IPerk, PerkRegistry, PerkLoader, [все перки] |
|
||||||
|
| `com.dbd.plugin.items` | IItem, ItemRegistry, ChestManager |
|
||||||
|
| `com.dbd.plugin.ui` | HUDManager, ActionBarManager, TitleManager, SoundManager |
|
||||||
|
| `com.dbd.plugin.data` | DatabaseManager, PlayerStats, LocationsConfig |
|
||||||
|
| `com.dbd.plugin.commands` | DBDCommand, TabCompleter |
|
||||||
|
|
||||||
|
### 15.2 Ключевые принципы
|
||||||
|
|
||||||
|
- Каждый раунд — отдельный объект `GameSession` со своим состоянием.
|
||||||
|
- Все механики управляются через `BukkitScheduler` (tick-based системы).
|
||||||
|
- Перки реализованы через Event-Driven подход (не хардкод в механиках).
|
||||||
|
- Конфиги не перезаписывают пользовательские настройки при обновлении (`saveDefaultConfig`).
|
||||||
|
- Логирование всех событий в отдельный лог-файл (`logs/dbd.log`).
|
||||||
|
|
||||||
|
> ⚠ Плагин должен корректно обрабатывать disconnect игрока во время матча — замена ботом или перераспределение ролей.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. Приоритет разработки
|
||||||
|
|
||||||
|
| Этап | Функционал | Статус |
|
||||||
|
|---|---|---|
|
||||||
|
| **MVP (Этап 1)** | Старт/стоп игры, роли, спавн, базовые состояния выжившего, атака киллера | 🔴 В разработке |
|
||||||
|
| **Этап 2** | Генераторы (починка, прогресс, регрессия, skill check), хуки (все стадии) | 🔴 В разработке |
|
||||||
|
| **Этап 3** | Паллеты, окна, перенос, вырывание, люк, ворота, эндгейм | 🔴 В разработке |
|
||||||
|
| **Этап 4** | Предметы, сундуки, тотемы, базовые перки (10 survivor + 10 killer) | 🔴 В разработке |
|
||||||
|
| **Этап 5** | Полный HUD, звуки, Terror Radius, Red Stain, Bloodpoints, база данных | 🔴 В разработке |
|
||||||
|
| **Этап 6** | Балансировка, все остальные перки, тест-раунды, оптимизация | 🔴 В разработке |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*ТЗ подготовлено с учётом всех оригинальных механик Dead by Daylight (4v1) | Версия 1.0*
|
||||||
332
PLAN.md
Normal file
332
PLAN.md
Normal file
|
|
@ -0,0 +1,332 @@
|
||||||
|
# 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 17, 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 строк на файл
|
||||||
|
|
||||||
|
```java
|
||||||
|
// ✅ Правильно: 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
|
||||||
|
```java
|
||||||
|
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
|
||||||
|
```java
|
||||||
|
public interface Phase {
|
||||||
|
void enter(GameSession session);
|
||||||
|
void tick(GameSession session); // каждую секунду
|
||||||
|
void exit(GameSession session);
|
||||||
|
boolean isComplete();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### DataStorage
|
||||||
|
```java
|
||||||
|
public interface DataStorage {
|
||||||
|
void saveStats(UUID player, PlayerStats stats);
|
||||||
|
PlayerStats loadStats(UUID player);
|
||||||
|
void saveMatch(MatchResult result);
|
||||||
|
}
|
||||||
|
```
|
||||||
34
build.gradle.kts
Normal file
34
build.gradle.kts
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
plugins {
|
||||||
|
id("java-library")
|
||||||
|
id("xyz.jpenilla.run-paper") version "3.0.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://repo.papermc.io/repository/maven-public/")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly("io.papermc.paper:paper-api:26.1.2.build.+")
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain.languageVersion = JavaLanguageVersion.of(25)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
runServer {
|
||||||
|
// Configure the Minecraft version for our task.
|
||||||
|
// This is the only required configuration besides applying the plugin.
|
||||||
|
// Your plugin's jar (or shadowJar if present) will be used automatically.
|
||||||
|
minecraftVersion("26.1.2")
|
||||||
|
jvmArgs("-Xms2G", "-Xmx2G")
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
val props = mapOf("version" to version)
|
||||||
|
filesMatching("paper-plugin.yml") {
|
||||||
|
expand(props)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
gradle.properties
Normal file
5
gradle.properties
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
group=dev.loki
|
||||||
|
version=1.0
|
||||||
|
org.gradle.configuration-cache=true
|
||||||
|
org.gradle.parallel=true
|
||||||
|
org.gradle.caching=true
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
248
gradlew
vendored
Normal file
248
gradlew
vendored
Normal file
|
|
@ -0,0 +1,248 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
93
gradlew.bat
vendored
Normal file
93
gradlew.bat
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
1
settings.gradle.kts
Normal file
1
settings.gradle.kts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
rootProject.name = "Mdbd"
|
||||||
16
src/main/java/dev/loki/mdbd.java
Normal file
16
src/main/java/dev/loki/mdbd.java
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
package dev.loki;
|
||||||
|
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
public final class mdbd extends JavaPlugin {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
// Plugin startup logic
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
// Plugin shutdown logic
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/main/java/dev/loki/mdbdBootstrap.java
Normal file
12
src/main/java/dev/loki/mdbdBootstrap.java
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package dev.loki;
|
||||||
|
|
||||||
|
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
||||||
|
import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
|
||||||
|
|
||||||
|
class mdbdBootstrap implements PluginBootstrap {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bootstrap(final BootstrapContext context) {
|
||||||
|
// Plugin bootstrap logic
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/main/java/dev/loki/mdbdLoader.java
Normal file
12
src/main/java/dev/loki/mdbdLoader.java
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package dev.loki;
|
||||||
|
|
||||||
|
import io.papermc.paper.plugin.loader.PluginClasspathBuilder;
|
||||||
|
import io.papermc.paper.plugin.loader.PluginLoader;
|
||||||
|
|
||||||
|
class mdbdLoader implements PluginLoader {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void classloader(final PluginClasspathBuilder builder) {
|
||||||
|
// Add dynamically loaded libraries here
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/main/resources/paper-plugin.yml
Normal file
10
src/main/resources/paper-plugin.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
name: Mdbd
|
||||||
|
version: '${version}'
|
||||||
|
|
||||||
|
main: dev.loki.mdbd
|
||||||
|
bootstrapper: dev.loki.mdbdBootstrap
|
||||||
|
loader: dev.loki.mdbdLoader
|
||||||
|
api-version: '26.1.2'
|
||||||
|
load: POSTWORLD
|
||||||
|
|
||||||
|
authors: [ loki ]
|
||||||
Loading…
Add table
Add a link
Reference in a new issue