210 lines
7.8 KiB
Kotlin
210 lines
7.8 KiB
Kotlin
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.joinAll
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.runBlocking
|
|
import java.io.File
|
|
|
|
const val LOG4J_CONFIG = """<?xml version="1.0" encoding="UTF-8"?>
|
|
<Configuration status="WARN" packages="com.mojang.util">
|
|
<Appenders>
|
|
<Console name="WINDOWS_COMPAT" target="SYSTEM_OUT"></Console>
|
|
<Queue name="TerminalConsole">
|
|
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg{nolookups}%n" />
|
|
</Queue>
|
|
<RollingRandomAccessFile name="File" fileName="$\{'sys:logPath'}/latest.log" filePattern="$\{'sys:logPath'}/%d{yyyy.MM.dd}.log.gz">
|
|
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg{nolookups}%n" />
|
|
<Policies>
|
|
<TimeBasedTriggeringPolicy />
|
|
</Policies>
|
|
<DefaultRolloverStrategy max="7"/>
|
|
</RollingRandomAccessFile>
|
|
</Appenders>
|
|
<Loggers>
|
|
<Root level="info">
|
|
<filters>
|
|
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL" />
|
|
</filters>
|
|
<AppenderRef ref="WINDOWS_COMPAT" level="info"/>
|
|
<AppenderRef ref="File"/>
|
|
<AppenderRef ref="TerminalConsole" level="info"/>
|
|
</Root>
|
|
</Loggers>
|
|
</Configuration>"""
|
|
|
|
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<String>()
|
|
|
|
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) arrayOf("-forceUpgrade") else arrayOf()),
|
|
"--port", port.toString(),
|
|
"--level-name", worldFile.name,
|
|
"--world-dir", workingDir.absolutePath,
|
|
"--nogui",
|
|
*(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<String>) {
|
|
args += "-DlogPath=${workingDir.absolutePath}/logs"
|
|
args += "-Dlog4j.configurationFile=${log4jConfig.absolutePath}"
|
|
|
|
if (!log4jConfig.exists()) {
|
|
log4jConfig.writeText(LOG4J_CONFIG)
|
|
}
|
|
}
|
|
|
|
fun runServer(args: List<String>, jvmArgs: List<String>, cmd: List<String>, 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) arrayOf("-javaagent:/jars/LixfelsProfiler.jar=start") else arrayOf()),
|
|
"-Xshareclasses:nonfatal,name=$server",
|
|
"-jar",
|
|
*cmd.toTypedArray()
|
|
)
|
|
echo(command.joinToString(" "))
|
|
val process = ProcessBuilder(
|
|
*command
|
|
).directory(serverDir).start()
|
|
|
|
val input = launch {
|
|
while (process.isAlive) {
|
|
process.inputStream.transferTo(System.out)
|
|
}
|
|
}
|
|
val error = launch {
|
|
while (process.isAlive) {
|
|
process.errorStream.transferTo(System.err)
|
|
}
|
|
}
|
|
val console = launch {
|
|
while (process.isAlive) {
|
|
System.`in`.transferTo(process.outputStream)
|
|
}
|
|
}
|
|
process.waitFor()
|
|
input.cancel()
|
|
error.cancel()
|
|
console.cancel()
|
|
joinAll(input, error, console)
|
|
echo("Process finished with exit code ${process.exitValue()}")
|
|
process.errorStream.transferTo(System.err)
|
|
}
|
|
} |