Fixed logging spaces and tabs missing, unclickable version item, removing 'logging' element when installing forge and liteloader
This commit is contained in:
@@ -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")
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user