HMCL modpack output model

This commit is contained in:
huangyuhui 2017-08-22 21:07:56 +08:00
parent d83291eac0
commit 86cef86fc9
3 changed files with 179 additions and 4 deletions

View File

@ -22,12 +22,21 @@ import org.jackhuang.hmcl.download.game.VersionJSONSaveTask
import org.jackhuang.hmcl.mod.Modpack
import org.jackhuang.hmcl.setting.Profile
import org.jackhuang.hmcl.task.Task
import org.jackhuang.hmcl.util.GSON
import org.jackhuang.hmcl.util.fromJson
import org.jackhuang.hmcl.util.readTextFromZipFile
import org.jackhuang.hmcl.util.unzipSubDirectory
import java.io.File
import java.io.IOException
import sun.misc.IOUtils
import jdk.nashorn.internal.objects.NativeFunction.call
import org.jackhuang.hmcl.task.TaskResult
import org.jackhuang.hmcl.util.*
import sun.plugin2.util.PojoUtil.toJson
import sun.tools.jar.resources.jar
import java.util.Collections.addAll
import java.util.ArrayList
import java.util.Arrays
/**
* Read the manifest in a HMCL modpack.
@ -70,4 +79,43 @@ class HMCLModpackInstallTask(profile: Profile, private val zipFile: File, privat
if (repository.getVersionJson(name) != json)
json.delete()
}
}
val MODPACK_BLACK_LIST = listOf("usernamecache.json", "asm", "logs", "backups", "versions", "assets", "usercache.json", "libraries", "crash-reports", "launcher_profiles.json", "NVIDIA", "AMD", "TCNodeTracker", "screenshots", "natives", "native", "\$native", "pack.json", "launcher.jar", "minetweaker.log", "launcher.pack.lzma", "hmclmc.log")
val MODPACK_SUGGESTED_BLACK_LIST = listOf("fonts", "saves", "servers.dat", "options.txt", "optionsof.txt", "journeymap", "optionsshaders.txt", "mods/VoxelMods")
class HMCLModpackExportTask @JvmOverloads constructor(
private val repository: DefaultGameRepository,
private val version: String,
private val blacklist: List<String>,
private val modpack: Modpack,
private val output: File,
override val id: String = ID): TaskResult<ZipEngine>() {
override fun execute() {
val b = ArrayList<String>(MODPACK_BLACK_LIST)
b.addAll(blacklist)
b.add(version + ".jar")
b.add(version + ".json")
LOG.info("Compressing game files without some files in blacklist, including files or directories: usernamecache.json, asm, logs, backups, versions, assets, usercache.json, libraries, crash-reports, launcher_profiles.json, NVIDIA, TCNodeTracker")
ZipEngine(output).use { zip ->
zip.putDirectory(repository.getRunDirectory(version)) a@ { x: String, y: Boolean ->
for (s in b)
if (y) {
if (x.startsWith(s + "/"))
return@a null
} else if (x == s)
return@a null
"minecraft/" + x
}
val mv = repository.getVersion(version).resolve(repository)
val gameVersion = minecraftVersion(repository.getVersionJar(version)) ?: throw IllegalStateException("Cannot parse the version of $version")
zip.putTextFile(GSON.toJson(mv), "minecraft/pack.json")
zip.putTextFile(GSON.toJson(modpack.copy(gameVersion = gameVersion)), "modpack.json")
}
}
companion object {
val ID = "zip_engine"
}
}

View File

@ -21,6 +21,7 @@ data class Modpack @JvmOverloads constructor(
val name: String = "",
val author: String = "",
val version: String = "",
val gameVersion: String = "",
val description: String = "",
val manifest: Any? = null
)

View File

@ -0,0 +1,126 @@
/*
* 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.util
import java.util.zip.ZipEntry
import java.util.HashSet
import java.io.*
import java.util.zip.ZipOutputStream
/**
* Non thread-safe
*
* @author huangyuhui
*/
class ZipEngine
@Throws(IOException::class)
constructor(f: File) : Closeable {
val buf = ByteArray(1024)
val zos: ZipOutputStream = ZipOutputStream(BufferedOutputStream(f.outputStream()))
private val names = HashSet<String>()
@Throws(IOException::class)
override fun close() {
zos.closeEntry()
zos.close()
}
/**
* 功能 sourceDir 目录下的所有文件进行 zip 格式的压缩保存为指定 zip 文件
*
* @param sourceDir 源文件夹
* @param pathNameCallback callback(pathName, isDirectory) returns your
* modified pathName
*
* @throws java.io.IOException 压缩失败或无法读取
*/
@Throws(IOException::class)
@JvmOverloads
fun putDirectory(sourceDir: File, pathNameCallback: ((String, Boolean) -> String?)? = null) {
putDirectoryImpl(sourceDir, if (sourceDir.isDirectory) sourceDir.path else sourceDir.parent, pathNameCallback)
}
/**
* 将文件压缩成zip文件
*
* @param source zip文件路径
* @param basePath 待压缩文件根目录
* @param zos zip文件的os
* @param pathNameCallback callback(pathName, isDirectory) returns your
* modified pathName, null if you dont want this file zipped
*/
@Throws(IOException::class)
private fun putDirectoryImpl(source: File, basePath: String, pathNameCallback: ((String, Boolean) -> String?)?) {
val files: Array<File>?
if (source.isDirectory)
files = source.listFiles()
else
files = arrayOf(source)
if (files == null)
return
var pathName: String? //存相对路径(相对于待压缩的根目录)
for (file in files)
if (file.isDirectory) {
pathName = file.path.substring(basePath.length + 1) + "/"
pathName = pathName.replace('\\', '/')
if (pathNameCallback != null)
pathName = pathNameCallback(pathName, true)
if (pathName == null)
continue
put(ZipEntry(pathName))
putDirectoryImpl(file, basePath, pathNameCallback)
} else {
if (".DS_Store" == file.name) // For Mac computers.
continue
pathName = file.path.substring(basePath.length + 1)
pathName = pathName.replace('\\', '/')
if (pathNameCallback != null)
pathName = pathNameCallback(pathName, false)
if (pathName == null)
continue
putFile(file, pathName)
}
}
@Throws(IOException::class)
fun putFile(file: File, pathName: String) =
file.inputStream().use { putStream(it, pathName) }
@Throws(IOException::class)
fun putStream(inputStream: InputStream, pathName: String) {
put(ZipEntry(pathName))
inputStream.copyTo(zos, buf)
}
@Throws(IOException::class)
fun putTextFile(text: String, pathName: String) =
putTextFile(text, "UTF-8", pathName)
@Throws(IOException::class)
fun putTextFile(text: String, encoding: String, pathName: String) =
putStream(ByteArrayInputStream(text.toByteArray(charset(encoding))), pathName)
@Throws(IOException::class)
fun put(entry: ZipEntry) {
if (names.add(entry.name))
zos.putNextEntry(entry)
}
}