Files
portfolio/content/en/blog/how-to-build-your-first-hytale-plugin.md
T
kayjaydee 0ba23acd1b feat(08-02): add EN article how-to-build-your-first-hytale-plugin
- Equivalent EN version (970 mots), same slug
- 3 Kotlin code blocks (build.gradle.kts, event listener, command)
- 2 inline links to /en/hytale (intro + build section)
- Frontmatter Zod-valid : draft false, tags [hytale, tutorial, kotlin], date 2026-04-22
2026-04-22 21:52:00 +02:00

6.7 KiB

title, description, date, tags, draft
title description date tags draft
How to build your first Hytale plugin: a step-by-step guide Learn to build your first Hytale plugin in Kotlin: project setup, event listener, custom command — with the complete source code. 2026-04-22
hytale
tutorial
kotlin
false

Why Hytale, why now

The first time I booted a local Hytale server, I realized this platform was about to replay exactly what Minecraft did with Bukkit back in 2012 — except that in 2026, we start with Kotlin, a typed API, and an SDK designed from day one for plugin developers. Translation: wide-open window for anyone who wants to get in early.

In this guide, I'll walk you through building my first Hytale plugin — a minimal module that listens for a player joining and adds a /hello command. Nothing spectacular, but it's exactly the skeleton you need to iterate on more ambitious features. If you'd rather commission a Hytale plugin instead of writing it yourself, that works too — but if you're here, you probably want to get your hands dirty.

::alert{type="info"} API note — The API names referenced here are based on the public Hytale SDK 2026 documentation. They may evolve at official launch — adapt based on the most current docs at the time you're reading this. ::

Prerequisites

Before cloning anything, make sure you have:

  • JDK 17+ (I recommend Temurin 21 — the Hytale 2026 SDK runs on it without issue)
  • IntelliJ IDEA Community Edition — free, and the Gradle + Kotlin integration is excellent
  • Gradle 8.x (IntelliJ bundles it, no need to install separately)
  • Solid basics in Kotlin: classes, lambdas, annotations, nullability

I'm assuming you already have a local Hytale server that boots. If not, the official server docs are your starting point — this guide focuses on the plugin, not on hosting.

Project scaffold

The minimal tree looks like this:

my-first-plugin/
├── build.gradle.kts
├── src/
│   └── main/
│       ├── kotlin/
│       │   └── com/example/myplugin/
│       │       └── MyPlugin.kt
│       └── resources/
│           └── plugin.toml

The minimal build.gradle.kts I use:

plugins {
    kotlin("jvm") version "2.0.0"
    id("com.github.johnrengelman.shadow") version "8.1.1"
}

repositories {
    mavenCentral()
    maven("https://repo.hytale.io/public")
}

dependencies {
    compileOnly("io.hytale:hytale-api:1.0.0")
}

tasks {
    build { dependsOn("shadowJar") }
}

The plugin.toml manifest declares your plugin to the server:

name = "MyPlugin"
version = "0.1.0"
main = "com.example.myplugin.MyPlugin"
authors = ["you"]

That's it. No boilerplate stands between you and the first useful line of code.

First event listener — the heart of the plugin

Here's the main class. This is the file you'll spend the most time in during the first weeks, so treat it seriously:

package com.example.myplugin

import io.hytale.api.HytalePlugin
import io.hytale.api.event.EventHandler
import io.hytale.api.event.player.PlayerJoinEvent

class MyPlugin : HytalePlugin() {

    override fun onEnable() {
        logger.info("MyPlugin enabled")
        server.events.register(this)
    }

    override fun onDisable() {
        logger.info("MyPlugin disabled — cleaning up")
    }

    @EventHandler
    fun onPlayerJoin(event: PlayerJoinEvent) {
        val player = event.player
        player.sendMessage("Welcome to the server, ${player.name}!")
        logger.info("Player ${player.name} joined at ${event.timestamp}")
    }
}

Quick breakdown:

  • HytalePlugin is the base class provided by the API. It exposes logger, server, and the lifecycle hooks (onEnable / onDisable).
  • server.events.register(this) tells the server that this instance holds @EventHandler methods. Without that line, your listener will never fire — classic mistake I made the first time around.
  • The @EventHandler annotation marks the method as an event target. The PlayerJoinEvent parameter type acts as a filter: only that event triggers the method.
  • event.player exposes a Player object with sendMessage, teleport, inventory, and so on.

Compile, start the server, connect: you should see the welcome message in chat. If not, check the server logs — a ClassNotFoundException usually means the shadow jar isn't packed correctly.

Adding a custom command

Listening to events is half the job. The other half is letting players interact with your plugin through commands. Add this method in the same class:

import io.hytale.api.command.Command
import io.hytale.api.command.CommandSender

@Command(name = "hello", description = "Says hello back")
fun onHelloCommand(sender: CommandSender, args: List<String>) {
    val target = args.firstOrNull() ?: sender.name
    sender.sendMessage("Hello, $target!")
}

You can now type /hello or /hello Killian in-game. The @Command annotation registers the command automatically — no need to list it in plugin.toml. If you want strict argument validation, CommandSender exposes hasPermission(node) to gate access.

Build + local deploy

The loop I run 20 times a day:

./gradlew shadowJar
cp build/libs/my-first-plugin-all.jar ~/hytale-server/plugins/
# Then in the server console:
> reload MyPlugin

The shadowJar task packs all your runtime dependencies into a single .jar, which avoids classpath headaches. On more ambitious plugins — SQLite persistence, embedded REST API, Discord integrations — it quickly becomes essential. If that kind of scope resonates but you'd rather delegate the development side, you can always commission a custom Hytale plugin from someone doing it day in, day out.

Next steps

Once your first plugin is running, the natural paths forward are:

  • Listen to more events: BlockBreakEvent, PlayerChatEvent, EntityDamageEvent — the full list lives in the io.hytale.api.event package.
  • Persist data: start with a simple JsonFile in your plugin folder, switch to SQLite once you cross 50 KB of state.
  • Add permissions: the Hytale API ships with a node system like myplugin.admin.reload that integrates with server groups.
  • Profile your handlers: a slow event listener directly impacts the server's TPS. logger.info with timestamps is your first tool, then Flight Recorder when you get serious.

Wrapping up

A Hytale plugin is essentially a Kotlin class that extends HytalePlugin, registers listeners, and exposes commands. Everything else — persistence, UI, integrations — builds on top of that 50-line foundation. If you've followed along this far, you already have the technical base to ship any idea you have in mind. Code an ugly first thing, get it running, iterate. That's always how it starts.