Tags
Creators
Details
1.1.0
Compatibility
Changes
KotlinScriptLoader 1.1.0
Главный релиз после 1.0.0 — Addon API, GUI, межскриптовые библиотеки, состояние между рестартами, интеграции с WorldEdit/WorldGuard/Vault/SkinsRestorer/Discord, и много работы над надёжностью.
✨ Новое
Addon API
KSLAddon/KSLAPI/KSLContextExtension— сторонние Bukkit-плагины могут регистрировать свои сервисы, импорты и хуки жизненного цикла скрипта, доступные потом любому.ktsчерезservice<T>("key").dependsOn— аддон может объявить зависимость от другого KSL-аддона.onAddonReady(id) { addon -> ... }— безопасная привязка к другому аддону независимо от порядка загрузки Bukkit-плагинов.- Автоматическая очистка: сервисы/импорты/расширения контекста, которые аддон зарегистрировал, снимаются сами при
unregisterAddon, даже если автор аддона забыл отписать их вручную.
GUI
gui(title, rows) { }— DSL для инвентарь-меню:set,fill,border,paginate(с автокнопками next/prev),onClose.- Один-единственный listener на весь плагин вместо отдельного на каждое меню — клик обрабатывается за O(1) независимо от количества открытых GUI.
- Анти-дюп по умолчанию: клик по слоту меню отменяется, если явно не разрешено (
allowItemMovement). - Открытые GUI скрипта принудительно закрываются при его выгрузке — правка скрипта с открытым у игроков меню больше не оставляет "мёртвые" обработчики.
Состояние и данные
persist(key, persistent = false) { default }— состояние скрипта, переживает/ksl reload; сpersistent = trueпереживает полный рестарт сервера (SQLite).table(name)— общая key-value таблица между разными скриптами, сset/get/getInt/getLong/getDouble/getBoolean/increment/delete/row, переживает рестарт.export(key, value)/library<T>(key)/requireLibrary<T>(key)— один.ktsможет отдавать данные/функции другому. Порядок загрузки скриптов теперь управляется директивой// @requires: name1, name2(топологическая сортировка).
YAML
config.message(path, vararg "key" to value)/messageList/richMessage— сообщения с@placeholder@-подстановками и авто-покраской&→§.- Перегрузка с
Player— автоматически заполняет@player@,@world@,@online@,@maxplayers@,@health@,@ping@. - Прозрачная интеграция с PlaceholderAPI:
%papi_placeholder%резолвится в той же строке, что и свои@custom@. config.getOrSetDefault(path, default)— конфиг скрипта сам дозаполняется новыми ключами при обновлении.- Предупреждение в лог при незаменённом
@placeholder@(типичная опечатка) — один раз на комбинацию скрипт/путь/плейсхолдер.
Интеграции
- Vault — экономика и права (
vaultBalance,vaultDeposit,vaultHasPermission,vaultGroupи т.д.) - SkinsRestorer —
setSkin,setSkinRaw. - WorldEdit — доступ к выделению игрока (
weSelection,weSelectionVolume,weFillSelection). - WorldGuard — регионы и любые флаги по имени, включая кастомные от сторонних плагинов (
wgRegionsAt,wgCanBuild,wgFlag). - Discord — вебхуки прямо из скриптов (
discordSend,discordEmbed), настраиваются вconfig.yml. - LuckPerms, EssentialsX, PlaceholderAPI — как и раньше, все софт-зависимости.
Команды и разработка
/ksl reload <имя_скрипта>— точечная перезагрузка одного файла без остальных.registerCommand(..., permission = "...", tabComplete = { player, args -> ... })— свои права и автодополнение у команд скрипта./ksl validate— dry-run компиляция всех скриптов без их выполнения./ksl doctor— живая диагностика: реально компилирует и выполняет тестовый скрипт прямо в момент вызова, проверяет БД,commandMap, все интеграции./ksl errors— счётчик и последняя ошибка скриптов с последнего старта./ksl libraries//ksl addons(с зависимостями) //ksl services.- Sandbox-режим (
config.yml: sandbox: true) — блокирует опасные Java API в скриптах.
🛠 Исправления
- Скрипты не видели даже собственные импорты —
dependenciesFromCurrentContext()брал classpath из текущего потока, а не плагина. Заменено на явную привязку к classloader'у плагина. Cannot inline bytecode built with JVM target 21 into bytecode built with JVM target 1.8— добавлен явный-jvm-target 21в конфигурацию компиляции скриптов.UnsupportedOperationException: removeпри/ksl reloadна некоторых сборках Purpur — двухступенчатый фоллбэк снятия команд (публичный API → reflection).- Исключение в обработчике события/команды/GUI-клика раньше либо падало в общий Bukkit-лог без привязки к скрипту, либо (для команд) вообще не показывалось игроку. Теперь везде отдельный try-catch с логированием по имени скрипта и понятным сообщением игроку.
dbExecute/dbQuery/persist-запись не гарантировали порядок выполнения (обычный Bukkit async scheduler крутит таски без строгой последовательности) — переведены на выделенный однопоточный executor.- Все хук-классы (Vault/LuckPerms/EssentialsX/SkinsRestorer/WorldEdit/WorldGuard) обёрнуты в защиту — сбой стороннего плагина в рантайме даёт
null/false, а не падение скрипта. ScriptValidator//ksl validateне проверял sandbox-правила и мог упасть целиком на одном проблемном файле — исправлено, правила sandbox теперь общие для загрузки и валидации.Cannot select module with conflict on capability 'org.bukkit:bukkit'при подключении VaultAPI/WorldEdit/WorldGuard — исключены транзитивные зависимости на устаревшийorg.bukkit:bukkit.Platform declaration clashмеждуservice<T>()и нетипизированнымservice()— убран лишний overload.- Kotlin
Unresolved referenceиз-за$varперед кириллицей в строковых шаблонах (кириллица — валидный символ для идентификаторов) — переменные обёрнуты в${}. ConcurrentHashMap+ операторin— компилятор не может однозначно выбрать междуcontainsKeyи унаследованным отHashtablecontains(value)(KT-18053) — заменено на явныйcontainsKey.
📦 Прочее
.gitignoreдля Gradle/Kotlin/IntelliJ-проекта.- Реальные unit-тесты (28 проверок) для чистой логики без Bukkit-зависимостей —
KSLPersistCodec,KSLCooldownStore,KSLScriptOrder; можно прогнать однимkotlincбез Gradle и сети. - Полный гайд по разработке аддонов:
docs/Addon-Development-Guide.md. - Примеры: GUI-магазин с пагинацией, межскриптовые библиотеки (
kd.kts/pvp.kts), WorldEdit/WorldGuard, второй аддон сdependsOn/onAddonReady(BonusAddon), YAML-сообщения + общая таблица (stats.kts).
Optional dependencies
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:eyvb3TmW:yUtMEbFF"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:eyvb3TmW:yUtMEbFF"
}

