Skip to Content
Hytale logoCommunity-built docsOpen source and updated by the community.
Plugin DevelopmentGetting Started with Plugin Development

Getting Started with Plugin Development

Welcome to Hytale plugin development! This guide will help you create your first plugin.

Prerequisites

Required Tools

  • Java Development Kit (JDK) 21+ - Hytale uses modern Java features
  • IntelliJ IDEA or Eclipse - Recommended IDEs
  • Gradle - Build system (included in project)
  • Git - Version control

Knowledge Requirements

  • Java programming fundamentals
  • Basic understanding of object-oriented programming
  • Familiarity with event-driven architecture (helpful)

Alternative Languages

Kotlin Support: Kotlin is fully compatible with Hytale plugins since both Java and Kotlin compile to JVM bytecode.

“If it supports Java, it also supports Kotlin” - Community consensus

Benefits of Kotlin:

  • Null safety
  • Extension functions
  • Less boilerplate
  • Modern syntax

Important: When using Kotlin, you must shade the Kotlin standard library into your JAR:

// build.gradle.kts plugins { kotlin("jvm") version "1.9.0" id("com.github.johnrengelman.shadow") version "8.1.1" } tasks.shadowJar { // Include Kotlin runtime }

Development Environment Setup

1. Install JDK 21

Windows:

# Download from Oracle or use Chocolatey choco install openjdk21

Mac:

# Using Homebrew brew install openjdk@21

Linux:

# Ubuntu/Debian sudo apt install openjdk-21-jdk

2. Set Up IDE

IntelliJ IDEA (Recommended):

  1. Download IntelliJ IDEA Community Edition
  2. Install Gradle plugin
  3. Configure JDK 21 in Project Structure

Eclipse:

  1. Download Eclipse IDE for Java Developers
  2. Install Buildship Gradle plugin
  3. Configure JDK 21 in Installed JREs

3. Create Hytale Server

Download Hytale Server from official sources:

# Extract server files unzip hytale-server.zip # Run server once to generate files cd hytale-server ./start.sh

Creating Your First Plugin

Project Structure

MyPlugin/ ├── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── myplugin/ │ │ └── MyPlugin.java │ └── resources/ │ └── manifest.json ├── build.gradle └── settings.gradle

1. Initialize Gradle Project

build.gradle:

plugins { id 'java' } group = 'com.example' version = '1.0.0' repositories { mavenCentral() // Hytale repository (when available) maven { url 'https://repo.hytale.com/releases' } } dependencies { // Hytale API compileOnly 'com.hytale:hytale-api:1.0.0' } java { toolchain { languageVersion = JavaLanguageVersion.of(21) } } tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } jar { archiveBaseName = 'MyPlugin' archiveVersion = project.version }

settings.gradle:

rootProject.name = 'MyPlugin'

2. Create Plugin Manifest

The manifest.json file is required in your plugin JAR root. This format was confirmed from the decompiled server source code.

src/main/resources/manifest.json:

{ "Group": "com.example", "Name": "MyPlugin", "Version": "1.0.0", "Description": "My first Hytale plugin", "Authors": [ { "Name": "YourName" } ], "Main": "com.example.myplugin.MyPlugin", "ServerVersion": "*", "Dependencies": {}, "IncludesAssetPack": false }

Manifest Fields Explained:

FieldRequiredDescription
GroupYesPlugin group/namespace (e.g., com.example)
NameYesPlugin name
VersionYesSemantic version (e.g., 1.0.0)
DescriptionNoPlugin description
AuthorsNoArray of author objects with Name field
MainYesFully qualified main class name
ServerVersionNoServer version requirements (* for any)
DependenciesNoMap of plugin dependencies with version ranges
OptionalDependenciesNoOptional plugin dependencies
LoadBeforeNoPlugins this should load before
DisabledByDefaultNoIf true, plugin must be enabled manually
IncludesAssetPackNoSet to true if plugin includes custom assets

Example with Dependencies:

{ "Group": "com.example", "Name": "MyPlugin", "Version": "1.0.0", "Main": "com.example.myplugin.MyPlugin", "ServerVersion": "2026.1.*", "Dependencies": { "Hytale:DamageModule": "*" }, "OptionalDependencies": { "SomePlugin:Economy": ">=1.0.0" } }

3. Create Main Plugin Class

src/main/java/com/example/myplugin/MyPlugin.java:

package com.example.myplugin; import com.hytale.api.plugin.JavaPlugin; import com.hytale.api.event.player.PlayerReadyEvent; import com.hytale.api.message.Message; public class MyPlugin extends JavaPlugin { @Override protected void setup() { getLogger().atInfo().log("Setting up MyPlugin..."); // Register event listener getEventRegistry().registerGlobal(PlayerReadyEvent.class, this::onPlayerReady); // Register command getCommandRegistry().registerCommand(new HelloCommand()); } @Override protected void start() { getLogger().atInfo().log("MyPlugin started successfully!"); } @Override protected void shutdown() { getLogger().atInfo().log("MyPlugin shutting down..."); } private void onPlayerReady(PlayerReadyEvent event) { event.getPlayer().sendMessage( Message.raw("Welcome to the server!") ); } }

4. Create a Simple Command

HelloCommand.java:

package com.example.myplugin; import com.hytale.api.command.CommandBase; import com.hytale.api.command.CommandSender; import com.hytale.api.entity.player.Player; import com.hytale.api.message.Message; public class HelloCommand extends CommandBase { @Override public String getName() { return "hello"; } @Override public String getDescription() { return "Say hello!"; } @Override public void execute(CommandSender sender, String[] args) { if (!(sender instanceof Player)) { sender.sendMessage("Only players can use this command"); return; } Player player = (Player) sender; player.sendMessage(Message.raw("Hello, " + player.getName() + "!")); } }

Building Your Plugin

Using Gradle

# Build the plugin ./gradlew build # Output location # build/libs/MyPlugin-1.0.0.jar

Manual Build (IntelliJ)

  1. Build > Build Project
  2. Find JAR in out/artifacts/ or build/libs/

Installing Your Plugin

1. Copy to Server

# Copy JAR to server mods directory cp build/libs/MyPlugin-1.0.0.jar /path/to/hytale-server/mods/

2. Start Server

cd /path/to/hytale-server ./start.sh

3. Verify Plugin Loaded

Check server console for:

[INFO] Setting up MyPlugin... [INFO] MyPlugin started successfully!

Testing Your Plugin

1. Join Server

Connect to your server using Hytale client:

localhost:5520

2. Test Welcome Message

When you join, you should see:

Welcome to the server!

3. Test Command

In game chat:

/hello

Expected output:

Hello, YourName!

Development Workflow

Hot Reload Setup

Install the HotPluginReload plugin for faster development:

# Copy HotPluginReload to mods cp HotPluginReload.jar /path/to/server/mods/

Workflow:

# 1. Make code changes # 2. Build ./gradlew build # 3. Copy to server cp build/libs/MyPlugin-1.0.0.jar /path/to/server/mods/ # 4. HotPluginReload automatically detects and reloads

Debugging

IntelliJ Remote Debugging:

  1. Add to server start script:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar hytale-server.jar
  1. In IntelliJ: Run > Edit Configurations > Add Remote JVM Debug
  2. Set port to 5005
  3. Start debugging session

Common First Plugin Ideas

1. Welcome Plugin

  • Welcome message on join
  • Configurable message
  • Permission-based VIP message

2. Simple Teleport

  • /spawn command
  • /sethome and /home commands
  • Save locations to file

3. Player Stats

  • Track kills/deaths
  • Display on command
  • Save to database

4. Chat Features

  • Custom chat format
  • Colored names by rank
  • Chat filter

5. Admin Tools

  • /heal command
  • /feed command
  • /fly command

Plugin Architecture Best Practices

1. Separate Concerns

myplugin/ ├── MyPlugin.java # Main class ├── commands/ # All commands │ ├── HelloCommand.java │ └── SpawnCommand.java ├── listeners/ # Event handlers │ └── PlayerListener.java ├── data/ # Data management │ ├── DataStore.java │ └── PlayerData.java └── config/ # Configuration └── ConfigManager.java

2. Use Services

@Override protected void setup() { // Register services for other plugins to use registerService(new EconomyService()); registerService(new PermissionService()); }

3. Handle Errors Gracefully

@Override public void execute(CommandSender sender, String[] args) { try { // Command logic } catch (Exception e) { sender.sendMessage("An error occurred"); getLogger().atSevere().log("Command error", e); } }

4. Use Async for Heavy Operations

CompletableFuture.runAsync(() -> { // Load data from database }).thenAccept(data -> { // Update player on main thread });

Next Steps

Now that you have your first plugin running:

  1. Learn Event System - Event System
  2. Create Commands - Commands
  3. Understand ECS - ECS Architecture
  4. Add Configuration - Configuration
  5. Implement Permissions - Permissions
  6. Study Examples - Complete Examples

Troubleshooting

Plugin Not Loading

Check manifest.json:

  • Correct main class path
  • Valid JSON format
  • Dependencies listed correctly

Check logs:

tail -f logs/latest.log

ClassNotFoundException

  • Ensure all dependencies in build.gradle
  • Verify main class package matches manifest

Events Not Firing

  • Check event is registered in setup()
  • Verify correct event type
  • Check if dependencies required (e.g., DamageModule)

Community Resources

  • Discord - Active community for questions
  • GitHub - Example plugins and libraries
  • Documentation - This site!

Development Tips

  1. Start Simple - Don’t try to build everything at once
  2. Test Frequently - Use hot reload to iterate quickly
  3. Read Examples - Study existing plugins
  4. Ask Questions - Community is helpful
  5. Version Control - Use Git from the start
  6. Document Code - Future you will thank you

Example Development Session

# 1. Create project mkdir MyPlugin && cd MyPlugin gradle init # 2. Add dependencies to build.gradle # 3. Create manifest.json # 4. Write MyPlugin.java # 5. Build ./gradlew build # 6. Copy to server cp build/libs/MyPlugin-1.0.0.jar ~/hytale-server/mods/ # 7. Test cd ~/hytale-server ./start.sh # 8. Verify in logs tail -f logs/latest.log | grep MyPlugin

Ready to dive deeper? Check out the Event System to learn about handling game events!

Last updated on