Files
Documentation/content/getting-started/creating-a-plugin.en.md
2026-01-20 20:33:59 +01:00

5.0 KiB

title, type, weight
title type weight
Creating a Plugin docs 3

This guide walks you through creating your first Hytale plugin from scratch.

Project Structure

A typical Hytale plugin project has this structure:

my-plugin/
├── app/
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/example/myplugin/
│       │   │       └── MyPlugin.java
│       │   └── resources/
│       │       └── manifest.json
│       └── test/
│           └── java/
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
├── build.gradle.kts
├── settings.gradle.kts
└── gradlew

The manifest.json

Every plugin requires a manifest.json file in src/main/resources/:

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

Manifest Fields

Field Required Description
Group Yes Package group (e.g., "com.example")
Name Yes Plugin name (used for identification)
Version Yes Semantic version (e.g., "1.0.0")
Description No Brief description of the plugin
Authors No List of authors with Name field
Main Yes Fully qualified main class name
ServerVersion Yes Server version compatibility ("*" for any)
Dependencies No Required plugin dependencies
OptionalDependencies No Optional plugin dependencies
DisabledByDefault No Whether plugin is disabled by default
IncludesAssetPack No Whether plugin includes assets
SubPlugins No List of sub-plugins

{{< callout type="warning" >}} All manifest field names use PascalCase (e.g., ServerVersion, not serverVersion). {{< /callout >}}

Main Plugin Class

Create your main plugin class extending JavaPlugin:

package com.example.myplugin;

import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import java.util.logging.Level;

public class MyPlugin extends JavaPlugin {

    public MyPlugin(JavaPluginInit init) {
        super(init);
    }

    @Override
    public void setup() {
        // Called during plugin initialization
        // Register configs, prepare resources
        getLogger().at(Level.INFO).log("MyPlugin is setting up!");
    }

    @Override
    public void start() {
        // Called when the plugin starts
        // Register commands, events, entities
        getLogger().at(Level.INFO).log("MyPlugin has started!");
    }

    @Override
    public void shutdown() {
        // Called when the plugin is stopping
        // Clean up resources
        getLogger().at(Level.INFO).log("MyPlugin is shutting down!");
    }
}

{{< callout type="info" >}} The constructor with JavaPluginInit parameter is required. Always call super(init). {{< /callout >}}

Logger API

Hytale uses a Flogger-based logging API:

import java.util.logging.Level;

// Basic logging
getLogger().at(Level.INFO).log("Information message");
getLogger().at(Level.WARNING).log("Warning message");
getLogger().at(Level.SEVERE).log("Error message");

// With formatting
getLogger().at(Level.INFO).log("Player %s joined the game", playerName);

build.gradle.kts

Configure your Gradle build file (Kotlin DSL):

plugins {
    java
}

group = "com.example"
version = "1.0.0"

repositories {
    mavenCentral()
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(25)
    }
}

dependencies {
    // Hytale Server API - compile only since it's provided at runtime
    compileOnly(files("../../../HytaleServer.jar"))

    // Testing
    testImplementation(libs.junit)
}

tasks.jar {
    archiveBaseName.set("MyPlugin")
}

{{< callout type="info" >}} The path to HytaleServer.jar depends on where your plugin source is located relative to the game directory. {{< /callout >}}

Available Registries

Your plugin has access to several registries through the base class:

Method Registry Type Purpose
getEventRegistry() EventRegistry Register event listeners
getCommandRegistry() CommandRegistry Register commands
getEntityRegistry() EntityRegistry Register custom entities
getBlockStateRegistry() BlockStateRegistry Register block states
getTaskRegistry() TaskRegistry Schedule tasks
getAssetRegistry() AssetRegistry Register assets
getEntityStoreRegistry() EntityStoreRegistry Register entity components
getChunkStoreRegistry() ChunkStoreRegistry Register chunk components

Next Steps

Learn about the Plugin Lifecycle to understand when each method is called.