Why
Requirements: Paper 1.21.4+ (26.x included), Java 21, Kotlin 2.2. The framework is installed on the server as a regular plugin; the Kotlin runtime and coroutines live inside it.
A child plugin does not depend on the framework directly. It applies the ru.hukm.effective-plugin gradle plugin, which brings Kotlin, shadow, relocation of kotlin classes, the Paper API and a compileOnly dependency on the latest EffectiveSpigot.
On the server EffectiveSpigot is a separate plugin and your jar lists it in depend. The Kotlin runtime and coroutines already live inside the framework — they are not bundled into your jar.
Minimal example
pluginManagement {
repositories {
gradlePluginPortal()
maven("https://maven.hukm.dev/repository/maven-public/")
}
}
rootProject.name = "MyPlugin"plugins {
kotlin("jvm") version "2.2.0"
id("com.gradleup.shadow") version "8.3.6"
id("ru.hukm.effective-plugin") version "1.0.0-SNAPSHOT"
}
group = "ru.example"
version = "1.0.0"The version in id("ru.hukm.effective-plugin") is the gradle plugin version, not the framework. The framework resolves as latest.integration automatically.
name: MyPlugin
version: '${version}'
main: ru.example.myplugin.MyPlugin
api-version: '1.21'
depend: [EffectiveSpigot]class MyPlugin : JavaPlugin() {
companion object {
lateinit var instance: MyPlugin
private set
}
override fun onLoad() {
instance = this
MyCommand.init()
}
override fun onEnable() {
RubyItem.init()
MyMenu.init()
EffectiveResourcepack.addServerResourcepack(this, "", "")
}
}Every Effective* object is lazy: until something touches it, it is neither created nor registered. That is why each has an init() called from onEnable (commands — from onLoad). addServerResourcepack at the end is required for anything that uses the resource pack (item and block textures, glyphs, textured menus): without it no pack is built for the plugin. Empty url and sha1 — when the framework's built-in HTTP server serves the pack.
Pitfalls
- A forgotten init() is the most common cause of "the item is not in /egive". The object is not created, so it is not registered.
- A forgotten addServerResourcepack — the item exists but has no texture: no pack was built for the plugin. Call it after init() of all items and blocks.
- Commands are registered in onLoad, not onEnable — Brigadier only accepts them during the load phase.
- If you add your own relocate rules to shadow, they must match the framework relocation (ru.hukm.effectiveSpigot.libs.*), otherwise Kotlin classes get duplicated.
- After the gradle plugin itself is republished, build the child project once with --refresh-dependencies.
- Built-in debug commands: /egive, /emob, /ecomposite, /emenu, /ezone, /escreen — everything registered shows up in tab completion.