This guide shows patterns for handling real-time events in your plugins.Documentation Index
Fetch the complete documentation index at: https://new-docs.simplecloud.app/llms.txt
Use this file to discover all available pages before exploring further.
Basic Event Handling
Subscribe to Events
// Subscribe returns a Subscription object
Subscription sub = api.event().server().onStarted(event -> {
System.out.println("Server started: " + event.getServerId());
});
// Remember to close when done
sub.close();
Plugin Lifecycle Management
public class MyPlugin extends JavaPlugin {
private CloudApi api;
private final List<Subscription> subscriptions = new ArrayList<>();
@Override
public void onEnable() {
api = CloudApi.create();
registerEvents();
}
@Override
public void onDisable() {
// Clean up all subscriptions
subscriptions.forEach(Subscription::close);
subscriptions.clear();
}
private void registerEvents() {
subscriptions.add(api.event().server().onStarted(this::onServerStarted));
subscriptions.add(api.event().server().onStopped(this::onServerStopped));
subscriptions.add(api.event().group().onUpdated(this::onGroupUpdated));
}
private void onServerStarted(ServerStartedEvent event) {
getLogger().info("Server started: " + event.getServerId());
}
private void onServerStopped(ServerStoppedEvent event) {
getLogger().info("Server stopped: " + event.getServerId());
}
private void onGroupUpdated(GroupUpdatedEvent event) {
getLogger().info("Group updated: " + event.getServerGroupId());
}
}
Common Event Patterns
Auto-Start Servers When Group Empty
public void setupAutoStart(String groupName, int minimum) {
api.event().server().onStopped(event -> {
if (!event.getGroupName().equals(groupName)) return;
api.server().getServersByGroup(groupName).thenAccept(servers -> {
long running = servers.stream()
.filter(s -> s.getState() != ServerState.STOPPING)
.count();
if (running < minimum) {
api.group().getGroupByName(groupName).thenAccept(group -> {
if (group != null) {
api.server().startServer(new StartServerRequest(group.getId(), groupName));
}
});
}
});
});
}
Log All State Changes
public void setupStateLogging() {
api.event().server().onStateChanged(event -> {
String message = String.format("[%s] %s → %s",
event.getServerId(),
event.getOldState(),
event.getNewState());
// Log to file, database, or external service
logger.info(message);
});
}
Notify Staff on Server Crash
public void setupCrashNotifications() {
api.event().server().onStopped(event -> {
api.server().getServerById(event.getServerId()).thenAccept(server -> {
// If server stopped unexpectedly (not graceful shutdown)
// This is a simplified check - adjust based on your needs
notifyStaff(Component.text("[Alert] Server stopped: " + event.getServerId())
.color(NamedTextColor.RED));
});
});
}
private void notifyStaff(Component message) {
api.player().getOnlinePlayers().thenAccept(players -> {
players.stream()
.filter(p -> hasStaffPermission(p))
.forEach(p -> p.sendMessage(message));
});
}
Sync Data When Server Starts
public void setupDataSync() {
api.event().server().onStateChanged(event -> {
if (event.getNewState() == ServerState.AVAILABLE) {
// Server is ready, sync data
syncDataToServer(event.getServerId());
}
});
}
private void syncDataToServer(String serverId) {
// Your data synchronization logic
System.out.println("Syncing data to: " + serverId);
}
Filtering Events
Filter by Group
Server events fire for both group servers and persistent servers. When filtering by group name, persistent server events have an emptygroupName and are skipped automatically.
public void watchGroup(String groupName) {
api.event().server().onStarted(event -> {
if (event.getGroupName().equals(groupName)) {
handleGroupServerStart(event);
}
});
}
Filter by Server Type
public void watchProxies() {
api.event().server().onStarted(event -> {
api.group().getGroupByName(event.getGroupName()).thenAccept(group -> {
if (group != null && group.getType() == GroupServerType.PROXY) {
handleProxyStart(event);
}
});
});
}
One-Time Events
Wait for Specific Server
public CompletableFuture<Void> waitForServer(String serverId) {
CompletableFuture<Void> future = new CompletableFuture<>();
Subscription sub = api.event().server().onStateChanged(event -> {
if (event.getServerId().equals(serverId) &&
event.getNewState() == ServerState.AVAILABLE) {
future.complete(null);
}
});
// Clean up subscription when future completes
future.whenComplete((result, error) -> sub.close());
return future;
}
// Usage
waitForServer("lobby-1").thenRun(() -> {
System.out.println("Server is ready!");
});
Timeout Handling
public CompletableFuture<Void> waitForServerWithTimeout(String serverId, Duration timeout) {
CompletableFuture<Void> future = new CompletableFuture<>();
Subscription sub = api.event().server().onStateChanged(event -> {
if (event.getServerId().equals(serverId) &&
event.getNewState() == ServerState.AVAILABLE) {
future.complete(null);
}
});
// Timeout after duration
CompletableFuture.delayedExecutor(timeout.toMillis(), TimeUnit.MILLISECONDS)
.execute(() -> future.completeExceptionally(
new TimeoutException("Server did not start in time")));
future.whenComplete((result, error) -> sub.close());
return future;
}