package de.steamwar.commands.dev import com.github.ajalt.clikt.command.SuspendingCliktCommand import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.CliktError import com.github.ajalt.clikt.core.Context import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.help import com.github.ajalt.clikt.parameters.arguments.multiple import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.multiple import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.file import com.github.ajalt.clikt.parameters.types.long import com.sun.security.auth.module.UnixSystem import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import java.io.File const val LOG4J_CONFIG = """ """ class DevCommand : CliktCommand("dev") { override fun help(context: Context): String = "Start a dev Server" override val treatUnknownOptionsAsArgs = true val server by argument().help("Server Template") val port by option("--port").long().default( if (System.getProperty("os.name").lowercase() .let { os -> listOf("mac", "nix", "sunos").any { it in os } } ) UnixSystem().uid else 2050 ).help("Port for Server") val world by option("--world", "-w").help("User World") val plugins by option("--plugins", "-p").help("Plugin Dir") val profile by option().flag().help("Add Profiling Arguments") val forceUpgrade by option().flag().help("Force Upgrade") val jar by option().file().help("Jar File") val jvmArgs by argument().multiple() override val printHelpOnEmptyArgs = true val workingDir = File(".").absoluteFile val log4jConfig = File(workingDir, "log4j2.xml") override fun run() { val args = mutableListOf() val serverDirectory = File(workingDir, server) val serverDir = if (serverDirectory.exists() && serverDirectory.isDirectory) serverDirectory else File(workingDir, server) if (isVelocity(server)) { runServer(args, jvmArgs, listOf(jar?.absolutePath ?: File("/jar/Velocity.jar").absolutePath), serverDir) } else { setLogConfig(args) val version = findVersion(server) ?: throw CliktError("Unknown Server Version") val worldFile = world?.let { File(workingDir, it) } ?: File(serverDir, "devtempworld") val jarFile = jar?.absolutePath ?: JARS[server]?.let { VERSIONS[it] } ?: VERSIONS[version] ?: throw CliktError("Unknown Server Version") if (!worldFile.exists()) { val templateFile = File(serverDir, "Bauwelt") if (!templateFile.exists()) { throw CliktError("World Template not found!") } templateFile.copyRecursively(worldFile) } val devFile = File("/configs/DevServer/${System.getProperty("user.name")}.$port.$version") if (System.getProperty("user.name") != "minecraft") { devFile.createNewFile() } runServer( args, jvmArgs, listOf( jarFile, if (forceUpgrade) "-forceUpgrade" else "", "--port", port.toString(), "--level-name", worldFile.name, "--world-dir", workingDir.absolutePath, "--no-gui", *(if (plugins != null) arrayOf("--plugins", plugins!!) else arrayOf()) ), serverDir ) try { devFile.delete() } catch (_: Exception) { } } } val OPENJ9_ARGS = arrayOf( "-Xmx1G", "-Xgc:excessiveGCratio=80", "-Xsyslog:none", "-Xtrace:none", "-Xnoclassgc", "-Xdisableexplicitgc", "-XX:+AlwaysPreTouch", "-XX:+CompactStrings", "-XX:-HeapDumpOnOutOfMemory", "-XX:+ExitOnOutOfMemoryError" ) val JAVA17_ARGS = arrayOf("--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED") val VERSIONS = mapOf( 8 to "/jars/paper-1.8.8.jar", 9 to "/jars/spigot-1.9.4.jar", 10 to "/jars/paper-1.10.2.jar", 12 to "/jars/spigot-1.12.2.jar", 14 to "/jars/spigot-1.14.4.jar", 15 to "/jars/spigot-1.15.2.jar", 18 to "/jars/paper-1.18.2.jar", 19 to "/jars/paper-1.19.3.jar", 20 to "/jars/paper-1.20.1.jar", 21 to "/jars/paper-1.21.6.jar" ) val JARS = mapOf( "Tutorial" to 15, "Lobby" to 20 ) fun findVersion(server: String): Int? = server.dropWhile { !it.isDigit() }.toIntOrNull() fun isJava8(server: String): Boolean = findVersion(server)?.let { it <= 10 } ?: false fun isVelocity(server: String): Boolean = server.endsWith("Velocity") fun setLogConfig(args: MutableList) { args += "-DlogPath=${workingDir.absolutePath}/logs" args += "-Dlog4j.configurationFile=${log4jConfig.absolutePath}" if (!log4jConfig.exists()) { log4jConfig.writeText(LOG4J_CONFIG) } } fun runServer(args: List, jvmArgs: List, cmd: List, serverDir: File) = runBlocking { val command = arrayOf( if (isJava8(server)) "/usr/lib/jvm/openj9-8/bin/java" else "java", *jvmArgs.toTypedArray(), *args.toTypedArray(), *OPENJ9_ARGS, *(if (isJava8(server)) arrayOf() else JAVA17_ARGS), if (profile) "-javaagent:/jars/LixfelsProfiler.jar=start" else "", "-Xshareclasses:nonfatal,name=$server", "-jar", *cmd.toTypedArray() ) echo(command.joinToString(" ")) val process = ProcessBuilder( *command ).directory(serverDir).start() launch { process.inputStream.transferTo(System.out) } launch { process.errorStream.transferTo(System.err) } launch { System.`in`.transferTo(process.outputStream) } process.waitFor() } }