Skip to content

saydov/dw-bosses

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DiamondWorld

DiamondWorld Bosses

Расширяемая API-библиотека для создания боссов в Minecraft и функциональный плагин, использующий её.

Java 17 Paper 1.19.4 Maven ProtocolLib 5.3 Guice 7 SQLite 3.44


Возможности

  • Три типа триггеров умений: по кулдауну, по порогу здоровья, по типу полученного урона.
  • Отдельная иммутабельная конфигурация и локализация с горячей перезагрузкой (/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 package

Shaded-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/ и запустит сервер.

Установка

  1. Положить boss-plugin-1.0.0-SNAPSHOT.jar в plugins/.
  2. Установить ProtocolLib 5.3.0+.
  3. Запустить сервер — plugins/DiamondWorldBosses/config.yml и messages.yml будут созданы автоматически.

Конфигурация

config.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.0

display-name — строка MiniMessage (цвета/декораторы вида <gold>, <bold>).

messages.yml

Сообщения — MiniMessage с позиционными плейсхолдерами <0>, <1>, … При перезагрузке ник игрока автоматически экранируется, так что MiniMessage-теги внутри ника не интерпретируются (защита от инъекций).

Горячая перезагрузка

/bosses reload

Пересчитывает config.yml и messages.yml без рестарта сервера. Живые боссы не переспавниваются — displayName/maxHealth/baseDamage применятся при следующем появлении; spawnLocation и respawnSeconds подхватываются сразу через делегирующие геттеры.

Команды и права

Команда Право Действие
/bosses reload (aliases: /dwbosses) bosses.reload (по умолчанию op) Перезагружает конфиг и локализацию

Боссы из коробки

Призыватель (Summoner)

  • Zombie с костью в руке.
  • Защита: урон от зелий и стрел отменяется.
  • Таргетит только игроков и их помощников (волки, кошки, попугаи).
  • Призыв: раз в минуту — 1–3 маленьких зомби-миньона, агрящихся на ближайшего игрока.
  • Вооружение: раз в 10 минут на 5 минут — зачарованная на защиту IV кожаная броня и каменный меч с остротой V, в момент применения отталкивает игроков в радиусе 4 блоков. В фазе вооружения кулдаун призыва растёт до 3 минут.

Разоритель (Robber)

  • Pillager с арбалетом, зачарованным на «Пронзающую стрелу IV» и «Тройной выстрел».
  • Иммунен к отталкиванию (атрибут knockback_resistance = 1.0).
  • Ярость: однократно при HP ≤ 50% — замена арбалета на железный топор.
  • Рывок: раз в минуту — «Сила II» + импульс к ближайшему игроку. Работает только в фазе ярости.

Расширение API

Чтобы добавить своего босса, функциональный плагин-потребитель:

  1. Подключает boss-api и boss-core как зависимости.

  2. Реализует 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);
        }
    }
  3. Пишет свой 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);
        }
    }
  4. Добавляет в 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"}
]

About

Тестовое техническое задание от проекта DiamondWorld

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages