-
Notifications
You must be signed in to change notification settings - Fork 0
Local Addon Guide
# 🛠️ Создание локального аддона и расширение DSL скриптов
В этом руководстве мы разберем, как создать собственный аддон (на примере модуля `ExampleAddon`) прямо внутри вашего проекта, зарегистрировать его в `KSLAddonManager` и добавить новые методы в `.kts` скрипты через `KSLContextExtension`[cite: 3, 4].
---
## 📂 1. Структура модуля аддона
Если вы разрабатываете аддон в рамках мультимодульного Gradle-проекта, его структура должна выглядеть следующим образом:
```text
ВашПроект/
├── examples/
│ └── ExampleAddon/
│ ├── build.gradle.kts
│ └── src/main/kotlin/ru/example/
│ ├── ExampleAddonPlugin.kt # Буккит-плагин аддона
│ ├── CoinService.kt # Логика вашего сервиса
│ └── CoinContextExtension.kt # Расширение контекста скриптов
├── build.gradle.kts
└── settings.gradle.kts
Для начала создадим основной класс аддона, который будет отвечать за его регистрацию и инициализацию в ядре KSL.
package ru.example
import ru.privateserver.ksl.KSLAddon
import ru.privateserver.ksl.KSLAPI
class CoinAddon(private val plugin: ExampleAddonPlugin) : KSLAddon {
override val addonId: String = "coin-addon"
override val addonVersion: String = "1.0.0"
override val addonDescription: String = "Аддон для интеграции кастомной валюты в KSL скрипты"
override fun onLoad(api: KSLAPI) {
// 1. Регистрируем сервис, чтобы к нему можно было получить доступ по ключу[cite: 3, 4]
val coinService = CoinService()
api.registerService("coin_service", coinService)[cite: 3, 4]
// 2. Добавляем автоматический импорт классов нашего аддона в скрипты[cite: 3, 4]
api.addDefaultImports("ru.example.*")[cite: 3, 4]
// 3. Регистрируем расширение контекста для внедрения новых методов в DSL[cite: 3, 4]
api.registerContextExtension(CoinContextExtension(coinService))[cite: 3, 4]
}
override fun onUnload() {
// Вызывается при выгрузке аддона (удаляем зависимости)[cite: 2, 3]
// KSLAddonManager автоматически очистит зависимости, привязанные к этому ID[cite: 3]
}
}
Чтобы в .kts скриптах появились новые методы (например, player.getCoins() или addCoins()), нам нужно использовать KSLContextExtension. Это позволяет выполнять логику в момент создания контекста для каждого скрипта.
package ru.example
import ru.privateserver.ksl.KSLContextExtension
import ru.privateserver.ksl.BukkitScriptContext
import org.bukkit.entity.Player
class CoinContextExtension(private val coinService: CoinService) : KSLContextExtension {
override val extensionId: String = "coin-context-ext"
override fun onContextCreated(context: BukkitScriptContext) {
// Данный код выполняется при компиляции/инициализации скрипта[cite: 3]
// Здесь мы можем логировать интеграцию или готовить локальные структуры данных для скрипта
}
override fun onContextDestroyed(scriptName: String) {
// Очищаем кэш или данные конкретного скрипта при его перезагрузке (`/ksl reload`)[cite: 3]
}
}
/**
* Расширения (Extension Functions) для DSL скриптов.
* Благодаря автоматическому импорту "ru.example.*", эти методы будут
* доступны внутри любого .kts файла без ручных импортов!
*/
fun Player.getCoins(): Int {
// Пример обращения к синглтону KSL для получения сервиса на лету
val service = ru.privateserver.ksl.KSL.api.getService("coin_service") as? CoinService[cite: 1, 3]
return service?.getBalance(this) ?: 0
}
fun Player.addCoins(amount: Int) {
val service = ru.privateserver.ksl.KSL.api.getService("coin_service") as? CoinService[cite: 1, 3]
service?.addBalance(this, amount)
}
В главном классе вашего Bukkit-плагина аддона необходимо дождаться инициализации KSL и передать наш аддон в менеджер.
package ru.example
import org.bukkit.plugin.java.JavaPlugin
import ru.privateserver.ksl.KSL
class ExampleAddonPlugin : JavaPlugin() {
override fun onEnable() {
// Проверяем, запущен ли загрузчик скриптов на сервере[cite: 1]
if (!KSL.isAvailable) {[cite: 1]
logger.severe("KotlinScriptLoader не найден! Аддон отключен.")
server.pluginManager.disablePlugin(this)
return
}
// Регистрируем наш локальный аддон в системе[cite: 3, 4]
val addon = CoinAddon(this)
KSL.api.registerAddon(addon)[cite: 1, 3]
}
override fun onDisable() {
if (KSL.isAvailable) {[cite: 1]
// Безопасно удаляем аддон при выключении сервера или плагина[cite: 3, 4]
KSL.api.unregisterAddon("coin-addon")[cite: 1, 3]
}
}
}
После того как ваш локальный аддон загружен:
-
В рантайм автоматически добавился импорт пакета
ru.example.*. -
Расширения для класса
Playerстали глобальными.
Теперь любой администратор или контент-мейкер может написать в своем .kts файле следующий лаконичный код:
// Пример скрипта custom_eco.kts
onEvent<PlayerJoinEvent> { event ->
val player = event.player
// Метод .getCoins() доступен автоматически благодаря нашему аддону!
val coins = player.getCoins()
player.sendMessage("§6[Баланс] У вас на счету: $coins монет.")
}
registerCommand("givecoins", listOf("gcoins")) { player, args ->
if (!player.isOp) return@registerCommand
player.addCoins(100)
player.sendMessage("§aВы выдали себе 100 локальных монет!")
}
-
Изоляция сбоев (Fail-Safety):
KSLAddonManagerзапускает методonLoadвашего аддона внутри блокаrunCatching. Если в вашем аддоне произойдет ошибка (например, не подключилась внешняя БД), KSL отловит её, выведет красивыйsevere-лог в консоль сервера, но продолжит работать и загружать остальные скрипты и аддоны. -
Потоковая безопасность: Все внутренние хранилища аддонов, расширений контекста и сервисов работают на базе
ConcurrentHashMap. Вы можете безопасно регистрировать или вызывать сервисы из асинхронных задач Bukkit (runAsync).
---
Отличный, максимально подробный гайд получился! Всё разложено по полочкам: от Gradle-структуры до конечного вида скрипта.
Что пишем дальше? Давай сделаем полноценный **Гайд по написанию самих скриптов (`.kts`)**, где покажем вообще всё встроенное в ядро DSL: базы данных, команды, ивенты, и как раз то, как со всем этим взлетать. Или есть другие идеи?