Расширяемая API-библиотека для создания боссов в Minecraft и функциональный плагин, использующий её.
- Три типа триггеров умений: по кулдауну, по порогу здоровья, по типу полученного урона.
- Отдельная иммутабельная конфигурация и локализация с горячей перезагрузкой (
/bosses reload). - SQLite-хранилище записей об убийствах с асинхронной записью — без просадок тикрейта.
- Голограммы на ArmorStand'ах с per-player плейсхолдерами через ProtocolLib и кешем сериализации в пределах кадра.
- ActionBar с HP босса, broadcast топ-3 по урону после смерти.
- Guice-DI «из коробки» в
BossesCoreModule: потребителю остаётся написать только своиBossDefinition.
| Компонент | Версия |
|---|---|
| Java | 17 |
| Ядро сервера | Paper 1.19.4 |
| ProtocolLib | 5.3.0+ |
| Maven | 3.8+ |
Проект — Maven multi-module со строгим разделением «контракт / движок / продукт»:
diamondworld-bosses-parent
├── boss-api — только контракты: интерфейсы, DTO, events, exceptions
├── boss-core — референс-реализация + BossesCoreModule (Guice)
└── boss-plugin — конкретные боссы + точка входа Bukkit
boss-api — публичные контракты (Boss, BossDefinition, Ability, AbilityTrigger,
BossRegistry, BossesConfig, Localization, BossKillRepository, Hologram,
PlayerLocator, TickSource) + value-объекты (BossId, BossLocation, PlayerDamage,
BossKill, MessageKey) + готовые триггеры (Cooldown, HealthThreshold, DamageType).
Не зависит от Guice, SQLite, ProtocolLib-реализации — чистый API.
boss-core — собранный движок: YAML-конфиг/локализация, SQLite + асинхронный
декоратор репозитория, in-memory реестр, AbilityExecutor, BossSpawner,
BossLifecycleScheduler, WaitingHologramManager, core-листенеры урона/смерти/broadcast,
BukkitPlayerLocator, команда /bosses reload. Всё поднимается одной строкой —
install(new BossesCoreModule(plugin)).
boss-plugin — продуктовый код: RobberBossDefinition, SummonerBossDefinition
с их умениями, SummonerTargetListener, BossesPlugin (JavaPlugin) и BossesPluginModule,
который подключает BossesCoreModule и добавляет свои definitions через Multibinder.
mvn clean packageShaded-jar готового плагина: boss-plugin/target/boss-plugin-1.0.0-SNAPSHOT.jar
(Guice и SQLite релоцированы в ru.saydov.bosses.plugin.libs.* во избежание
конфликтов с другими плагинами).
Для быстрой проверки с автозапуском Paper-сервера:
mvn -pl boss-plugin -Prun-paper verifyПрофиль скачает paper-jar нужной версии, ProtocolLib, скопирует плагин в
run/plugins/ и запустит сервер.
- Положить
boss-plugin-1.0.0-SNAPSHOT.jarвplugins/. - Установить ProtocolLib 5.3.0+.
- Запустить сервер —
plugins/DiamondWorldBosses/config.ymlиmessages.ymlбудут созданы автоматически.
database:
file: bosses.db
bosses:
summoner:
display-name: "<green>Призыватель"
spawn:
world: world
x: 100.5
y: 70.0
z: 100.5
respawn-seconds: 600
max-health: 200.0
base-damage: 8.0
robber:
display-name: "<gold>Разоритель"
spawn:
world: world
x: 200.5
y: 70.0
z: 200.5
respawn-seconds: 900
max-health: 250.0
base-damage: 10.0display-name — строка MiniMessage (цвета/декораторы вида <gold>, <bold>).
Сообщения — MiniMessage с позиционными плейсхолдерами <0>, <1>, …
При перезагрузке ник игрока автоматически экранируется, так что MiniMessage-теги
внутри ника не интерпретируются (защита от инъекций).
/bosses reload
Пересчитывает config.yml и messages.yml без рестарта сервера. Живые боссы
не переспавниваются — displayName/maxHealth/baseDamage применятся при
следующем появлении; spawnLocation и respawnSeconds подхватываются сразу
через делегирующие геттеры.
| Команда | Право | Действие |
|---|---|---|
/bosses reload (aliases: /dwbosses) |
bosses.reload (по умолчанию op) |
Перезагружает конфиг и локализацию |
- Zombie с костью в руке.
- Защита: урон от зелий и стрел отменяется.
- Таргетит только игроков и их помощников (волки, кошки, попугаи).
- Призыв: раз в минуту — 1–3 маленьких зомби-миньона, агрящихся на ближайшего игрока.
- Вооружение: раз в 10 минут на 5 минут — зачарованная на защиту IV кожаная броня и каменный меч с остротой V, в момент применения отталкивает игроков в радиусе 4 блоков. В фазе вооружения кулдаун призыва растёт до 3 минут.
- Pillager с арбалетом, зачарованным на «Пронзающую стрелу IV» и «Тройной выстрел».
- Иммунен к отталкиванию (атрибут
knockback_resistance = 1.0). - Ярость: однократно при HP ≤ 50% — замена арбалета на железный топор.
- Рывок: раз в минуту — «Сила II» + импульс к ближайшему игроку. Работает только в фазе ярости.
Чтобы добавить своего босса, функциональный плагин-потребитель:
-
Подключает
boss-apiиboss-coreкак зависимости. -
Реализует
BossDefinition:public final class MyBossDefinition implements BossDefinition { public static final BossId ID = BossId.of("my_boss"); @Override public BossId id() { return ID; } @Override public EntityType entityType() { return EntityType.SKELETON; } @Override public void applyEquipment(EntityEquipment eq) { eq.setItemInMainHand(new ItemStack(Material.BOW)); } @Override public void applyAttributes(LivingEntity entity) { /* speed, armor ... */ } @Override public List<Ability> abilities() { return List.of(/* свои Ability */); } @Override public Set<DamageType> damageProtections() { return Set.of(DamageType.FIRE); } }
-
Пишет свой Guice-модуль, подключает core и регистрирует definition:
public final class MyPluginModule extends AbstractModule { private final Plugin plugin; public MyPluginModule(Plugin plugin) { this.plugin = plugin; } @Override protected void configure() { install(new BossesCoreModule(plugin)); Multibinder.newSetBinder(binder(), BossDefinition.class) .addBinding().to(MyBossDefinition.class).in(Singleton.class); } }
-
Добавляет в
config.ymlсекциюbosses.my_bossс теми же полями, что у штатных.
Core автоматически создаст живой экземпляр в статусе WAITING, запустит таймер спавна, голограмму, обработку урона и запись в БД.
Готовые фабрики:
AbilityTrigger.cooldown(Duration.ofSeconds(30)) // раз в N секунд
AbilityTrigger.healthBelow(0.5) // однократно при HP ≤ 50%
AbilityTrigger.onDamageType(DamageType.PROJECTILE) // реактивно на каждый удар категорииCooldownAbilityTrigger также принимает Supplier<Duration> — так реализовано
переменное окно призыва у Призывателя в фазе вооружения.
Файл SQLite по пути plugins/DiamondWorldBosses/bosses.db (конфигурируемо).
Запись асинхронная через AsyncBossKillRepository — main thread свободен.
CREATE TABLE IF NOT EXISTS boss_kills (
id INTEGER PRIMARY KEY AUTOINCREMENT,
boss_id TEXT NOT NULL,
killed_at INTEGER NOT NULL, -- epoch millis
top_damagers TEXT NOT NULL -- JSON
);Пример строки top_damagers:
[
{"player": "Steve", "damage": "142.5"},
{"player": "Alex", "damage": "98.0"},
{"player": "Herobrine", "damage": "31.2"}
]