mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-09 03:46:18 -04:00
Launching 1.13
This commit is contained in:
parent
4bde509708
commit
d9225b9529
48
HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/Argument.kt
Normal file
48
HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/Argument.kt
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher.
|
||||||
|
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.game
|
||||||
|
|
||||||
|
import com.google.gson.*
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
|
||||||
|
interface Argument {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse this argument in form: ${key name} or simply a string.
|
||||||
|
*
|
||||||
|
* @param keys the parse map
|
||||||
|
* @param features the map that contains some features such as 'is_demo_user', 'has_custom_resolution'
|
||||||
|
* @return parsed argument element, empty if this argument is ignored and will not be added.
|
||||||
|
*/
|
||||||
|
fun toString(keys: Map<String, String>, features: Map<String, Boolean>): List<String>
|
||||||
|
|
||||||
|
companion object Serializer : JsonDeserializer<Argument>, JsonSerializer<Argument> {
|
||||||
|
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Argument =
|
||||||
|
if (json.isJsonPrimitive)
|
||||||
|
StringArgument(json.asString)
|
||||||
|
else
|
||||||
|
context.deserialize(json, RuledArgument::class.java)
|
||||||
|
|
||||||
|
override fun serialize(src: Argument, typeOfSrc: Type, context: JsonSerializationContext): JsonElement =
|
||||||
|
when (src) {
|
||||||
|
is StringArgument -> JsonPrimitive(src.argument)
|
||||||
|
is RuledArgument -> context.serialize(src, RuledArgument::class.java)
|
||||||
|
else -> throw AssertionError("Unrecognized argument type: $src")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher.
|
||||||
|
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.game
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import org.jackhuang.hmcl.util.OS
|
||||||
|
import org.jackhuang.hmcl.game.CompatibilityRule.*
|
||||||
|
|
||||||
|
class Arguments @JvmOverloads constructor(
|
||||||
|
@SerializedName("game")
|
||||||
|
val game: List<Argument>? = null,
|
||||||
|
@SerializedName("jvm")
|
||||||
|
val jvm: List<Argument>? = null
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun parseStringArguments(arguments: List<String>, keys: Map<String, String>, features: Map<String, Boolean> = emptyMap()): List<String> {
|
||||||
|
return arguments.flatMap { StringArgument(it).toString(keys, features) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseArguments(arguments: List<Argument>, keys: Map<String, String>, features: Map<String, Boolean> = emptyMap()): List<String> {
|
||||||
|
return arguments.flatMap { it.toString(keys, features) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val DEFAULT_JVM_ARGUMENTS = listOf(
|
||||||
|
RuledArgument(listOf(CompatibilityRule(Action.ALLOW, OSRestriction(OS.OSX))), listOf("-XstartOnFirstThread")),
|
||||||
|
RuledArgument(listOf(CompatibilityRule(Action.ALLOW, OSRestriction(OS.WINDOWS))), listOf("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump")),
|
||||||
|
RuledArgument(listOf(CompatibilityRule(Action.ALLOW, OSRestriction(OS.WINDOWS, "^10\\."))), listOf("-Dos.name=Windows 10", "-Dos.version=10.0")),
|
||||||
|
StringArgument("-Djava.library.path=\${natives_directory}"),
|
||||||
|
StringArgument("-Dminecraft.launcher.brand=\${launcher_name}"),
|
||||||
|
StringArgument("-Dminecraft.launcher.version=\${launcher_version}"),
|
||||||
|
StringArgument("-cp"),
|
||||||
|
StringArgument("\${classpath}")
|
||||||
|
)
|
||||||
|
|
||||||
|
val DEFAULT_GAME_ARGUMENTS = listOf(
|
||||||
|
RuledArgument(listOf(CompatibilityRule(Action.ALLOW, features = mapOf("has_custom_resolution" to true))), listOf("--width", "\${resolution_width}", "--height", "\${resolution_height}"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -26,18 +26,28 @@ import java.util.regex.Pattern
|
|||||||
@Immutable
|
@Immutable
|
||||||
data class CompatibilityRule(
|
data class CompatibilityRule(
|
||||||
val action: Action = CompatibilityRule.Action.ALLOW,
|
val action: Action = CompatibilityRule.Action.ALLOW,
|
||||||
val os: OSRestriction? = null
|
val os: OSRestriction? = null,
|
||||||
|
val features: Map<String, Boolean>? = null
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val appliedAction: Action? get() = if (os != null && !os.allow()) null else action
|
fun getAppliedAction(supportedFeatures: Map<String, Boolean>): Action? {
|
||||||
|
if (os != null && !os.allow()) return null
|
||||||
|
if (features != null) {
|
||||||
|
features.entries.forEach {
|
||||||
|
if (supportedFeatures[it.key] != it.value)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return action
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun appliesToCurrentEnvironment(rules: Collection<CompatibilityRule>?): Boolean {
|
fun appliesToCurrentEnvironment(rules: Collection<CompatibilityRule>?, features: Map<String, Boolean> = emptyMap()): Boolean {
|
||||||
if (rules == null)
|
if (rules == null)
|
||||||
return true
|
return true
|
||||||
var action = CompatibilityRule.Action.DISALLOW
|
var action = CompatibilityRule.Action.DISALLOW
|
||||||
for (rule in rules) {
|
for (rule in rules) {
|
||||||
val thisAction = rule.appliedAction
|
val thisAction = rule.getAppliedAction(features)
|
||||||
if (thisAction != null) action = thisAction
|
if (thisAction != null) action = thisAction
|
||||||
}
|
}
|
||||||
return action == CompatibilityRule.Action.ALLOW
|
return action == CompatibilityRule.Action.ALLOW
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher.
|
||||||
|
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.game
|
||||||
|
|
||||||
|
import com.google.gson.*
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import org.jackhuang.hmcl.util.typeOf
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
|
||||||
|
|
||||||
|
class RuledArgument @JvmOverloads constructor(
|
||||||
|
val rules: List<CompatibilityRule>? = null,
|
||||||
|
val value: List<String>? = null) : Argument {
|
||||||
|
|
||||||
|
override fun toString(keys: Map<String, String>, features: Map<String, Boolean>): List<String> =
|
||||||
|
if (CompatibilityRule.appliesToCurrentEnvironment(rules))
|
||||||
|
value?.map { StringArgument(it).toString(keys, features).single() } ?: emptyList()
|
||||||
|
else
|
||||||
|
emptyList()
|
||||||
|
|
||||||
|
companion object Serializer : JsonSerializer<RuledArgument>, JsonDeserializer<RuledArgument> {
|
||||||
|
override fun serialize(src: RuledArgument, typeOfSrc: Type, context: JsonSerializationContext) =
|
||||||
|
JsonObject().apply {
|
||||||
|
add("rules", context.serialize(src.rules))
|
||||||
|
add("value", context.serialize(src.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): RuledArgument {
|
||||||
|
val obj = json.asJsonObject
|
||||||
|
return RuledArgument(
|
||||||
|
rules = context.deserialize(obj["rules"], typeOf<List<CompatibilityRule>>()),
|
||||||
|
value = if (obj["value"].isJsonPrimitive)
|
||||||
|
listOf(obj["value"].asString)
|
||||||
|
else
|
||||||
|
context.deserialize(obj["value"], typeOf<List<String>>())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher.
|
||||||
|
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.game
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
class StringArgument(var argument: String) : Argument {
|
||||||
|
|
||||||
|
override fun toString(keys: Map<String, String>, features: Map<String, Boolean>): List<String> {
|
||||||
|
var res = argument
|
||||||
|
val pattern = Pattern.compile("\\$\\{(.*?)\\}")
|
||||||
|
val m = pattern.matcher(argument)
|
||||||
|
while (m.find()) {
|
||||||
|
val entry = m.group()
|
||||||
|
res = res.replace(entry, keys.getOrDefault(entry, entry))
|
||||||
|
}
|
||||||
|
return Collections.singletonList(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -26,6 +26,8 @@ import java.util.*
|
|||||||
open class Version(
|
open class Version(
|
||||||
@SerializedName("minecraftArguments")
|
@SerializedName("minecraftArguments")
|
||||||
val minecraftArguments: String? = null,
|
val minecraftArguments: String? = null,
|
||||||
|
@SerializedName("arguments")
|
||||||
|
val arguments: Arguments? = null,
|
||||||
@SerializedName("mainClass")
|
@SerializedName("mainClass")
|
||||||
val mainClass: String? = null,
|
val mainClass: String? = null,
|
||||||
@SerializedName("time")
|
@SerializedName("time")
|
||||||
@ -138,6 +140,7 @@ open class Version(
|
|||||||
|
|
||||||
fun copy(
|
fun copy(
|
||||||
minecraftArguments: String? = this.minecraftArguments,
|
minecraftArguments: String? = this.minecraftArguments,
|
||||||
|
arguments: Arguments? = this.arguments,
|
||||||
mainClass: String? = this.mainClass,
|
mainClass: String? = this.mainClass,
|
||||||
time: Date = this.time,
|
time: Date = this.time,
|
||||||
releaseTime: Date = this.releaseTime,
|
releaseTime: Date = this.releaseTime,
|
||||||
@ -153,6 +156,7 @@ open class Version(
|
|||||||
downloads: Map<DownloadType, DownloadInfo>? = this.downloads,
|
downloads: Map<DownloadType, DownloadInfo>? = this.downloads,
|
||||||
logging: Map<DownloadType, LoggingInfo>? = this.logging) =
|
logging: Map<DownloadType, LoggingInfo>? = this.logging) =
|
||||||
Version(minecraftArguments,
|
Version(minecraftArguments,
|
||||||
|
arguments,
|
||||||
mainClass,
|
mainClass,
|
||||||
time,
|
time,
|
||||||
id,
|
id,
|
||||||
|
@ -18,10 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.launch
|
package org.jackhuang.hmcl.launch
|
||||||
|
|
||||||
import org.jackhuang.hmcl.auth.AuthInfo
|
import org.jackhuang.hmcl.auth.AuthInfo
|
||||||
import org.jackhuang.hmcl.game.DownloadType
|
import org.jackhuang.hmcl.game.*
|
||||||
import org.jackhuang.hmcl.game.GameException
|
|
||||||
import org.jackhuang.hmcl.game.GameRepository
|
|
||||||
import org.jackhuang.hmcl.game.LaunchOptions
|
|
||||||
import org.jackhuang.hmcl.task.TaskResult
|
import org.jackhuang.hmcl.task.TaskResult
|
||||||
import org.jackhuang.hmcl.util.*
|
import org.jackhuang.hmcl.util.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -48,6 +45,9 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
|||||||
throw NullPointerException("Version main class can not be null")
|
throw NullPointerException("Version main class can not be null")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open val defaultJVMArguments = Arguments.DEFAULT_JVM_ARGUMENTS
|
||||||
|
protected open val defaultGameArguments = Arguments.DEFAULT_GAME_ARGUMENTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: the [account] must have logged in when calling this property
|
* Note: the [account] must have logged in when calling this property
|
||||||
*/
|
*/
|
||||||
@ -84,9 +84,7 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OS.CURRENT_OS == OS.WINDOWS)
|
if (OS.CURRENT_OS != OS.WINDOWS)
|
||||||
res.add("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump")
|
|
||||||
else
|
|
||||||
res.add("-Duser.home=${options.gameDir.parent}")
|
res.add("-Duser.home=${options.gameDir.parent}")
|
||||||
|
|
||||||
if (options.java.version >= JavaVersion.JAVA_7)
|
if (options.java.version >= JavaVersion.JAVA_7)
|
||||||
@ -114,9 +112,6 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
|||||||
res.add("-Dfml.ignorePatchDiscrepancies=true")
|
res.add("-Dfml.ignorePatchDiscrepancies=true")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Classpath
|
|
||||||
res.add("-Djava.library.path=${native.absolutePath}")
|
|
||||||
|
|
||||||
val lateload = LinkedList<File>()
|
val lateload = LinkedList<File>()
|
||||||
val classpath = StringBuilder()
|
val classpath = StringBuilder()
|
||||||
for (library in version.libraries)
|
for (library in version.libraries)
|
||||||
@ -135,32 +130,21 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
|||||||
if (!jar.exists() || !jar.isFile)
|
if (!jar.exists() || !jar.isFile)
|
||||||
throw GameException("Minecraft jar does not exist")
|
throw GameException("Minecraft jar does not exist")
|
||||||
classpath.append(jar.absolutePath)
|
classpath.append(jar.absolutePath)
|
||||||
res.add("-cp")
|
|
||||||
res.add(classpath.toString())
|
|
||||||
|
|
||||||
// Main Class
|
|
||||||
res.add(version.mainClass!!)
|
|
||||||
|
|
||||||
// Provided Minecraft arguments
|
// Provided Minecraft arguments
|
||||||
val gameAssets = repository.getActualAssetDirectory(version.id, version.actualAssetIndex.id)
|
val gameAssets = repository.getActualAssetDirectory(version.id, version.actualAssetIndex.id)
|
||||||
|
val configuration = getConfigurations()
|
||||||
|
configuration["\${classpath}"] = classpath.toString()
|
||||||
|
configuration["\${natives_directory}"] = native.absolutePath
|
||||||
|
configuration["\${game_assets}"] = gameAssets.absolutePath
|
||||||
|
configuration["\${assets_root}"] = gameAssets.absolutePath
|
||||||
|
|
||||||
version.minecraftArguments!!.tokenize().forEach { line ->
|
res.addAll(Arguments.parseArguments(version.arguments?.jvm ?: defaultJVMArguments, configuration))
|
||||||
res.add(line
|
res.add(version.mainClass!!)
|
||||||
.replace("\${auth_player_name}", account.username)
|
|
||||||
.replace("\${auth_session}", account.authToken)
|
val features = getFeatures()
|
||||||
.replace("\${auth_access_token}", account.authToken)
|
res.addAll(Arguments.parseArguments(version.arguments?.game ?: defaultGameArguments, configuration, features))
|
||||||
.replace("\${auth_uuid}", account.userId)
|
res.addAll(Arguments.parseStringArguments(version.minecraftArguments?.tokenize()?.toList() ?: emptyList(), configuration))
|
||||||
.replace("\${version_name}", options.versionName ?: version.id)
|
|
||||||
.replace("\${profile_name}", options.profileName ?: "Minecraft")
|
|
||||||
.replace("\${version_type}", version.type.id)
|
|
||||||
.replace("\${game_directory}", repository.getRunDirectory(version.id).absolutePath)
|
|
||||||
.replace("\${game_assets}", gameAssets.absolutePath)
|
|
||||||
.replace("\${assets_root}", gameAssets.absolutePath)
|
|
||||||
.replace("\${user_type}", account.userType.toString().toLowerCase())
|
|
||||||
.replace("\${assets_index_name}", version.actualAssetIndex.id)
|
|
||||||
.replace("\${user_properties}", account.userProperties)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optional Minecraft arguments
|
// Optional Minecraft arguments
|
||||||
if (options.height != null && options.height != 0 && options.width != null && options.width != 0) {
|
if (options.height != null && options.height != 0 && options.width != null && options.width != 0) {
|
||||||
@ -222,6 +206,24 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun getConfigurations(): MutableMap<String, String> = mutableMapOf(
|
||||||
|
"\${auth_player_name}" to account.username,
|
||||||
|
"\${auth_session}" to account.authToken,
|
||||||
|
"\${auth_access_token}" to account.authToken,
|
||||||
|
"\${auth_uuid}" to account.userId,
|
||||||
|
"\${version_name}" to (options.versionName ?: version.id),
|
||||||
|
"\${profile_name}" to (options.profileName ?: "Minecraft"),
|
||||||
|
"\${version_type}" to version.type.id,
|
||||||
|
"\${game_directory}" to repository.getRunDirectory(version.id).absolutePath,
|
||||||
|
"\${user_type}" to account.userType.toString().toLowerCase(),
|
||||||
|
"\${assets_index_name}" to version.actualAssetIndex.id,
|
||||||
|
"\${user_properties}" to account.userProperties
|
||||||
|
)
|
||||||
|
|
||||||
|
open fun getFeatures(): MutableMap<String, Boolean> = mutableMapOf(
|
||||||
|
"has_custom_resolution" to (options.height != null && options.height != 0 && options.width != null && options.width != 0)
|
||||||
|
)
|
||||||
|
|
||||||
override fun launch(): ManagedProcess {
|
override fun launch(): ManagedProcess {
|
||||||
|
|
||||||
// To guarantee that when failed to generate code, we will not call precalled command
|
// To guarantee that when failed to generate code, we will not call precalled command
|
||||||
@ -232,8 +234,8 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
|||||||
if (options.precalledCommand != null && options.precalledCommand.isNotBlank()) {
|
if (options.precalledCommand != null && options.precalledCommand.isNotBlank()) {
|
||||||
try {
|
try {
|
||||||
val process = Runtime.getRuntime().exec(options.precalledCommand)
|
val process = Runtime.getRuntime().exec(options.precalledCommand)
|
||||||
if (process.isAlive)
|
if (process.isAlive)
|
||||||
process.waitFor()
|
process.waitFor()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
// TODO: alert precalledCommand is wrong.
|
// TODO: alert precalledCommand is wrong.
|
||||||
// rethrow InterruptedException
|
// rethrow InterruptedException
|
||||||
@ -301,7 +303,7 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
|||||||
processListener.setProcess(managedProcess)
|
processListener.setProcess(managedProcess)
|
||||||
val logHandler = Log4jHandler { line, level -> processListener.onLog(line, level); managedProcess.lines += line }.apply { start() }
|
val logHandler = Log4jHandler { line, level -> processListener.onLog(line, level); managedProcess.lines += line }.apply { start() }
|
||||||
managedProcess.relatedThreads += logHandler
|
managedProcess.relatedThreads += logHandler
|
||||||
val stdout = thread(name = "stdout-pump", isDaemon = isDaemon, block = StreamPump(managedProcess.process.inputStream, { logHandler.newLine(it) } )::run)
|
val stdout = thread(name = "stdout-pump", isDaemon = isDaemon, block = StreamPump(managedProcess.process.inputStream, { logHandler.newLine(it) })::run)
|
||||||
managedProcess.relatedThreads += stdout
|
managedProcess.relatedThreads += stdout
|
||||||
val stderr = thread(name = "stderr-pump", isDaemon = isDaemon, block = StreamPump(managedProcess.process.errorStream, { processListener.onLog(it + OS.LINE_SEPARATOR, Log4jLevel.ERROR); managedProcess.lines += it })::run)
|
val stderr = thread(name = "stderr-pump", isDaemon = isDaemon, block = StreamPump(managedProcess.process.errorStream, { processListener.onLog(it + OS.LINE_SEPARATOR, Log4jLevel.ERROR); managedProcess.lines += it })::run)
|
||||||
managedProcess.relatedThreads += stderr
|
managedProcess.relatedThreads += stderr
|
||||||
|
@ -22,7 +22,9 @@ import com.google.gson.reflect.TypeToken
|
|||||||
import com.google.gson.stream.JsonReader
|
import com.google.gson.stream.JsonReader
|
||||||
import com.google.gson.stream.JsonToken
|
import com.google.gson.stream.JsonToken
|
||||||
import com.google.gson.stream.JsonWriter
|
import com.google.gson.stream.JsonWriter
|
||||||
|
import org.jackhuang.hmcl.game.Argument
|
||||||
import org.jackhuang.hmcl.game.Library
|
import org.jackhuang.hmcl.game.Library
|
||||||
|
import org.jackhuang.hmcl.game.RuledArgument
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.lang.reflect.Type
|
import java.lang.reflect.Type
|
||||||
@ -36,6 +38,8 @@ val GSON: Gson = GsonBuilder()
|
|||||||
.enableComplexMapKeySerialization()
|
.enableComplexMapKeySerialization()
|
||||||
.setPrettyPrinting()
|
.setPrettyPrinting()
|
||||||
.registerTypeAdapter(Library::class.java, Library)
|
.registerTypeAdapter(Library::class.java, Library)
|
||||||
|
.registerTypeAdapter(Argument::class.java, Argument)
|
||||||
|
.registerTypeAdapter(RuledArgument::class.java, RuledArgument)
|
||||||
.registerTypeAdapter(Date::class.java, DateTypeAdapter)
|
.registerTypeAdapter(Date::class.java, DateTypeAdapter)
|
||||||
.registerTypeAdapter(UUID::class.java, UUIDTypeAdapter)
|
.registerTypeAdapter(UUID::class.java, UUIDTypeAdapter)
|
||||||
.registerTypeAdapter(Platform::class.java, Platform)
|
.registerTypeAdapter(Platform::class.java, Platform)
|
||||||
|
@ -20,7 +20,7 @@ group 'org.jackhuang'
|
|||||||
version '3.0'
|
version '3.0'
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.1.4-2'
|
ext.kotlin_version = '1.1.4-4'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user