---
title: Creating a Plugin
type: docs
weight: 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/`:

```json
{
  "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`:

```java
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:

```java
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):

```kotlin
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](../plugin-lifecycle) to understand when each method is called.
