HMCL modpack import

This commit is contained in:
huangyuhui
2017-08-22 20:15:26 +08:00
parent 0cc7d621bc
commit d83291eac0
9 changed files with 186 additions and 21 deletions

View File

@@ -15,11 +15,12 @@
* 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.setting
package org.jackhuang.hmcl.game
import javafx.scene.image.Image
import org.jackhuang.hmcl.Main
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount
import org.jackhuang.hmcl.setting.Settings
import org.jackhuang.hmcl.task.FileDownloadTask
import org.jackhuang.hmcl.task.Scheduler
import org.jackhuang.hmcl.task.Task

View File

@@ -0,0 +1,73 @@
/*
* 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.JsonParseException
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
/**
* Read the manifest in a HMCL modpack.
*
* @param f a HMCL modpack file.
* @throws IOException if the file is not a valid zip file.
* @throws JsonParseException if the manifest.json is missing or malformed.
* @return the manifest of HMCL modpack.
*/
@Throws(IOException::class, JsonParseException::class)
fun readHMCLModpackManifest(f: File): Modpack {
val json = readTextFromZipFile(f, "modpack.json")
return GSON.fromJson<Modpack>(json)?.copy(manifest = HMCLModpackManifest) ?: throw JsonParseException("`modpack.json` not found. Not a valid CurseForge modpack.")
}
object HMCLModpackManifest
class HMCLModpackInstallTask(profile: Profile, private val zipFile: File, private val name: String): Task() {
private val dependency = profile.dependency
private val repository = profile.repository
override val dependencies = mutableListOf<Task>()
override val dependents = mutableListOf<Task>()
init {
check(!repository.hasVersion(name), { "Version $name already exists." })
val json = readTextFromZipFile(zipFile, "minecraft/pack.json")
var version = GSON.fromJson<Version>(json)!!
val jar = version.jar!!
version = version.copy(jar = null)
dependents += dependency.gameBuilder().name(name).gameVersion(jar).buildAsync()
dependencies += dependency.checkGameCompletionAsync(version)
dependencies += VersionJSONSaveTask(dependency, version)
}
private val run = repository.getRunDirectory(name)
override fun execute() {
unzipSubDirectory(zipFile, run, "minecraft/", false)
val json = run.resolve("pack.json")
if (repository.getVersionJson(name) != json)
json.delete()
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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 org.jackhuang.hmcl.mod.Modpack
import org.jackhuang.hmcl.mod.readCurseForgeModpackManifest
import org.jackhuang.hmcl.util.readTextFromZipFileQuietly
import java.io.File
fun readModpackManifest(f: File): Modpack {
try {
val manifest = readCurseForgeModpackManifest(f)
return Modpack(
name = manifest.name,
version = manifest.version,
author = manifest.author,
description = readTextFromZipFileQuietly(f, "modlist.html") ?: "No description",
manifest = manifest)
} catch (e: Exception) {
// ignore it, not a CurseForge modpack.
}
try {
val manifest = readHMCLModpackManifest(f)
return manifest
} catch (e: Exception) {
// ignore it, not a HMCL modpack.
}
throw IllegalArgumentException("Modpack file $f is not supported.")
}

View File

@@ -36,7 +36,7 @@ import javafx.scene.paint.Color
import org.jackhuang.hmcl.auth.Account
import org.jackhuang.hmcl.auth.OfflineAccount
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount
import org.jackhuang.hmcl.setting.AccountHelper
import org.jackhuang.hmcl.game.AccountHelper
import org.jackhuang.hmcl.setting.Settings
import org.jackhuang.hmcl.task.Scheduler
import java.util.concurrent.Callable

View File

@@ -19,8 +19,11 @@ package org.jackhuang.hmcl.ui.download
import javafx.scene.Node
import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider
import org.jackhuang.hmcl.game.HMCLModpackInstallTask
import org.jackhuang.hmcl.game.HMCLModpackManifest
import org.jackhuang.hmcl.mod.CurseForgeModpackInstallTask
import org.jackhuang.hmcl.mod.CurseForgeModpackManifest
import org.jackhuang.hmcl.mod.Modpack
import org.jackhuang.hmcl.setting.EnumGameDirectory
import org.jackhuang.hmcl.setting.Profile
import org.jackhuang.hmcl.setting.Settings
@@ -62,11 +65,12 @@ class DownloadWizardProvider(): WizardProvider() {
return null
val selectedFile = settings[ModpackPage.MODPACK_FILE] as? File? ?: return null
val manifest = settings[ModpackPage.MODPACK_CURSEFORGE_MANIFEST] as? CurseForgeModpackManifest? ?: return null
val modpack = settings[ModpackPage.MODPACK_CURSEFORGE_MANIFEST] as? Modpack? ?: return null
val name = settings[ModpackPage.MODPACK_NAME] as? String? ?: return null
profile.repository.markVersionAsModpack(name)
return CurseForgeModpackInstallTask(profile.dependency, selectedFile, manifest, name) with task {
val finalizeTask = task {
profile.repository.refreshVersions()
val vs = profile.specializeVersionSetting(name)
profile.repository.undoMark(name)
@@ -74,6 +78,12 @@ class DownloadWizardProvider(): WizardProvider() {
vs.gameDirType = EnumGameDirectory.VERSION_FOLDER
}
}
return when (modpack.manifest) {
is CurseForgeModpackManifest -> CurseForgeModpackInstallTask(profile.dependency, selectedFile, modpack.manifest as CurseForgeModpackManifest, name)
is HMCLModpackManifest -> HMCLModpackInstallTask(profile, selectedFile, name)
else -> throw Error()
} with finalizeTask
}
override fun finish(settings: MutableMap<String, Any>): Any? {

View File

@@ -25,6 +25,7 @@ import javafx.fxml.FXML
import javafx.scene.control.Label
import javafx.scene.layout.StackPane
import javafx.stage.FileChooser
import org.jackhuang.hmcl.game.readModpackManifest
import org.jackhuang.hmcl.i18n
import org.jackhuang.hmcl.mod.readCurseForgeModpackManifest
import org.jackhuang.hmcl.setting.Profile
@@ -52,6 +53,7 @@ class ModpackPage(private val controller: WizardController): StackPane(), Wizard
val chooser = FileChooser()
chooser.title = i18n("modpack.choose")
chooser.extensionFilters += FileChooser.ExtensionFilter("Zip", "*.zip")
val selectedFile = chooser.showOpenDialog(Controllers.stage)
if (selectedFile == null) Platform.runLater { controller.onFinish() }
else {
@@ -65,14 +67,12 @@ class ModpackPage(private val controller: WizardController): StackPane(), Wizard
}
try {
val manifest = readCurseForgeModpackManifest(selectedFile)
val manifest = readModpackManifest(selectedFile)
controller.settings[MODPACK_CURSEFORGE_MANIFEST] = manifest
lblName.text = manifest.name
lblVersion.text = manifest.version
lblAuthor.text = manifest.author
} catch (e: IOException) {
// TODO
} catch (e: JsonParseException) {
} catch (e: Exception) {
// TODO
}
}

View File

@@ -30,7 +30,6 @@ import java.io.File
import java.io.IOException
import java.net.URL
import java.util.logging.Level
import java.util.zip.ZipFile
class CurseForgeModpackManifest @JvmOverloads constructor(
@SerializedName("manifestType")
@@ -54,6 +53,8 @@ class CurseForgeModpackManifest @JvmOverloads constructor(
check(manifestType == MINECRAFT_MODPACK, { "Only support Minecraft modpack" })
}
fun toModpack() = Modpack(name = name, author = author, version = version, description = "No description")
companion object {
val MINECRAFT_MODPACK = "minecraftModpack"
}
@@ -101,14 +102,15 @@ class CurseForgeModpackManifestFile (
/**
* @param f the CurseForge modpack file.
* @throws IOException if the file is not a valid zip file.
* @throws JsonParseException if the manifest.json is missing or malformed.
* @return the manifest.
*/
@Throws(IOException::class, JsonParseException::class)
fun readCurseForgeModpackManifest(f: File): CurseForgeModpackManifest {
ZipFile(f).use { zipFile ->
val entry = zipFile.getEntry("manifest.json") ?: throw IOException("`manifest.json` not found. Not a valid CurseForge modpack.")
val json = zipFile.getInputStream(entry).readFullyAsString()
return GSON.fromJson<CurseForgeModpackManifest>(json) ?: throw JsonParseException("`manifest.json` not found. Not a valid CurseForge modpack.")
}
val json = readTextFromZipFile(f, "manifest.json")
return GSON.fromJson<CurseForgeModpackManifest>(json)
?: throw JsonParseException("`manifest.json` not found. Not a valid CurseForge modpack.")
}
/**
@@ -123,8 +125,7 @@ fun readCurseForgeModpackManifest(f: File): CurseForgeModpackManifest {
class CurseForgeModpackInstallTask(private val dependencyManager: DefaultDependencyManager, private val zipFile: File, private val manifest: CurseForgeModpackManifest, private val name: String): Task() {
val repository = dependencyManager.repository
init {
if (repository.hasVersion(name))
throw IllegalStateException("Version $name already exists.")
check(!repository.hasVersion(name), { "Version $name already exists." })
}
val root = repository.getVersionRoot(name)

View File

@@ -17,8 +17,10 @@
*/
package org.jackhuang.hmcl.mod
import java.io.File
class Modpack(val file: File) {
}
data class Modpack @JvmOverloads constructor(
val name: String = "",
val author: String = "",
val version: String = "",
val description: String = "",
val manifest: Any? = null
)

View File

@@ -20,6 +20,7 @@ package org.jackhuang.hmcl.util
import java.io.File
import java.io.IOException
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
@@ -194,4 +195,35 @@ 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
* @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.")
return zipFile.getInputStream(entry).readFullyAsString()
}
}
/**
* 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
* @return the content of given file.
*/
fun readTextFromZipFileQuietly(f: File, location: String): String? {
try {
return readTextFromZipFile(f, location)
} catch (e: IOException) {
return null
}
}