Fixed logging spaces and tabs missing, unclickable version item, removing 'logging' element when installing forge and liteloader

This commit is contained in:
huangyuhui
2017-08-25 13:22:10 +08:00
parent e70226afba
commit 3b4359f7eb
16 changed files with 96 additions and 118 deletions

View File

@@ -43,10 +43,10 @@ object BMCLAPIDownloadProvider : DownloadProvider() {
}
override fun injectURL(baseURL: String): String = baseURL
.replace("https://launchermeta.mojang.com", "http://bmclapi2.bangbang93.com")
.replace("https://launcher.mojang.com", "http://bmclapi2.bangbang93.com")
.replace("https://libraries.minecraft.net", "http://bmclapi2.bangbang93.com/libraries")
.replace("http://files.minecraftforge.net/maven", "http://bmclapi2.bangbang93.com/maven")
.replace("http://dl.liteloader.com/versions/versions.json", "http://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json")
.replace("http://dl.liteloader.com/versions", "http://bmclapi2.bangbang93.com/maven")
.replace("https://launchermeta.mojang.com", "https://bmclapi2.bangbang93.com")
.replace("https://launcher.mojang.com", "https://bmclapi2.bangbang93.com")
.replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries")
.replace("http://files.minecraftforge.net/maven", "https://bmclapi2.bangbang93.com/maven")
.replace("http://dl.liteloader.com/versions/versions.json", "httsp://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json")
.replace("http://dl.liteloader.com/versions", "https://bmclapi2.bangbang93.com/maven")
}

View File

@@ -46,8 +46,6 @@ object MojangDownloadProvider : DownloadProvider() {
override fun injectURL(baseURL: String): String {
if (baseURL.endsWith("net/minecraftforge/forge/json"))
return baseURL
else if (Locale.getDefault() == Locale.CHINA)
return baseURL.replace("http://files.minecraftforge.net/maven", "http://maven.aliyun.com/nexus/content/groups/public");
else
return baseURL.replace("http://files.minecraftforge.net/maven", "http://ftb.cursecdn.com/FTB2/maven")
}

View File

@@ -73,7 +73,7 @@ class ForgeInstallTask(private val dependencyManager: DefaultDependencyManager,
val versionProvider = SimpleVersionProvider()
versionProvider.addVersion(version)
result = installProfile.versionInfo!!.copy(inheritsFrom = version.id).resolve(versionProvider).copy(id = version.id)
result = installProfile.versionInfo!!.copy(inheritsFrom = version.id).resolve(versionProvider).copy(id = version.id, logging = emptyMap())
dependencies += GameLibrariesTask(dependencyManager, installProfile.versionInfo)
}

View File

@@ -69,7 +69,8 @@ class LiteLoaderInstallTask(private val dependencyManager: DefaultDependencyMana
result = version.copy(
mainClass = "net.minecraft.launchwrapper.Launch",
minecraftArguments = version.minecraftArguments + " --tweakClass " + remote.tag.tweakClass,
libraries = merge(tempVersion.libraries, version.libraries)
libraries = merge(tempVersion.libraries, version.libraries),
logging = emptyMap()
)
dependencies += GameLibrariesTask(dependencyManager, tempVersion)
}

View File

@@ -73,7 +73,7 @@ open class Library(
companion object LibrarySerializer : JsonDeserializer<Library>, JsonSerializer<Library> {
fun fromName(name: String, url: String? = null, downloads: LibrariesDownloadInfo? = null, extract: ExtractRules? = null, natives: Map<OS, String>? = null, rules: List<CompatibilityRule>? = null): Library {
val arr = name.split(":".toRegex(), 3)
val arr = name.split(":".toRegex(), 4)
if (arr.size != 3 && arr.size != 4)
throw IllegalArgumentException("Library name is malformed. Correct example: group:artifact:version.")
return Library(

View File

@@ -214,11 +214,11 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
open fun decompressNatives() {
version.libraries.filter { it.isNative }.forEach { library ->
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
unzip(zip = repository.getLibraryFile(version, library),
repository.getLibraryFile(version, library).uncompressTo(
dest = native,
callback = if (library.extract == null) null
else library.extract!!::shouldExtract,
ignoreExistsFile = false)
ignoreExistentFile = false)
}
}
@@ -230,10 +230,13 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
decompressNatives()
if (options.precalledCommand != null && options.precalledCommand.isNotBlank()) {
val process = Runtime.getRuntime().exec(options.precalledCommand)
ignoreException {
if (process.isAlive)
process.waitFor()
try {
val process = Runtime.getRuntime().exec(options.precalledCommand)
if (process.isAlive)
process.waitFor()
} catch (e: IOException) {
// TODO: alert precalledCommand is wrong.
// rethrow InterruptedException
}
}
@@ -287,6 +290,14 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
}
private fun startMonitors(managedProcess: ManagedProcess, processListener: ProcessListener, isDaemon: Boolean = true) {
val enablesLoggingInfo = version.logging?.containsKey(DownloadType.CLIENT) ?: false
if (enablesLoggingInfo)
startMonitorsWithLoggingInfo(managedProcess, processListener, isDaemon)
else
startMonitorsWithoutLoggingInfo(managedProcess, processListener, isDaemon)
}
private fun startMonitorsWithLoggingInfo(managedProcess: ManagedProcess, processListener: ProcessListener, isDaemon: Boolean = true) {
processListener.setProcess(managedProcess)
val logHandler = Log4jHandler { line, level -> processListener.onLog(line, level); managedProcess.lines += line }.apply { start() }
managedProcess.relatedThreads += logHandler
@@ -297,6 +308,15 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
managedProcess.relatedThreads += thread(name = "exit-waiter", isDaemon = isDaemon, block = ExitWaiter(managedProcess, listOf(stdout, stderr), { exitCode, exitType -> logHandler.onStopped(); processListener.onExit(exitCode, exitType) })::run)
}
private fun startMonitorsWithoutLoggingInfo(managedProcess: ManagedProcess, processListener: ProcessListener, isDaemon: Boolean = true) {
processListener.setProcess(managedProcess)
val stdout = thread(name = "stdout-pump", isDaemon = isDaemon, block = StreamPump(managedProcess.process.inputStream, { processListener.onLog(it + OS.LINE_SEPARATOR, Log4jLevel.guessLevel(it) ?: Log4jLevel.INFO); managedProcess.lines += it })::run)
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)
managedProcess.relatedThreads += stderr
managedProcess.relatedThreads += thread(name = "exit-waiter", isDaemon = isDaemon, block = ExitWaiter(managedProcess, listOf(stdout, stderr), { exitCode, exitType -> processListener.onExit(exitCode, exitType) })::run)
}
companion object {
const val LAUNCH_ASYNC_ID = "process"
}

View File

@@ -106,7 +106,7 @@ class CurseForgeModpackManifestFile (
*/
@Throws(IOException::class, JsonParseException::class)
fun readCurseForgeModpackManifest(f: File): Modpack {
val json = readTextFromZipFile(f, "manifest.json")
val json = f.readTextZipEntry("manifest.json")
val manifest = GSON.fromJson<CurseForgeModpackManifest>(json)
?: throw JsonParseException("`manifest.json` not found. Not a valid CurseForge modpack.")
return Modpack(
@@ -114,7 +114,7 @@ fun readCurseForgeModpackManifest(f: File): Modpack {
version = manifest.version,
author = manifest.author,
gameVersion = manifest.minecraft.gameVersion,
description = readTextFromZipFileQuietly(f, "modlist.html") ?: "No description",
description = f.readTextZipEntryQuietly("modlist.html") ?: "No description",
manifest = manifest)
}
@@ -147,7 +147,7 @@ class CurseForgeModpackInstallTask(private val dependencyManager: DefaultDepende
}
override fun execute() {
unzipSubDirectory(zipFile, run, manifest.overrides)
zipFile.uncompressTo(run, subDirectory = manifest.overrides)
var finished = 0
for (f in manifest.files) {

View File

@@ -42,7 +42,7 @@ class InstancePatch @JvmOverloads constructor(
val libraries: List<Library> = emptyList()
)
class InstanceConfiguration(contentStream: InputStream) {
class InstanceConfiguration(defaultName: String, contentStream: InputStream) {
/**
* The instance's name
*/
@@ -183,15 +183,17 @@ class InstanceConfiguration(contentStream: InputStream) {
showConsole = p.getProperty("ShowConsole") == "true"
showConsoleOnError = p.getProperty("ShowConsoleOnError") == "true"
wrapperCommand = p.getProperty("WrapperCommand")
name = p.getProperty("name")
notes = p.getProperty("notes")
name = defaultName
notes = p.getProperty("notes") ?: ""
}
}
fun readMMCModpackManifest(f: File): Modpack {
ZipFile(f).use { zipFile ->
val entry = zipFile.getEntry("instance.cfg") ?: throw IOException("`instance.cfg` not found, $f is not a valid MultiMC modpack.")
val cfg = InstanceConfiguration(zipFile.getInputStream(entry))
val firstEntry = zipFile.entries.nextElement()
val name = firstEntry.name.substringBefore("/")
val entry = zipFile.getEntry("$name/instance.cfg") ?: throw IOException("`instance.cfg` not found, $f is not a valid MultiMC modpack.")
val cfg = InstanceConfiguration(name, zipFile.getInputStream(entry))
return Modpack(
name = cfg.name,
version = "",
@@ -217,12 +219,12 @@ class MMCModpackInstallTask(private val dependencyManager: DefaultDependencyMana
override fun execute() {
var version = repository.readVersionJson(name)!!
unzipSubDirectory(zipFile, run, "minecraft/", false)
zipFile.uncompressTo(run, subDirectory = "${manifest.name}/minecraft/", ignoreExistentFile = false, allowStoredEntriesWithDataDescriptor = true)
ZipFile(zipFile).use { zip ->
for (entry in zip.entries) {
// ensure that this entry is in folder 'patches' and is a json file.
if (!entry.isDirectory && entry.name.startsWith("patches/") && entry.name.endsWith(".json")) {
if (!entry.isDirectory && entry.name.startsWith("${manifest.name}/patches/") && entry.name.endsWith(".json")) {
val patch = GSON.fromJson<InstancePatch>(zip.getInputStream(entry).readFullyAsString())!!
val args = StringBuilder(version.minecraftArguments)
for (arg in patch.tweakers)

View File

@@ -34,21 +34,22 @@ import java.io.IOException
*/
@JvmOverloads
@Throws(IOException::class)
fun zip(src: File, destZip: File, pathNameCallback: ((String, Boolean) -> String?)? = null) {
fun File.zipTo(destZip: File, pathNameCallback: ((String, Boolean) -> String?)? = null) {
ZipArchiveOutputStream(destZip.outputStream()).use { zos ->
val basePath: String
if (src.isDirectory)
basePath = src.path
if (this.isDirectory)
basePath = this.path
else
//直接压缩单个文件时,取父目录
basePath = src.parent
zipFile(src, basePath, zos, pathNameCallback)
//直接压缩单个文件时,取父目录
basePath = this.parent
zipFile(this, basePath, zos, pathNameCallback)
zos.closeArchiveEntry()
}
}
/**
* Zip file.
*
* @param src source directory to be compressed.
* @param basePath the file directory to be compressed, if [src] is a file, this is the parent directory of [src]
* @param zos the [ZipOutputStream] of dest zip file.
@@ -92,69 +93,21 @@ private fun zipFile(src: File,
/**
* Decompress the given zip file to a directory.
* @param zip the source zip file.
* @param dest the dest directory.
* @param callback will be called for every entry in the zip file, returns false if you dont want this file unzipped.
* @throws IOException
*/
@JvmOverloads
@Throws(IOException::class)
fun unzip(zip: File, dest: File, callback: ((String) -> Boolean)? = null, ignoreExistsFile: Boolean = true) {
val buf = ByteArray(1024)
dest.mkdirs()
ZipArchiveInputStream(zip.inputStream()).use { zipFile ->
if (zip.exists()) {
val strPath = dest.absolutePath
while (true) {
val zipEnt = zipFile.nextEntry ?: break
var strtemp: String
var gbkPath = zipEnt.name
if (callback != null)
if (!callback.invoke(gbkPath))
continue
if (zipEnt.isDirectory) {
strtemp = strPath + File.separator + gbkPath
val dir = File(strtemp)
dir.mkdirs()
} else {
//读写文件
gbkPath = zipEnt.name
strtemp = strPath + File.separator + gbkPath
//建目录
val strsubdir = gbkPath
for (i in 0 until strsubdir.length)
if (strsubdir.substring(i, i + 1).equals("/", ignoreCase = true)) {
val temp = strPath + File.separator + strsubdir.substring(0, i)
val subdir = File(temp)
if (!subdir.exists())
subdir.mkdir()
}
if (ignoreExistsFile && File(strtemp).exists())
continue
File(strtemp).outputStream().use({ fos ->
zipFile.copyTo(fos, buf)
})
}
}
}
}
}
/**
* Decompress the subdirectory of given zip file.
* @param zip the source zip file.
*
* @param dest the dest directory.
* @param subDirectory the subdirectory of the zip file to be decompressed.
* @param callback will be called for every entry in the zip file, returns false if you dont want this file being uncompressed.
* @param ignoreExistentFile true if skip all existent files.
* @param allowStoredEntriesWithDataDescriptor whether the zip stream will try to read STORED entries that use a data descriptor
* @throws IOException
*/
@JvmOverloads
@Throws(IOException::class)
fun unzipSubDirectory(zip: File, dest: File, subDirectory: String, ignoreExistentFile: Boolean = true) {
fun File.uncompressTo(dest: File, subDirectory: String = "", callback: ((String) -> Boolean)? = null, ignoreExistentFile: Boolean = true, allowStoredEntriesWithDataDescriptor: Boolean = false) {
val buf = ByteArray(1024)
dest.mkdirs()
ZipArchiveInputStream(zip.inputStream()).use { zipFile ->
if (zip.exists()) {
ZipArchiveInputStream(this.inputStream(), null, true, allowStoredEntriesWithDataDescriptor).use { zipFile ->
if (this.exists()) {
val strPath = dest.absolutePath
while (true) {
val zipEnt = zipFile.nextEntry ?: break
@@ -166,13 +119,18 @@ fun unzipSubDirectory(zip: File, dest: File, subDirectory: String, ignoreExisten
gbkPath = gbkPath.substring(subDirectory.length)
if (gbkPath.startsWith("/") || gbkPath.startsWith("\\")) gbkPath = gbkPath.substring(1)
strtemp = strPath + File.separator + gbkPath
if (callback != null)
if (!callback.invoke(gbkPath))
continue
if (zipEnt.isDirectory) {
val dir = File(strtemp)
dir.mkdirs()
} else {
//建目录
val strsubdir = gbkPath
for (i in 0..strsubdir.length - 1)
for (i in 0 until strsubdir.length)
if (strsubdir.substring(i, i + 1).equals("/", ignoreCase = true)) {
val temp = strPath + File.separator + strsubdir.substring(0, i)
val subdir = File(temp)
@@ -194,14 +152,14 @@ fun unzipSubDirectory(zip: File, dest: File, subDirectory: String, ignoreExisten
* Read the text content of a file in zip.
*
* @param f the zip file
* @param location the location of the text in zip file, something like A/B/C/D.txt
* @param name the location of the text in zip file, something like A/B/C/D.txt
* @throws IOException if the file is not a valid zip file.
* @return the content of given file.
*/
@Throws(IOException::class)
fun readTextFromZipFile(f: File, location: String): String {
ZipFile(f).use { zipFile ->
val entry = zipFile.getEntry(location) ?: throw IOException("`$location` not found.")
fun File.readTextZipEntry(name: String): String {
ZipFile(this).use { zipFile ->
val entry = zipFile.getEntry(name) ?: throw IOException("`$name` not found.")
return zipFile.getInputStream(entry).readFullyAsString()
}
}
@@ -213,10 +171,9 @@ fun readTextFromZipFile(f: File, location: String): String {
* @param location the location of the text in zip file, something like A/B/C/D.txt
* @return the content of given file.
*/
fun readTextFromZipFileQuietly(f: File, location: String): String? {
fun File.readTextZipEntryQuietly(location: String) =
try {
return readTextFromZipFile(f, location)
readTextZipEntry(location)
} catch (e: IOException) {
return null
}
}
null
}