--- 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.