fix: colors, /dbd join flow, world creation, role assign, action bar lobby, /dbdadmin world, tab complete
This commit is contained in:
parent
327ad9b906
commit
1adb8c84fd
19 changed files with 874 additions and 112 deletions
524
COMMANDS_GUIDE.md
Normal file
524
COMMANDS_GUIDE.md
Normal file
|
|
@ -0,0 +1,524 @@
|
||||||
|
# Dead by Daylight Plugin — Руководство команд
|
||||||
|
|
||||||
|
**Версия:** 1.1
|
||||||
|
**Обновлено:** Июнь 2026
|
||||||
|
**Платформа:** Minecraft 1.21.1 (Paper)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Содержание
|
||||||
|
|
||||||
|
1. [Фазы игры](#фазы-игры)
|
||||||
|
2. [Команды игроков — /dbd](#команды-игроков--dbd)
|
||||||
|
3. [Команды администратора — /dbdadmin](#команды-администратора--dbdadmin)
|
||||||
|
4. [Команды настройки карты — /dbdsetup](#команды-настройки-карты--dbdsetup)
|
||||||
|
5. [Права доступа](#права-доступа)
|
||||||
|
6. [Порядок настройки сервера](#порядок-настройки-сервера)
|
||||||
|
7. [Таблица всех команд](#таблица-всех-команд)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Фазы игры
|
||||||
|
|
||||||
|
```
|
||||||
|
LOBBY
|
||||||
|
Игроки делают /dbd join → телепорт в мир lobby
|
||||||
|
Action bar показывает: ▶ Старт через: 45с ████████░░ (3/5)
|
||||||
|
Когда набралось минимум игроков — идёт отсчёт 60 сек
|
||||||
|
При нехватке игроков — таймер сбрасывается
|
||||||
|
↓
|
||||||
|
ROLE ASSIGN (5 сек)
|
||||||
|
Случайно выбирается 1 киллер, остальные — выжившие
|
||||||
|
Показывается тайтл с ролью
|
||||||
|
Все телепортируются на свои спавны в мире game
|
||||||
|
↓
|
||||||
|
GAMEPLAY
|
||||||
|
Выжившие чинят генераторы (нужно 5 из 7)
|
||||||
|
Киллер охотится
|
||||||
|
При починке всех нужных генераторов — открываются ворота
|
||||||
|
↓
|
||||||
|
ENDGAME (2 минуты)
|
||||||
|
Выжившие открывают ворота и убегают
|
||||||
|
Или используют люк (если остался 1 выживший)
|
||||||
|
Коллапс через 120 сек убивает всех оставшихся
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Команды игроков — /dbd
|
||||||
|
|
||||||
|
Все команды ниже доступны любому игроку (`mdbd.player`, по умолчанию `true`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbd join
|
||||||
|
|
||||||
|
Присоединиться к игровой очереди.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbd join
|
||||||
|
```
|
||||||
|
|
||||||
|
- Добавляет игрока в текущую сессию как выжившего (роль назначится позже)
|
||||||
|
- Телепортирует в мир `lobby`
|
||||||
|
- В action bar начинает отображаться счётчик и таймер
|
||||||
|
- Если игра не создана — сообщение об ошибке
|
||||||
|
|
||||||
|
```
|
||||||
|
→ [DBD] Вы присоединились к игре!
|
||||||
|
→ [DBD] PlayerName присоединился к очереди! (1/5)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbd leave
|
||||||
|
|
||||||
|
Покинуть сессию.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbd leave
|
||||||
|
```
|
||||||
|
|
||||||
|
- В лобби: просто убирает из очереди, таймер может сброситься
|
||||||
|
- В игре: выживший считается мёртвым, киллер завершает игру
|
||||||
|
- Игрок телепортируется обратно в `lobby`
|
||||||
|
|
||||||
|
```
|
||||||
|
→ [DBD] Вы покинули игру
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbd lobby
|
||||||
|
|
||||||
|
Телепортироваться в лобби-мир.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbd lobby
|
||||||
|
```
|
||||||
|
|
||||||
|
- Работает в любой момент, не убирает из сессии
|
||||||
|
- Телепортирует на точку спавна лобби (из `locations.yml`) или на спавн мира `lobby`
|
||||||
|
|
||||||
|
```
|
||||||
|
→ [DBD] Вы телепортированы в лобби!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Команды администратора — /dbd (admin)
|
||||||
|
|
||||||
|
Требуют право `mdbd.admin` (по умолчанию только OP).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbd create
|
||||||
|
|
||||||
|
Создать новую игровую сессию.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbd create
|
||||||
|
```
|
||||||
|
|
||||||
|
- Создаёт сессию и открывает лобби
|
||||||
|
- Нельзя создать вторую сессию пока первая активна
|
||||||
|
|
||||||
|
```
|
||||||
|
→ [DBD] Игра создана!
|
||||||
|
→ [DBD] Игра уже существует (если уже есть)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbd forcestart
|
||||||
|
|
||||||
|
Принудительно запустить игру, пропустив таймер.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbd forcestart
|
||||||
|
```
|
||||||
|
|
||||||
|
- Работает только если сессия в фазе LOBBY
|
||||||
|
- Игроков в очереди может быть меньше минимума
|
||||||
|
|
||||||
|
```
|
||||||
|
→ [DBD] Игра форсирована!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbd stop
|
||||||
|
|
||||||
|
Немедленно завершить текущую сессию.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbd stop
|
||||||
|
```
|
||||||
|
|
||||||
|
- Все игроки телепортируются в `lobby`
|
||||||
|
- Сессия уничтожается, можно создавать новую
|
||||||
|
|
||||||
|
```
|
||||||
|
→ [DBD] Игра остановлена
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbd reload
|
||||||
|
|
||||||
|
Перезагрузить все конфиги без перезапуска сервера.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbd reload
|
||||||
|
```
|
||||||
|
|
||||||
|
Перезагружает: `config.yml`, `game.yml`, `messages.yml`, `skillcheck.yml`, `locations.yml`, `generators.yml`
|
||||||
|
|
||||||
|
```
|
||||||
|
→ [DBD] Конфиги перезагружены!
|
||||||
|
```
|
||||||
|
|
||||||
|
> Если игра в процессе — сначала `/dbd stop`, иначе новые настройки применятся только к следующей сессии.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbd setlobby
|
||||||
|
|
||||||
|
Установить текущую позицию игрока как точку спавна лобби.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbd setlobby
|
||||||
|
```
|
||||||
|
|
||||||
|
- Сохраняется в `locations.yml`
|
||||||
|
- Эквивалентно `/dbdsetup lobby`
|
||||||
|
|
||||||
|
```
|
||||||
|
→ [DBD] Лобби установлено!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Команды администратора — /dbdadmin
|
||||||
|
|
||||||
|
Требуют право `mdbd.admin`. Все команды только для игроков (не консоли).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdadmin create generator
|
||||||
|
|
||||||
|
Режим расстановки генераторов.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdadmin create generator
|
||||||
|
```
|
||||||
|
|
||||||
|
- Включает режим: в action bar оранжевая подсказка
|
||||||
|
- **Сломай блок** — координаты сохранятся, блок не разрушится
|
||||||
|
- Повторная команда — отключает режим
|
||||||
|
- Режим остаётся активным для нескольких генераторов подряд
|
||||||
|
|
||||||
|
```
|
||||||
|
→ Режим выбора генератора включен!
|
||||||
|
→ Сломайте блок, чтобы установить генератор
|
||||||
|
(сломал блок)
|
||||||
|
→ Генератор установлен! Всего: 1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tab complete:** `generator`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdadmin list
|
||||||
|
|
||||||
|
Список всех установленных генераторов.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdadmin list
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
=== Генераторы (3) ===
|
||||||
|
[0] game:100.00,64.00,200.00
|
||||||
|
[1] game:150.00,64.00,150.00
|
||||||
|
[2] game:200.00,64.00,100.00
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdadmin remove \<id\>
|
||||||
|
|
||||||
|
Удалить генератор по ID из списка.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdadmin remove 0
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tab complete:** подсказывает существующие ID (0, 1, 2...)
|
||||||
|
|
||||||
|
```
|
||||||
|
→ Генератор удален: game:100.00,64.00,200.00
|
||||||
|
→ Генератор с ID 5 не найден (если нет такого)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdadmin clear
|
||||||
|
|
||||||
|
Удалить все генераторы.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdadmin clear
|
||||||
|
```
|
||||||
|
|
||||||
|
> Необратимо.
|
||||||
|
|
||||||
|
```
|
||||||
|
→ Все генераторы удалены
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdadmin world \<мир\>
|
||||||
|
|
||||||
|
Телепортироваться в указанный мир для настройки карты.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdadmin world lobby
|
||||||
|
/dbdadmin world game
|
||||||
|
/dbdadmin world <любое_название_мира>
|
||||||
|
```
|
||||||
|
|
||||||
|
- `lobby` — телепорт в мир-лобби (void, платформа 7x7)
|
||||||
|
- `game` — телепорт в игровой мир
|
||||||
|
- Любое другое название — телепорт в мир с таким именем (если загружен)
|
||||||
|
|
||||||
|
```
|
||||||
|
→ Телепортирован в мир: lobby
|
||||||
|
→ Мир не найден: abc (если мир не существует)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tab complete:** `lobby`, `game`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Команды настройки карты — /dbdsetup
|
||||||
|
|
||||||
|
Требуют право `mdbd.admin`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdsetup wand
|
||||||
|
|
||||||
|
Выдать палочку для выделения регионов.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdsetup wand
|
||||||
|
```
|
||||||
|
|
||||||
|
- Выдаёт палку (STICK) с подписью
|
||||||
|
- ЛКМ = первая точка (pos1)
|
||||||
|
- ПКМ = вторая точка (pos2)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdsetup pos1 / pos2
|
||||||
|
|
||||||
|
Установить точку выделения вручную (по позиции игрока).
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdsetup pos1
|
||||||
|
/dbdsetup pos2
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
→ Установлена точка 1: [game, 100, 64, 200]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdsetup save \<название\>
|
||||||
|
|
||||||
|
Сохранить блоки между pos1 и pos2 как шаблон карты.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdsetup save main_map
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tab complete для load/save:** показывает существующие шаблоны.
|
||||||
|
|
||||||
|
```
|
||||||
|
→ Шаблон 'main_map' сохранен!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdsetup load \<название\>
|
||||||
|
|
||||||
|
Загрузить шаблон на текущую позицию игрока.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdsetup load main_map
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tab complete:** список сохранённых шаблонов.
|
||||||
|
|
||||||
|
```
|
||||||
|
→ Шаблон 'main_map' загружен!
|
||||||
|
→ Шаблон не найден! (если нет такого)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdsetup list
|
||||||
|
|
||||||
|
Показать список сохранённых шаблонов карт.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdsetup list
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdsetup set \<тип\>
|
||||||
|
|
||||||
|
Сохранить текущую позицию игрока как объект указанного типа.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdsetup set generator
|
||||||
|
/dbdsetup set hook
|
||||||
|
/dbdsetup set pallet
|
||||||
|
/dbdsetup set chest
|
||||||
|
/dbdsetup set totem
|
||||||
|
/dbdsetup set gate
|
||||||
|
/dbdsetup set lobby
|
||||||
|
```
|
||||||
|
|
||||||
|
| Тип | Описание | Рекомендуемое кол-во |
|
||||||
|
|-----|----------|---------------------|
|
||||||
|
| `generator` | Генератор | 7 |
|
||||||
|
| `hook` | Крюк | 7–10 |
|
||||||
|
| `pallet` | Паллет | 15–20 |
|
||||||
|
| `gate` | Ворота выхода | 2 |
|
||||||
|
| `lobby` | Спавн в лобби | 1 |
|
||||||
|
|
||||||
|
> `chest`, `totem` — сохраняются в `locations.yml`, но пока не подключены к игровой логике.
|
||||||
|
|
||||||
|
**Tab complete:** все типы выше.
|
||||||
|
|
||||||
|
```
|
||||||
|
→ Установлен: hook на [game, 150, 65, 200]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdsetup build
|
||||||
|
|
||||||
|
Построить карту по шаблону и `locations.yml`.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdsetup build
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
→ Строительство карты...
|
||||||
|
→ Карта построена!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdsetup clear
|
||||||
|
|
||||||
|
Очистить карту.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdsetup clear
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
→ Очистка карты...
|
||||||
|
→ Карта очищена!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### /dbdsetup lobby
|
||||||
|
|
||||||
|
Установить спавн лобби на текущую позицию.
|
||||||
|
|
||||||
|
```
|
||||||
|
/dbdsetup lobby
|
||||||
|
```
|
||||||
|
|
||||||
|
Аналог `/dbd setlobby`. Сохраняется в `locations.yml`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Права доступа
|
||||||
|
|
||||||
|
| Право | Кому | Что даёт |
|
||||||
|
|-------|------|----------|
|
||||||
|
| `mdbd.player` | Все (`default: true`) | `/dbd join`, `leave`, `lobby` |
|
||||||
|
| `mdbd.admin` | OP (`default: op`) | Все остальные команды |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Порядок настройки сервера
|
||||||
|
|
||||||
|
### Первый запуск
|
||||||
|
|
||||||
|
1. Запустить сервер — плагин создаст миры `lobby` и `game` автоматически
|
||||||
|
2. `/dbdadmin world lobby` — войти в лобби-мир и осмотреться (платформа 7x7)
|
||||||
|
3. `/dbd setlobby` — встать на нужную точку и сохранить спавн лобби
|
||||||
|
|
||||||
|
### Настройка игровой карты
|
||||||
|
|
||||||
|
4. `/dbdadmin world game` — перейти в игровой мир
|
||||||
|
5. Построить или загрузить карту
|
||||||
|
6. Расставить объекты:
|
||||||
|
- `/dbdadmin create generator` → ломать блоки для 7 генераторов
|
||||||
|
- `/dbdsetup set hook` → встать у каждого крюка (7–10 штук)
|
||||||
|
- `/dbdsetup set pallet` → паллеты (15–20 штук)
|
||||||
|
- `/dbdsetup set gate` → 2 ворот выхода
|
||||||
|
7. Установить спавны ролей в `locations.yml` вручную или через `/dbdsetup set`:
|
||||||
|
- `killer-spawn` — 1 точка
|
||||||
|
- `survivor-spawns` — 4 точки
|
||||||
|
|
||||||
|
### Тест
|
||||||
|
|
||||||
|
8. `/dbd create` — создать сессию
|
||||||
|
9. `/dbd join` (5 игроков или меньше с форс-стартом)
|
||||||
|
10. `/dbd forcestart` — запустить не дожидаясь таймера
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Таблица всех команд
|
||||||
|
|
||||||
|
| Команда | Право | Описание |
|
||||||
|
|---------|-------|----------|
|
||||||
|
| `/dbd join` | player | Войти в очередь |
|
||||||
|
| `/dbd leave` | player | Покинуть сессию |
|
||||||
|
| `/dbd lobby` | player | Телепорт в лобби |
|
||||||
|
| `/dbd create` | admin | Создать сессию |
|
||||||
|
| `/dbd forcestart` | admin | Принудительный старт |
|
||||||
|
| `/dbd stop` | admin | Остановить игру |
|
||||||
|
| `/dbd reload` | admin | Перезагрузить конфиги |
|
||||||
|
| `/dbd setlobby` | admin | Сохранить спавн лобби |
|
||||||
|
| `/dbdadmin create generator` | admin | Режим расстановки генераторов |
|
||||||
|
| `/dbdadmin list` | admin | Список генераторов |
|
||||||
|
| `/dbdadmin remove <id>` | admin | Удалить генератор |
|
||||||
|
| `/dbdadmin clear` | admin | Очистить все генераторы |
|
||||||
|
| `/dbdadmin world <lobby\|game\|мир>` | admin | Телепорт в мир |
|
||||||
|
| `/dbdsetup wand` | admin | Палочка выделения |
|
||||||
|
| `/dbdsetup pos1` / `pos2` | admin | Точки выделения |
|
||||||
|
| `/dbdsetup save <name>` | admin | Сохранить шаблон карты |
|
||||||
|
| `/dbdsetup load <name>` | admin | Загрузить шаблон |
|
||||||
|
| `/dbdsetup list` | admin | Список шаблонов |
|
||||||
|
| `/dbdsetup set <тип>` | admin | Сохранить позицию объекта |
|
||||||
|
| `/dbdsetup build` | admin | Построить карту |
|
||||||
|
| `/dbdsetup clear` | admin | Очистить карту |
|
||||||
|
| `/dbdsetup lobby` | admin | Сохранить спавн лобби |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Dead by Daylight Minecraft Plugin — актуально для версии 1.1+*
|
||||||
|
|
@ -21,26 +21,30 @@ java {
|
||||||
toolchain.languageVersion = JavaLanguageVersion.of(21)
|
toolchain.languageVersion = JavaLanguageVersion.of(21)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType<JavaCompile> {
|
||||||
|
options.encoding = "UTF-8"
|
||||||
|
}
|
||||||
|
|
||||||
val obfuscateTask = tasks.register<JavaExec>("obfuscate") {
|
val obfuscateTask = tasks.register<JavaExec>("obfuscate") {
|
||||||
description = "Obfuscate the plugin jar using ProGuard"
|
description = "Obfuscate the plugin jar using ProGuard"
|
||||||
mainClass.set("proguard.ProGuard")
|
mainClass.set("proguard.ProGuard")
|
||||||
classpath = proguardConfig
|
classpath = proguardConfig
|
||||||
|
|
||||||
val inJar = tasks.named<Jar>("jar").get().archiveFile.get().asFile.path
|
val jarFile = tasks.named<Jar>("jar").get().archiveFile.get().asFile
|
||||||
val outJar = layout.buildDirectory.file("libs/${project.name}-${version}-obf.jar").get().asFile.path
|
// Write to separate dir — avoids conflicts with jar task output on Windows
|
||||||
|
val obfJar = layout.buildDirectory.file("obfuscated/${project.name}-${version}.jar").get().asFile
|
||||||
|
|
||||||
args(
|
args(
|
||||||
"-injars", inJar,
|
"-injars", jarFile.path,
|
||||||
"-outjars", outJar,
|
"-outjars", obfJar.path,
|
||||||
"-dontwarn",
|
"-dontwarn",
|
||||||
"-ignorewarnings",
|
"-ignorewarnings",
|
||||||
|
|
||||||
"-keep", "class dev.loki.mdbd",
|
"-keep", "class dev.loki.mdbd",
|
||||||
"-keep", "class dev.loki.mdbdBootstrap",
|
"-keep", "class dev.loki.mdbdBootstrap",
|
||||||
"-keep", "class dev.loki.mdbdLoader",
|
"-keep", "class dev.loki.mdbdLoader",
|
||||||
"-keep", "class dev.loki.command.**",
|
"-keep", "class dev.loki.command.** { *; }",
|
||||||
"-keep", "class dev.loki.listener.**",
|
"-keep", "class dev.loki.listener.** { *; }",
|
||||||
"-keepclassmembers", "class * { @org.bukkit.event.EventHandler *; }",
|
|
||||||
"-keepnames", "class dev.loki.**",
|
"-keepnames", "class dev.loki.**",
|
||||||
|
|
||||||
"-dontoptimize",
|
"-dontoptimize",
|
||||||
|
|
@ -49,9 +53,32 @@ val obfuscateTask = tasks.register<JavaExec>("obfuscate") {
|
||||||
"-keepattributes", "Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,EnclosingMethod"
|
"-keepattributes", "Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,EnclosingMethod"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
outputs.file(obfJar)
|
||||||
dependsOn(tasks.named("jar"))
|
dependsOn(tasks.named("jar"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save original jar as -orig, then replace with obfuscated
|
||||||
|
val jarName = "${project.name}-${version}"
|
||||||
|
|
||||||
|
tasks.register("saveOriginalJar") {
|
||||||
|
val jarSrc = layout.buildDirectory.file("libs/$jarName.jar")
|
||||||
|
val jarDst = layout.buildDirectory.file("libs/$jarName-orig.jar")
|
||||||
|
dependsOn(tasks.named("jar"))
|
||||||
|
inputs.file(jarSrc)
|
||||||
|
outputs.file(jarDst)
|
||||||
|
doLast {
|
||||||
|
jarSrc.get().asFile.copyTo(jarDst.get().asFile, overwrite = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register<Copy>("replaceWithObfuscated") {
|
||||||
|
dependsOn(obfuscateTask, "saveOriginalJar")
|
||||||
|
from(layout.buildDirectory.dir("obfuscated"))
|
||||||
|
include("$jarName.jar")
|
||||||
|
into(layout.buildDirectory.dir("libs"))
|
||||||
|
outputs.upToDateWhen { false }
|
||||||
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
runServer {
|
runServer {
|
||||||
minecraftVersion("1.21.1")
|
minecraftVersion("1.21.1")
|
||||||
|
|
@ -66,6 +93,6 @@ tasks {
|
||||||
}
|
}
|
||||||
|
|
||||||
named("build") {
|
named("build") {
|
||||||
dependsOn(obfuscateTask)
|
dependsOn("replaceWithObfuscated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package dev.loki.command;
|
||||||
|
|
||||||
import dev.loki.data.GeneratorDataManager;
|
import dev.loki.data.GeneratorDataManager;
|
||||||
import dev.loki.mdbd;
|
import dev.loki.mdbd;
|
||||||
|
import dev.loki.util.TextUtil;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
|
@ -43,7 +44,7 @@ public class DBDAdminCommand implements TabExecutor {
|
||||||
Player p = Bukkit.getPlayer(uuid);
|
Player p = Bukkit.getPlayer(uuid);
|
||||||
if (p != null && p.isOnline()) {
|
if (p != null && p.isOnline()) {
|
||||||
p.sendActionBar(mm.deserialize(
|
p.sendActionBar(mm.deserialize(
|
||||||
"&#FFA500⚒ Режим установки: �FF00сломайте блок для генератора &#FFA500⚒"));
|
"<#FFA500>⚒ Режим установки: <#00FF00>сломайте блок для генератора <#FFA500>⚒"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0L, 20L);
|
}, 0L, 20L);
|
||||||
|
|
@ -72,6 +73,7 @@ public class DBDAdminCommand implements TabExecutor {
|
||||||
case "list" -> handleList(player);
|
case "list" -> handleList(player);
|
||||||
case "remove" -> handleRemove(player, args);
|
case "remove" -> handleRemove(player, args);
|
||||||
case "clear" -> handleClear(player);
|
case "clear" -> handleClear(player);
|
||||||
|
case "world" -> handleWorld(player, args);
|
||||||
default -> {
|
default -> {
|
||||||
sendUsage(sender);
|
sendUsage(sender);
|
||||||
yield true;
|
yield true;
|
||||||
|
|
@ -82,7 +84,7 @@ public class DBDAdminCommand implements TabExecutor {
|
||||||
@SuppressWarnings("UnreachableBranchError")
|
@SuppressWarnings("UnreachableBranchError")
|
||||||
private boolean handleCreate(Player player, String[] args) {
|
private boolean handleCreate(Player player, String[] args) {
|
||||||
if (args.length < 2) {
|
if (args.length < 2) {
|
||||||
player.sendMessage(Component.text("&#FF0000Использование: /dbdadmin create <generator>"));
|
player.sendMessage(TextUtil.color("<#FF0000>Использование: /dbdadmin create <generator>"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,18 +93,18 @@ public class DBDAdminCommand implements TabExecutor {
|
||||||
case "generator" -> {
|
case "generator" -> {
|
||||||
if (selectingGenerator.contains(player.getUniqueId())) {
|
if (selectingGenerator.contains(player.getUniqueId())) {
|
||||||
selectingGenerator.remove(player.getUniqueId());
|
selectingGenerator.remove(player.getUniqueId());
|
||||||
player.sendMessage(Component.text("&#FFA500Режим выбора генератора отключен"));
|
player.sendMessage(TextUtil.color("<#FFA500>Режим выбора генератора отключен"));
|
||||||
} else {
|
} else {
|
||||||
selectingGenerator.add(player.getUniqueId());
|
selectingGenerator.add(player.getUniqueId());
|
||||||
player.sendMessage(Component.text("�FF00Режим выбора генератора включен!"));
|
player.sendMessage(TextUtil.color("<#00FF00>Режим выбора генератора включен!"));
|
||||||
player.sendMessage(Component.text("&#FFD700Сломайте блок, чтобы установить генератор"));
|
player.sendMessage(TextUtil.color("<#FFD700>Сломайте блок, чтобы установить генератор"));
|
||||||
player.sendMessage(Component.text("&#FFD700(блок не сломается, а сохранятся его координаты)"));
|
player.sendMessage(TextUtil.color("<#FFD700>(блок не сломается, а сохранятся его координаты)"));
|
||||||
player.sendMessage(Component.text("&#FFA500Введите /dbdadmin create generator снова, чтобы отключить режим"));
|
player.sendMessage(TextUtil.color("<#FFA500>Введите /dbdadmin create generator снова, чтобы отключить режим"));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
default -> {
|
default -> {
|
||||||
player.sendMessage(Component.text("&#FF0000Неизвестный тип: " + type));
|
player.sendMessage(TextUtil.color("<#FF0000>Неизвестный тип: " + type));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,12 +112,12 @@ public class DBDAdminCommand implements TabExecutor {
|
||||||
|
|
||||||
private boolean handleList(Player player) {
|
private boolean handleList(Player player) {
|
||||||
var entries = generatorData.getGeneratorEntries();
|
var entries = generatorData.getGeneratorEntries();
|
||||||
player.sendMessage(Component.text("&#FFD700=== Генераторы (" + entries.size() + ") ==="));
|
player.sendMessage(TextUtil.color("<#FFD700>=== Генераторы (" + entries.size() + ") ==="));
|
||||||
if (entries.isEmpty()) {
|
if (entries.isEmpty()) {
|
||||||
player.sendMessage(Component.text("󅑀Нет установленных генераторов"));
|
player.sendMessage(TextUtil.color("<#808000>Нет установленных генераторов"));
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < entries.size(); i++) {
|
for (int i = 0; i < entries.size(); i++) {
|
||||||
player.sendMessage(Component.text("�CED1[" + i + "] " + entries.get(i)));
|
player.sendMessage(TextUtil.color("<#00CED1>[" + i + "] " + entries.get(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -123,7 +125,7 @@ public class DBDAdminCommand implements TabExecutor {
|
||||||
|
|
||||||
private boolean handleRemove(Player player, String[] args) {
|
private boolean handleRemove(Player player, String[] args) {
|
||||||
if (args.length < 2) {
|
if (args.length < 2) {
|
||||||
player.sendMessage(Component.text("&#FF0000Использование: /dbdadmin remove <id>"));
|
player.sendMessage(TextUtil.color("<#FF0000>Использование: /dbdadmin remove <id>"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,30 +133,65 @@ public class DBDAdminCommand implements TabExecutor {
|
||||||
int id = Integer.parseInt(args[1]);
|
int id = Integer.parseInt(args[1]);
|
||||||
var entries = generatorData.getGeneratorEntries();
|
var entries = generatorData.getGeneratorEntries();
|
||||||
if (id < 0 || id >= entries.size()) {
|
if (id < 0 || id >= entries.size()) {
|
||||||
player.sendMessage(Component.text("&#FF0000Генератор с ID " + id + " не найден"));
|
player.sendMessage(TextUtil.color("<#FF0000>Генератор с ID " + id + " не найден"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String removed = entries.get(id);
|
String removed = entries.get(id);
|
||||||
generatorData.removeGenerator(id);
|
generatorData.removeGenerator(id);
|
||||||
player.sendMessage(Component.text("�FF00Генератор удален: " + removed));
|
player.sendMessage(TextUtil.color("<#00FF00>Генератор удален: " + removed));
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
player.sendMessage(Component.text("&#FF0000ID должен быть числом"));
|
player.sendMessage(TextUtil.color("<#FF0000>ID должен быть числом"));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleClear(Player player) {
|
private boolean handleClear(Player player) {
|
||||||
generatorData.clearGenerators();
|
generatorData.clearGenerators();
|
||||||
player.sendMessage(Component.text("&#FFA500Все генераторы удалены"));
|
player.sendMessage(TextUtil.color("<#FFA500>Все генераторы удалены"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleWorld(Player player, String[] args) {
|
||||||
|
if (args.length < 2) {
|
||||||
|
player.sendMessage(TextUtil.color("<#FF0000>Использование: /dbdadmin world <lobby|game|<название мира>>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String worldArg = args[1].toLowerCase();
|
||||||
|
org.bukkit.World target;
|
||||||
|
|
||||||
|
if (worldArg.equals("lobby")) {
|
||||||
|
target = plugin.getLobbyManager().getLobbyWorld();
|
||||||
|
if (target == null) {
|
||||||
|
player.sendMessage(TextUtil.color("<#FF0000>Мир lobby не загружен!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (worldArg.equals("game")) {
|
||||||
|
target = plugin.getLobbyManager().getGameWorld();
|
||||||
|
if (target == null) {
|
||||||
|
player.sendMessage(TextUtil.color("<#FF0000>Мир game не загружен!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = org.bukkit.Bukkit.getWorld(args[1]);
|
||||||
|
if (target == null) {
|
||||||
|
player.sendMessage(TextUtil.color("<#FF0000>Мир не найден: " + args[1]));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player.teleport(target.getSpawnLocation());
|
||||||
|
player.sendMessage(TextUtil.color("<#00FF00>Телепортирован в мир: <#FFD700>" + target.getName()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendUsage(CommandSender sender) {
|
private void sendUsage(CommandSender sender) {
|
||||||
sender.sendMessage(Component.text("&#FF6B00=== DBD Admin ==="));
|
sender.sendMessage(TextUtil.color("<#FF6B00>=== DBD Admin ==="));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdadmin create generator — Режим установки генератора"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdadmin create generator — Режим установки генератора"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdadmin list — Список генераторов"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdadmin list — Список генераторов"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdadmin remove <id> — Удалить генератор"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdadmin remove <id> — Удалить генератор"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdadmin clear — Очистить все генераторы"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdadmin clear — Очистить все генераторы"));
|
||||||
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdadmin world <lobby|game|мир> — Телепорт в мир"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSelectingGenerator(UUID uuid) {
|
public boolean isSelectingGenerator(UUID uuid) {
|
||||||
|
|
@ -175,7 +212,7 @@ public class DBDAdminCommand implements TabExecutor {
|
||||||
if (!sender.hasPermission("mdbd.admin")) return List.of();
|
if (!sender.hasPermission("mdbd.admin")) return List.of();
|
||||||
|
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
return Arrays.asList("create", "list", "remove", "clear").stream()
|
return Arrays.asList("create", "list", "remove", "clear", "world").stream()
|
||||||
.filter(s -> s.startsWith(args[0].toLowerCase()))
|
.filter(s -> s.startsWith(args[0].toLowerCase()))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
@ -186,6 +223,12 @@ public class DBDAdminCommand implements TabExecutor {
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args.length == 2 && args[0].equalsIgnoreCase("world")) {
|
||||||
|
return Arrays.asList("lobby", "game").stream()
|
||||||
|
.filter(s -> s.startsWith(args[1].toLowerCase()))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
if (args.length == 2 && args[0].equalsIgnoreCase("remove")) {
|
if (args.length == 2 && args[0].equalsIgnoreCase("remove")) {
|
||||||
var entries = generatorData.getGeneratorEntries();
|
var entries = generatorData.getGeneratorEntries();
|
||||||
List<String> ids = new ArrayList<>();
|
List<String> ids = new ArrayList<>();
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ public class DBDCommand implements TabExecutor {
|
||||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||||
@NotNull String label, @NotNull String[] args) {
|
@NotNull String label, @NotNull String[] args) {
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
List<String> completions = new ArrayList<>(Arrays.asList("join", "leave"));
|
List<String> completions = new ArrayList<>(Arrays.asList("join", "leave", "lobby"));
|
||||||
if (sender.hasPermission("mdbd.admin")) {
|
if (sender.hasPermission("mdbd.admin")) {
|
||||||
completions.addAll(Arrays.asList("create", "forcestart", "stop", "reload", "setlobby"));
|
completions.addAll(Arrays.asList("create", "forcestart", "stop", "reload", "setlobby"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.loki.command;
|
package dev.loki.command;
|
||||||
|
|
||||||
import dev.loki.mdbd;
|
import dev.loki.mdbd;
|
||||||
|
import dev.loki.util.TextUtil;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
|
@ -8,11 +9,9 @@ import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.TabExecutor;
|
import org.bukkit.command.TabExecutor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.util.BlockVector;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -65,14 +64,14 @@ public class SetupCommand implements TabExecutor {
|
||||||
private boolean giveWand(Player player) {
|
private boolean giveWand(Player player) {
|
||||||
var wand = new org.bukkit.inventory.ItemStack(org.bukkit.Material.STICK);
|
var wand = new org.bukkit.inventory.ItemStack(org.bukkit.Material.STICK);
|
||||||
wand.editMeta(meta -> {
|
wand.editMeta(meta -> {
|
||||||
meta.displayName(Component.text("&#FF6B00DBD Wand").append(Component.text(" (Выделение)")));
|
meta.displayName(TextUtil.color("<#FF6B00>DBD Wand <white>(Выделение)"));
|
||||||
meta.lore(List.of(
|
meta.lore(List.of(
|
||||||
Component.text("&#FFD700ЛКМ — Первая точка"),
|
TextUtil.color("<#FFD700>ЛКМ — Первая точка"),
|
||||||
Component.text("&#FFD700ПКМ — Вторая точка")
|
TextUtil.color("<#FFD700>ПКМ — Вторая точка")
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
player.getInventory().addItem(wand);
|
player.getInventory().addItem(wand);
|
||||||
player.sendMessage(Component.text("�FF00Получена палочка выделения!", NamedTextColor.GREEN));
|
player.sendMessage(TextUtil.color("<#00FF00>Получена палочка выделения!"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,13 +79,13 @@ public class SetupCommand implements TabExecutor {
|
||||||
String key = player.getUniqueId().toString();
|
String key = player.getUniqueId().toString();
|
||||||
Location loc = player.getLocation().getBlock().getLocation();
|
Location loc = player.getLocation().getBlock().getLocation();
|
||||||
selectionCorners.put(key + "_pos" + num, loc);
|
selectionCorners.put(key + "_pos" + num, loc);
|
||||||
player.sendMessage(Component.text("�FF00Установлена точка " + num + ": " + formatLoc(loc)));
|
player.sendMessage(TextUtil.color("<#00FF00>Установлена точка " + num + ": " + formatLoc(loc)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean saveTemplate(Player player, String[] args) {
|
private boolean saveTemplate(Player player, String[] args) {
|
||||||
if (args.length < 2) {
|
if (args.length < 2) {
|
||||||
player.sendMessage(Component.text("&#FF0000Использование: /dbdsetup save <name>"));
|
player.sendMessage(TextUtil.color("<#FF0000>Использование: /dbdsetup save <name>"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String key = player.getUniqueId().toString();
|
String key = player.getUniqueId().toString();
|
||||||
|
|
@ -94,38 +93,38 @@ public class SetupCommand implements TabExecutor {
|
||||||
Location pos2 = selectionCorners.get(key + "_pos2");
|
Location pos2 = selectionCorners.get(key + "_pos2");
|
||||||
|
|
||||||
if (pos1 == null || pos2 == null) {
|
if (pos1 == null || pos2 == null) {
|
||||||
player.sendMessage(Component.text("&#FF0000Сначала установите обе точки!"));
|
player.sendMessage(TextUtil.color("<#FF0000>Сначала установите обе точки!"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin.getTemplateManager().saveTemplate(args[1], pos1, pos2);
|
plugin.getTemplateManager().saveTemplate(args[1], pos1, pos2);
|
||||||
player.sendMessage(Component.text("�FF00Шаблон '" + args[1] + "' сохранен!"));
|
player.sendMessage(TextUtil.color("<#00FF00>Шаблон '" + args[1] + "' сохранен!"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean loadTemplate(Player player, String[] args) {
|
private boolean loadTemplate(Player player, String[] args) {
|
||||||
if (args.length < 2) {
|
if (args.length < 2) {
|
||||||
player.sendMessage(Component.text("&#FF0000Использование: /dbdsetup load <name>"));
|
player.sendMessage(TextUtil.color("<#FF0000>Использование: /dbdsetup load <name>"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var template = plugin.getTemplateManager().getTemplate(args[1]);
|
var template = plugin.getTemplateManager().getTemplate(args[1]);
|
||||||
if (template == null) {
|
if (template == null) {
|
||||||
player.sendMessage(Component.text("&#FF0000Шаблон не найден!"));
|
player.sendMessage(TextUtil.color("<#FF0000>Шаблон не найден!"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
template.place(player.getLocation(), false);
|
template.place(player.getLocation(), false);
|
||||||
player.sendMessage(Component.text("�FF00Шаблон '" + args[1] + "' загружен!"));
|
player.sendMessage(TextUtil.color("<#00FF00>Шаблон '" + args[1] + "' загружен!"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean listTemplates(CommandSender sender) {
|
private boolean listTemplates(CommandSender sender) {
|
||||||
var templates = plugin.getTemplateManager().getAllTemplates();
|
var templates = plugin.getTemplateManager().getAllTemplates();
|
||||||
sender.sendMessage(Component.text("&#FFD700=== Шаблоны ==="));
|
sender.sendMessage(TextUtil.color("<#FFD700>=== Шаблоны ==="));
|
||||||
if (templates.isEmpty()) {
|
if (templates.isEmpty()) {
|
||||||
sender.sendMessage(Component.text("󅒐Нет шаблонов"));
|
sender.sendMessage(TextUtil.color("<#808080>Нет шаблонов"));
|
||||||
} else {
|
} else {
|
||||||
templates.keySet().forEach(name ->
|
templates.keySet().forEach(name ->
|
||||||
sender.sendMessage(Component.text("�CED1- " + name))
|
sender.sendMessage(TextUtil.color("<#00CED1>- " + name))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -133,7 +132,7 @@ public class SetupCommand implements TabExecutor {
|
||||||
|
|
||||||
private boolean setObject(Player player, String[] args) {
|
private boolean setObject(Player player, String[] args) {
|
||||||
if (args.length < 2) {
|
if (args.length < 2) {
|
||||||
player.sendMessage(Component.text("&#FF0000Использование: /dbdsetup set <generator|hook|pallet|chest|totem|gate|lobby>"));
|
player.sendMessage(TextUtil.color("<#FF0000>Использование: /dbdsetup set <generator|hook|pallet|chest|totem|gate|lobby>"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Location loc = player.getLocation().getBlock().getLocation();
|
Location loc = player.getLocation().getBlock().getLocation();
|
||||||
|
|
@ -149,26 +148,26 @@ public class SetupCommand implements TabExecutor {
|
||||||
case "gate" -> locations.addLocation("exitgates", loc);
|
case "gate" -> locations.addLocation("exitgates", loc);
|
||||||
case "lobby" -> locations.setLobby(loc);
|
case "lobby" -> locations.setLobby(loc);
|
||||||
default -> {
|
default -> {
|
||||||
player.sendMessage(Component.text("&#FF0000Неизвестный тип: " + type));
|
player.sendMessage(TextUtil.color("<#FF0000>Неизвестный тип: " + type));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig());
|
plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig());
|
||||||
player.sendMessage(Component.text("�FF00Установлен: " + type + " на " + formatLoc(loc)));
|
player.sendMessage(TextUtil.color("<#00FF00>Установлен: " + type + " на " + formatLoc(loc)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean buildMap(Player player) {
|
private boolean buildMap(Player player) {
|
||||||
player.sendMessage(Component.text("&#FFD700Строительство карты..."));
|
player.sendMessage(TextUtil.color("<#FFD700>Строительство карты..."));
|
||||||
plugin.getMapBuilder().buildMap(plugin.getConfigManager().getLocations());
|
plugin.getMapBuilder().buildMap(plugin.getConfigManager().getLocations());
|
||||||
player.sendMessage(Component.text("�FF00Карта построена!"));
|
player.sendMessage(TextUtil.color("<#00FF00>Карта построена!"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean clearMap(Player player) {
|
private boolean clearMap(Player player) {
|
||||||
player.sendMessage(Component.text("&#FFA500Очистка карты..."));
|
player.sendMessage(TextUtil.color("<#FFA500>Очистка карты..."));
|
||||||
plugin.getMapBuilder().clearMap(plugin.getConfigManager().getLocations());
|
plugin.getMapBuilder().clearMap(plugin.getConfigManager().getLocations());
|
||||||
player.sendMessage(Component.text("�FF00Карта очищена!"));
|
player.sendMessage(TextUtil.color("<#00FF00>Карта очищена!"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,21 +176,21 @@ public class SetupCommand implements TabExecutor {
|
||||||
plugin.getConfigManager().getLocations().setLobby(loc);
|
plugin.getConfigManager().getLocations().setLobby(loc);
|
||||||
plugin.getConfigManager().saveConfig("locations.yml",
|
plugin.getConfigManager().saveConfig("locations.yml",
|
||||||
plugin.getConfigManager().getLocations().getConfig());
|
plugin.getConfigManager().getLocations().getConfig());
|
||||||
player.sendMessage(Component.text("�FF00Лобби установлено на " + formatLoc(loc)));
|
player.sendMessage(TextUtil.color("<#00FF00>Лобби установлено на " + formatLoc(loc)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendUsage(CommandSender sender) {
|
private void sendUsage(CommandSender sender) {
|
||||||
sender.sendMessage(Component.text("&#FF6B00=== DBD Setup ==="));
|
sender.sendMessage(TextUtil.color("<#FF6B00>=== DBD Setup ==="));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdsetup wand — Получить палочку"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup wand — Получить палочку"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdsetup pos1/pos2 — Установить точки"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup pos1/pos2 — Установить точки"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdsetup save <name> — Сохранить шаблон"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup save <name> — Сохранить шаблон"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdsetup load <name> — Загрузить шаблон"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup load <name> — Загрузить шаблон"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdsetup list — Список шаблонов"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup list — Список шаблонов"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdsetup set <type> — Установить объект"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup set <type> — Установить объект"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdsetup build — Построить карту"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup build — Построить карту"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdsetup clear — Очистить карту"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup clear — Очистить карту"));
|
||||||
sender.sendMessage(Component.text("&#FFD700/dbdsetup lobby — Установить лобби"));
|
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup lobby — Установить лобби"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatLoc(Location loc) {
|
private String formatLoc(Location loc) {
|
||||||
|
|
@ -216,6 +215,11 @@ public class SetupCommand implements TabExecutor {
|
||||||
.filter(s -> s.startsWith(args[1].toLowerCase()))
|
.filter(s -> s.startsWith(args[1].toLowerCase()))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
if (args.length == 2 && (args[0].equalsIgnoreCase("save") || args[0].equalsIgnoreCase("load"))) {
|
||||||
|
return plugin.getTemplateManager().getAllTemplates().keySet().stream()
|
||||||
|
.filter(s -> s.startsWith(args[1].toLowerCase()))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.loki.core;
|
package dev.loki.core;
|
||||||
|
|
||||||
import dev.loki.mdbd;
|
import dev.loki.mdbd;
|
||||||
|
import dev.loki.player.Survivor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
@ -33,7 +34,14 @@ public class GameManager {
|
||||||
if (playerSessions.containsKey(player.getUniqueId())) {
|
if (playerSessions.containsKey(player.getUniqueId())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register the player in the session as a Survivor (role assigned later)
|
||||||
|
Survivor survivor = new Survivor(player.getUniqueId());
|
||||||
|
currentSession.addPlayer(survivor);
|
||||||
|
|
||||||
playerSessions.put(player.getUniqueId(), currentSession);
|
playerSessions.put(player.getUniqueId(), currentSession);
|
||||||
|
// Notify session that player joined (teleport to lobby etc)
|
||||||
|
currentSession.notifyPlayerJoined(player);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,6 +49,8 @@ public class GameManager {
|
||||||
GameSession session = playerSessions.remove(player.getUniqueId());
|
GameSession session = playerSessions.remove(player.getUniqueId());
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
session.removePlayer(player.getUniqueId());
|
session.removePlayer(player.getUniqueId());
|
||||||
|
// Teleport after removing from session
|
||||||
|
plugin.getLobbyManager().teleportToLobby(player);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,11 @@ public class GameSession {
|
||||||
eventBus.emit(new PlayerJoinEvent(player));
|
eventBus.emit(new PlayerJoinEvent(player));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Replaces an existing player entry with a new role-assigned instance (Killer/Survivor). */
|
||||||
|
public void replacePlayer(UUID uuid, BasePlayer newPlayer) {
|
||||||
|
players.put(uuid, newPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
public void removePlayer(UUID uuid) {
|
public void removePlayer(UUID uuid) {
|
||||||
BasePlayer removed = players.remove(uuid);
|
BasePlayer removed = players.remove(uuid);
|
||||||
if (removed != null) {
|
if (removed != null) {
|
||||||
|
|
@ -154,6 +159,13 @@ public class GameSession {
|
||||||
return eventBus;
|
return eventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void notifyPlayerJoined(org.bukkit.entity.Player player) {
|
||||||
|
// Called when player joins from command, updates UI
|
||||||
|
if (currentPhase != null) {
|
||||||
|
currentPhase.onPlayerJoined(this, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public record PlayerJoinEvent(BasePlayer player) {}
|
public record PlayerJoinEvent(BasePlayer player) {}
|
||||||
public record PlayerLeaveEvent(BasePlayer player) {}
|
public record PlayerLeaveEvent(BasePlayer player) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@ package dev.loki.listener;
|
||||||
|
|
||||||
import dev.loki.command.DBDAdminCommand;
|
import dev.loki.command.DBDAdminCommand;
|
||||||
import dev.loki.data.GeneratorDataManager;
|
import dev.loki.data.GeneratorDataManager;
|
||||||
import net.kyori.adventure.text.Component;
|
import dev.loki.util.TextUtil;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
|
|
@ -37,10 +36,10 @@ public class GeneratorSelectListener implements Listener {
|
||||||
|
|
||||||
generatorData.addGenerator(genLoc);
|
generatorData.addGenerator(genLoc);
|
||||||
|
|
||||||
player.sendMessage(Component.text("�FF00Генератор установлен!"));
|
player.sendMessage(TextUtil.color("<#00FF00>Генератор установлен!"));
|
||||||
player.sendMessage(Component.text("�CED1Координаты: " + GeneratorDataManager.formatLocation(genLoc)));
|
player.sendMessage(TextUtil.color("<#00CED1>Координаты: " + GeneratorDataManager.formatLocation(genLoc)));
|
||||||
player.sendMessage(Component.text("&#FFD700Всего генераторов: " + generatorData.getCount()));
|
player.sendMessage(TextUtil.color("<#FFD700>Всего генераторов: " + generatorData.getCount()));
|
||||||
player.sendMessage(Component.text("&#FFA500Режим выбора остается активным. Ломайте следующий блок или"));
|
player.sendMessage(TextUtil.color("<#FFA500>Режим выбора остается активным. Ломайте следующий блок или"));
|
||||||
player.sendMessage(Component.text("&#FFA500введите /dbdadmin create generator для отключения"));
|
player.sendMessage(TextUtil.color("<#FFA500>введите /dbdadmin create generator для отключения"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,9 @@ public class PlayerInteractListener implements Listener {
|
||||||
if (event.getHand() != EquipmentSlot.HAND) return;
|
if (event.getHand() != EquipmentSlot.HAND) return;
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
if (!gameManager.isInGame(player.getUniqueId())) return;
|
if (!gameManager.isInGame(player.getUniqueId())) return;
|
||||||
BasePlayer bp = gameManager.getPlayerSession(player.getUniqueId()).getPlayer(player.getUniqueId());
|
var session = gameManager.getPlayerSession(player.getUniqueId());
|
||||||
|
if (session == null) return;
|
||||||
|
BasePlayer bp = session.getPlayer(player.getUniqueId());
|
||||||
if (bp == null || isIncapacitated(bp)) { event.setCancelled(true); return; }
|
if (bp == null || isIncapacitated(bp)) { event.setCancelled(true); return; }
|
||||||
|
|
||||||
Action action = event.getAction();
|
Action action = event.getAction();
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import dev.loki.config.ConfigManager;
|
||||||
import dev.loki.core.GameManager;
|
import dev.loki.core.GameManager;
|
||||||
import dev.loki.data.GeneratorDataManager;
|
import dev.loki.data.GeneratorDataManager;
|
||||||
import dev.loki.listener.GeneratorSelectListener;
|
import dev.loki.listener.GeneratorSelectListener;
|
||||||
|
import dev.loki.listener.PlayerInteractListener;
|
||||||
|
import dev.loki.listener.PlayerQuitListener;
|
||||||
import dev.loki.map.MapBuilder;
|
import dev.loki.map.MapBuilder;
|
||||||
import dev.loki.map.TemplateManager;
|
import dev.loki.map.TemplateManager;
|
||||||
import dev.loki.world.LobbyManager;
|
import dev.loki.world.LobbyManager;
|
||||||
|
|
@ -19,7 +21,9 @@ public final class mdbd extends JavaPlugin {
|
||||||
private TemplateManager templateManager;
|
private TemplateManager templateManager;
|
||||||
private MapBuilder mapBuilder;
|
private MapBuilder mapBuilder;
|
||||||
private GeneratorDataManager generatorData;
|
private GeneratorDataManager generatorData;
|
||||||
|
private DBDCommand dbdCommand;
|
||||||
private DBDAdminCommand dbdAdminCommand;
|
private DBDAdminCommand dbdAdminCommand;
|
||||||
|
private SetupCommand setupCommand;
|
||||||
private LobbyManager lobbyManager;
|
private LobbyManager lobbyManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -44,10 +48,13 @@ public final class mdbd extends JavaPlugin {
|
||||||
|
|
||||||
this.gameManager = new GameManager(this);
|
this.gameManager = new GameManager(this);
|
||||||
|
|
||||||
getCommand("dbd").setExecutor(new DBDCommand(this, gameManager));
|
this.dbdCommand = new DBDCommand(this, gameManager);
|
||||||
getCommand("dbd").setTabCompleter(new DBDCommand(this, gameManager));
|
getCommand("dbd").setExecutor(dbdCommand);
|
||||||
getCommand("dbdsetup").setExecutor(new SetupCommand(this));
|
getCommand("dbd").setTabCompleter(dbdCommand);
|
||||||
getCommand("dbdsetup").setTabCompleter(new SetupCommand(this));
|
|
||||||
|
this.setupCommand = new SetupCommand(this);
|
||||||
|
getCommand("dbdsetup").setExecutor(setupCommand);
|
||||||
|
getCommand("dbdsetup").setTabCompleter(setupCommand);
|
||||||
|
|
||||||
this.dbdAdminCommand = new DBDAdminCommand(this, generatorData);
|
this.dbdAdminCommand = new DBDAdminCommand(this, generatorData);
|
||||||
getCommand("dbdadmin").setExecutor(dbdAdminCommand);
|
getCommand("dbdadmin").setExecutor(dbdAdminCommand);
|
||||||
|
|
@ -55,6 +62,10 @@ public final class mdbd extends JavaPlugin {
|
||||||
|
|
||||||
getServer().getPluginManager().registerEvents(
|
getServer().getPluginManager().registerEvents(
|
||||||
new GeneratorSelectListener(dbdAdminCommand, generatorData), this);
|
new GeneratorSelectListener(dbdAdminCommand, generatorData), this);
|
||||||
|
getServer().getPluginManager().registerEvents(
|
||||||
|
new PlayerQuitListener(this, gameManager), this);
|
||||||
|
getServer().getPluginManager().registerEvents(
|
||||||
|
new PlayerInteractListener(this, gameManager, null), this);
|
||||||
|
|
||||||
getLogger().info("Mdbd Plugin enabled successfully!");
|
getLogger().info("Mdbd Plugin enabled successfully!");
|
||||||
getLogger().info("Loaded " + templateManager.getAllTemplates().size() + " templates");
|
getLogger().info("Loaded " + templateManager.getAllTemplates().size() + " templates");
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ public class GeneratorRepair {
|
||||||
generator.setCurrentRepairer(uuid);
|
generator.setCurrentRepairer(uuid);
|
||||||
RepairSession session = new RepairSession(player, generator);
|
RepairSession session = new RepairSession(player, generator);
|
||||||
sessions.put(uuid, session);
|
sessions.put(uuid, session);
|
||||||
generator.setBlocked(true);
|
// Do NOT set blocked here - blocked means nobody can repair it (e.g. after a kick)
|
||||||
|
|
||||||
player.sendMessage(MiniMessage.miniMessage().deserialize("<gray>Зажмите <yellow>ПКМ</yellow> для починки"));
|
player.sendMessage(MiniMessage.miniMessage().deserialize("<gray>Зажмите <yellow>ПКМ</yellow> для починки"));
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +60,10 @@ public class GeneratorRepair {
|
||||||
|
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
session.generator.setCurrentRepairer(null);
|
session.generator.setCurrentRepairer(null);
|
||||||
session.generator.setBlocked(false);
|
// Only unblock if it was blocked due to an ongoing repair (not a kick)
|
||||||
|
if (!session.generator.isUnderRegression()) {
|
||||||
|
session.generator.setBlocked(false);
|
||||||
|
}
|
||||||
player.sendActionBar(Component.empty());
|
player.sendActionBar(Component.empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
package dev.loki.phase;
|
package dev.loki.phase;
|
||||||
|
|
||||||
import dev.loki.core.GameSession;
|
import dev.loki.core.GameSession;
|
||||||
import dev.loki.objective.Generator;
|
|
||||||
import dev.loki.objective.GeneratorManager;
|
import dev.loki.objective.GeneratorManager;
|
||||||
import dev.loki.player.BasePlayer;
|
import dev.loki.player.BasePlayer;
|
||||||
import dev.loki.player.PlayerState;
|
import dev.loki.player.PlayerState;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
@ -24,14 +25,14 @@ public class GameplayPhase implements Phase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void enter(GameSession session) {
|
public void enter(GameSession session) {
|
||||||
Bukkit.broadcastMessage("[DBD] Игра началась! Выжившие, чините генераторы!");
|
Bukkit.broadcast(Component.text("[DBD] Игра началась! Выжившие, чините генераторы!", NamedTextColor.GREEN));
|
||||||
tickCounter = 0;
|
tickCounter = 0;
|
||||||
|
// Teleport is handled by RoleAssigner.assignRoles — no double-teleport needed here
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick(GameSession session) {
|
public void tick(GameSession session) {
|
||||||
tickCounter++;
|
tickCounter++;
|
||||||
|
|
||||||
generatorManager.tick();
|
generatorManager.tick();
|
||||||
|
|
||||||
if (tickCounter % 20 == 0) {
|
if (tickCounter % 20 == 0) {
|
||||||
|
|
@ -45,7 +46,8 @@ public class GameplayPhase implements Phase {
|
||||||
|
|
||||||
if (generatorManager.areAllRequiredCompleted()) {
|
if (generatorManager.areAllRequiredCompleted()) {
|
||||||
allGensDone = true;
|
allGensDone = true;
|
||||||
Bukkit.broadcastMessage("[DBD] §a§lВсе генераторы починены! Открывайте ворота!");
|
Bukkit.broadcast(Component.text(
|
||||||
|
"[DBD] Все генераторы починены! Открывайте ворота!", NamedTextColor.GREEN));
|
||||||
for (BasePlayer bp : session.getPlayers().values()) {
|
for (BasePlayer bp : session.getPlayers().values()) {
|
||||||
Player p = bp.getPlayer();
|
Player p = bp.getPlayer();
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
|
|
@ -58,13 +60,11 @@ public class GameplayPhase implements Phase {
|
||||||
private void checkWinConditions(GameSession session) {
|
private void checkWinConditions(GameSession session) {
|
||||||
int aliveSurvivors = 0;
|
int aliveSurvivors = 0;
|
||||||
int escapedSurvivors = 0;
|
int escapedSurvivors = 0;
|
||||||
boolean killerDead = true;
|
int totalSurvivors = 0;
|
||||||
|
|
||||||
for (BasePlayer bp : session.getPlayers().values()) {
|
for (BasePlayer bp : session.getPlayers().values()) {
|
||||||
if (bp.isKiller()) {
|
if (bp.isKiller()) continue;
|
||||||
killerDead = false;
|
totalSurvivors++;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
PlayerState state = bp.getState();
|
PlayerState state = bp.getState();
|
||||||
if (state == PlayerState.ESCAPED) {
|
if (state == PlayerState.ESCAPED) {
|
||||||
escapedSurvivors++;
|
escapedSurvivors++;
|
||||||
|
|
@ -73,16 +73,17 @@ public class GameplayPhase implements Phase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean allSurvivorsDead = (aliveSurvivors == 0 && escapedSurvivors == 0);
|
boolean allSurvivorsDead = (aliveSurvivors == 0 && escapedSurvivors == 0 && totalSurvivors > 0);
|
||||||
|
boolean allEscaped = (escapedSurvivors == totalSurvivors && totalSurvivors > 0);
|
||||||
|
|
||||||
if (allSurvivorsDead || escapedSurvivors == session.getPlayerCount() - 1) {
|
if (allSurvivorsDead || allEscaped) {
|
||||||
shouldEnd = true;
|
shouldEnd = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exit(GameSession session) {
|
public void exit(GameSession session) {
|
||||||
Bukkit.broadcastMessage("[DBD] §6Игровая фаза завершена!");
|
Bukkit.broadcast(Component.text("[DBD] Игровая фаза завершена!", NamedTextColor.GOLD));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@ package dev.loki.phase;
|
||||||
|
|
||||||
import dev.loki.config.GameConfig;
|
import dev.loki.config.GameConfig;
|
||||||
import dev.loki.core.GameSession;
|
import dev.loki.core.GameSession;
|
||||||
|
import dev.loki.player.BasePlayer;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class LobbyPhase implements Phase {
|
public class LobbyPhase implements Phase {
|
||||||
private final GameConfig config;
|
private final GameConfig config;
|
||||||
|
|
@ -22,6 +24,14 @@ public class LobbyPhase implements Phase {
|
||||||
@Override
|
@Override
|
||||||
public void enter(GameSession session) {
|
public void enter(GameSession session) {
|
||||||
Bukkit.broadcast(Component.text("[DBD] Лобби открыто! Используйте /dbd join", NamedTextColor.GREEN));
|
Bukkit.broadcast(Component.text("[DBD] Лобби открыто! Используйте /dbd join", NamedTextColor.GREEN));
|
||||||
|
// Teleport already-in-session players to lobby (e.g. on restart)
|
||||||
|
var lobbyManager = session.getPlugin().getLobbyManager();
|
||||||
|
for (var player : session.getPlayers().values()) {
|
||||||
|
var bukkitPlayer = player.getPlayer();
|
||||||
|
if (bukkitPlayer != null && bukkitPlayer.isOnline()) {
|
||||||
|
lobbyManager.teleportToLobby(bukkitPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -33,6 +43,9 @@ public class LobbyPhase implements Phase {
|
||||||
secondsLeft = config.getLobbyCountdown();
|
secondsLeft = config.getLobbyCountdown();
|
||||||
countdown = 0;
|
countdown = 0;
|
||||||
started = false;
|
started = false;
|
||||||
|
// Show waiting message in action bar to all players in lobby
|
||||||
|
sendActionBarToAll(session,
|
||||||
|
Component.text("⏳ Ожидание игроков: " + playerCount + "/" + minPlayers, NamedTextColor.YELLOW));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,12 +53,18 @@ public class LobbyPhase implements Phase {
|
||||||
if (countdown >= 20) {
|
if (countdown >= 20) {
|
||||||
countdown = 0;
|
countdown = 0;
|
||||||
secondsLeft--;
|
secondsLeft--;
|
||||||
|
}
|
||||||
|
|
||||||
if (secondsLeft <= 5 || secondsLeft % 10 == 0) {
|
// Action bar: показываем каждый тик (обновляется плавно)
|
||||||
Bukkit.broadcast(Component.text(
|
String bar = buildCountdownBar(secondsLeft, config.getLobbyCountdown());
|
||||||
"[DBD] До начала: " + secondsLeft + " сек. (" + playerCount + "/" + minPlayers + ")",
|
sendActionBarToAll(session,
|
||||||
NamedTextColor.YELLOW));
|
Component.text("▶ Старт через: " + secondsLeft + "с " + bar +
|
||||||
}
|
" (" + playerCount + "/" + minPlayers + ")", NamedTextColor.GREEN));
|
||||||
|
|
||||||
|
// Chat-announce на ключевых отметках
|
||||||
|
if (countdown == 0 && (secondsLeft <= 5 || secondsLeft == 10 || secondsLeft == 30)) {
|
||||||
|
Bukkit.broadcast(Component.text(
|
||||||
|
"[DBD] До начала: " + secondsLeft + " сек.", NamedTextColor.YELLOW));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secondsLeft <= 0) {
|
if (secondsLeft <= 0) {
|
||||||
|
|
@ -53,11 +72,41 @@ public class LobbyPhase implements Phase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendActionBarToAll(GameSession session, Component msg) {
|
||||||
|
for (BasePlayer bp : session.getPlayers().values()) {
|
||||||
|
Player p = bp.getPlayer();
|
||||||
|
if (p != null && p.isOnline()) {
|
||||||
|
p.sendActionBar(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildCountdownBar(int current, int total) {
|
||||||
|
int filled = total > 0 ? (int) (10.0 * current / total) : 0;
|
||||||
|
int empty = 10 - filled;
|
||||||
|
return "§a" + "█".repeat(Math.max(0, filled)) + "§7" + "░".repeat(Math.max(0, empty));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exit(GameSession session) {
|
public void exit(GameSession session) {
|
||||||
|
// Clear action bar for all
|
||||||
|
for (BasePlayer bp : session.getPlayers().values()) {
|
||||||
|
Player p = bp.getPlayer();
|
||||||
|
if (p != null && p.isOnline()) p.sendActionBar(Component.empty());
|
||||||
|
}
|
||||||
Bukkit.broadcast(Component.text("[DBD] Игра начинается!", NamedTextColor.GREEN));
|
Bukkit.broadcast(Component.text("[DBD] Игра начинается!", NamedTextColor.GREEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlayerJoined(GameSession session, Player player) {
|
||||||
|
session.getPlugin().getLobbyManager().teleportToLobby(player);
|
||||||
|
int playerCount = session.getPlayerCount();
|
||||||
|
int minPlayers = config.getMinPlayers();
|
||||||
|
Bukkit.broadcast(Component.text(
|
||||||
|
"[DBD] " + player.getName() + " присоединился к очереди! (" + playerCount + "/" + minPlayers + ")",
|
||||||
|
NamedTextColor.YELLOW));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isComplete() {
|
public boolean isComplete() {
|
||||||
return started;
|
return started;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
package dev.loki.phase;
|
package dev.loki.phase;
|
||||||
|
|
||||||
import dev.loki.core.GameSession;
|
import dev.loki.core.GameSession;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public interface Phase {
|
public interface Phase {
|
||||||
void enter(GameSession session);
|
void enter(GameSession session);
|
||||||
void tick(GameSession session);
|
void tick(GameSession session);
|
||||||
void exit(GameSession session);
|
void exit(GameSession session);
|
||||||
boolean isComplete();
|
boolean isComplete();
|
||||||
|
default void onPlayerJoined(GameSession session, Player player) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package dev.loki.phase;
|
||||||
|
|
||||||
import dev.loki.core.GameSession;
|
import dev.loki.core.GameSession;
|
||||||
import dev.loki.role.RoleAssigner;
|
import dev.loki.role.RoleAssigner;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
public class RoleAssignPhase implements Phase {
|
public class RoleAssignPhase implements Phase {
|
||||||
|
|
@ -30,7 +32,7 @@ public class RoleAssignPhase implements Phase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exit(GameSession session) {
|
public void exit(GameSession session) {
|
||||||
Bukkit.broadcastMessage("[DBD] Роли назначены!");
|
Bukkit.broadcast(Component.text("[DBD] Роли назначены!", NamedTextColor.GREEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,11 @@ import dev.loki.core.GameSession;
|
||||||
import dev.loki.player.BasePlayer;
|
import dev.loki.player.BasePlayer;
|
||||||
import dev.loki.player.Killer;
|
import dev.loki.player.Killer;
|
||||||
import dev.loki.player.Survivor;
|
import dev.loki.player.Survivor;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
@ -31,19 +35,54 @@ public class RoleAssigner {
|
||||||
if (players.isEmpty()) return;
|
if (players.isEmpty()) return;
|
||||||
|
|
||||||
List<UUID> uuids = new ArrayList<>(players.keySet());
|
List<UUID> uuids = new ArrayList<>(players.keySet());
|
||||||
|
|
||||||
UUID killerUuid = selectKiller(uuids);
|
UUID killerUuid = selectKiller(uuids);
|
||||||
|
|
||||||
|
List<Location> survivorSpawns = locations.getSurvivorSpawns();
|
||||||
|
int spawnIndex = 0;
|
||||||
|
|
||||||
for (UUID uuid : uuids) {
|
for (UUID uuid : uuids) {
|
||||||
BasePlayer player;
|
BasePlayer newPlayer;
|
||||||
if (uuid.equals(killerUuid)) {
|
if (uuid.equals(killerUuid)) {
|
||||||
player = new Killer(uuid);
|
newPlayer = new Killer(uuid);
|
||||||
Location spawn = locations.getKillerSpawn();
|
Location spawn = locations.getKillerSpawn();
|
||||||
player.setSpawnLocation(spawn);
|
if (spawn != null) newPlayer.setSpawnLocation(spawn);
|
||||||
} else {
|
} else {
|
||||||
player = new Survivor(uuid);
|
newPlayer = new Survivor(uuid);
|
||||||
|
if (!survivorSpawns.isEmpty()) {
|
||||||
|
Location spawn = survivorSpawns.get(spawnIndex % survivorSpawns.size());
|
||||||
|
newPlayer.setSpawnLocation(spawn);
|
||||||
|
spawnIndex++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
session.getEventBus().emit(new RoleAssignedEvent(uuid, player));
|
|
||||||
|
// Actually replace the player object in session
|
||||||
|
session.replacePlayer(uuid, newPlayer);
|
||||||
|
|
||||||
|
// Announce role and teleport
|
||||||
|
Player bukkit = Bukkit.getPlayer(uuid);
|
||||||
|
if (bukkit != null && bukkit.isOnline()) {
|
||||||
|
if (newPlayer.isKiller()) {
|
||||||
|
bukkit.sendTitle("§4§lКИЛЛЕР", "§cОхоться на выживших!", 10, 60, 20);
|
||||||
|
bukkit.sendMessage(Component.text("[DBD] Ваша роль: Киллер", NamedTextColor.RED));
|
||||||
|
} else {
|
||||||
|
bukkit.sendTitle("§a§lВЫЖИВШИЙ", "§eЧини генераторы и сбегай!", 10, 60, 20);
|
||||||
|
bukkit.sendMessage(Component.text("[DBD] Ваша роль: Выживший", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teleport to game world spawn (or role spawn)
|
||||||
|
Location spawn = newPlayer.getSpawnLocation();
|
||||||
|
if (spawn != null) {
|
||||||
|
bukkit.teleport(spawn);
|
||||||
|
} else {
|
||||||
|
// Fallback: game world spawn
|
||||||
|
var gameWorld = session.getPlugin().getLobbyManager().getGameWorld();
|
||||||
|
if (gameWorld != null) {
|
||||||
|
bukkit.teleport(gameWorld.getSpawnLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session.getEventBus().emit(new RoleAssignedEvent(uuid, newPlayer));
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.rotate();
|
queue.rotate();
|
||||||
|
|
|
||||||
29
src/main/java/dev/loki/util/TextUtil.java
Normal file
29
src/main/java/dev/loki/util/TextUtil.java
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package dev.loki.util;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility for converting legacy &#RRGGBB color codes to MiniMessage format.
|
||||||
|
* Usage: TextUtil.color("&#FFD700Hello") → renders as gold colored text.
|
||||||
|
*/
|
||||||
|
public final class TextUtil {
|
||||||
|
private static final MiniMessage MM = MiniMessage.miniMessage();
|
||||||
|
|
||||||
|
private TextUtil() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts &#RRGGBB color codes to MiniMessage <#RRGGBB> and deserializes.
|
||||||
|
*/
|
||||||
|
public static Component color(String text) {
|
||||||
|
return MM.deserialize(toMiniMessage(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts &#RRGGBB to MiniMessage <#RRGGBB> syntax without deserializing.
|
||||||
|
*/
|
||||||
|
public static String toMiniMessage(String text) {
|
||||||
|
// &#RRGGBB → <#RRGGBB>
|
||||||
|
return text.replaceAll("&#([0-9A-Fa-f]{6})", "<#$1>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,6 @@ import org.bukkit.GameRule;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldCreator;
|
import org.bukkit.WorldCreator;
|
||||||
import org.bukkit.WorldType;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
|
@ -31,7 +30,6 @@ public class LobbyManager {
|
||||||
|
|
||||||
WorldCreator creator = new WorldCreator("lobby");
|
WorldCreator creator = new WorldCreator("lobby");
|
||||||
creator.generator(new VoidWorldGenerator());
|
creator.generator(new VoidWorldGenerator());
|
||||||
creator.type(WorldType.FLAT);
|
|
||||||
creator.environment(World.Environment.NORMAL);
|
creator.environment(World.Environment.NORMAL);
|
||||||
creator.generateStructures(false);
|
creator.generateStructures(false);
|
||||||
|
|
||||||
|
|
@ -143,7 +141,14 @@ public class LobbyManager {
|
||||||
|
|
||||||
public void teleportToLobby(org.bukkit.entity.Player player) {
|
public void teleportToLobby(org.bukkit.entity.Player player) {
|
||||||
if (lobbyWorld != null) {
|
if (lobbyWorld != null) {
|
||||||
player.teleport(lobbyWorld.getSpawnLocation());
|
// Use the configured lobby location from locations.yml if available,
|
||||||
|
// otherwise fall back to spawn location on the platform
|
||||||
|
org.bukkit.Location configLobby = plugin.getConfigManager().getLocations().getLobby();
|
||||||
|
if (configLobby != null && configLobby.getWorld() != null) {
|
||||||
|
player.teleport(configLobby);
|
||||||
|
} else {
|
||||||
|
player.teleport(lobbyWorld.getSpawnLocation());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,22 +5,22 @@ api-version: '1.21'
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
dbd:
|
dbd:
|
||||||
description: "Главная команда DBD плагина"
|
description: "Main DBD command"
|
||||||
usage: "/dbd <join|leave|create|forcestart|stop|reload|lobby|setlobby>"
|
usage: "/dbd <join|leave|create|forcestart|stop|reload|lobby|setlobby>"
|
||||||
permission: mdbd.player
|
permission: mdbd.player
|
||||||
dbdsetup:
|
dbdsetup:
|
||||||
description: "Команды настройки карты и объектов"
|
description: "Map setup commands"
|
||||||
usage: "/dbdsetup <wand|pos1|pos2|save|load|set|build|clear|lobby>"
|
usage: "/dbdsetup <wand|pos1|pos2|save|load|set|build|clear|lobby>"
|
||||||
permission: mdbd.admin
|
permission: mdbd.admin
|
||||||
dbdadmin:
|
dbdadmin:
|
||||||
description: "Админ-команды для управления генераторами и объектами"
|
description: "Admin commands for generators and objects"
|
||||||
usage: "/dbdadmin <create|list|remove|clear>"
|
usage: "/dbdadmin <create|list|remove|clear|world>"
|
||||||
permission: mdbd.admin
|
permission: mdbd.admin
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
mdbd.admin:
|
mdbd.admin:
|
||||||
description: "Полный доступ к админ-командам плагина"
|
description: "Full access to admin commands"
|
||||||
default: op
|
default: op
|
||||||
mdbd.player:
|
mdbd.player:
|
||||||
description: "Базовые команды для игроков"
|
description: "Basic player commands"
|
||||||
default: true
|
default: true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue