Skip to content

GUI API

Полное руководство по GUI API 1.0.8: загрузка меню, YAML-контракт, действия, условия, перезагрузка, масштабирование и UX-паттерны.

Обновлено: 01 янв. 1980 г.Чтение: ~4 мин

GUI API

GUI API NextLib — это YAML-driven система инвентарных интерфейсов. Вы храните меню в файлах, а библиотека превращает их в рабочие GUI с обработкой кликов.

1. Ментальная модель GUI API

Система состоит из трёх слоёв:

  1. GuiManager — загрузка/реестр/открытие/refresh.
  2. GuiLoader — парсинг YAML в Gui и GuiItem.
  3. Actions + Conditions — DSL для поведения и динамики.

Ключевой плюс: контент редактабелен без перекомпиляции плагина.

2. Инициализация и жизненный цикл

GuiManager guiManager = new GuiManager(plugin);
guiManager.loadFromFolder(new File(plugin.getDataFolder(), "menus"));

Что делает loadFromFolder:

  • сохраняет директорию меню,
  • запускает reloadAll().

Что делает reloadAll:

  1. Закрывает открытые GUI игрокам.
  2. Очищает текущий registry.
  3. Сканирует .yml файлы.
  4. Создаёт Gui через GuiLoader.
  5. Регистрирует GUI по id (обычно имя файла без .yml).

Практическое следствие: любые изменения YAML можно подхватить без перезапуска сервера.

3. Полный YAML-контракт

Верхний уровень

  • title: заголовок инвентаря.
  • size: размер (обычно 9..54, кратно 9).
  • items: словарь элементов.

Item-уровень

  • material
  • amount
  • name
  • lore
  • slot или slots
  • on_left_click
  • on_right_click
  • enchanted_when

Минимальный пример:

title: "&8Главное меню"
size: 27
items:
  shop:
    material: EMERALD
    slot: 11
    name: "&aМагазин"
    on_left_click:
      - "opengui shop"

Важно: runtime использует snake_case ключи. CamelCase-варианты не сработают.

4. Слоты: точка, диапазон, композиция

Один слот

slot: 13

Несколько/диапазоны

slots:
  - "0-8"
  - "9"
  - "17"
  - "18-26"

Поведение парсера:

  • некорректные значения -> warning в лог,
  • слот вне размера меню -> warning и пропуск,
  • дубли слотов внутри элемента дедуплицируются.

5. Встроенные actions: полный список

  • close
  • command <cmd>
  • console <cmd>
  • message <text>
  • opengui <id>
  • update
  • playsound <SOUND> [volume] [pitch]

Что делает каждый

close

Закрывает текущий инвентарь игрока.

command

Выполняет команду от игрока.

console

Выполняет команду от консоли.

message

Шлёт сообщение игроку через formatter библиотеки.

opengui

Открывает другое меню по id.

update

Вызывает refresh GUI для игрока.

playsound

Воспроизводит звук. Если имя звука неверное, будет warning и no-op.

6. Примеры composable actions

buy:
  material: DIAMOND
  slot: 13
  name: "&bКупить"
  lore:
    - "&7Цена: &e100"
  on_left_click:
    - "console eco take %player% 100"
    - "message &aПокупка успешна"
    - "playsound ENTITY_PLAYER_LEVELUP 1.0 1.0"
    - "update"

Практика:

  • сначала побочный эффект (команда экономики),
  • потом feedback (message/sound),
  • затем update для визуальной консистентности.

7. Условия (Conditions)

Из коробки только:

  • always
  • never

Всё остальное вы регистрируете сами.

Регистрация кастомного условия

Conditions.registerCondition("has_permission", (manager, args) ->
    player -> player.hasPermission(args)
);

YAML:

admin:
  material: COMMAND_BLOCK
  slot: 10
  name: "&cАдминка"
  enchanted_when:
    - "has_permission myplugin.admin"

8. Кастомные actions

Actions.registerAction("teleport", (manager, args) -> player -> {
    String[] parts = args.split(",");
    double x = Double.parseDouble(parts[0]);
    double y = Double.parseDouble(parts[1]);
    double z = Double.parseDouble(parts[2]);
    player.teleport(new Location(player.getWorld(), x, y, z));
});

YAML:

spawn:
  material: ENDER_PEARL
  slot: 15
  name: "&bНа спавн"
  on_left_click:
    - "teleport 0,100,0"

Рекомендация: все кастомные actions/conditions регистрируйте до loadFromFolder.

9. Programmatic GUI (без YAML)

Gui gui = guiManager.createGui("debug", "&8Debug", 27);
GuiItem item = new GuiItem(new ItemStack(Material.PAPER), 13);
item.addLeftClickAction(player -> player.sendMessage("clicked"));
gui.addItem(item);

Используйте этот подход для временных/диагностических меню или динамической сборки из БД.

10. Интеграция с Reload API

context.reload().register(new Reloadable() {
    @Override
    public String id() { return "gui.menus"; }

    @Override
    public void reload() {
        guiManager.reloadAll();
    }
});

Так /reload команды перестают быть опасными и становятся управляемыми.

11. Большие паттерны проектирования GUI

Паттерн A: Main hub

  • main.yml только навигация.
  • Бизнес-логика в дочерних меню.

Паттерн B: Domain folders

  • menus/shop/*.yml
  • menus/quests/*.yml
  • menus/admin/*.yml

Паттерн C: Action naming policy

Если у вас много кастомных actions, используйте namespace:

  • shop_buy
  • quest_accept
  • admin_reset

12. Производительность

Симптомы:

  • лаги при массовом открытии меню,
  • задержка кликов,
  • частые refresh на каждом тике.

Решения:

  1. Не делайте дорогие DB-вызовы прямо в click actions без кеша.
  2. Не спамьте update без необходимости.
  3. Крупные вычисления предварительно кэшируйте.

13. Частые ошибки и диагностика

GUI '<id>' not found!

  • меню не загружено,
  • id не совпадает с файлом,
  • вызов открытия раньше загрузки.

Unknown GUI action ...

  • опечатка,
  • забыли Actions.registerAction.

Unknown GUI condition ...

  • забыли Conditions.registerCondition.

Кнопка «есть», но клик пустой

  • неверный ключ действия,
  • слот вышел за границы и item не создался,
  • действие содержит неверные аргументы.

14. UX-рекомендации

  • Давайте явные названия кнопок («Купить», «Назад», «Подтвердить»).
  • Добавляйте контекст в lore (цена, лимиты, награда).
  • После важных действий давайте моментальный feedback (message + playsound).
  • На рискованных действиях делайте confirm-экран.

15. Антипаттерны

  • Один огромный YAML на всё.
  • Дублирование одинаковых блоков без структуры.
  • Скрытая бизнес-логика в лоре.
  • Непредсказуемый set команд без логирования.

16. Большой FAQ

Можно ли делать пагинацию?

Да. Обычно через несколько меню (shop_page_1, shop_page_2) или динамическую сборку programmatic GUI.

Можно ли работать без PlaceholderAPI?

Базово да, но встроенные action-команды могут использовать PlaceholderAPI для подстановок.

Можно ли condition на основе базы данных?

Да, но лучше читать из кеша/предзагруженной модели, а не делать SQL в каждый рендер/клик.

Если следовать этим правилам, GUI API остаётся стабильным даже на большом количестве меню и игроков.