Files
Documentation/content/core-concepts/events/event-reference/server-events.en.md
2026-01-20 20:33:59 +01:00

13 KiB

title, type, weight
title type weight
Server Events docs 6

Events related to server lifecycle, plugins, and system operations.

Server Lifecycle Events

BootEvent

Fired when the server finishes booting up. This is a marker event with no fields.

Package: com.hypixel.hytale.server.core.event.events

{{< tabs items="Fields,Example" >}} {{< tab >}} This event has no fields. It is a simple notification that boot has completed. {{< /tab >}} {{< tab >}}

getEventRegistry().register(BootEvent.class, event -> {
    getLogger().at(Level.INFO).log("Server boot complete!");

    // Initialize post-boot features
    initializeMetrics();
    startBackgroundTasks();
    openConnectionsToExternalServices();
});

{{< /tab >}} {{< /tabs >}}


ShutdownEvent

Fired when the server is shutting down. This is a marker event with priority constants.

Package: com.hypixel.hytale.server.core.event.events

{{< tabs items="Constants,Example" >}} {{< tab >}}

Constant Value Description
DISCONNECT_PLAYERS -48 Priority for disconnecting players
UNBIND_LISTENERS -40 Priority for unbinding network listeners
SHUTDOWN_WORLDS -32 Priority for shutting down worlds

Use these constants with EventPriority to order shutdown handlers. {{< /tab >}} {{< tab >}}

getEventRegistry().register(ShutdownEvent.class, event -> {
    getLogger().at(Level.INFO).log("Server shutting down!");

    // Perform cleanup
    saveAllPlayerData();
    closeExternalConnections();
    flushMetrics();
});

// Use priority constants for ordering
getEventRegistry().register(
    ShutdownEvent.DISCONNECT_PLAYERS,
    ShutdownEvent.class,
    event -> {
        // Notify players before disconnect
        Universe.get().getPlayers().forEach(player ->
            player.sendMessage(Message.raw("Server shutting down!"))
        );
    }
);

{{< /tab >}} {{< /tabs >}}

{{< callout type="warning" >}} Important: Keep shutdown handlers fast and synchronous. The server may force-terminate if handlers take too long. {{< /callout >}}


Plugin Events

PluginSetupEvent

Fired when a plugin is being set up (before start).

Package: com.hypixel.hytale.server.core.event.events.plugin

{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}

Field Type Description
plugin JavaPlugin The plugin being set up
pluginInfo PluginInfo Plugin metadata
{{< /tab >}}
{{< tab >}}
  • getPlugin() - Returns the plugin instance
  • getPluginInfo() - Returns plugin metadata {{< /tab >}} {{< tab >}}
getEventRegistry().register(PluginSetupEvent.class, event -> {
    PluginInfo info = event.getPluginInfo();

    getLogger().at(Level.INFO).log("Plugin setting up: " + info.getName() +
        " v" + info.getVersion());

    // Check for plugin dependencies
    if (isDependencyPlugin(info.getName())) {
        registerDependencyHooks(event.getPlugin());
    }
});

{{< /tab >}} {{< /tabs >}}


PluginEnableEvent

Fired when a plugin is enabled.

Package: com.hypixel.hytale.server.core.event.events.plugin

{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}

Field Type Description
plugin JavaPlugin The enabled plugin
{{< /tab >}}
{{< tab >}}
  • getPlugin() - Returns the plugin instance {{< /tab >}} {{< tab >}}
getEventRegistry().register(PluginEnableEvent.class, event -> {
    JavaPlugin plugin = event.getPlugin();

    getLogger().at(Level.INFO).log("Plugin enabled: " + plugin.getName());

    // Hook into other plugins
    if (plugin.getName().equals("Economy")) {
        hookEconomyPlugin(plugin);
    }
});

{{< /tab >}} {{< /tabs >}}


PluginDisableEvent

Fired when a plugin is disabled.

Package: com.hypixel.hytale.server.core.event.events.plugin

{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}

Field Type Description
plugin JavaPlugin The disabled plugin
{{< /tab >}}
{{< tab >}}
  • getPlugin() - Returns the plugin instance {{< /tab >}} {{< tab >}}
getEventRegistry().register(PluginDisableEvent.class, event -> {
    JavaPlugin plugin = event.getPlugin();

    getLogger().at(Level.INFO).log("Plugin disabled: " + plugin.getName());

    // Unhook from other plugins
    if (plugin.getName().equals("Economy")) {
        unhookEconomyPlugin();
    }
});

{{< /tab >}} {{< /tabs >}}


Tick Events

ServerTickEvent

Fired every server tick (typically 20 times per second).

Package: com.hypixel.hytale.server.core.event.events.server

{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}

Field Type Description
tickNumber long Current tick number
deltaTime float Time since last tick (seconds)
{{< /tab >}}
{{< tab >}}
  • getTickNumber() - Returns current tick count
  • getDeltaTime() - Returns delta time in seconds {{< /tab >}} {{< tab >}}
getEventRegistry().register(ServerTickEvent.class, event -> {
    long tick = event.getTickNumber();

    // Run every second (20 ticks)
    if (tick % 20 == 0) {
        updateScoreboards();
    }

    // Run every minute (1200 ticks)
    if (tick % 1200 == 0) {
        saveAutoSave();
        cleanupExpiredData();
    }
});

{{< /tab >}} {{< /tabs >}}

{{< callout type="warning" >}} Performance Critical: This event fires 20 times per second. Keep handlers extremely lightweight. Use tick counting for periodic tasks instead of running on every tick. {{< /callout >}}


Command Events

CommandExecuteEvent

{{< badge "Cancellable" >}}

Fired when a command is executed.

Package: com.hypixel.hytale.server.core.event.events.command

{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}

Field Type Description
sender CommandSender Who executed the command
command String Command name
args String[] Command arguments
{{< /tab >}}
{{< tab >}}
  • getSender() - Returns the command sender
  • getCommand() - Returns command name
  • getArgs() - Returns arguments array
  • isCancelled() - Check if cancelled
  • setCancelled(boolean) - Cancel command {{< /tab >}} {{< tab >}}
getEventRegistry().register(CommandExecuteEvent.class, event -> {
    CommandSender sender = event.getSender();
    String command = event.getCommand();

    // Log all commands
    getLogger().at(Level.INFO).log(sender.getName() + " executed: /" + command +
        " " + String.join(" ", event.getArgs()));

    // Block certain commands for non-ops
    if (command.equals("stop") && !sender.isOp()) {
        event.setCancelled(true);
        sender.sendMessage("You don't have permission!");
    }
});

{{< /tab >}} {{< /tabs >}}


Practical Examples

Server Metrics Plugin

public class MetricsPlugin extends JavaPlugin {

    private long startTime;
    private long tickCount = 0;
    private long lastTickTime;

    @Override
    public void start() {
        // Track server boot
        getEventRegistry().register(BootEvent.class, event -> {
            startTime = System.currentTimeMillis();
            lastTickTime = startTime;
            getLogger().at(Level.INFO).log("Server boot complete, tracking metrics...");
        });

        // Calculate TPS
        getEventRegistry().register(ServerTickEvent.class, event -> {
            tickCount++;

            // Calculate TPS every second
            if (tickCount % 20 == 0) {
                long now = System.currentTimeMillis();
                long elapsed = now - lastTickTime;
                double tps = 20000.0 / elapsed;
                lastTickTime = now;

                if (tps < 18.0) {
                    getLogger().warning("Low TPS: " + String.format("%.2f", tps));
                }
            }
        });

        // Save metrics on shutdown
        getEventRegistry().register(ShutdownEvent.class, event -> {
            long uptime = System.currentTimeMillis() - startTime;
            saveMetrics(uptime, tickCount);
        });
    }
}

Plugin Dependency Manager

public class DependencyPlugin extends JavaPlugin {

    private final Map<String, JavaPlugin> loadedDependencies = new HashMap<>();
    private final Set<String> requiredPlugins = Set.of("Economy", "Permissions");

    @Override
    public void start() {
        // Track plugin loading
        getEventRegistry().register(PluginEnableEvent.class, event -> {
            JavaPlugin plugin = event.getPlugin();

            if (requiredPlugins.contains(plugin.getName())) {
                loadedDependencies.put(plugin.getName(), plugin);
                getLogger().at(Level.INFO).log("Dependency loaded: " + plugin.getName());

                // Check if all dependencies are loaded
                if (loadedDependencies.keySet().containsAll(requiredPlugins)) {
                    initializeDependentFeatures();
                }
            }
        });

        // Handle dependency unload
        getEventRegistry().register(PluginDisableEvent.class, event -> {
            JavaPlugin plugin = event.getPlugin();

            if (loadedDependencies.remove(plugin.getName()) != null) {
                getLogger().warning("Dependency unloaded: " + plugin.getName());
                disableDependentFeatures();
            }
        });
    }
}

Command Logging & Rate Limiting

public class CommandSecurityPlugin extends JavaPlugin {

    private final Map<UUID, List<Long>> commandHistory = new HashMap<>();
    private static final int MAX_COMMANDS_PER_SECOND = 5;

    @Override
    public void start() {
        getEventRegistry().register(CommandExecuteEvent.class, event -> {
            CommandSender sender = event.getSender();

            // Only rate limit players
            if (!(sender instanceof Player)) return;

            Player player = (Player) sender;
            UUID uuid = player.getUuid();

            // Get command history
            List<Long> history = commandHistory.computeIfAbsent(
                uuid, k -> new ArrayList<>()
            );

            long now = System.currentTimeMillis();

            // Remove old entries (older than 1 second)
            history.removeIf(time -> now - time > 1000);

            // Check rate limit
            if (history.size() >= MAX_COMMANDS_PER_SECOND) {
                event.setCancelled(true);
                player.sendMessage("Too many commands! Please slow down.");
                getLogger().warning("Rate limited: " + player.getDisplayName());
                return;
            }

            // Record this command
            history.add(now);

            // Log to file
            logCommand(player, event.getCommand(), event.getArgs());
        });

        // Cleanup on disconnect
        getEventRegistry().register(PlayerDisconnectEvent.class, event -> {
            commandHistory.remove(event.getPlayer().getUuid());
        });
    }
}

Scheduled Tasks Manager

public class SchedulerPlugin extends JavaPlugin {

    private final List<ScheduledTask> tasks = new ArrayList<>();

    @Override
    public void start() {
        // Schedule various tasks
        scheduleTask("autosave", 6000, this::autoSave);      // Every 5 minutes
        scheduleTask("cleanup", 72000, this::cleanup);        // Every hour
        scheduleTask("broadcast", 12000, this::broadcast);    // Every 10 minutes

        // Execute tasks based on tick
        getEventRegistry().register(ServerTickEvent.class, event -> {
            long tick = event.getTickNumber();

            for (ScheduledTask task : tasks) {
                if (tick % task.interval() == 0) {
                    try {
                        task.runnable().run();
                    } catch (Exception e) {
                        getLogger().error("Task failed: " + task.name(), e);
                    }
                }
            }
        });
    }

    private void scheduleTask(String name, int intervalTicks, Runnable runnable) {
        tasks.add(new ScheduledTask(name, intervalTicks, runnable));
    }

    record ScheduledTask(String name, int interval, Runnable runnable) {}
}

Best Practices

{{< callout type="info" >}} Server Event Guidelines:

  • Keep ShutdownEvent handlers fast and reliable
  • Use tick counting in ServerTickEvent for periodic tasks
  • Clean up resources in PluginDisableEvent
  • Initialize cross-plugin features in PluginEnableEvent
  • Log important command executions for auditing {{< /callout >}}

{{< callout type="error" >}} Critical: Never perform blocking operations (I/O, network, database) directly in ServerTickEvent. Use async tasks instead. {{< /callout >}}