Перейти к содержимому

Хендлеры провайдеров

Разработчик аддонов

В AbstractMenus пять секций провайдеров: экономика, права, уровни, плейсхолдеры, скины. Каждая секция - это аксессор api.providers().<section>(), возвращающий ProviderSection<T>. В секцию можно зарегистрировать несколько хендлеров с id и приоритетом; какой из них становится дефолтным - выбирает оператор в config.conf. Если в HOCON-действии указан конкретный провайдер, он перебивает дефолт из конфига.

Старого статического фасада Handlers (как было до 2.0) больше нет - всё идёт через ProviderSection.

СекцияВозвращаетНазначение
api.providers().economy()ProviderSection<EconomyHandler>takeMoney/giveMoney/hasMoney
api.providers().permissions()ProviderSection<PermissionsHandler>правила permission/group, мутация групп и нод
api.providers().levels()ProviderSection<LevelHandler>giveXp/takeXp/giveLevel/takeLevel, правила xp/level
api.providers().placeholders()ProviderSection<PlaceholderHandler>подстановка плейсхолдеров
api.providers().skins()ProviderSection<SkinHandler>setSkin/resetSkin

Встроенные дефолты регистрируются с приоритетом 50:

  • economy - vault (Vault), playerpoints если установлен PlayerPointsAddon
  • permissions - vault, luckperms
  • levels - bukkit (ванильный XP)
  • placeholders - papi (PlaceholderAPI), internal (встроенные)
  • skins - skinsrestorer

Аддонные провайдеры обычно регистрируются с приоритетом 100 - так они выигрывают авто-резолв, когда есть и дефолт, и аддон.

Реализуй нужный интерфейс *Handler и зарегистрируй из MenuExtension.onEnable(api):

public final class MyAddon implements MenuExtension {
@Override
public void onEnable(AbstractMenusApi api) {
api.providers().economy().register(
"playerpoints", // id
new PlayerPointsEconomy(playerPointsApi), // хендлер
100, // приоритет - больший выигрывает auto-резолв
this); // владелец - AbstractMenus использует для чистки
}
}

id - это то, на что ссылаются HOCON-меню и config.conf (provider: "playerpoints"). Регистр не важен. Один и тот же экземпляр хендлера используется для всех вызовов.

EconomyHandler eco = api.providers().economy().resolve(); // дефолт из конфига или хендлер с наивысшим приоритетом
EconomyHandler vault = api.providers().economy().resolve("vault"); // по id, либо null
boolean hasPP = api.providers().economy().has("playerpoints");
Set<String> ids = api.providers().economy().ids();
Collection<EconomyHandler> all = api.providers().economy().all();

resolve() сначала смотрит в config.conf providers.<section>. Если оператор зафиксировал конкретный id - выиграет он. Если стоит "auto" - выиграет хендлер с наибольшим приоритетом. Поиск атомарен: параллельный unregister не вернёт устаревший хендлер.

resolve(String) дёргают действия меню, когда в HOCON прописан provider: "...". Указание провайдера на уровне действия всегда перебивает дефолт из конфига.

Заменяем дефолтную экономику на свою - с балансами в Map:

public final class MapEconomy implements EconomyHandler {
private final Map<UUID, Double> balance = new ConcurrentHashMap<>();
@Override
public boolean hasBalance(Player player, double amount) {
return balance.getOrDefault(player.getUniqueId(), 0.0) >= amount;
}
@Override
public void takeBalance(Player player, double amount) {
balance.merge(player.getUniqueId(), -amount,
(current, delta) -> Math.max(0, current + delta));
}
@Override
public void giveBalance(Player player, double amount) {
balance.merge(player.getUniqueId(), amount, Double::sum);
}
}

Регистрируем из аддона:

@Override
public void onEnable(AbstractMenusApi api) {
api.providers().economy().register(
"memory",
new MapEconomy(),
100,
this);
}

Чтобы сделать его серверным дефолтом, оператор пишет:

config.conf
providers {
economy = "memory"
}

Или точечно, на конкретное меню, не трогая глобальный дефолт:

actions {
click: [
{ type: takeMoney, amount: 100, provider: "memory" }
]
}

Все пять интерфейсов лежат в ru.abstractmenus.api.handler.*:

ИнтерфейсМетоды
EconomyHandlerhasBalance, takeBalance, giveBalance
PermissionsHandleraddPermission, removePermission, hasPermission, addGroup, removeGroup, hasGroup
LevelHandlergetXp, giveXp, takeXp, getLevel, giveLevel, takeLevel
PlaceholderHandlerreplacePlaceholder, replace(Player, String), replace(Player, List<String>), registerAll
SkinHandlersetSkin, resetSkin

Имена и сигнатуры методов стабильны в пределах всей линейки 2.0.

При onDisable твоего аддона AbstractMenus сам снимает все зарегистрированные тобой провайдеры. Самому unregisterAll дёргать нельзя - публичный ProviderRegistry его сознательно не выставляет, чтобы один аддон не мог сносить провайдеры другого.

Для Пути 1 чистка идёт сама собой: AbstractMenus ведёт его через AddonManager и при выключении сносит все регистрации. У Пути 2 “выключение” - это JavaPlugin.onDisable, и под автоматическую чистку он не попадает: регистрация остаётся в карте владельцев до выключения самого AbstractMenus. Повторная регистрация под тем же id из нового onEnable перетрёт живую запись - на практике утечки нет.