Source: Decompiled from
HytaleServer.jar-com.hypixel.hytale.server.core.plugin
This document contains the plugin development API for Hytale Server, extracted from the decompiled source code.
| Type | Class | Description |
|---|---|---|
PLUGIN |
JavaPlugin |
Standard server plugin (JAR) |
ADDON |
PluginBase |
Asset addon |
public enum PluginState {
NONE, // Initial state
SETUP, // setup() called
START, // start() called
ENABLED, // Fully enabled
SHUTDOWN, // shutdown() called
DISABLED // Plugin disabled
}package com.example.myplugin;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
public class MyPlugin extends JavaPlugin {
public MyPlugin(JavaPluginInit init) {
super(init);
}
@Override
protected void setup() {
// Called during plugin setup phase
// Register commands, events, configs here
getLogger().info("MyPlugin setting up...");
}
@Override
protected void start() {
// Called when plugin starts
// Plugin is now enabled
getLogger().info("MyPlugin started!");
}
@Override
protected void shutdown() {
// Called when plugin shuts down
// Clean up resources here
getLogger().info("MyPlugin shutting down...");
}
}{
"Group": "com.example",
"Name": "MyPlugin",
"Version": "1.0.0",
"Description": "My awesome Hytale plugin",
"Authors": [
{
"Name": "Your Name",
"Email": "you@example.com",
"Url": "https://example.com"
}
],
"Website": "https://github.com/you/myplugin",
"Main": "com.example.myplugin.MyPlugin",
"ServerVersion": ">=1.0.0",
"Dependencies": {
"com.example/OtherPlugin": ">=1.0.0"
},
"OptionalDependencies": {
"com.example/OptionalPlugin": ">=1.0.0"
},
"LoadBefore": {
"com.example/LoadAfterMe": "*"
},
"DisabledByDefault": false,
"IncludesAssetPack": true
}| Field | Type | Required | Description |
|---|---|---|---|
Group |
String | No | Plugin group/organization |
Name |
String | Yes | Plugin name |
Version |
Semver | No | Plugin version |
Description |
String | No | Plugin description |
Authors |
Array | No | Author information |
Website |
String | No | Plugin website |
Main |
String | No | Main class path |
ServerVersion |
SemverRange | No | Compatible server versions |
Dependencies |
Map | No | Required dependencies |
OptionalDependencies |
Map | No | Optional dependencies |
LoadBefore |
Map | No | Plugins to load after this |
DisabledByDefault |
Boolean | No | Start disabled |
IncludesAssetPack |
Boolean | No | Contains asset pack |
SubPlugins |
Array | No | Nested sub-plugins |
From PluginBase, you have access to:
// Logging
HytaleLogger getLogger();
// Plugin identification
PluginIdentifier getIdentifier();
PluginManifest getManifest();
Path getDataDirectory();
PluginState getState();
String getBasePermission(); // e.g., "com.example.myplugin"
// Registration APIs
CommandRegistry getCommandRegistry();
EventRegistry getEventRegistry();
ClientFeatureRegistry getClientFeatureRegistry();
BlockStateRegistry getBlockStateRegistry();
EntityRegistry getEntityRegistry();
TaskRegistry getTaskRegistry();
AssetRegistry getAssetRegistry();
// Storage
ComponentRegistryProxy<EntityStore> getEntityStoreRegistry();
ComponentRegistryProxy<ChunkStore> getChunkStoreRegistry();@Override
protected void setup() {
// Register a command
getCommandRegistry().registerCommand(new MyCommand());
}public class MyCommand extends AbstractCommand {
private final RequiredArg<String> playerArg;
private final OptionalArg<Integer> amountArg;
private final FlagArg silentFlag;
public MyCommand() {
super("mycommand", "server.commands.mycommand.description");
// Set permission
requirePermission("myplugin.command.mycommand");
// Required arguments
playerArg = withRequiredArg("player", "Target player", ArgumentTypes.STRING);
// Optional arguments (prefixed with -amount)
amountArg = withOptionalArg("amount", "Amount", ArgumentTypes.INTEGER);
// Flag arguments (-silent)
silentFlag = withFlagArg("silent", "Silent mode");
// Add subcommands
addSubCommand(new MySubCommand());
}
@Override
protected CompletableFuture<Void> execute(CommandContext context) {
String playerName = playerArg.get(context);
Integer amount = amountArg.get(context); // May be null
boolean silent = silentFlag.get(context);
// Command implementation
context.sender().sendMessage(Message.raw("Hello, " + playerName));
return null; // or CompletableFuture for async
}
}// Built-in argument types
ArgumentTypes.STRING // String
ArgumentTypes.INTEGER // Integer
ArgumentTypes.FLOAT // Float
ArgumentTypes.DOUBLE // Double
ArgumentTypes.BOOLEAN // Boolean
ArgumentTypes.PLAYER // Player reference
ArgumentTypes.WORLD // World reference
ArgumentTypes.POSITION // Vector3i position
ArgumentTypes.BLOCK_TYPE // Block type
ArgumentTypes.ITEM_TYPE // Item type
ArgumentTypes.GAME_MODE // GameMode enum@Override
protected void setup() {
EventRegistry events = getEventRegistry();
// Simple registration
events.register(PlayerConnectEvent.class, this::onPlayerConnect);
// With priority
events.register(EventPriority.HIGH, PlayerChatEvent.class, this::onPlayerChat);
// Global listener (all keys)
events.registerGlobal(ChunkUnloadEvent.class, this::onChunkUnload);
// Async event
events.registerAsync(PlayerChatEvent.class, this::onPlayerChatAsync);
}
private void onPlayerConnect(PlayerConnectEvent event) {
PlayerRef player = event.getPlayerRef();
getLogger().info(player.getUsername() + " connected!");
}
private void onPlayerChat(PlayerChatEvent event) {
if (event.getContent().contains("badword")) {
event.setCancelled(true);
}
}
private CompletableFuture<PlayerChatEvent> onPlayerChatAsync(CompletableFuture<PlayerChatEvent> future) {
return future.thenApply(event -> {
// Async processing
return event;
});
}public class MyPlugin extends JavaPlugin {
private Config<MyConfig> config;
public MyPlugin(JavaPluginInit init) {
super(init);
// Must be called before setup()
config = withConfig(MyConfig.CODEC);
}
@Override
protected void setup() {
MyConfig cfg = config.get();
getLogger().info("Message: " + cfg.getMessage());
}
}public class MyConfig {
public static final BuilderCodec<MyConfig> CODEC = BuilderCodec
.builder(MyConfig.class, MyConfig::new)
.append(new KeyedCodec<>("message", Codec.STRING),
(c, v) -> c.message = v,
c -> c.message)
.add()
.append(new KeyedCodec<>("maxPlayers", Codec.INTEGER),
(c, v) -> c.maxPlayers = v,
c -> c.maxPlayers)
.add()
.build();
private String message = "Hello World";
private int maxPlayers = 100;
public String getMessage() { return message; }
public int getMaxPlayers() { return maxPlayers; }
}Config file saved to: plugins/<plugin-name>/config.json
// In commands
context.sender().hasPermission("myplugin.admin");
// With PlayerRef
playerRef.hasPermission("myplugin.feature");
// Permission holder interface
public interface PermissionHolder {
boolean hasPermission(String permission);
}Access the permission system:
PermissionsModule perms = PermissionsModule.get();
PermissionProvider provider = perms.getProvider();
// User permissions
provider.addUserPermissions(uuid, Set.of("perm1", "perm2"));
provider.removeUserPermissions(uuid, Set.of("perm1"));
Set<String> userPerms = provider.getUserPermissions(uuid);
// Group permissions
provider.addGroupPermissions("Admin", Set.of("*"));
provider.removeGroupPermissions("Admin", Set.of("perm1"));
Set<String> groupPerms = provider.getGroupPermissions("Admin");
// User-group membership
provider.addUserToGroup(uuid, "Admin");
provider.removeUserFromGroup(uuid, "Admin");
Set<String> userGroups = provider.getGroupsForUser(uuid);TaskRegistry tasks = getTaskRegistry();
// Schedule a task
tasks.scheduleTask("myTask", () -> {
// Task logic
}, 20); // Delay in ticks
// Repeating task
tasks.scheduleRepeatingTask("myRepeatingTask", () -> {
// Runs periodically
}, 0, 100); // Initial delay, periodHytaleLogger logger = getLogger();
// Log levels
logger.info("Information message");
logger.warning("Warning message");
logger.severe("Error message");
// With formatting
logger.at(Level.INFO).log("Player %s joined", playerName);
// With exception
logger.at(Level.SEVERE).withCause(exception).log("Error occurred");AssetRegistry assets = getAssetRegistry();
// Register custom assets
assets.register(myAssetType, myAsset);EntityRegistry entities = getEntityRegistry();
// Register custom entity types
entities.register(myEntityType);BlockStateRegistry blocks = getBlockStateRegistry();
// Register custom block states
blocks.register(myBlockState);- Construction - Plugin JAR loaded, constructor called
- PreLoad -
preLoad()- Configs loaded async - Setup -
setup()- Register commands, events, etc. - Start -
start()- Plugin fully initialized - Enabled - Plugin running normally
- Shutdown -
shutdown()- Cleanup on disable/server stop
boolean isEnabled(); // SETUP, START, or ENABLED
boolean isDisabled(); // NONE, DISABLED, or SHUTDOWN
PluginState getState();@Override
protected void setup() {
// Correct: Register commands/events here
getCommandRegistry().registerCommand(new MyCommand());
getEventRegistry().register(PlayerConnectEvent.class, this::onConnect);
}@Override
protected void shutdown() {
// Save data, cancel tasks, close connections
saveData();
}Path configPath = getDataDirectory().resolve("custom-data.json");// Return CompletableFuture for async commands
@Override
protected CompletableFuture<Void> execute(CommandContext context) {
return CompletableFuture.runAsync(() -> {
// Async work
}).thenRun(() -> {
context.sender().sendMessage(Message.raw("Done!"));
});
}// Good: namespaced permissions
requirePermission("myplugin.command.mycommand");
// Good: use base permission
requirePermission(getBasePermission() + ".admin");package com.example.welcomeplugin;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.event.events.player.PlayerConnectEvent;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
public class WelcomePlugin extends JavaPlugin {
public WelcomePlugin(JavaPluginInit init) {
super(init);
}
@Override
protected void setup() {
getEventRegistry().register(PlayerConnectEvent.class, this::onPlayerConnect);
getCommandRegistry().registerCommand(new WelcomeCommand());
getLogger().info("WelcomePlugin setup complete!");
}
@Override
protected void start() {
getLogger().info("WelcomePlugin started!");
}
private void onPlayerConnect(PlayerConnectEvent event) {
event.getPlayerRef().sendMessage(
Message.raw("Welcome to the server, " + event.getPlayerRef().getUsername() + "!")
);
}
@Override
protected void shutdown() {
getLogger().info("WelcomePlugin shutting down...");
}
}| Package | Description |
|---|---|
com.hypixel.hytale.server.core.plugin |
Plugin base classes |
com.hypixel.hytale.server.core.command |
Command system |
com.hypixel.hytale.server.core.event |
Event system |
com.hypixel.hytale.server.core.permissions |
Permissions |
com.hypixel.hytale.server.core.universe |
World/Player APIs |
com.hypixel.hytale.server.core.entity |
Entity APIs |
com.hypixel.hytale.server.core.inventory |
Inventory APIs |
com.hypixel.hytale.server.core.task |
Task scheduling |
com.hypixel.hytale.common.plugin |
Shared plugin types |
com.hypixel.hytale.event |
Event bus core |
com.hypixel.hytale.codec |
Serialization codecs |