| name | taboolib-dev |
| description | Help developers build Minecraft plugins using TabooLib 6.x framework (Kotlin/Java). Use when user mentions "taboolib", "TabooLib plugin", "minecraft plugin with taboolib", "bukkit plugin framework", "create taboolib project", "taboolib command", "taboolib config", "taboolib UI", "taboolib database", "taboolib NMS", "taboolib kether", or asks about TabooLib module setup, @Awake lifecycle, cross-version compatibility. Covers project setup, module selection, API usage, and troubleshooting.
|
| license | MIT |
| compatibility | Claude Code, Claude.ai |
| metadata | {"author":"community","version":"1.0.0","category":"minecraft-development","tags":["minecraft","kotlin","taboolib","bukkit","plugin-development"],"source-repo":"https://github.com/TabooLib/taboolib","source-commit":"4eaffc793a25962453849ae77597198d1643d765","source-date":"2026-02-23","taboolib-version":"6.1.2-beta12","gradle-plugin-version":"2.0.31"} |
TabooLib Plugin Development
Overview
TabooLib is a Kotlin-based cross-platform Minecraft plugin framework (supports Bukkit/Spigot/Paper, BungeeCord, Velocity). Current stable version: 6.1.2-beta12, Gradle plugin: 2.0.31.
Key traits:
- ~30KB runtime footprint (modules downloaded on demand)
- Kotlin DSL APIs for commands, UI, config, database
- Cross-version NMS abstraction (1.8 ~ 1.21+)
- Annotation-driven lifecycle (
@Awake, @SubscribeEvent, @Schedule, @Config)
Instructions
Step 1: Project Setup
When user wants to create a new TabooLib plugin:
- Generate
build.gradle.kts with the TabooLib Gradle plugin:
import io.izzel.taboolib.gradle.*
plugins {
java
id("io.izzel.taboolib") version "2.0.31"
kotlin("jvm") version "2.0.0"
}
taboolib {
env {
install(UNIVERSAL, BUKKIT)
}
version { taboolib = "6.1.2-beta12" }
}
repositories {
mavenCentral()
}
dependencies {
compileOnly("ink.ptms.core:v12004:12004:mapped")
compileOnly("ink.ptms.core:v12004:12004:universal")
compileOnly(kotlin("stdlib"))
taboo("ink.ptms:um:1.2.0")
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
}
- Create the plugin main class (use
object, NOT class):
import taboolib.common.platform.Plugin
object MyPlugin : Plugin() {
override fun onLoad() { }
override fun onEnable() { info("Plugin enabled!") }
override fun onActive() { }
override fun onDisable() { }
}
- No
plugin.yml needed — TabooLib auto-generates it.
Step 2: Module Selection Guide
Help user pick the right modules based on their needs:
| Need | Module Constant | Notes |
|---|
| Config files (YAML/TOML/HOCON) | CONFIGURATION | Enables @Config, @ConfigNode |
| Multi-language / i18n | LANG | Requires CONFIGURATION |
| Rich text / clickable messages | CHAT | Components API |
| NMS / packet operations | NMS, NMS_UTIL | Cross-version abstraction |
| Chest GUI / Anvil GUI | UI | Requires CHAT + NMS |
| Database (MySQL/SQLite) | DATABASE | HikariCP connection pool |
| Kether scripting | KETHER | Requires CONFIGURATION |
| Bukkit utilities (ItemBuilder etc) | BUKKIT_ALL | XMaterial, ItemBuilder |
| PlaceholderAPI / Vault hooks | BUKKIT_HOOK | Third-party integration |
| BungeeCord messaging | PORTICUS | Cross-server communication |
Module dependencies (auto-resolved by Gradle plugin, but useful to know):
UI depends on CHAT + NMS
LANG depends on CONFIGURATION
NMS_UTIL depends on NMS
Step 3: Core API Patterns
Always follow these patterns when writing TabooLib code:
Pattern: Singleton Object + @Awake
@Awake
object PlayerManager {
private val cache = ConcurrentHashMap<UUID, PlayerData>()
@Awake(LifeCycle.ENABLE)
fun init() { }
@SubscribeEvent
fun onQuit(event: PlayerQuitEvent) {
cache.remove(event.player.uniqueId)
}
@Schedule(async = true, period = 6000L)
fun autoSave() {
cache.values.forEach { it.save() }
}
}
Pattern: Config Injection
@Awake
object Settings {
@Config("config.yml", autoReload = true)
lateinit var config: Configuration
@ConfigNode("debug")
var debug = false
@ConfigNode("settings.max-players")
var maxPlayers = 100
}
Pattern: Command DSL
command("myplugin", aliases = listOf("mp"), permission = "myplugin.use") {
literal("reload") {
execute<ProxyCommandSender> { sender, _, _ ->
Settings.config.reload()
sender.sendMessage("Reloaded!")
}
}
dynamic("player") {
suggestion<ProxyCommandSender> { _, _ ->
Bukkit.getOnlinePlayers().map { it.name }
}
execute<ProxyCommandSender> { sender, _, argument ->
sender.sendMessage("Target: $argument")
}
}
}
Pattern: Event Listening
@Awake
object Listeners {
@SubscribeEvent
fun onJoin(event: PlayerJoinEvent) {
event.player.sendMessage("Welcome!")
}
@SubscribeEvent(priority = EventPriority.HIGHEST, ignoreCancelled = true)
fun onDamage(event: EntityDamageEvent) { }
}
listenEvent<PlayerJoinEvent> {
it.player.sendMessage("Welcome!")
}
Pattern: Chest UI
player.openMenu<Chest> {
title("My Menu")
rows(3)
map(
"# # # # # # # # #",
"# A # B # C # D #",
"# # # # # # # # #"
)
set('A', buildItem(XMaterial.DIAMOND) { name = "&bDiamond"; colored() })
onClick('A') { event -> event.clicker.sendMessage("Clicked!") }
handLocked(false)
}
Pattern: Database Table
val table = Table<HostSQL, Connection>("player_data", host) {
add("uuid") { type(ColumnTypeSQL.VARCHAR, 36) }
add("data") { type(ColumnTypeSQL.TEXT) }
}
submitAsync {
table.createTable(dataSource)
table.select(dataSource) {
where { "uuid" eq player.uniqueId.toString() }
}.firstOrNull()
}
Pattern: Task Scheduling
submit(delay = 20L) { }
submit(async = true, period = 20L) { }
@Schedule(async = true, period = 100L, delay = 20L)
fun periodicTask() { }
Pattern: NMS Version Guard
if (MinecraftVersion.isHigherOrEqual(MinecraftVersion.V1_17)) {
}
val ver = MinecraftVersion.majorLegacy
Step 4: Validation Checklist
Before the plugin is considered complete, verify:
Examples
Example 1: Basic Plugin with Config and Command
User says: "Create a TabooLib plugin with a config and a reload command"
Action:
- Set up
build.gradle.kts with UNIVERSAL, BUKKIT, CONFIGURATION
- Create
Plugin object main class
- Create
Settings object with @Config
- Create command with
reload subcommand
- Create default
config.yml
Example 2: Plugin with Chest GUI
User says: "I need a shop GUI plugin with TabooLib"
Action:
- Set up with
UNIVERSAL, BUKKIT, CONFIGURATION, CHAT, NMS, NMS_UTIL, UI, BUKKIT_ALL
- Create config for shop items
- Build Chest menu with
map() layout
- Handle click events for purchase logic
- Add NMS version check if using version-specific features
Example 3: Plugin with Database
User says: "Player data storage plugin with MySQL"
Action:
- Set up with
UNIVERSAL, BUKKIT, CONFIGURATION, DATABASE
- Define table schema using
Table API
- Create async data load/save in
@SubscribeEvent handlers
- Use
submitAsync {} for all DB operations
- Configure
config.yml with database connection settings
Troubleshooting
Error: Module not found at runtime
- Cause: Module not installed in
taboolib { env { install(...) } }
- Solution: Add the missing module constant. Check
references/module-map.md for dependencies.
Error: @Awake object not being discovered
- Cause: Missing
@Awake annotation on the object, or object is in a package not scanned
- Solution: Ensure
@Awake is on the object declaration. TabooLib scans all classes in the plugin JAR.
Error: NMS operation fails on specific MC version
- Cause: NMS API changed between versions
- Solution: Use
MinecraftVersion.isHigherOrEqual() guards. For packet operations, check field names per version.
Error: Config not reloading
- Cause:
autoReload = true not set, or FileWatcher not active
- Solution: Set
autoReload = true in @Config. For manual reload call config.reload().
Error: UI clicks not registering
- Cause: Missing
handLocked(false) or wrong slot mapping
- Solution: Verify
map() character assignments match set() and onClick() characters.
Error: Gradle build fails with TabooLib plugin
- Cause: Version mismatch or repository not configured
- Solution: Ensure
io.izzel.taboolib plugin version matches, and mavenCentral() is in repositories.
Error: Chinese filename causes server crash on restart
- Known bug: Avoid Chinese characters in config file names. Use ASCII-only filenames.