--- title: Server Events type: docs weight: 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 >}} ```java 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 >}} ```java 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 >}} ```java 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 >}} ```java 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 >}} ```java 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 >}} ```java 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 >}} ```java 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 ```java 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 ```java public class DependencyPlugin extends JavaPlugin { private final Map loadedDependencies = new HashMap<>(); private final Set 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 ```java public class CommandSecurityPlugin extends JavaPlugin { private final Map> 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 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 ```java public class SchedulerPlugin extends JavaPlugin { private final List 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 >}}