Katton is a Minecraft Fabric mod that brings Kotlin scripting to datapacks. It lets you interact directly with Minecraft server internals and Fabric APIs from scripts, making it easy to build custom mechanics, commands, and items with Kotlin's concise syntax. Katton also supports hot reloading (similar to vanilla functions), so you can iterate quickly without restarting the server.
- Basic Kotlin script support
- Script hot reloading
- Remote JVM debugging support
- Simple APIs for common tasks (registering commands, items)
- Documentation and usage examples
Warning
Katton is still in early development. Bugs and incomplete features are expected. Feedback and contributions are welcome.
Add Katton to your Fabric modpack, then create a datapack in your world's datapacks directory. Inside your datapack namespace folder, create a scripts subdirectory and place your Kotlin script files there. Katton compiles these scripts automatically when the datapack is loaded.
A ready-to-use example project (with dependencies and basic configuration) is available at Katton-Example.
In IDEs such as IntelliJ IDEA, you may see unresolved references for Minecraft/Fabric classes because those types are provided by the game runtime. To fix this and enable completion, create a minimal Gradle project for script development.
Note
Even though these are "Kotlin Script" files, using the .kt extension usually provides better IDE support. So Katton only processes .kt files as scripts, and you can use regular Kotlin syntax without worrying about script-specific limitations.
Some IDE inspections may complain about top-level statements in .kt files. In that case, use fun main() as the script entry point, move your top-level logic into main, and invoke it at the end of the file with val __entrypoint__ = main().
Katton supports debugging datapack Kotlin scripts through standard JVM remote debugging.
-
Start Minecraft (or the dedicated server) with a debug agent, for example:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -
In IntelliJ IDEA, create an Attach to remote JVM run configuration and connect to the same host and port.
-
Set breakpoints in the actual datapack script file (for example,
data/<namespace>/scripts/*.kt). -
Enjoy debugging your scripts with the IDE's standard debugging tools.
Note
- A successful debugger attachment does not guarantee that script breakpoints will be hit; source mapping must match the runtime-compiled script source name.
- When the same script is executed again, Katton replaces event handlers previously registered by that script owner, preventing duplicate registrations during reload/debug iteration.
- If breakpoints still do not trigger, restart the target JVM process and attach again to avoid stale classes from previous runs.
Katton supports registering native Minecraft Items from scripts with hot-reload capability. Items registered this way have the same capabilities as items registered by regular Fabric mods.
Use registerNativeItem to register a custom Item:
import net.minecraft.world.item.Item
import top.katton.api.*
registerNativeItem(
id = "mymod:custom_item",
registerMode = RegisterMode.RELOADABLE,
configure = {
stacksTo(64) // max stack size
}
) {
Item(it) // 'it' is the configured Item.Properties
}To create an item with custom behavior (like right-click actions), create an anonymous object extending Item:
import net.minecraft.world.item.Item
import net.minecraft.world.InteractionResult
import net.minecraft.world.InteractionHand
import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.Level
import top.katton.api.*
registerNativeItem(
id = "mymod:magic_wand",
registerMode = RegisterMode.RELOADABLE,
configure = {
stacksTo(1)
}
) { props ->
object : Item(props) {
override fun use(level: Level, player: Player, hand: InteractionHand): InteractionResult {
if (level.isClientSide) return InteractionResult.SUCCESS
// Custom server-side logic here
return InteractionResult.SUCCESS
}
}
}RegisterMode.AUTO- Automatically choose the best mode based on current game stateRegisterMode.RELOADABLE- Item can be hot-reloaded; changes take effect after/katton reloadRegisterMode.PERSISTENT- Item persists across reloads; use for items that should always exist
-
Item Construction Timing: The
itemFactorylambda is called during the registration window when the registry is temporarily unfrozen. Do not construct Item instances outside this lambda. -
Hot Reload Behavior: When using
RELOADABLEmode, the item's behavior can be updated by modifying the script and running/katton reload. The item instance itself remains registered in the game's registry. -
Accessing Registered Items: Use the
ITEMSregistry to get your registered items:
import top.katton.registry.KattonRegistry.ITEMS
import top.katton.registry.id
val myItem = ITEMS[id("mymod:custom_item")]
val itemStack = myItem?.getDefaultInstance()import top.katton.api.*
// Give item to player
ITEMS[id("mymod:custom_item")]?.let {
giveItem(player, it.getDefaultInstance())
}Run /katton reload to reload all scripts without restarting the server. This will:
- Re-read all script files from datapacks
- Re-compile and execute the scripts
- Update event handlers and item behaviors
Note
Items registered with RELOADABLE mode will have their behavior updated on reload, but the item instance itself remains in the game registry. To add new items, simply add new registerNativeItem calls in your scripts.