### Start a server using Impulse CLI Source: https://github.com/arson-club/impulse/blob/main/docs/reference/start-command.md The 'impulse start' command initiates a configured server. Provide the server name as defined in 'config.yaml'. This is beneficial for scripting or preparing server instances before client connections. Aliases include 'impulse warm'. ```bash impulse start ``` ```bash impulse start smp ``` -------------------------------- ### Example JAR Broker Command Source: https://github.com/arson-club/impulse/blob/main/docs/getting_started/jar_broker.md Illustrates the equivalent shell command executed by the JAR broker based on the provided YAML configuration. This command launches the Minecraft server with specified JVM and JAR arguments. ```shell java -Xms4G -Xmx4G -jar fabric.jar --nogui ``` -------------------------------- ### Example Docker Server Configuration Source: https://github.com/arson-club/impulse/blob/main/docs/reference/docker-broker.md This YAML configuration demonstrates how to set up a 'docker' type server within the Impulse project. It includes essential Docker options like port bindings, volume mounts for data persistence, and environment variables for the container. ```yaml servers: - name: "lobby" type: "docker" docker: portBindings: - "25566:25565" volumes: - "/path/to/host/data:/data" env: ONLINE_MODE: "false" EULA: "true" ``` -------------------------------- ### Minecraft EULA Configuration Source: https://github.com/arson-club/impulse/blob/main/docs/getting_started/jar_broker.md Demonstrates the required change in the `eula.txt` file to accept the Minecraft End User License Agreement, which is necessary for the server to start. ```properties eula=true ``` -------------------------------- ### Impulse Reconcile Command Example Source: https://github.com/arson-club/impulse/blob/main/docs/reference/reconcile-command.md An example demonstrating how to use the 'impulse reconcile' command to reconcile a specific server named 'smp'. This command forces an immediate configuration reload and restart for the specified server, overriding the default automatic reconciliation behavior. ```bash impulse reconcile smp ``` -------------------------------- ### Minecraft server.properties Example Source: https://github.com/arson-club/impulse/blob/main/docs/getting_started/jar_broker.md Shows how to configure the server port in the `server.properties` file. This is necessary when Velocity is already using the default Minecraft port (25565). ```properties server-port=25566 ``` -------------------------------- ### Configure Spigot Server with Custom Java Options Source: https://context7.com/arson-club/impulse/llms.txt Configuration for a Spigot server with custom Java installation settings. Disables auto-start and auto-stop, and includes specific Java flags for IPv4 preference and EULA agreement. ```yaml servers: - name: spigot-dev type: jar lifecycleSettings: allowAutoStart: false allowAutoStop: false jar: workingDirectory: "/home/dev/minecraft/spigot" jarFile: "spigot-1.20.4.jar" address: "127.0.0.1:25590" javaFlags: - "-Xms2G" - "-Xmx2G" - "-Djava.net.preferIPv4Stack=true" - "-Dcom.mojang.eula.agree=true" flags: - "--nogui" - "--world-dir=worlds" - "--plugins=plugins" ``` -------------------------------- ### Configure Systemd Managed Server Source: https://context7.com/arson-club/impulse/llms.txt Configuration for a server managed by systemd, launched via a command. Auto-start and auto-stop are disabled. Specifies the working directory, address, and the systemctl command to start the service. ```yaml servers: - name: systemd-managed type: cmd lifecycleSettings: allowAutoStart: false allowAutoStop: false cmd: workingDirectory: "/tmp" address: "127.0.0.1:25610" command: - "/usr/bin/systemctl" - "start" - "minecraft-server.service" ``` -------------------------------- ### Implement Kubernetes Broker Interface for Server Lifecycle Management (Kotlin) Source: https://context7.com/arson-club/impulse/llms.txt This Kotlin code defines a custom broker implementation for managing Minecraft servers deployed on Kubernetes. It implements the `Broker` interface to handle server lifecycle events such as starting, stopping, removing, and reconciling server configurations. Dependencies include the Impulse API and a Kubernetes client library. ```kotlin import club.arson.impulse.api.server.Broker import club.arson.impulse.api.server.Status import club.arson.impulse.api.config.ServerConfig import java.net.InetSocketAddress import java.util.logging.Logger // Example: Implementing a custom broker for Kubernetes class KubernetesBroker( private val config: ServerConfig, private val logger: Logger? ) : Broker { override fun getStatus(): Status { val pod = kubernetesClient.getPod(config.name) return when (pod?.status?.phase) { "Running" -> Status.RUNNING "Succeeded", "Failed" -> Status.STOPPED null -> Status.REMOVED else -> Status.UNKNOWN } } override fun isRunning(): Boolean = getStatus() == Status.RUNNING override fun address(): Result { return try { val service = kubernetesClient.getService(config.name) val address = InetSocketAddress(service.clusterIP, 25565) Result.success(address) } catch (e: Exception) { Result.failure(e) } } override fun startServer(): Result { return try { logger?.info("Starting Kubernetes deployment: ${config.name}") kubernetesClient.scale(config.name, replicas = 1) Result.success(Unit) } catch (e: Exception) { logger?.error("Failed to start server", e) Result.failure(e) } } override fun stopServer(): Result { return try { logger?.info("Stopping Kubernetes deployment: ${config.name}") kubernetesClient.scale(config.name, replicas = 0) Result.success(Unit) } catch (e: Exception) { Result.failure(e) } } override fun removeServer(): Result { return try { logger?.info("Removing Kubernetes resources: ${config.name}") kubernetesClient.deleteDeployment(config.name) kubernetesClient.deleteService(config.name) Result.success(Unit) } catch (e: Exception) { Result.failure(e) } } override fun reconcile(config: ServerConfig): Result { val currentSpec = kubernetesClient.getDeployment(this.config.name)?.spec val newSpec = buildDeploymentSpec(config) return if (currentSpec != newSpec) { Result.success(Runnable { logger?.info("Reconciling deployment: ${config.name}") kubernetesClient.updateDeployment(config.name, newSpec) }) } else { Result.success(null) // No changes needed } } } ``` -------------------------------- ### Configure Impulse Docker Broker for SMP Server Source: https://github.com/arson-club/impulse/blob/main/docs/getting_started/docker_broker.md This YAML configuration defines an SMP server managed by Docker within Impulse. It specifies the Docker image, port mappings, environment variables for server setup (like Fabric and offline mode), and volume mounts for persistent data. ```yaml instanceName: MyCoolSMP servers: - name: smp type: docker lifecycleSettings: timeouts: inactiveGracePeriod: 300 docker: image: "itzg/minecraft-server:latest" portBindings: - "25566:25565" env: ONLINE_MODE: "FALSE" TYPE: "FABRIC" EULA: "TRUE" MODRINTH_PROJECTS: "fabricproxy-lite" volumes: - "/srv/smp:/data" ``` -------------------------------- ### Kotlin Server Control Command for Advanced Server Management Source: https://context7.com/arson-club/impulse/llms.txt This Kotlin command allows players to interact with server instances, performing actions like starting, stopping, removing, pinning, unpinning, reconciling configuration, scheduling shutdowns, and checking status. It requires the Velocity API and Impulse's ServiceRegistry. The command takes the server name and an action as arguments. ```kotlin import club.arson.impulse.ServiceRegistry import com.velocitypowered.api.proxy.Player import net.kyori.adventure.text.Component import kotlin.time.Duration.Companion.minutes // Example: Custom command for advanced server control class ServerControlCommand : SimpleCommand { override fun execute(invocation: SimpleCommand.Invocation) { val args = invocation.arguments() val player = invocation.source() as? Player ?: return if (args.isEmpty()) { player.sendMessage(Component.text("Usage: /serverctl ")) return } val serverName = args[0] val action = args.getOrNull(1) ?: "status" val serverManager = ServiceRegistry.instance.serverManager val server = serverManager?.getServer(serverName) if (server == null) { player.sendMessage(Component.text("Server $serverName not found")) return } when (action.lowercase()) { "start", "warm" -> { player.sendMessage(Component.text("Starting $serverName...")) server.startServer() .onSuccess { server.awaitReady() .onSuccess { player.sendMessage(Component.text("$serverName is ready!")) player.createConnectionRequest(server.serverRef).fireAndForget() } .onFailure { player.sendMessage(Component.text("$serverName failed to respond")) } } .onFailure { e -> player.sendMessage(Component.text("Failed to start: ${e.message}")) } } "stop" -> { if (server.pinned) { player.sendMessage(Component.text("$serverName is pinned, unpin first")) return } player.sendMessage(Component.text("Stopping $serverName...")) server.stopServer() .onSuccess { player.sendMessage(Component.text("$serverName stopped")) } .onFailure { e -> player.sendMessage(Component.text("Error: ${e.message}")) } } "remove" -> { player.sendMessage(Component.text("Removing $serverName...")) server.removeServer() .onSuccess { player.sendMessage(Component.text("$serverName removed")) } .onFailure { e -> player.sendMessage(Component.text("Error: ${e.message}")) } } "pin" -> { server.pinned = true player.sendMessage(Component.text("$serverName pinned (won't auto-stop)")) } "unpin" -> { server.pinned = false player.sendMessage(Component.text("$serverName unpinned")) } "reconcile" -> { player.sendMessage(Component.text("Reconciling $serverName configuration...")) server.reconcile(server.config) .onSuccess { player.sendMessage(Component.text("Reconciliation scheduled")) } .onFailure { e -> player.sendMessage(Component.text("Error: ${e.message}")) } } "schedule-stop" -> { val delay = args.getOrNull(2)?.toLongOrNull() ?: 300 player.sendMessage(Component.text("Scheduling stop in $delay seconds...")) server.scheduleShutdown(delay) .onSuccess { player.sendMessage(Component.text("Stop scheduled")) } } "status" -> { val status = server.getStatus() val players = server.serverRef.playersConnected.size val pinned = if (server.pinned) " [PINNED]" else "" val autoStart = server.config.lifecycleSettings.allowAutoStart val autoStop = server.config.lifecycleSettings.allowAutoStop player.sendMessage(Component.text(""" $serverName Status: - State: $status$pinned - Players: $players - Auto-start: $autoStart - Auto-stop: $autoStop - Broker: ${server.config.type} """.trimIndent())) } else -> { player.sendMessage(Component.text("Unknown action: $action")) } } } } ``` -------------------------------- ### Set Default Server with 'try' Block in Velocity Source: https://github.com/arson-club/impulse/blob/main/docs/getting_started/velocity_configuration.md This TOML snippet configures the 'try' block in Velocity, specifying which server(s) players should attempt to connect to by default. By listing 'smp' as the first and only option, all players will be directed to the SMP server upon connecting to the proxy. ```toml try = ["smp"] ``` -------------------------------- ### RegisterBrokerEvent: Load Brokers from Custom Directory (Kotlin) Source: https://context7.com/arson-club/impulse/llms.txt Demonstrates how to use the RegisterBrokerEvent to load broker implementations from a specified directory at runtime. It includes logic for creating the directory if it doesn't exist, iterating through JAR files, validating them, and firing the event. Dependencies include Impulse API, Velocity API, and Java NIO. Input is a directory path, and output is broker registration status logged to the console. ```kotlin import club.arson.impulse.api.events.RegisterBrokerEvent import com.velocitypowered.api.event.Subscribe import com.velocitypowered.api.event.ResultedEvent.GenericResult import java.nio.file.Path import java.nio.file.Paths import java.nio.file.Files import java.util.jar.JarFile import net.kyori.adventure.text.Component // Assuming proxy, logger, and BrokerFactory are available in the scope // Example: Plugin that loads brokers from a custom directory class BrokerLoader { private val customBrokerDir = Paths.get("/srv/minecraft/custom-brokers") @Subscribe fun onProxyInitialize(event: ProxyInitializeEvent) { // Assuming ProxyInitializeEvent is available loadCustomBrokers() } private fun loadCustomBrokers() { val eventManager = proxy.eventManager if (!Files.exists(customBrokerDir)) { Files.createDirectories(customBrokerDir) logger.info("Created custom broker directory: $customBrokerDir") return } Files.walk(customBrokerDir) .filter { it.toString().endsWith(".jar") } .forEach { jarPath -> logger.info("Attempting to load broker from: ${jarPath.fileName}") // Validate JAR before loading if (!validateBrokerJar(jarPath)) { logger.warn("Skipping invalid broker JAR: ${jarPath.fileName}") return@forEach } // Fire event to register broker val event = RegisterBrokerEvent(jarPath) eventManager.fire(event).thenAccept { resultEvent -> if (resultEvent.result.isAllowed) { logger.info("Successfully loaded broker: ${jarPath.fileName}") } else { logger.error("Failed to load broker: ${jarPath.fileName}") logger.error("Reason: ${resultEvent.result.reasonComponent.orElse(null)}") } } } } private fun validateBrokerJar(jarPath: Path): Boolean { try { // Basic validation: check if JAR contains broker factory JarFile(jarPath.toFile()).use { jar -> val hasFactory = jar.entries().asSequence() .filter { it.name.endsWith(".class") } .any { entry -> val className = entry.name .replace("/", ".") .removeSuffix(".class") // Load class and check if it implements BrokerFactory try { val clazz = Class.forName(className) BrokerFactory::class.java.isAssignableFrom(clazz) } catch (e: Exception) { false } } if (!hasFactory) { logger.warn("JAR missing BrokerFactory implementation: ${jarPath.fileName}") return false } // Check for required metadata val manifest = jar.manifest val brokerName = manifest?.mainAttributes?.getValue("Impulse-Broker-Name") if (brokerName == null) { logger.warn("JAR missing Impulse-Broker-Name in manifest") return false } return true } } catch (e: Exception) { logger.error("Failed to validate broker JAR", e) return false } } } ``` -------------------------------- ### Configuring Command-based Custom Server with Impulse Source: https://context7.com/arson-club/impulse/llms.txt This snippet illustrates setting up a custom server launched via a command with Impulse. It defines the working directory, address, and the command to execute, including its arguments. This is useful for launching bespoke server applications. ```yaml # Command-based custom server - name: minigames type: cmd lifecycleSettings: allowAutoStart: false # Manual start only allowAutoStop: false # Manual stop only cmd: workingDirectory: "/srv/minecraft/minigames" address: "127.0.0.1:25568" command: - "/usr/local/bin/minigame-launcher" - "--port=25568" - "--mode=skywars" ``` -------------------------------- ### Configure Bedrock Server Source: https://context7.com/arson-club/impulse/llms.txt Configuration for a Bedrock Edition server launched via a command. Sets auto-start, a startup timeout, working directory, network address, and the command to execute the server binary. ```yaml servers: - name: bedrock type: cmd lifecycleSettings: allowAutoStart: true timeouts: startup: 60 cmd: workingDirectory: "/srv/minecraft/bedrock" address: "127.0.0.1:19132" command: - "./bedrock_server" ``` -------------------------------- ### Customizing Server Messages in Impulse Source: https://context7.com/arson-club/impulse/llms.txt This snippet shows how to customize the messages displayed by Impulse for various server events. It allows for user-defined text and color codes for messages like server starting, timeouts, and auto-start notifications. ```yaml messages: serverStarting: "Server is starting, please wait..." serverTimeout: "Server failed to start in time" autoStartDisabled: "This server requires manual activation" reconciliationWarning: "Server will restart in {time} seconds due to config changes" ``` -------------------------------- ### Include Impulse API in build.gradle Source: https://github.com/arson-club/impulse/blob/main/docs/contributing/creating-a-broker.md Adds the Impulse API dependency to your project and configures the Maven repository for fetching the library. This is essential for building a custom broker. ```groovy dependencies { implementation 'club.arson.impulse:impulse-api' } repositories { maven { name = "Impulse" url = uri("https://maven.pkg.github.com/Arson-Club/Impulse") } } ``` -------------------------------- ### Register Kubernetes Broker with Kotlin BrokerFactory Source: https://context7.com/arson-club/impulse/llms.txt This Kotlin code demonstrates how to implement the BrokerFactory interface to dynamically register a Kubernetes broker. It defines the broker types provided and includes logic to create a Broker instance from ServerConfig, handling potential configuration errors and initializing the Kubernetes client. Dependencies include impulse API classes and SLF4j. ```kotlin import club.arson.impulse.api.server.BrokerFactory import club.arson.impulse.api.server.Broker import club.arson.impulse.api.config.ServerConfig import org.slf4j.Logger // Example: Factory for Kubernetes broker class KubernetesBrokerFactory : BrokerFactory { // Declare which broker types this factory provides override val provides: List = listOf("kubernetes", "k8s") override fun createFromConfig( config: ServerConfig, logger: Logger? ): Result { return try { // Extract broker-specific config val k8sConfig = config.config as? KubernetesBrokerConfig ?: return Result.failure(IllegalArgumentException("Invalid k8s config")) // Validate configuration if (k8sConfig.namespace.isBlank()) { return Result.failure(IllegalArgumentException("namespace required")) } // Initialize Kubernetes client val client = KubernetesClientBuilder() .withKubeConfig(k8sConfig.kubeConfigPath) .build() logger?.info("Created Kubernetes broker for ${config.name}") Result.success(KubernetesBroker(config, client, logger)) } catch (e: Exception) { logger?.error("Failed to create Kubernetes broker", e) Result.failure(e) } } } // Broker-specific configuration class @BrokerConfig("kubernetes") @Serializable data class KubernetesBrokerConfig( var namespace: String = "minecraft", var kubeConfigPath: String = "~/.kube/config", var image: String = "itzg/minecraft-server", var resources: ResourceRequirements = ResourceRequirements(), var serviceType: String = "ClusterIP", var address: String? = null ) @Serializable data class ResourceRequirements( var memoryLimit: String = "2Gi", var cpuLimit: String = "1000m", var memoryRequest: String = "1Gi", var cpuRequest: String = "500m" ) ``` -------------------------------- ### Define SMP Server in Velocity Configuration Source: https://github.com/arson-club/impulse/blob/main/docs/getting_started/velocity_configuration.md This TOML snippet defines the 'smp' server with its IP address and port within the Velocity proxy configuration. This is crucial for Velocity to recognize and manage connections to your SMP server, especially when using features like 'try' or 'forced-hosts'. ```toml [servers] smp = "127.0.0.1:25566" ``` -------------------------------- ### Configure Minecraft Server for Forwarding Source: https://github.com/arson-club/impulse/blob/main/docs/README.md This TOML configuration is for a FabricProxy-Lite server, enabling it to work with modern forwarding. It requires a secret key, which should be stored in a separate forwarding.secret file. ```toml # create the file /srv/lobby/config/FabricProxy-Lite.toml hackOnlineMode = true hackEarlySend = false hackMessageChain = true disconnectMessage = "This server requires you to connect through the proxy." secret = "" ``` -------------------------------- ### Configure Impulse Server Instance (Docker) Source: https://github.com/arson-club/impulse/blob/main/docs/README.md This YAML configuration defines an Impulse server instance named 'Bones' that manages a 'lobby' server. It uses a Docker container, binds ports, sets environment variables for Minecraft server configuration, and mounts a volume for persistent data. ```yaml instanceName: Bones servers: - name: lobby inactiveTimeout: 300 type: docker docker: image: itzg/minecraft-server portBindings: - "25566:25565" env: ONLINE_MODE: "FALSE" TYPE: "FABRIC" EULA: "TRUE" MODRINTH_PROJECTS: "fabricproxy-lite" DIFFICULTY: "PEACEFUL" ALLOW_NETHER: "FALSE" MODE: "adventure" volumes: - "/srv/lobby:/data" ``` -------------------------------- ### Enable Modern Player Info Forwarding in Velocity Source: https://github.com/arson-club/impulse/blob/main/docs/getting_started/velocity_configuration.md This TOML snippet enables modern player info forwarding in Velocity. Setting `player-info-forwarding` to `"modern"` ensures that player data, including skins and correct usernames, is accurately forwarded to backend servers when Velocity is running in online mode. ```toml player-info-forwarding = "modern" ``` -------------------------------- ### Pre-pull Minecraft Docker Image Source: https://github.com/arson-club/impulse/blob/main/docs/getting_started/docker_broker.md This bash command pulls the specified Docker image for the Minecraft server. Pre-pulling the image is recommended to reduce server startup and connection times. ```bash docker pull itzg/minecraft-server:latest ``` -------------------------------- ### Configuring JAR-based Minecraft Server with Impulse Source: https://context7.com/arson-club/impulse/llms.txt This snippet demonstrates configuring a JAR-based Minecraft server with Impulse. It specifies the working directory, JAR file, address, and Java flags for server execution. This configuration is suitable for servers launched directly via a JAR file. ```yaml # JAR-based survival server - name: survival type: jar lifecycleSettings: allowAutoStart: true allowAutoStop: true reconciliationBehavior: ON_STOP shutdownBehavior: REMOVE timeouts: startup: 180 inactiveGracePeriod: 600 # 10 minutes jar: workingDirectory: "/srv/minecraft/survival" jarFile: "paper-1.20.4.jar" address: "127.0.0.1:25567" javaFlags: - "-Xms2G" - "-Xmx4G" - "-XX:+UseG1GC" - "-XX:+ParallelRefProcEnabled" flags: - "--nogui" ``` -------------------------------- ### Configure FabricProxy-Lite for Velocity Identity Forwarding Source: https://github.com/arson-club/impulse/blob/main/docs/getting_started/docker_broker.md This TOML configuration file is placed within the mounted volume for the SMP server. It enables specific FabricProxy-Lite features required for Velocity's modern forwarding and online mode, including setting a disconnect message and providing a secret for secure communication. ```toml hackOnlineMode = true hackEarlySend = false hackMessageChain = true disconnectMessage = "This server requires you to connect with Velocity." secret = "" ``` -------------------------------- ### JAR Broker Configuration for Direct Process Management Source: https://context7.com/arson-club/impulse/llms.txt Configure Minecraft servers to run as direct Java processes using the JAR broker. This method offers direct control over JVM flags and command-line arguments, suitable for traditional hosting environments. ```yaml # JAR broker configurations are not provided in the text, only mentioned. # This is a placeholder demonstrating where such configuration would typically reside. # servers: # - name: my-jar-server # type: jar # jarPath: "/path/to/server.jar" # jvmArgs: # - "-Xmx4G" # - "-XX:+UseG1GC" # commandLineArgs: # - "--nogui" ``` -------------------------------- ### Configuring Docker-based Minecraft Server with Impulse Source: https://context7.com/arson-club/impulse/llms.txt This snippet shows how to configure a Docker-based Minecraft server using Impulse. It includes settings for image, port bindings, environment variables, and lifecycle management. Dependencies include a running Docker daemon and the specified Minecraft server image. ```yaml servers: # Docker-based lobby server - name: lobby type: docker lifecycleSettings: allowAutoStart: true # Start when player connects allowAutoStop: true # Stop when last player leaves reconciliationBehavior: FORCE # Apply config changes immediately (FORCE or ON_STOP) shutdownBehavior: STOP # STOP (pause) or REMOVE (cleanup) timeouts: startup: 120 # Max seconds to wait for server ready shutdown: 60 # Max seconds to wait for graceful shutdown inactiveGracePeriod: 300 # Seconds of inactivity before auto-stop reconciliationGracePeriod: 60 # Warning time before config reconciliation docker: image: itzg/minecraft-server imagePullPolicy: IF_NOT_PRESENT # ALWAYS, IF_NOT_PRESENT, or NEVER address: "127.0.0.1:25566" # Override detected address portBindings: - "25566:25565" volumes: - "/srv/minecraft/lobby:/data" env: ONLINE_MODE: "FALSE" TYPE: "FABRIC" VERSION: "1.20.4" EULA: "TRUE" MODRINTH_PROJECTS: "fabricproxy-lite" DIFFICULTY: "PEACEFUL" MAX_MEMORY: "2G" MAX_PLAYERS: "100" hostPath: "unix:///var/run/docker.sock" tlsConfig: enabled: false keystorePath: "" keystorePassword: "" ``` -------------------------------- ### Kotlin: Manage Impulse Servers via ServerManager Source: https://context7.com/arson-club/impulse/llms.txt This snippet demonstrates how to interact with the Impulse ServerManager to monitor server health, initiate server startups, and perform emergency shutdowns. It utilizes the ServiceRegistry to access the ServerManager and server instances. Dependencies include Impulse API classes like ServiceRegistry, Status, and Component. ```kotlin import club.arson.impulse.ServiceRegistry import club.arson.impulse.api.server.Status import net.kyori.adventure.text.Component import java.time.Duration // Assuming HealthStatus and calculateUptime are defined elsewhere or available in scope // data class HealthStatus(...) // fun calculateUptime(server: Server): Duration? // val logger: Logger = ... // Example: Velocity plugin that monitors Impulse servers class MonitoringPlugin { fun checkAllServerHealth(): Map { val serverManager = ServiceRegistry.instance.serverManager ?: return emptyMap() val healthMap = mutableMapOf() for ((name, server) in serverManager.servers) { val status = server.getStatus() val playerCount = server.serverRef.playersConnected.size val isPinned = server.pinned val config = server.config healthMap[name] = HealthStatus( status = status, players = playerCount, pinned = isPinned, autoStartEnabled = config.lifecycleSettings.allowAutoStart, autoStopEnabled = config.lifecycleSettings.allowAutoStop, uptime = calculateUptime(server) ) // Alert if server is in unknown state if (status == Status.UNKNOWN) { alertOps("Server $name is in UNKNOWN state!") } } return healthMap } fun warmAllServers(): Map> { val serverManager = ServiceRegistry.instance.serverManager ?: return emptyMap() val results = mutableMapOf>() for ((name, server) in serverManager.servers) { if (!server.isRunning()) { logger.info("Warming up server: $name") results[name] = server.startServer() .onSuccess { logger.info("$name started successfully") } .onFailure { e -> logger.error("Failed to start $name", e) } } else { results[name] = Result.success("Already running") } } return results } fun emergencyShutdown(serverName: String, reason: String) { val serverManager = ServiceRegistry.instance.serverManager ?: return val server = serverManager.getServer(serverName) ?: return // Notify players server.serverRef.playersConnected.forEach { player -> player.disconnect(Component.text("Emergency shutdown: $reason")) } // Force immediate stop server.stopServer() .onSuccess { logger.warn("Emergency shutdown of $serverName: $reason") } .onFailure { e -> logger.error("Failed emergency shutdown", e) } } } data class HealthStatus( val status: Status, val players: Int, val pinned: Boolean, val autoStartEnabled: Boolean, val autoStopEnabled: Boolean, val uptime: Duration? ) // Placeholder functions and variables assuming they exist in the environment fun alertOps(message: String) { println("ALERT: $message") } fun calculateUptime(server: Any): Duration? { return Duration.ofMinutes(10) } val logger = object { fun info(msg: String) { println("INFO: $msg") } fun warn(msg: String) { println("WARN: $msg") } fun error(msg: String, e: Throwable?) { println("ERROR: $msg ${e?.message}") } } // Dummy Server and ServerRef for compilation interface Server { fun getStatus(): Status fun isRunning(): Boolean fun startServer(): Result fun stopServer(): Result val serverRef: ServerRef val pinned: Boolean val config: ServerConfig } interface ServerRef { val playersConnected: List } interface Player { fun disconnect(component: Component) } interface ServerConfig { val lifecycleSettings: LifecycleSettings } interface LifecycleSettings { val allowAutoStart: Boolean val allowAutoStop: Boolean } ``` -------------------------------- ### RegisterBrokerEvent: Security Filter for Blocking Malicious Brokers (Kotlin) Source: https://context7.com/arson-club/impulse/llms.txt Illustrates a security mechanism using the RegisterBrokerEvent to block brokers from untrusted locations or those with invalid signatures. It checks against a list of blocked paths and calls a (placeholder) JAR signature verification function. Dependencies include Impulse API, Velocity API, and Java NIO. Input is the `RegisterBrokerEvent` object, and output is the event's result being set to denied with a reason, or logged as passed. ```kotlin import club.arson.impulse.api.events.RegisterBrokerEvent import com.velocitypowered.api.event.Subscribe import com.velocitypowered.api.event.ResultedEvent.GenericResult import java.nio.file.Path import net.kyori.adventure.text.Component // Assuming proxy, logger, and Component are available in the scope // Example: Blocking malicious brokers class BrokerSecurityFilter { private val blockedPaths = listOf( "/tmp/suspicious-broker.jar", "/untrusted/location" ) @Subscribe fun onRegisterBroker(event: RegisterBrokerEvent) { val jarPath = event.jarPath // Block brokers from untrusted locations if (blockedPaths.any { jarPath.toString().startsWith(it) }) { logger.warn("Blocked broker from untrusted location: $jarPath") event.result = GenericResult.denied( Component.text("Broker location not trusted") ) return } // Verify JAR signature if (!verifyJarSignature(jarPath)) { logger.error("Broker JAR signature verification failed: $jarPath") event.result = GenericResult.denied( Component.text("Broker signature invalid") ) return } logger.info("Broker security check passed: ${jarPath.fileName}") } private fun verifyJarSignature(jarPath: Path): Boolean { // Implementation would verify JAR is signed by trusted certificate return true } } ``` -------------------------------- ### Configure Paper Server with Aikar's Flags Source: https://context7.com/arson-club/impulse/llms.txt Configuration for an optimized Paper server using Aikar's flags for improved performance and garbage collection. Specifies working directory, JAR file, network address, and detailed Java flags for 8GB RAM. ```yaml servers: - name: paper-optimized type: jar lifecycleSettings: allowAutoStart: true allowAutoStop: true timeouts: startup: 180 shutdown: 90 inactiveGracePeriod: 600 jar: workingDirectory: "/srv/minecraft/paper" jarFile: "paper-1.20.4-497.jar" address: "127.0.0.1:25565" javaFlags: # Aikar's optimized flags for 8GB RAM - "-Xms8G" - "-Xmx8G" - "-XX:+UseG1GC" - "-XX:+ParallelRefProcEnabled" - "-XX:MaxGCPauseMillis=200" - "-XX:+UnlockExperimentalVMOptions" - "-XX:+DisableExplicitGC" - "-XX:+AlwaysPreTouch" - "-XX:G1NewSizePercent=30" - "-XX:G1MaxNewSizePercent=40" - "-XX:G1HeapRegionSize=8M" - "-XX:G1ReservePercent=20" - "-XX:G1HeapWastePercent=5" - "-XX:G1MixedGCCountTarget=4" - "-XX:InitiatingHeapOccupancyPercent=15" - "-XX:G1MixedGCLiveThresholdPercent=90" - "-XX:G1RSetUpdatingPauseTimePercent=5" - "-XX:SurvivorRatio=32" - "-XX:+PerfDisableSharedMem" - "-XX:MaxTenuringThreshold=1" - "-Dusing.aikars.flags=https://mcflags.emc.gs" - "-Daikars.new.flags=true" flags: - "--nogui" ``` -------------------------------- ### Configure Impulse JAR Broker in YAML Source: https://github.com/arson-club/impulse/blob/main/docs/getting_started/jar_broker.md Defines the configuration for the JAR broker within Impulse, specifying server details, lifecycle settings, and JVM/JAR execution parameters. This YAML file is crucial for managing a Minecraft server instance. ```yaml instanceName: MyCoolSMP servers: - name: smp type: jar lifecycleSettings: timeouts: inactiveGracePeriod: 300 jar: workingDirectory: /srv/smp jarFile: fabric.jar javaFlags: - -Xms4G - -Xmx4G flags: - --nogui ``` -------------------------------- ### Configure Custom Command Server Source: https://context7.com/arson-club/impulse/llms.txt Configuration for a server launched via a custom command script. Enables auto-start and auto-stop, specifying the working directory, address, and the command with its arguments. ```yaml servers: - name: custom-launcher type: cmd lifecycleSettings: allowAutoStart: true allowAutoStop: true cmd: workingDirectory: "/srv/minecraft/custom" address: "127.0.0.1:25600" command: - "/srv/minecraft/custom/launcher.sh" - "--port=25600" - "--mode=survival" - "--max-players=100" ``` -------------------------------- ### Docker Broker Configuration for Minecraft Servers Source: https://context7.com/arson-club/impulse/llms.txt Configure Minecraft servers to run in Docker containers using the Docker broker. This allows for advanced control over images, networking, volumes, and environment variables, including automatic mod downloads and lifecycle management. ```yaml # Advanced Docker broker configurations servers: # Modded Fabric server with automatic mod downloads - name: modded-fabric type: docker lifecycleSettings: allowAutoStart: true allowAutoStop: true timeouts: startup: 300 # Mods take longer to download and start inactiveGracePeriod: 900 docker: image: itzg/minecraft-server:java17 imagePullPolicy: ALWAYS # Always pull to get mod updates portBindings: - "25570:25565" - "25571:25575" # RCON port volumes: - "/srv/minecraft/modded/data:/data" - "/srv/minecraft/modded/mods:/mods:ro" # Read-only mod directory env: TYPE: "FABRIC" VERSION: "1.20.4" FABRIC_LOADER_VERSION: "0.15.7" EULA: "TRUE" ONLINE_MODE: "FALSE" MEMORY: "4G" MAX_MEMORY: "6G" USE_AIKAR_FLAGS: "true" ENABLE_RCON: "true" RCON_PASSWORD: "secure_password_here" RCON_PORT: "25575" # Automatic mod installation from various sources MODRINTH_PROJECTS: | fabric-api lithium phosphor ferrite-core CURSEFORGE_FILES: | 123456:fabric-language-kotlin GITHUB_RELEASES: | owner/repo:asset-name.jar # Server configuration MOTD: "Modded Fabric Server - Managed by Impulse" MAX_PLAYERS: "50" VIEW_DISTANCE: "12" SIMULATION_DISTANCE: "10" DIFFICULTY: "hard" MODE: "survival" PVP: "true" SPAWN_PROTECTION: "0" # Performance tuning JVM_OPTS: "-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC" # Paper server with custom Docker socket - name: paper-production type: docker docker: image: itzg/minecraft-server:latest hostPath: "tcp://192.168.1.100:2375" # Remote Docker daemon tlsConfig: enabled: true keystorePath: "/etc/impulse/docker-tls.p12" keystorePassword: "changeit" portBindings: - "25565:25565" volumes: - "paper-data:/data" # Named volume - "/backups/paper:/backups:ro" env: TYPE: "PAPER" VERSION: "1.20.4" EULA: "TRUE" ONLINE_MODE: "FALSE" # Paper-specific optimizations PAPER_DOWNLOAD_URL: "https://api.papermc.io/v2/projects/paper/versions/1.20.4/builds/latest/downloads/paper-1.20.4-latest.jar" # BungeeCord/Waterfall proxy as Docker container - name: bungeecord type: docker lifecycleSettings: allowAutoStart: false # Manual start - should stay up allowAutoStop: false shutdownBehavior: REMOVE docker: image: itzg/bungeecord autoStartOnCreate: true # Start immediately when created portBindings: - "25577:25577" volumes: - "/srv/minecraft/bungee:/server" env: TYPE: "WATERFALL" MEMORY: "512M" ``` -------------------------------- ### Broker Interface - Server Lifecycle Contract Source: https://context7.com/arson-club/impulse/llms.txt The `Broker` interface defines the contract for server broker implementations, abstracting deployment platforms and providing APIs for server lifecycle management. ```APIDOC ## Broker Interface - Server Lifecycle Contract ### Description Defines the contract for all server broker implementations, abstracting the underlying deployment platform (e.g., Docker, JAR files, cloud providers) and providing a unified API for server lifecycle management. ### Methods #### `getStatus()` - **Returns**: `Status` - The current status of the server (e.g., RUNNING, STOPPED, REMOVED, UNKNOWN). #### `isRunning()` - **Returns**: `Boolean` - `true` if the server is currently running, `false` otherwise. #### `address()` - **Returns**: `Result` - The network address of the server if running, or an error. #### `startServer()` - **Returns**: `Result` - Attempts to start the server. Returns success or an error. #### `stopServer()` - **Returns**: `Result` - Attempts to stop the server. Returns success or an error. #### `removeServer()` - **Returns**: `Result` - Attempts to remove the server and its associated resources. Returns success or an error. #### `reconcile(config: ServerConfig)` - **Parameters**: - **config** (`ServerConfig`) - The desired server configuration. - **Returns**: `Result` - Returns a `Runnable` to apply configuration changes if needed, or `null` if no changes are required. Returns success or an error. ``` -------------------------------- ### Import Client Certificate to Docker Keystore Source: https://github.com/arson-club/impulse/blob/main/docs/reference/docker-broker.md This shell command imports an existing PKCS12 keystore into a new one, effectively setting the password for the Docker keystore. It's a step in configuring TLS for Docker connections. Ensure the source and destination keystore paths and passwords match. ```shell keytool -importkeystore -srckeystore docker-keystore.p12 -srcstoretype PKCS12 \ -srcstorepass -destkeystore docker-keystore.p12 -deststoretype PKCS12 \ -deststorepass ```