Auto-installing

This commit is contained in:
huangyuhui 2017-08-24 19:20:15 +08:00
parent 6da1dc5372
commit 0fa601ad5e
25 changed files with 472 additions and 68 deletions

View File

@ -76,7 +76,7 @@ class HMCLModpackInstallTask(profile: Profile, private val zipFile: File, privat
version = version.copy(jar = null)
dependents += dependency.gameBuilder().name(name).gameVersion(modpack.gameVersion!!).buildAsync()
dependencies += dependency.checkGameCompletionAsync(version)
dependencies += VersionJSONSaveTask(dependency, version)
dependencies += VersionJSONSaveTask(repository, version)
}
private val run = repository.getRunDirectory(name)

View File

@ -0,0 +1,86 @@
/*
* 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.ui
import javafx.fxml.FXML
import javafx.scene.control.ScrollPane
import javafx.scene.layout.VBox
import org.jackhuang.hmcl.download.game.VersionJSONSaveTask
import org.jackhuang.hmcl.game.Version
import org.jackhuang.hmcl.game.minecraftVersion
import org.jackhuang.hmcl.setting.Profile
import org.jackhuang.hmcl.task.Scheduler
import org.jackhuang.hmcl.task.task
import org.jackhuang.hmcl.ui.download.InstallWizardProvider
import java.util.*
class InstallerController {
private lateinit var profile: Profile
private lateinit var versionId: String
private lateinit var version: Version
@FXML lateinit var scrollPane: ScrollPane
@FXML lateinit var contentPane: VBox
private var forge: String? = null
private var liteloader: String? = null
private var optifine: String? = null
fun initialize() {
scrollPane.smoothScrolling()
}
fun loadVersion(profile: Profile, versionId: String) {
this.profile = profile
this.versionId = versionId
this.version = profile.repository.getVersion(versionId).resolve(profile.repository)
contentPane.children.clear()
forge = null
liteloader = null
optifine = null
for (library in version.libraries) {
val removeAction = { _: InstallerItem ->
val newList = LinkedList(version.libraries)
newList.remove(library)
VersionJSONSaveTask(profile.repository, version.copy(libraries = newList))
.with(task { profile.repository.refreshVersions() })
.with(task(Scheduler.JAVAFX) { loadVersion(this.profile, this.versionId) })
.start()
}
if (library.groupId.equals("net.minecraftforge", ignoreCase = true) && library.artifactId.equals("forge", ignoreCase = true)) {
contentPane.children += InstallerItem("Forge", library.version, removeAction)
forge = library.version
} else if (library.groupId.equals("com.mumfrey", ignoreCase = true) && library.artifactId.equals("liteloader", ignoreCase = true)) {
contentPane.children += InstallerItem("LiteLoader", library.version, removeAction)
liteloader = library.version
} else if ((library.groupId.equals("net.optifine", ignoreCase = true) || library.groupId.equals("optifine", ignoreCase = true)) && library.artifactId.equals("optifine", ignoreCase = true)) {
contentPane.children += InstallerItem("OptiFine", library.version, removeAction)
optifine = library.version
}
}
}
fun onAdd() {
// TODO: if minecraftVersion returns null.
val gameVersion = minecraftVersion(profile.repository.getVersionJar(version)) ?: return
Controllers.decorator.startWizard(InstallWizardProvider(profile, gameVersion, version, forge, liteloader, optifine))
}
}

View File

@ -0,0 +1,24 @@
package org.jackhuang.hmcl.ui
import com.jfoenix.effects.JFXDepthManager
import javafx.fxml.FXML
import javafx.scene.control.Label
import javafx.scene.layout.BorderPane
class InstallerItem(artifact: String, version: String, private val deleteCallback: (InstallerItem) -> Unit) : BorderPane() {
@FXML lateinit var lblInstallerArtifact: Label
@FXML lateinit var lblInstallerVersion: Label
init {
loadFXML("/assets/fxml/version/installer-item.fxml")
style = "-fx-background-radius: 2; -fx-background-color: white; -fx-padding: 8;"
JFXDepthManager.setDepth(this, 1)
lblInstallerArtifact.text = artifact
lblInstallerVersion.text = version
}
fun onDelete() {
deleteCallback(this)
}
}

View File

@ -69,9 +69,6 @@ class ModController {
modManager.removeMods(versionId, modInfo)
loadMods(modManager, versionId)
}.apply {
JFXDepthManager.setDepth(this, 1)
style += "-fx-background-radius: 2; -fx-background-color: white; -fx-padding: 8;"
modInfo.activeProperty.onChange {
if (it)
styleClass -= "disabled"

View File

@ -18,6 +18,7 @@
package org.jackhuang.hmcl.ui
import com.jfoenix.controls.JFXCheckBox
import com.jfoenix.effects.JFXDepthManager
import javafx.fxml.FXML
import javafx.scene.control.Label
import javafx.scene.layout.BorderPane
@ -30,8 +31,10 @@ class ModItem(info: ModInfo, private val deleteCallback: (ModItem) -> Unit) : Bo
@FXML lateinit var chkEnabled: JFXCheckBox
init {
loadFXML("/assets/fxml/mod-item.fxml")
loadFXML("/assets/fxml/version/mod-item.fxml")
style = "-fx-background-radius: 2; -fx-background-color: white; -fx-padding: 8;"
JFXDepthManager.setDepth(this, 1)
lblModFileName.text = info.fileName
lblModAuthor.text = "${info.name}, Version: ${info.version}, Game Version: ${info.mcversion}, Authors: ${info.authors}"
chkEnabled.isSelected = info.isActive

View File

@ -37,6 +37,8 @@ class VersionPage : StackPane(), DecoratorPage {
@FXML lateinit var versionSettingsController: VersionSettingsController
@FXML lateinit var modController: ModController
@FXML lateinit var installerController: InstallerController
@FXML lateinit var browseList: JFXListView<*>
@FXML lateinit var managementList: JFXListView<*>
@FXML lateinit var btnBrowseMenu: JFXButton
@ -48,7 +50,7 @@ class VersionPage : StackPane(), DecoratorPage {
lateinit var version: String
init {
loadFXML("/assets/fxml/version.fxml")
loadFXML("/assets/fxml/version/version.fxml")
children -= browseList
children -= managementList
@ -68,6 +70,7 @@ class VersionPage : StackPane(), DecoratorPage {
versionSettingsController.loadVersionSetting(profile.getVersionSetting(id))
modController.loadMods(profile.modManager, id)
installerController.loadVersion(profile, id)
}
fun onBrowseMenu() {

View File

@ -0,0 +1,103 @@
/*
* 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.ui.download
import com.jfoenix.controls.JFXButton
import com.jfoenix.controls.JFXListView
import javafx.fxml.FXML
import javafx.scene.control.Label
import javafx.scene.layout.StackPane
import javafx.scene.layout.VBox
import org.jackhuang.hmcl.download.DownloadProvider
import org.jackhuang.hmcl.game.GameRepository
import org.jackhuang.hmcl.ui.loadFXML
import org.jackhuang.hmcl.ui.wizard.WizardController
import org.jackhuang.hmcl.ui.wizard.WizardPage
class AdditionalInstallersPage(private val provider: InstallWizardProvider, private val controller: WizardController, private val repository: GameRepository, private val downloadProvider: DownloadProvider): StackPane(), WizardPage {
@FXML lateinit var list: VBox
@FXML lateinit var btnForge: JFXButton
@FXML lateinit var btnLiteLoader: JFXButton
@FXML lateinit var btnOptiFine: JFXButton
@FXML lateinit var lblGameVersion: Label
@FXML lateinit var lblVersionName: Label
@FXML lateinit var lblForge: Label
@FXML lateinit var lblLiteLoader: Label
@FXML lateinit var lblOptiFine: Label
@FXML lateinit var btnInstall: JFXButton
init {
loadFXML("/assets/fxml/download/additional-installers.fxml")
lblGameVersion.text = provider.gameVersion
lblVersionName.text = provider.version.id
btnForge.setOnMouseClicked {
controller.settings[INSTALLER_TYPE] = 0
controller.onNext(VersionsPage(controller, provider.gameVersion, downloadProvider, "forge") { controller.onPrev(false) })
}
btnLiteLoader.setOnMouseClicked {
controller.settings[INSTALLER_TYPE] = 1
controller.onNext(VersionsPage(controller, provider.gameVersion, downloadProvider, "liteloader") { controller.onPrev(false) })
}
btnOptiFine.setOnMouseClicked {
controller.settings[INSTALLER_TYPE] = 2
controller.onNext(VersionsPage(controller, provider.gameVersion, downloadProvider, "optifine") { controller.onPrev(false) })
}
}
override val title: String
get() = "Choose a game version"
override fun onNavigate(settings: MutableMap<String, Any>) {
lblGameVersion.text = "Current Game Version: ${provider.gameVersion}"
btnForge.isDisable = provider.forge != null
if (provider.forge != null || controller.settings.containsKey("forge"))
lblForge.text = "Forge Versoin: ${provider.forge ?: controller.settings["forge"]}"
else
lblForge.text = "Forge not installed"
btnLiteLoader.isDisable = provider.liteloader != null
if (provider.liteloader != null || controller.settings.containsKey("liteloader"))
lblLiteLoader.text = "LiteLoader Versoin: ${provider.liteloader ?: controller.settings["liteloader"]}"
else
lblLiteLoader.text = "LiteLoader not installed"
btnOptiFine.isDisable = provider.optifine != null
if (provider.optifine != null || controller.settings.containsKey("optifine"))
lblOptiFine.text = "OptiFine Versoin: ${provider.optifine ?: controller.settings["optifine"]}"
else
lblOptiFine.text = "OptiFine not installed"
}
override fun cleanup(settings: MutableMap<String, Any>) {
settings.remove(INSTALLER_TYPE)
}
fun onInstall() {
controller.onFinish()
}
companion object {
val INSTALLER_TYPE = "INSTALLER_TYPE"
}
}

View File

@ -95,10 +95,11 @@ class DownloadWizardProvider(): WizardProvider() {
}
override fun createPage(controller: WizardController, step: Int, settings: MutableMap<String, Any>): Node {
val provider = profile.dependency.downloadProvider
return when (step) {
0 -> InstallTypePage(controller)
1 -> when (settings[InstallTypePage.INSTALL_TYPE]) {
0 -> VersionsPage(controller, "", BMCLAPIDownloadProvider, "game") { controller.onNext(InstallersPage(controller, profile.repository, BMCLAPIDownloadProvider)) }
0 -> VersionsPage(controller, "", provider, "game") { controller.onNext(InstallersPage(controller, profile.repository, provider)) }
1 -> ModpackPage(controller)
else -> throw Error()
}

View File

@ -0,0 +1,52 @@
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.game.Version
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
import org.jackhuang.hmcl.task.Scheduler
import org.jackhuang.hmcl.task.Task
import org.jackhuang.hmcl.task.task
import org.jackhuang.hmcl.ui.wizard.WizardController
import org.jackhuang.hmcl.ui.wizard.WizardProvider
import java.io.File
class InstallWizardProvider(val profile: Profile, val gameVersion: String, val version: Version, val forge: String? = null, val liteloader: String? = null, val optifine: String? = null): WizardProvider() {
override fun start(settings: MutableMap<String, Any>) {
}
override fun finish(settings: MutableMap<String, Any>): Any? {
var ret = task {}
if (settings.containsKey("forge"))
ret = ret with profile.dependency.installLibraryAsync(gameVersion, version, "forge", settings["forge"] as String)
if (settings.containsKey("liteloader"))
ret = ret with profile.dependency.installLibraryAsync(gameVersion, version, "liteloader", settings["liteloader"] as String)
if (settings.containsKey("optifine"))
ret = ret with profile.dependency.installLibraryAsync(gameVersion, version, "optifine", settings["optifine"] as String)
return ret with task(Scheduler.JAVAFX) { profile.repository.refreshVersions() }
}
override fun createPage(controller: WizardController, step: Int, settings: MutableMap<String, Any>): Node {
return when (step) {
0 -> AdditionalInstallersPage(this, controller, profile.repository, BMCLAPIDownloadProvider)
else -> throw IllegalStateException()
}
}
override fun cancel(): Boolean {
return true
}
}

View File

@ -23,6 +23,7 @@ import com.jfoenix.controls.JFXTextField
import javafx.fxml.FXML
import javafx.scene.control.Label
import javafx.scene.layout.StackPane
import javafx.scene.layout.VBox
import org.jackhuang.hmcl.download.DownloadProvider
import org.jackhuang.hmcl.game.GameRepository
import org.jackhuang.hmcl.i18n
@ -30,11 +31,13 @@ import org.jackhuang.hmcl.ui.construct.Validator
import org.jackhuang.hmcl.ui.loadFXML
import org.jackhuang.hmcl.ui.wizard.WizardController
import org.jackhuang.hmcl.ui.wizard.WizardPage
import org.jackhuang.hmcl.util.onChange
class InstallersPage(private val controller: WizardController, private val repository: GameRepository, private val downloadProvider: DownloadProvider): StackPane(), WizardPage {
@FXML lateinit var list: JFXListView<VersionsPageItem>
@FXML lateinit var list: VBox
@FXML lateinit var btnForge: JFXButton
@FXML lateinit var btnLiteLoader: JFXButton
@FXML lateinit var btnOptiFine: JFXButton
@FXML lateinit var lblGameVersion: Label
@FXML lateinit var lblForge: Label
@FXML lateinit var lblLiteLoader: Label
@ -52,14 +55,19 @@ class InstallersPage(private val controller: WizardController, private val repos
}
txtName.text = gameVersion
list.selectionModel.selectedIndexProperty().onChange {
controller.settings[INSTALLER_TYPE] = it
controller.onNext(when (it){
0 -> VersionsPage(controller, gameVersion, downloadProvider, "forge") { controller.onPrev(false) }
1 -> VersionsPage(controller, gameVersion, downloadProvider, "liteloader") { controller.onPrev(false) }
2 -> VersionsPage(controller, gameVersion, downloadProvider, "optifine") { controller.onPrev(false) }
else -> throw IllegalStateException()
})
btnForge.setOnMouseClicked {
controller.settings[INSTALLER_TYPE] = 0
controller.onNext(VersionsPage(controller, gameVersion, downloadProvider, "forge") { controller.onPrev(false) })
}
btnLiteLoader.setOnMouseClicked {
controller.settings[INSTALLER_TYPE] = 1
controller.onNext(VersionsPage(controller, gameVersion, downloadProvider, "liteloader") { controller.onPrev(false) })
}
btnOptiFine.setOnMouseClicked {
controller.settings[INSTALLER_TYPE] = 2
controller.onNext(VersionsPage(controller, gameVersion, downloadProvider, "optifine") { controller.onPrev(false) })
}
}

View File

@ -28,10 +28,15 @@ class WizardController(protected val displayer: WizardDisplayer) : Navigation {
override fun onStart() {
settings.clear()
provider.start(settings)
pages.clear()
val page = navigatingTo(0)
pages.push(page)
provider.start(settings)
if (page is WizardPage)
page.onNavigate(settings)
displayer.onStart()
displayer.navigateTo(page, Navigation.NavigationDirection.START)
}

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.*?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane" style="-fx-padding: 16;">
<BorderPane>
<top>
<VBox alignment="CENTER" style="-fx-padding: 40px;" spacing="20">
<Label fx:id="lblGameVersion" alignment="CENTER"/>
<Label fx:id="lblVersionName" alignment="CENTER"/>
</VBox>
</top>
<center>
<VBox fx:id="list" styleClass="jfx-list-view" maxHeight="150" maxWidth="300">
<JFXButton fx:id="btnForge" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblForge">Install Forge</Label>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnLiteLoader" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblLiteLoader">Install LiteLoader</Label>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnOptiFine" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblOptiFine">Install OptiFine</Label>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
</VBox>
</center>
<bottom>
<HBox alignment="CENTER">
<JFXButton fx:id="btnInstall" onMouseClicked="#onInstall" prefWidth="100" prefHeight="40"
buttonType="RAISED" text="%ui.button.install" styleClass="jfx-button-raised"/>
</HBox>
</bottom>
</BorderPane>
</fx:root>

View File

@ -1,54 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXListView?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import com.jfoenix.controls.*?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.scene.layout.HBox?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.scene.layout.*?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
type="StackPane" style="-fx-padding: 16;">
<BorderPane>
<top>
<VBox alignment="CENTER" style="-fx-padding: 40px;" spacing="20">
<Label fx:id="lblGameVersion" alignment="CENTER" />
<JFXTextField fx:id="txtName" labelFloat="true" promptText="%modpack.enter_name" maxWidth="300" />
<Label fx:id="lblGameVersion" alignment="CENTER"/>
<JFXTextField fx:id="txtName" labelFloat="true" promptText="%modpack.enter_name" maxWidth="300"/>
</VBox>
</top>
<center>
<JFXListView fx:id="list" styleClass="jfx-list-view" maxHeight="150" maxWidth="300">
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblForge">Install Forge</Label>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblLiteLoader">Install LiteLoader</Label>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblOptiFine">Install OptiFine</Label>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</JFXListView>
<VBox fx:id="list" styleClass="jfx-list-view" maxHeight="150" maxWidth="300">
<JFXButton fx:id="btnForge" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblForge">Install Forge</Label>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnLiteLoader" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblLiteLoader">Install LiteLoader</Label>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnOptiFine" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblOptiFine">Install OptiFine</Label>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
</VBox>
</center>
<bottom>
<HBox alignment="CENTER">
<JFXButton fx:id="btnInstall" onMouseClicked="#onInstall" prefWidth="100" prefHeight="40" buttonType="RAISED" text="%ui.button.install" styleClass="jfx-button-raised" />
<JFXButton fx:id="btnInstall" onMouseClicked="#onInstall" prefWidth="100" prefHeight="40"
buttonType="RAISED" text="%ui.button.install" styleClass="jfx-button-raised"/>
</HBox>
</bottom>
</BorderPane>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import com.jfoenix.controls.JFXButton?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="BorderPane">
<center>
<VBox BorderPane.alignment="CENTER">
<Label fx:id="lblInstallerArtifact" style="-fx-font-size: 15;" />
<Label fx:id="lblInstallerVersion" style="-fx-font-size: 10;" />
</VBox>
</center>
<right>
<JFXButton onMouseClicked="#onDelete" styleClass="toggle-icon4" BorderPane.alignment="CENTER">
<graphic>
<fx:include source="/assets/svg/close-black.fxml"/>
</graphic>
</JFXButton>
</right>
</fx:root>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.scene.control.ScrollPane?>
<StackPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.jackhuang.hmcl.ui.InstallerController">
<ScrollPane fx:id="scrollPane" fitToWidth="true" fitToHeight="true">
<VBox fx:id="contentPane" spacing="10" style="-fx-padding: 20;">
</VBox>
</ScrollPane>
<VBox style="-fx-padding: 15;" spacing="15" pickOnBounds="false" alignment="BOTTOM_RIGHT">
<JFXButton prefWidth="40" prefHeight="40" buttonType="RAISED" onMouseClicked="#onAdd"
style="-fx-background-color:#5264AE;-fx-background-radius: 50px;">
<graphic>
<fx:include source="/assets/svg/plus.fxml" />
</graphic>
</JFXButton>
</VBox>
</StackPane>

View File

@ -13,6 +13,9 @@
<Tab text="%mods">
<fx:include source="mod.fxml" fx:id="mod" />
</Tab>
<Tab text="%settings.tabs.installers">
<fx:include source="installer.fxml" fx:id="installer" />
</Tab>
</JFXTabPane>
<HBox alignment="TOP_RIGHT" style="-fx-padding: 3px;" pickOnBounds="false">

View File

@ -51,13 +51,13 @@ class DefaultDependencyManager(override val repository: DefaultGameRepository, o
override fun installLibraryAsync(gameVersion: String, version: Version, libraryId: String, libraryVersion: String): Task {
if (libraryId == "forge")
return ForgeInstallTask(this, gameVersion, version, libraryVersion)
.then { VersionJSONSaveTask(this, it["version"]) }
.then { VersionJSONSaveTask(repository, it["version"]) }
else if (libraryId == "liteloader")
return LiteLoaderInstallTask(this, gameVersion, version, libraryVersion)
.then { VersionJSONSaveTask(this, it["version"]) }
.then { VersionJSONSaveTask(repository, it["version"]) }
else if (libraryId == "optifine")
return OptiFineInstallTask(this, gameVersion, version, libraryVersion)
.then { VersionJSONSaveTask(this, it["version"]) }
.then { VersionJSONSaveTask(repository, it["version"]) }
else
throw IllegalArgumentException("Library id $libraryId is unrecognized.")
}

View File

@ -45,7 +45,7 @@ class DefaultGameBuilder(val dependencyManager: DefaultDependencyManager): GameB
GameLoggingDownloadTask(dependencyManager, version),
GameDownloadTask(version),
GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
) then VersionJSONSaveTask(dependencyManager, version)
) then VersionJSONSaveTask(dependencyManager.repository, version)
if (toolVersions.containsKey("forge"))
result = result then libraryTaskHelper(gameVersion, "forge")

View File

@ -20,10 +20,7 @@ package org.jackhuang.hmcl.download.game
import org.jackhuang.hmcl.download.AbstractDependencyManager
import org.jackhuang.hmcl.download.DefaultDependencyManager
import org.jackhuang.hmcl.download.DependencyManager
import org.jackhuang.hmcl.game.AssetIndex
import org.jackhuang.hmcl.game.AssetObject
import org.jackhuang.hmcl.game.DownloadType
import org.jackhuang.hmcl.game.Version
import org.jackhuang.hmcl.game.*
import org.jackhuang.hmcl.task.FileDownloadTask
import org.jackhuang.hmcl.task.Task
import org.jackhuang.hmcl.task.TaskResult
@ -164,12 +161,12 @@ class GameAssetDownloadTask(private val dependencyManager: DefaultDependencyMana
/**
* This task is to save the version json.
* @param dependencyManager the dependency manager that can provides proxy settings and [GameRepository]
* @param repository the game repository
* @param version the **resolved** version
*/
class VersionJSONSaveTask(private val dependencyManager: DefaultDependencyManager, private val version: Version): Task() {
class VersionJSONSaveTask(private val repository: DefaultGameRepository, private val version: Version): Task() {
override fun execute() {
val json = dependencyManager.repository.getVersionJson(version.id).absoluteFile
val json = repository.getVersionJson(version.id).absoluteFile
if (!json.makeFile())
throw IOException("Cannot create file $json")
json.writeText(GSON.toJson(version))

View File

@ -74,12 +74,13 @@ 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)
if (arr.size != 3)
if (arr.size != 3 && arr.size != 4)
throw IllegalArgumentException("Library name is malformed. Correct example: group:artifact:version.")
return Library(
groupId = arr[0].replace("\\", "/"),
artifactId = arr[1],
version = arr[2],
classifier_ = arr.getOrNull(3),
url = url,
downloads = downloads,
extract = extract,

View File

@ -65,6 +65,10 @@ class GetTask @JvmOverloads constructor(val url: URL, val encoding: Charset = Ch
return
}
if (size > 0 && size != read) {
throw IllegalStateException("Not completed! Readed: $read, Size: $size")
}
result = baos.toString(encoding.name())
return
} catch (e: IOException) {

View File

@ -50,7 +50,7 @@ abstract class Task {
*/
open val reliant: Boolean = true
var title: String = this.javaClass.toString()
open var title: String = this.javaClass.toString()
var variables: AutoTypingMap<String>? = null