Develop Your First Hytale Plugin
Hytale just launched into Early Access - let’s build our first server plugin. This guide assumes you already have a dev server running.
Prefer video? Watch this tutorial on YouTube.
Prerequisites
- Java 21 or 25 - Java 25 is recommended by Hypixel, but 21 works fine too
- Any Java IDE - I’ll use IntelliJ IDEA in this tutorial, but Eclipse, VS Code with Java extensions, or any other IDE works just as well
- A running Hytale dev server - Follow the Hytale Server Manual to set one up
- The
HytaleServer.jarfile - You get this from your server installation
Create the Project
Create a new Gradle project with Kotlin DSL and Java. In IntelliJ: File → New → Project → Gradle, select “Kotlin DSL” and your Java version. Name it something like HelloPlugin with the GroupId com.example. Other IDEs have similar workflows - the important part is that you end up with a Gradle project using Kotlin DSL (build.gradle.kts).
Add the Hytale Server JAR
Create a libs folder in your project root and drop the HytaleServer.jar in there. Then open build.gradle.kts and add it as a compileOnly dependency - we don’t want to bundle it, just compile against it:
dependencies {
compileOnly(files("libs/HytaleServer.jar"))
}
After saving the file, you need to reload the Gradle project so it picks up the new dependency. In IntelliJ, click the elephant icon in the top right corner or press Ctrl+Shift+O (Windows/Linux) / Cmd+Shift+I (macOS). In other IDEs, look for “Reload Gradle Project” or similar. Wait until the sync completes and shows “BUILD SUCCESSFUL”.
Create the Plugin Manifest
Every Hytale plugin needs a manifest.json in the src/main/resources folder. This tells the server how to load your plugin:
{
"Group": "Example",
"Name": "HelloPlugin",
"Version": "1.0.0",
"Main": "com.example.plugin.HelloPlugin"
}
- Group - A namespace for your plugin
- Name - Your plugin’s name
- Version - Follows semver
- Main - Fully qualified class name of your main plugin class (we’ll create this next)
The Main Plugin Class
Create a package com.example.plugin in src/main/java, then create a new class HelloPlugin.java.
First, let’s set up the basic structure:
package com.example.plugin;
public class HelloPlugin {
}
Now extend JavaPlugin - Hytale’s base class for all plugins:
package com.example.plugin;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
public class HelloPlugin extends JavaPlugin {
}
Add the constructor. It takes a JavaPluginInit parameter which contains metadata like the manifest and data directory:
package com.example.plugin;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import javax.annotation.Nonnull;
public class HelloPlugin extends JavaPlugin {
public HelloPlugin(@Nonnull JavaPluginInit init) {
super(init);
}
}
Override the setup method - this is where we register our command when the plugin loads:
package com.example.plugin;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import javax.annotation.Nonnull;
public class HelloPlugin extends JavaPlugin {
public HelloPlugin(@Nonnull JavaPluginInit init) {
super(init);
}
@Override
protected void setup() {
super.setup();
this.getCommandRegistry().registerCommand(
new HelloCommand("hello", "Shows a hello world title", false)
);
}
}
The Command Class
Now for the interesting part. Create HelloCommand.java in the same package.
Start with an empty class extending AbstractPlayerCommand:
package com.example.plugin;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
import javax.annotation.Nonnull;
public class HelloCommand extends AbstractPlayerCommand {
public HelloCommand(@Nonnull String name, @Nonnull String description, boolean requiresConfirmation) {
super(name, description, requiresConfirmation);
}
}
Why AbstractPlayerCommand?
This is important. Hytale runs each world on its own thread for performance. If you try to access player data from the wrong thread, you’ll get an assertion error. AbstractPlayerCommand handles this automatically - it makes sure your code runs on the correct world thread.
The Execute Method
Now override the execute method. This is where our command logic goes:
Click to show imports
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
@Override
protected void execute(
@Nonnull CommandContext commandContext,
@Nonnull Store<EntityStore> store,
@Nonnull Ref<EntityStore> ref,
@Nonnull PlayerRef playerRef,
@Nonnull World world
) {
// Our code goes here
}
The execute method gives you five parameters:
| Parameter | Purpose |
|---|---|
CommandContext | Who ran the command, what arguments were passed |
Store<EntityStore> | The ECS data store - Hytale uses Entity Component System architecture |
Ref<EntityStore> | A reference to the player’s entity in that store |
PlayerRef | The player component - this is what we need |
World | The current world instance (remember: each world has its own thread!) |
Showing a Title
Add the title display logic. EventTitleUtil.showEventTitleToPlayer displays a banner on the player’s screen:
@Override
protected void execute(
@Nonnull CommandContext commandContext,
@Nonnull Store<EntityStore> store,
@Nonnull Ref<EntityStore> ref,
@Nonnull PlayerRef playerRef,
@Nonnull World world
) {
EventTitleUtil.showEventTitleToPlayer(
playerRef,
Message.raw("Hello world!"),
Message.raw("Like and subscribe :)"),
true
);
}
Don’t forget the imports:
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.util.EventTitleUtil;
Parameters explained:
playerRef- the player to show the title to- First
Message.raw()- primary title text - Second
Message.raw()- secondary subtitle text true- major event flag (bigger, more prominent display)
Complete HelloCommand.java
Here’s the complete command class:
Click to show full code with all imports
package com.example.plugin;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.server.core.util.EventTitleUtil;
import javax.annotation.Nonnull;
public class HelloCommand extends AbstractPlayerCommand {
public HelloCommand(@Nonnull String name, @Nonnull String description, boolean requiresConfirmation) {
super(name, description, requiresConfirmation);
}
@Override
protected void execute(
@Nonnull CommandContext commandContext,
@Nonnull Store<EntityStore> store,
@Nonnull Ref<EntityStore> ref,
@Nonnull PlayerRef playerRef,
@Nonnull World world
) {
EventTitleUtil.showEventTitleToPlayer(
playerRef,
Message.raw("Hello world!"),
Message.raw("Like and subscribe :)"),
true
);
}
}
Build and Deploy
Build the JAR by running the Gradle jar task. You can do this from your IDE’s Gradle panel or run in terminal:
./gradlew jar
Find your JAR in build/libs/, copy it to your server’s mods folder, and restart the server. You should see your plugin loading in the console.
Join the game and run /hello - you’ll see your title banner appear!
Source Code
The full source code is available on GitHub: hytale-example-plugin
Happy modding!