Kotlin4MC : library for making high level Minecraft plugins 3.0

for Spigot & BungeeCord

  1. Hazae41
    Tested Minecraft Versions:
    • 1.7
    • 1.8
    • 1.9
    • 1.10
    • 1.11
    • 1.12
    • 1.13
    Source Code:
    https://github.com/hazae41/mc-kotlin
    [​IMG]

    〰️ Spigot & BungeeCord 〰️

    ______________________________________________________

    Kotlin4MC helps you to build high level Minecraft plugins by providing simple but powerful tools using the Kotlin language.

    If you want to see how to make a whole plugin using Kotlin4MC, check the #kotlin4mc on GitHub

    ______________________________________________________​

    Getting started

    To avoid classpath conflict, you need to use package relocation

    Add the following at the top of your build.gradle

    Code (Text):
    plugins {
        id 'com.github.johnrengelman.shadow' version '4.0.2'
    }

    import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation
    task relocateShadowJar(type: ConfigureShadowRelocation) {
        target = tasks.shadowJar
        prefix = rootProject.name
    }

    tasks.shadowJar {
        classifier = 'bundle'
        dependsOn tasks.relocateShadowJar
    }

    artifacts {
        archives shadowJar
    }
    Then use the shadowJar task to build your jar

    Provides Kotlin stdlib

    Don't compile Kotlin stdlib any more!
    This library includes the latest version of Kotlin!

    Simplified event listening
    You can use listen() to easily listen to events

    With Kotlin4MC
    Code (Java):
    listen<PlayerJoinEvent>{
      it.player.msg("Hello world!")
    }
    Without Kotlin4MC
    Code (Java):
    server.pluginManager.registerEvent(object: Listener{
      @EventHandler
      fun onPlayerJoin(e: PlayerJoinEvent){
          e.player.sendMessage("Hello world!")
      }
    }, this)
    In Java
    Code (Java):
    getServer().getPluginManager().registerEvents(new Listener() {
      @EventHandler
      public void onPlayerJoin(PlayerJoinEvent e){
          e.getPlayer().sendMessage("Hello world!");
      }
    }, this);
    Simplified scheduling
    Code (Java):
    schedule(delay = 10){
        // this will be executed after 10 ticks
    }

    schedule(delay = 10, period = 20){
        // this will be executed after 10 ticks then each 20 ticks (1 second)
    }

    schedule(async = true){
        // this will be executed asynchronously now
    }

    schedule(true, delay = 20){
        // this will be executed asynchronously after 20 ticks (1 second)
    }

    schedule(true, period = 3, unit = TimeUnit.MINUTES){
        // this will be executed asynchronously each 3 minutes
    }

    // Tasks can cancel themselves
    schedule(period = ...) {
        if(...) cancel()
    }
    Warning: the default unit is ticks, even on BungeeCord

    Warning 2: never use TimeUnit.NANOSECONDS and TimeUnit.MICROSECONDS

    Warning 3: do not use TimeUnit.MILLISECONDS with Bukkit

    Simplified commands

    With Kotlin4MC
    Code (Java):
    command("hello"){ args ->
        msg("&bHello!")
    }
    Without Kotlin4MC
    Code (Java):
    // Bungee
    proxy.pluginManager.registerCommand(this,
        object: Command("hello"){
            override fun execute(sender: CommandSender, args: Array<String>){
                sender.sendMessage("§bHello!")
            }
        }
    )

    // Bukkit
    getCommand("hello").executor = CommandExecutor {
        sender, command, label, args ->
        sender.sendMessage("§bHello!")
        true;
    }
    Delegated configurations

    You can use delegated configurations to manage big configurations
    Code (Java):
    class MyPlugin: BukkitPlugin(){

        object MyConfig: ConfigFile("config"){
            var debug by boolean("debug")
            var alertMessage by string("alert-message")
            var enabledWorlds by stringList("enabled-worlds")
        }

        override fun onEnable(){
            // Initialize the object with the current file
            init(MyConfig) // (it will copy the resource config.yml to the data folder)
            // We can access properties dynamically
            info("debug: " + MyConfig.debug)
            // Change them (if "var" is used)
            MyConfig.debug = false
            // Save them (if auto-saving is disabled)
            MyConfig.save()
            // Reload the config from the file
            MyConfig.reload()
        }
    }
    More infos here

    Simplified messages sending
    Let's send a message to a player (any Player, ProxiedPlayer, CommandSender is supported)

    With Kotlin4MC
    Code (Java):
    player.msg("&6Hello world!")
    Without Kotlin4MC
    Code (Java):
    // BungeeCord
    player.sendMessage(TextComponent("&6Hello world!".replace("&", "§")))

    // Bukkit
    player.sendMessage("&6Hello world!".replace("&", "§"))
    Fast logging
    You can use info(), warning() and severe() with String or Exception to log them in the console
    You can also use logToFile() to write to a file named "log.txt" in your plugin's data folder

    With Kotlin4MC
    Code (Java):
    info("Hello world!")

    Without Kotlin4MC
    Code (Java):
    logger.info("Hello world!")
    In Java
    Code (Java):
    getLogger().info("Hello world!");
    Type aliases for multi-platform plugins
    If you want to specify the platform of any type, just add "Bungee" or "Bukkit" before its name

    With Kotlin4MC
    Code (Java):
    class MyPluginOnBungee: BungeePlugin(){
        override fun onEnable() = info("Hello Bungee!")
    }

    class MyPluginOnBukkit: BukkitPlugin(){
        override fun onEnable() = info("Hello Bukkit!")
    }
    Without Kotlin4MC: two separated files for each platform

    Plugin updates checker
    You can check for updates of your plugin using Spiget
    [​IMG]

    Just use update() with your Spigot resource ID
    Code (Java):
    update(15938)
    You can specify the color
    Code (Java):
    update(15938, LIGHT_PURPLE)
    and the permission (the default permission is "rhaz.update")
    Code (Java):
    update(15938, LIGHT_PURPLE, "myplugin.updates")

    Advanced exception catching

    Exceptions can be catched with a beautiful syntax

    With Kotlin4MC

    Code (Java):
    // This will catch any exception and log it as a warning
    catch<Exception>(::warning){
        // ex() is a short replacement of Exception()
        throw ex("An error occured")
    }
    Without Kotlin4MC
    Code (Java):
    try{
        throw Exception("An error occured")
    } catch(ex: Exception){
        warning(ex)
    }

    Catch only specific exceptions

    Code (Java):
    // The callback can be ommited, the default one is ::printStackTrace
    catch<CommandException>{
        throw Exception("This won't be catched")
    }
    Catch and redirect to the sender
    Code (Java):
    val sender: CommandSender = ...
    catch<Exception>(sender::msg){
        if(sender !is Player)
            throw ex("&cYou're not a player!")
        sender.gamemode = GameMode.CREATIVE
        sender.msg("&bYou're now in creative mode :)")
    }
    Custom callbacks
    Code (Java):
    // Tell the admins about the exception
    val admins = server.onlinePlayers.filter{it.hasPermission("test.admin")}
    fun tellToAdmins(ex: Exception) = admins.forEach{it.msg(ex)}

    catch<Exception>(::tellToAdmins){
        throw ex("Alert!")
    }

    // Anonymous callback that prepend the warning with "An error occured"
    catch<Exception>({ warning("An error occured: ${it.message}")}){
        throw ex(...)
    }
    Custom exceptions
    Code (Java):
    class RedException(message: String): Exception(){
        override val message = "&c$message"
    }

    fun test(){
        catch<RedException>(::warning){
            throw RedException("This message will be red")
        }
    }
    Catching with result, callback and default value
    Code (Java):
    fun default(ex: Exception) =
        {warning(ex); "This is the default message"}()

    val msg = catch(::default){
        val line1 = read() ?: throw ex("Could not read first line")
        val line2 = read() ?: throw ex("Could not read second line")
        val line3 = read() ?: throw ex("Could not read third line")
        info("Sucessfully read three lines")
        "$line1, $line2, $line3"
        // Return the three lines separated by ","
    }

    // Will print "This is the default message"
    // if one of the three lines could not be read
    info("The message is: $msg")
    And much more here

    Do not forget to add the #kotlin4mc on your GitHub repository!
    TomCreeper, MustafaFX, Lazo and 2 others like this.

Recent Updates

  1. 3.0
  2. 2.1.2
  3. 2.1.2

Recent Reviews

  1. read_me
    read_me
    3/5,
    Version: 3.0
    I can't download it. Please help me how to download a new version?
    100charssssss
  2. TheLukeGuy
    TheLukeGuy
    5/5,
    Version: 2.1.1
    Really beautiful and simple Spigot API for Kotlin. Works perfectly and simplifies making plugins by a lot!

    (I've changed my review to 5 stars because I didn't see the GitHub documentation)
    1. Hazae41
      Author's Response
      Thanks! ;)
  3. Shynixn
    Shynixn
    5/5,
    Version: 2.0.11
    Great idea! I personally shade and relocate Kotlin myself in my bigger plugins however I like the idea by providing Kotlin itself as plugin.
    1. Hazae41
  4. LartyHD
    LartyHD
    5/5,
    Version: 1.2.61
    Simple and Fast Upadates the Plugin is very good :D Keep it up! I'm looking forward to 1.3
  5. En_0t_S
    En_0t_S
    3/5,
    Version: 1.2.60
    This plugin creates empty file ".noads" inside bungee directory.
    Please fix it..