mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-04-18 18:40:34 +08:00
Launching progress
This commit is contained in:
parent
27939c6b61
commit
383453f9af
@ -17,27 +17,86 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.game
|
||||
|
||||
import org.jackhuang.hmcl.auth.AuthenticationException
|
||||
import org.jackhuang.hmcl.launch.DefaultLauncher
|
||||
import org.jackhuang.hmcl.mod.CurseForgeModpackCompletionTask
|
||||
import org.jackhuang.hmcl.setting.Settings
|
||||
import org.jackhuang.hmcl.task.Scheduler
|
||||
import org.jackhuang.hmcl.task.*
|
||||
import org.jackhuang.hmcl.ui.Controllers
|
||||
import org.jackhuang.hmcl.ui.DialogController
|
||||
import org.jackhuang.hmcl.ui.LaunchingStepsPane
|
||||
import org.jackhuang.hmcl.ui.runOnUiThread
|
||||
|
||||
|
||||
object LauncherHelper {
|
||||
val launchingStepsPane = LaunchingStepsPane()
|
||||
|
||||
fun launch() {
|
||||
val profile = Settings.selectedProfile
|
||||
val repository = profile.repository
|
||||
val dependency = profile.dependency
|
||||
val account = Settings.selectedAccount ?: throw IllegalStateException("No account here")
|
||||
val version = repository.getVersion(profile.selectedVersion)
|
||||
val launcher = HMCLGameLauncher(
|
||||
repository = repository,
|
||||
versionId = profile.selectedVersion,
|
||||
options = profile.getVersionSetting(profile.selectedVersion).toLaunchOptions(profile.gameDir),
|
||||
account = account.logIn(Settings.proxy)
|
||||
)
|
||||
var finished = 0
|
||||
|
||||
dependency.checkGameCompletionAsync(version)
|
||||
Controllers.dialog(launchingStepsPane)
|
||||
task(Scheduler.JAVAFX) { emitStatus(LoadingState.DEPENDENCIES) }
|
||||
.then(dependency.checkGameCompletionAsync(version))
|
||||
|
||||
.then(task(Scheduler.JAVAFX) { emitStatus(LoadingState.MODS) })
|
||||
.then(CurseForgeModpackCompletionTask(dependency, profile.selectedVersion))
|
||||
.then(launcher.launchAsync())
|
||||
.subscribe(Scheduler.JAVAFX) { println("lalala") }
|
||||
|
||||
.then(task(Scheduler.JAVAFX) { emitStatus(LoadingState.LOGIN) })
|
||||
.then(task {
|
||||
try {
|
||||
it["account"] = account.logIn(Settings.proxy)
|
||||
} catch (e: AuthenticationException) {
|
||||
it["account"] = DialogController.logIn(account)
|
||||
runOnUiThread { Controllers.dialog(launchingStepsPane) }
|
||||
}
|
||||
})
|
||||
|
||||
.then(task(Scheduler.JAVAFX) { emitStatus(LoadingState.LAUNCHING) })
|
||||
.then(task {
|
||||
it["launcher"] = HMCLGameLauncher(
|
||||
repository = repository,
|
||||
versionId = profile.selectedVersion,
|
||||
options = profile.getVersionSetting(profile.selectedVersion).toLaunchOptions(profile.gameDir),
|
||||
account = it["account"]
|
||||
)
|
||||
})
|
||||
.then { it.get<DefaultLauncher>("launcher").launchAsync() }
|
||||
|
||||
.then(task(Scheduler.JAVAFX) { emitStatus(LoadingState.DONE) })
|
||||
.executor()
|
||||
.apply {
|
||||
taskListener = object : TaskListener {
|
||||
override fun onFinished(task: Task) {
|
||||
++finished
|
||||
runOnUiThread { launchingStepsPane.pgsTasks.progress = 1.0 * finished / totTask.get() }
|
||||
}
|
||||
|
||||
override fun onTerminate() {
|
||||
runOnUiThread { Controllers.closeDialog() }
|
||||
}
|
||||
|
||||
override fun end() {
|
||||
runOnUiThread { Controllers.closeDialog() }
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
fun emitStatus(state: LoadingState) {
|
||||
launchingStepsPane.lblCurrentState.text = state.toString()
|
||||
launchingStepsPane.lblSteps.text = "${state.ordinal + 1} / ${LoadingState.values().size}"
|
||||
}
|
||||
|
||||
enum class LoadingState {
|
||||
DEPENDENCIES,
|
||||
MODS,
|
||||
LOGIN,
|
||||
LAUNCHING,
|
||||
DONE
|
||||
}
|
||||
}
|
@ -23,10 +23,11 @@ import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask
|
||||
import org.jackhuang.hmcl.task.Scheduler
|
||||
import org.jackhuang.hmcl.task.Task
|
||||
import org.jackhuang.hmcl.ui.DialogController
|
||||
import org.jackhuang.hmcl.util.toURL
|
||||
import java.net.Proxy
|
||||
|
||||
object AccountSkin {
|
||||
object AccountHelper {
|
||||
val SKIN_DIR = Main.APPDATA.resolve("skins")
|
||||
|
||||
fun loadSkins(proxy: Proxy = Settings.proxy) {
|
||||
@ -49,7 +50,7 @@ object AccountSkin {
|
||||
|
||||
override fun execute() {
|
||||
if (account.canLogIn && (account.selectedProfile == null || refresh))
|
||||
account.logIn(proxy)
|
||||
DialogController.logIn(account)
|
||||
val profile = account.selectedProfile ?: return
|
||||
val name = profile.name ?: return
|
||||
val url = "http://skins.minecraft.net/MinecraftSkins/$name.png"
|
@ -18,10 +18,8 @@
|
||||
package org.jackhuang.hmcl.ui
|
||||
|
||||
import com.jfoenix.controls.JFXButton
|
||||
import com.jfoenix.controls.JFXCheckBox
|
||||
import com.jfoenix.controls.JFXProgressBar
|
||||
import com.jfoenix.controls.JFXRadioButton
|
||||
import com.jfoenix.effects.JFXDepthManager
|
||||
import javafx.beans.binding.Bindings
|
||||
import javafx.fxml.FXML
|
||||
import javafx.geometry.Rectangle2D
|
||||
@ -30,13 +28,15 @@ import javafx.scene.control.ToggleGroup
|
||||
import javafx.scene.effect.BlurType
|
||||
import javafx.scene.effect.DropShadow
|
||||
import javafx.scene.image.ImageView
|
||||
import javafx.scene.layout.HBox
|
||||
import javafx.scene.layout.Pane
|
||||
import javafx.scene.layout.StackPane
|
||||
import javafx.scene.layout.VBox
|
||||
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.AccountSkin
|
||||
import org.jackhuang.hmcl.setting.AccountHelper
|
||||
import org.jackhuang.hmcl.setting.Settings
|
||||
import org.jackhuang.hmcl.task.Scheduler
|
||||
import java.util.concurrent.Callable
|
||||
@ -53,6 +53,7 @@ class AccountItem(i: Int, val account: Account, group: ToggleGroup) : StackPane(
|
||||
@FXML lateinit var lblType: Label
|
||||
@FXML lateinit var pgsSkin: JFXProgressBar
|
||||
@FXML lateinit var portraitView: ImageView
|
||||
@FXML lateinit var buttonPane: HBox
|
||||
|
||||
init {
|
||||
loadFXML("/assets/fxml/account-item.fxml")
|
||||
@ -78,11 +79,19 @@ class AccountItem(i: Int, val account: Account, group: ToggleGroup) : StackPane(
|
||||
lblUser.text = account.username
|
||||
lblType.text = accountType(account)
|
||||
|
||||
if (account is YggdrasilAccount)
|
||||
if (account is YggdrasilAccount) {
|
||||
btnRefresh.setOnMouseClicked {
|
||||
pgsSkin.isVisible = true
|
||||
AccountSkin.refreshSkinAsync(account).subscribe(Scheduler.JAVAFX) { loadSkin() }
|
||||
AccountHelper.refreshSkinAsync(account)
|
||||
.subscribe(Scheduler.JAVAFX) { loadSkin() }
|
||||
}
|
||||
AccountHelper.loadSkinAsync(account)
|
||||
.subscribe(Scheduler.JAVAFX) { loadSkin() }
|
||||
}
|
||||
|
||||
if (account is OfflineAccount) { // Offline Account cannot be refreshed,
|
||||
buttonPane.children -= btnRefresh
|
||||
}
|
||||
}
|
||||
|
||||
fun loadSkin() {
|
||||
@ -91,7 +100,7 @@ class AccountItem(i: Int, val account: Account, group: ToggleGroup) : StackPane(
|
||||
pgsSkin.isVisible = false
|
||||
val size = 8.0 * 4
|
||||
portraitView.viewport = Rectangle2D(size, size, size, size)
|
||||
portraitView.image = AccountSkin.getSkin(account, 4.0)
|
||||
portraitView.image = AccountHelper.getSkin(account, 4.0)
|
||||
portraitView.fitHeight = 32.0
|
||||
portraitView.fitWidth = 32.0
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ import org.jackhuang.hmcl.auth.Account
|
||||
import org.jackhuang.hmcl.auth.OfflineAccount
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount
|
||||
import org.jackhuang.hmcl.i18n
|
||||
import org.jackhuang.hmcl.setting.AccountSkin
|
||||
import org.jackhuang.hmcl.setting.Settings
|
||||
import org.jackhuang.hmcl.task.Scheduler
|
||||
import org.jackhuang.hmcl.task.taskResult
|
||||
@ -117,11 +116,6 @@ class AccountsPage() : StackPane(), DecoratorPage {
|
||||
Settings.deleteAccount(account.username)
|
||||
Platform.runLater(this@AccountsPage::loadAccounts)
|
||||
}
|
||||
|
||||
if (account is YggdrasilAccount)
|
||||
AccountSkin.loadSkinAsync(account).subscribe(Scheduler.JAVAFX) {
|
||||
loadSkin()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,6 +130,7 @@ class AccountsPage() : StackPane(), DecoratorPage {
|
||||
val username = txtUsername.text
|
||||
val password = txtPassword.text
|
||||
progressBar.isVisible = true
|
||||
lblCreationWarning.text = ""
|
||||
taskResult("create_account") {
|
||||
try {
|
||||
val account = when (type) {
|
||||
|
@ -17,9 +17,11 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui
|
||||
|
||||
import com.jfoenix.controls.JFXDialog
|
||||
import javafx.fxml.FXMLLoader
|
||||
import javafx.scene.Node
|
||||
import javafx.scene.Scene
|
||||
import javafx.scene.layout.Region
|
||||
import javafx.stage.Stage
|
||||
import org.jackhuang.hmcl.Main
|
||||
|
||||
@ -32,7 +34,6 @@ object Controllers {
|
||||
val versionPane = VersionPage()
|
||||
|
||||
lateinit var leftPaneController: LeftPaneController
|
||||
lateinit var sidePaneController: SidePaneController
|
||||
|
||||
lateinit var decorator: Decorator
|
||||
|
||||
@ -42,7 +43,6 @@ object Controllers {
|
||||
decorator = Decorator(stage, mainPane, Main.TITLE, max = false)
|
||||
decorator.showPage(null)
|
||||
leftPaneController = LeftPaneController(decorator.leftPane)
|
||||
sidePaneController = SidePaneController(decorator.sidePane, decorator.drawer)
|
||||
|
||||
decorator.isCustomMaximize = false
|
||||
|
||||
@ -54,6 +54,14 @@ object Controllers {
|
||||
stage.minHeight = 480.0
|
||||
}
|
||||
|
||||
fun dialog(content: Region): JFXDialog {
|
||||
return decorator.showDialog(content)
|
||||
}
|
||||
|
||||
fun closeDialog() {
|
||||
decorator.dialog.close()
|
||||
}
|
||||
|
||||
fun navigate(node: Node?) {
|
||||
decorator.showPage(node)
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
package org.jackhuang.hmcl.ui
|
||||
|
||||
import com.jfoenix.controls.JFXButton
|
||||
import com.jfoenix.controls.JFXDialog
|
||||
import com.jfoenix.controls.JFXDrawer
|
||||
import com.jfoenix.controls.JFXHamburger
|
||||
import com.jfoenix.effects.JFXDepthManager
|
||||
@ -64,6 +65,7 @@ class Decorator @JvmOverloads constructor(private val primaryStage: Stage, priva
|
||||
private var allowMove: Boolean = false
|
||||
private var isDragging: Boolean = false
|
||||
private var windowDecoratorAnimation: Timeline? = null
|
||||
private var dialogShown = false
|
||||
@FXML lateinit var contentPlaceHolder: StackPane
|
||||
@FXML lateinit var drawerWrapper: StackPane
|
||||
@FXML lateinit var titleContainer: BorderPane
|
||||
@ -78,9 +80,9 @@ class Decorator @JvmOverloads constructor(private val primaryStage: Stage, priva
|
||||
@FXML lateinit var lblTitle: Label
|
||||
@FXML lateinit var leftPane: AdvancedListBox
|
||||
@FXML lateinit var drawer: JFXDrawer
|
||||
@FXML lateinit var sidePane: AdvancedListBox
|
||||
@FXML lateinit var titleBurgerContainer: StackPane
|
||||
@FXML lateinit var titleBurger: JFXHamburger
|
||||
@FXML lateinit var dialog: JFXDialog
|
||||
|
||||
private val onCloseButtonActionProperty: ObjectProperty<Runnable> = SimpleObjectProperty(Runnable { Main.stop() })
|
||||
@JvmName("onCloseButtonActionProperty") get
|
||||
@ -125,6 +127,11 @@ class Decorator @JvmOverloads constructor(private val primaryStage: Stage, priva
|
||||
}
|
||||
}
|
||||
|
||||
drawerWrapper.children -= dialog
|
||||
dialog.dialogContainer = drawerWrapper
|
||||
dialog.setOnDialogClosed { dialogShown = false }
|
||||
dialog.setOnDialogOpened { dialogShown = true }
|
||||
|
||||
if (!min) buttonsContainer.children.remove(btnMin)
|
||||
if (!max) buttonsContainer.children.remove(btnMax)
|
||||
|
||||
@ -136,25 +143,6 @@ class Decorator @JvmOverloads constructor(private val primaryStage: Stage, priva
|
||||
|
||||
setOverflowHidden(lookup("#contentPlaceHolderRoot") as Pane)
|
||||
setOverflowHidden(drawerWrapper)
|
||||
|
||||
// init the title hamburger icon
|
||||
drawer.setOnDrawerOpening {
|
||||
val animation = titleBurger.getAnimation()
|
||||
animation.setRate(1.0)
|
||||
animation.play()
|
||||
}
|
||||
drawer.setOnDrawerClosing {
|
||||
val animation = titleBurger.getAnimation()
|
||||
animation.setRate(-1.0)
|
||||
animation.play()
|
||||
}
|
||||
titleBurgerContainer.setOnMouseClicked({
|
||||
if (drawer.isHidden || drawer.isHiding) {
|
||||
drawer.open()
|
||||
} else {
|
||||
drawer.close()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun onMouseMoved(mouseEvent: MouseEvent) {
|
||||
@ -423,6 +411,13 @@ class Decorator @JvmOverloads constructor(private val primaryStage: Stage, priva
|
||||
}
|
||||
}
|
||||
|
||||
fun showDialog(content: Region): JFXDialog {
|
||||
dialog.content = content
|
||||
if (!dialogShown)
|
||||
dialog.show()
|
||||
return dialog
|
||||
}
|
||||
|
||||
fun startWizard(wizardProvider: WizardProvider, category: String? = null) {
|
||||
this.category = category
|
||||
wizardController.provider = wizardProvider
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 org.jackhuang.hmcl.auth.Account
|
||||
import org.jackhuang.hmcl.auth.AuthInfo
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount
|
||||
import org.jackhuang.hmcl.task.SilentException
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
object DialogController {
|
||||
|
||||
fun logIn(account: Account): AuthInfo? {
|
||||
if (account is YggdrasilAccount) {
|
||||
val latch = CountDownLatch(1)
|
||||
val res = AtomicReference<AuthInfo>(null)
|
||||
runOnUiThread {
|
||||
val pane = YggdrasilAccountLoginPane(account, success = {
|
||||
res.set(it)
|
||||
latch.countDown()
|
||||
Controllers.closeDialog()
|
||||
}, failed = {
|
||||
latch.countDown()
|
||||
Controllers.closeDialog()
|
||||
})
|
||||
pane.dialog = Controllers.dialog(pane)
|
||||
}
|
||||
latch.await()
|
||||
if (res.get() == null)
|
||||
throw SilentException()
|
||||
else
|
||||
return res.get()
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
@ -98,9 +98,7 @@ fun ListView<*>.smoothScrolling() {
|
||||
|
||||
fun ScrollPane.smoothScrolling() = JFXScrollPane.smoothScrolling(this)
|
||||
|
||||
fun runOnUiThread(runnable: () -> Unit) = {
|
||||
JFXUtilities.runInFX(runnable)
|
||||
}
|
||||
fun runOnUiThread(runnable: () -> Unit) = JFXUtilities.runInFX(runnable)
|
||||
|
||||
fun takeSnapshot(node: Parent, width: Double, height: Double): WritableImage {
|
||||
val scene = Scene(node, width, height)
|
||||
|
@ -17,9 +17,20 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui
|
||||
|
||||
import com.jfoenix.controls.JFXDrawer
|
||||
import com.jfoenix.controls.JFXProgressBar
|
||||
import javafx.fxml.FXML
|
||||
import javafx.scene.control.Label
|
||||
import javafx.scene.layout.StackPane
|
||||
|
||||
class SidePaneController(sidePane: AdvancedListBox, drawer: JFXDrawer) {
|
||||
class LaunchingStepsPane(): StackPane() {
|
||||
@FXML lateinit var pgsTasks: JFXProgressBar
|
||||
@FXML lateinit var lblCurrentState: Label
|
||||
@FXML lateinit var lblSteps: Label
|
||||
init {
|
||||
loadFXML("/assets/fxml/launching-steps.fxml")
|
||||
|
||||
limitHeight(200.0)
|
||||
limitWidth(400.0)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 com.jfoenix.controls.JFXDialog
|
||||
import com.jfoenix.controls.JFXPasswordField
|
||||
import com.jfoenix.controls.JFXProgressBar
|
||||
import javafx.fxml.FXML
|
||||
import javafx.scene.control.Label
|
||||
import javafx.scene.layout.StackPane
|
||||
import org.jackhuang.hmcl.auth.AuthInfo
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.InvalidCredentialsException
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount
|
||||
import org.jackhuang.hmcl.i18n
|
||||
import org.jackhuang.hmcl.setting.Settings
|
||||
import org.jackhuang.hmcl.task.Scheduler
|
||||
import org.jackhuang.hmcl.task.taskResult
|
||||
|
||||
class YggdrasilAccountLoginPane(private val oldAccount: YggdrasilAccount, private val success: (AuthInfo) -> Unit, private val failed: () -> Unit) : StackPane() {
|
||||
@FXML lateinit var lblUsername: Label
|
||||
@FXML lateinit var txtPassword: JFXPasswordField
|
||||
@FXML lateinit var lblCreationWarning: Label
|
||||
@FXML lateinit var progressBar: JFXProgressBar
|
||||
lateinit var dialog: JFXDialog
|
||||
|
||||
init {
|
||||
loadFXML("/assets/fxml/yggdrasil-account-login.fxml")
|
||||
|
||||
lblUsername.text = oldAccount.username
|
||||
txtPassword.setOnAction {
|
||||
onAccept()
|
||||
}
|
||||
}
|
||||
|
||||
fun onAccept() {
|
||||
val username = oldAccount.username
|
||||
val password = txtPassword.text
|
||||
progressBar.isVisible = true
|
||||
lblCreationWarning.text = ""
|
||||
taskResult("login") {
|
||||
try {
|
||||
val account = YggdrasilAccount.fromUsername(username, password)
|
||||
account.logIn(Settings.proxy)
|
||||
} catch (e: Exception) {
|
||||
e
|
||||
}
|
||||
}.subscribe(Scheduler.JAVAFX) {
|
||||
val account: Any = it["login"]
|
||||
if (account is AuthInfo) {
|
||||
success(account)
|
||||
dialog.close()
|
||||
} else if (account is InvalidCredentialsException) {
|
||||
lblCreationWarning.text = i18n("login.wrong_password")
|
||||
} else if (account is Exception) {
|
||||
lblCreationWarning.text = account.javaClass.toString() + ": " + account.localizedMessage
|
||||
}
|
||||
progressBar.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
fun onCancel() {
|
||||
failed()
|
||||
dialog.close()
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@
|
||||
<StackPane fx:id="body" style="-fx-background-radius: 0 0 2 2; -fx-background-color: rgb(255,255,255,0.87); -fx-padding: 8;" minHeight="40">
|
||||
<BorderPane>
|
||||
<left>
|
||||
<HBox spacing="8">
|
||||
<HBox fx:id="buttonPane" spacing="8">
|
||||
<JFXButton fx:id="btnRefresh" styleClass="toggle-icon4" maxWidth="30" maxHeight="30" minWidth="30" minHeight="30" prefWidth="30" prefHeight="30" />
|
||||
<JFXButton fx:id="btnDelete" styleClass="toggle-icon4" maxWidth="30" maxHeight="30" minWidth="30" minHeight="30" prefWidth="30" prefHeight="30" />
|
||||
</HBox>
|
||||
|
@ -29,7 +29,7 @@
|
||||
</JFXButton>
|
||||
</AnchorPane>
|
||||
|
||||
<JFXDialog fx:id="dialog" transitionType="CENTER">
|
||||
<JFXDialog fx:id="dialog">
|
||||
<StackPane>
|
||||
<JFXDialogLayout>
|
||||
<heading>
|
||||
|
@ -6,8 +6,8 @@
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.shape.Rectangle?>
|
||||
<?import java.lang.String?>
|
||||
<?import org.jackhuang.hmcl.ui.AdvancedListBox?>
|
||||
<?import java.lang.String?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
type="StackPane"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
@ -18,42 +18,36 @@
|
||||
<BorderPane>
|
||||
<center>
|
||||
<StackPane fx:id="drawerWrapper">
|
||||
<JFXDrawer fx:id="drawer" defaultDrawerSize="200" direction="LEFT">
|
||||
<styleClass>
|
||||
<String fx:value="body"/>
|
||||
</styleClass>
|
||||
<sidePane>
|
||||
<AdvancedListBox fx:id="sidePane" />
|
||||
</sidePane>
|
||||
<BorderPane>
|
||||
<left>
|
||||
<StackPane minWidth="200" maxWidth="200" styleClass="jfx-decorator-content-container">
|
||||
<BorderPane fx:id="leftRootPane">
|
||||
<center>
|
||||
<BorderPane>
|
||||
<center>
|
||||
<AdvancedListBox fx:id="leftPane" />
|
||||
</center>
|
||||
</BorderPane>
|
||||
</center>
|
||||
<right>
|
||||
<Rectangle height="${leftRootPane.height}" width="1" fill="gray"/>
|
||||
</right>
|
||||
</BorderPane>
|
||||
<JFXDialog fx:id="dialog" overlayClose="false" />
|
||||
<BorderPane>
|
||||
<left>
|
||||
<StackPane minWidth="200" maxWidth="200" styleClass="jfx-decorator-content-container">
|
||||
<BorderPane fx:id="leftRootPane">
|
||||
<center>
|
||||
<BorderPane>
|
||||
<center>
|
||||
<AdvancedListBox fx:id="leftPane"/>
|
||||
</center>
|
||||
</BorderPane>
|
||||
</center>
|
||||
<right>
|
||||
<Rectangle height="${leftRootPane.height}" width="1" fill="gray"/>
|
||||
</right>
|
||||
</BorderPane>
|
||||
</StackPane>
|
||||
</left>
|
||||
<center>
|
||||
<StackPane fx:id="contentPlaceHolderRoot" styleClass="jfx-decorator-content-container"
|
||||
VBox.vgrow="ALWAYS">
|
||||
<StackPane fx:id="contentPlaceHolder" styleClass="jfx-decorator-content-container">
|
||||
<styleClass>
|
||||
<String fx:value="jfx-decorator-content-container"/>
|
||||
</styleClass>
|
||||
<!-- Node -->
|
||||
</StackPane>
|
||||
</left>
|
||||
<center>
|
||||
<StackPane fx:id="contentPlaceHolderRoot" styleClass="jfx-decorator-content-container" VBox.vgrow="ALWAYS">
|
||||
<StackPane fx:id="contentPlaceHolder" styleClass="jfx-decorator-content-container">
|
||||
<styleClass>
|
||||
<String fx:value="jfx-decorator-content-container"/>
|
||||
</styleClass>
|
||||
<!-- Node -->
|
||||
</StackPane>
|
||||
</StackPane>
|
||||
</center>
|
||||
</BorderPane>
|
||||
</JFXDrawer>
|
||||
</StackPane>
|
||||
</center>
|
||||
</BorderPane>
|
||||
</StackPane>
|
||||
</center>
|
||||
<top>
|
||||
@ -65,18 +59,8 @@
|
||||
<left>
|
||||
<BorderPane minWidth="200" maxWidth="200" fx:id="titleWrapper">
|
||||
<center>
|
||||
<HBox>
|
||||
<JFXRippler maskType="CIRCLE" style="-fx-ripple-color:WHITE;">
|
||||
<StackPane fx:id="titleBurgerContainer" maxWidth="30" maxHeight="30" minWidth="30" minHeight="30" prefWidth="30" prefHeight="30">
|
||||
<JFXHamburger fx:id="titleBurger">
|
||||
<HamburgerBackArrowBasicTransition/>
|
||||
</JFXHamburger>
|
||||
</StackPane>
|
||||
</JFXRippler>
|
||||
<Label fx:id="lblTitle" BorderPane.alignment="CENTER"
|
||||
mouseTransparent="true"
|
||||
style="-fx-background-color: transparent; -fx-text-fill: white; -fx-font-size: 15px;"/>
|
||||
</HBox>
|
||||
<Label fx:id="lblTitle" BorderPane.alignment="CENTER" mouseTransparent="true"
|
||||
style="-fx-background-color: transparent; -fx-text-fill: white; -fx-font-size: 15px;"/>
|
||||
</center>
|
||||
<right>
|
||||
<Rectangle height="${navBar.height}" width="1" fill="gray"/>
|
||||
@ -87,7 +71,8 @@
|
||||
<BorderPane fx:id="navBar">
|
||||
<left>
|
||||
<HBox fx:id="navLeft" alignment="CENTER_LEFT" style="-fx-padding: 0 5 0 5;">
|
||||
<JFXButton fx:id="backNavButton" onMouseClicked="#onBack" styleClass="jfx-decorator-button" ripplerFill="white">
|
||||
<JFXButton fx:id="backNavButton" onMouseClicked="#onBack"
|
||||
styleClass="jfx-decorator-button" ripplerFill="white">
|
||||
<graphic>
|
||||
<fx:include source="/assets/svg/arrow-left.fxml"/>
|
||||
</graphic>
|
||||
@ -97,12 +82,14 @@
|
||||
</left>
|
||||
<right>
|
||||
<HBox fx:id="navRight" alignment="CENTER_LEFT">
|
||||
<JFXButton fx:id="refreshNavButton" onMouseClicked="#onRefresh" styleClass="jfx-decorator-button" ripplerFill="white">
|
||||
<JFXButton fx:id="refreshNavButton" onMouseClicked="#onRefresh"
|
||||
styleClass="jfx-decorator-button" ripplerFill="white">
|
||||
<graphic>
|
||||
<fx:include source="/assets/svg/refresh.fxml"/>
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<JFXButton fx:id="closeNavButton" onMouseClicked="#onCloseNav" styleClass="jfx-decorator-button" ripplerFill="white">
|
||||
<JFXButton fx:id="closeNavButton" onMouseClicked="#onCloseNav"
|
||||
styleClass="jfx-decorator-button" ripplerFill="white">
|
||||
<graphic>
|
||||
<fx:include source="/assets/svg/close.fxml"/>
|
||||
</graphic>
|
||||
|
16
HMCL/src/main/resources/assets/fxml/launching-steps.fxml
Normal file
16
HMCL/src/main/resources/assets/fxml/launching-steps.fxml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<?import com.jfoenix.controls.JFXProgressBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
type="StackPane">
|
||||
<JFXProgressBar fx:id="pgsTasks" StackPane.alignment="TOP_CENTER" />
|
||||
<VBox alignment="CENTER">
|
||||
<Label fx:id="lblCurrentState" style="-fx-font-size: 20px;" />
|
||||
<Label fx:id="lblSteps" style="-fx-font-size: 14px;" />
|
||||
</VBox>
|
||||
|
||||
</fx:root>
|
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import com.jfoenix.controls.*?>
|
||||
<?import com.jfoenix.validation.RequiredFieldValidator?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
type="StackPane">
|
||||
<JFXDialogLayout>
|
||||
<heading>
|
||||
<Label text="%ui.message.enter_password" />
|
||||
</heading>
|
||||
<body>
|
||||
<VBox spacing="15" style="-fx-padding: 15 0 0 0;">
|
||||
<Label fx:id="lblUsername" />
|
||||
<JFXPasswordField fx:id="txtPassword" promptText="%ui.label.password" labelFloat="true">
|
||||
<validators>
|
||||
<RequiredFieldValidator message="Input Required!">
|
||||
</RequiredFieldValidator>
|
||||
</validators>
|
||||
</JFXPasswordField>
|
||||
</VBox>
|
||||
</body>
|
||||
<actions>
|
||||
<Label fx:id="lblCreationWarning" />
|
||||
<JFXButton onMouseClicked="#onAccept" text="%button.ok" styleClass="dialog-accept"/>
|
||||
<JFXButton onMouseClicked="#onCancel" text="%button.cancel" styleClass="dialog-cancel"/>
|
||||
</actions>
|
||||
</JFXDialogLayout>
|
||||
<JFXProgressBar fx:id="progressBar" visible="false" StackPane.alignment="TOP_CENTER"/>
|
||||
</fx:root>
|
@ -167,8 +167,8 @@ ui.label.version=版本
|
||||
ui.label.password=密碼
|
||||
ui.label.profile=配置
|
||||
|
||||
ui.message.first_load=請在左邊輸入您的帳號
|
||||
ui.message.enter_password=請在左邊輸入您的密碼
|
||||
ui.message.first_load=請輸入您的帳號
|
||||
ui.message.enter_password=請輸入您的密碼
|
||||
ui.message.launching=啟動中
|
||||
ui.message.making=生成中
|
||||
ui.message.sure_remove=真的要刪除配置%s嗎?
|
||||
|
@ -167,8 +167,8 @@ ui.label.version=版本
|
||||
ui.label.password=密码
|
||||
ui.label.profile=配置
|
||||
|
||||
ui.message.first_load=请在左边输入您的账号
|
||||
ui.message.enter_password=请在左边输入您的密码
|
||||
ui.message.first_load=请输入您的账号
|
||||
ui.message.enter_password=请输入您的密码
|
||||
ui.message.launching=启动中
|
||||
ui.message.making=生成中
|
||||
ui.message.sure_remove=真的要删除配置%s吗?
|
||||
|
@ -43,20 +43,14 @@ 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 { task ->
|
||||
val newVersion = task.result!!
|
||||
VersionJSONSaveTask(this@DefaultDependencyManager, newVersion)
|
||||
}
|
||||
return ForgeInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then { VersionJSONSaveTask(this, it["version"]) }
|
||||
else if (libraryId == "liteloader")
|
||||
return LiteLoaderInstallTask(this, gameVersion, version, libraryVersion) then { task ->
|
||||
val newVersion = task.result!!
|
||||
VersionJSONSaveTask(this@DefaultDependencyManager, newVersion)
|
||||
}
|
||||
return LiteLoaderInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then { VersionJSONSaveTask(this, it["version"]) }
|
||||
else if (libraryId == "optifine")
|
||||
return OptiFineInstallTask(this, gameVersion, version, libraryVersion) then { task ->
|
||||
val newVersion = task.result!!
|
||||
VersionJSONSaveTask(this@DefaultDependencyManager, newVersion)
|
||||
}
|
||||
return OptiFineInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then { VersionJSONSaveTask(this, it["version"]) }
|
||||
else
|
||||
throw IllegalArgumentException("Library id $libraryId is unrecognized.")
|
||||
}
|
||||
|
@ -28,53 +28,48 @@ class DefaultGameBuilder(val dependencyManager: DefaultDependencyManager): GameB
|
||||
|
||||
override fun buildAsync(): Task {
|
||||
val gameVersion = gameVersion
|
||||
return VersionJSONDownloadTask(gameVersion = gameVersion) then a@{ task ->
|
||||
var version = GSON.fromJson<Version>(task.result!!) ?: return@a null
|
||||
version = version.copy(id = name, jar = null)
|
||||
var result = ParallelTask(
|
||||
GameAssetDownloadTask(dependencyManager, version),
|
||||
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)
|
||||
return VersionJSONDownloadTask(gameVersion, dependencyManager, "raw_version_json")
|
||||
.then {
|
||||
var version = GSON.fromJson<Version>(it["raw_version_json"])!!
|
||||
it["version"] = version
|
||||
version = version.copy(id = name, jar = null)
|
||||
var result = ParallelTask(
|
||||
GameAssetDownloadTask(dependencyManager, version),
|
||||
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)
|
||||
|
||||
if (toolVersions.containsKey("forge"))
|
||||
result = result then libraryTaskHelper(gameVersion, version, "forge")
|
||||
if (toolVersions.containsKey("liteloader"))
|
||||
result = result then libraryTaskHelper(gameVersion, version, "liteloader")
|
||||
if (toolVersions.containsKey("optifine"))
|
||||
result = result then libraryTaskHelper(gameVersion, version, "optifine")
|
||||
result
|
||||
}
|
||||
if (toolVersions.containsKey("forge"))
|
||||
result = result then libraryTaskHelper(gameVersion, "forge")
|
||||
if (toolVersions.containsKey("liteloader"))
|
||||
result = result then libraryTaskHelper(gameVersion, "liteloader")
|
||||
if (toolVersions.containsKey("optifine"))
|
||||
result = result then libraryTaskHelper(gameVersion, "optifine")
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
private fun libraryTaskHelper(gameVersion: String, version: Version, libraryId: String): Task.(Task) -> Task = { prev ->
|
||||
var thisVersion = version
|
||||
if (prev is TaskResult<*> && prev.result is Version) {
|
||||
thisVersion = prev.result as Version
|
||||
}
|
||||
dependencyManager.installLibraryAsync(gameVersion, thisVersion, libraryId, toolVersions[libraryId]!!)
|
||||
private fun libraryTaskHelper(gameVersion: String, libraryId: String): (AutoTypingMap<String>) -> Task = {
|
||||
dependencyManager.installLibraryAsync(gameVersion, it["version"], libraryId, toolVersions[libraryId]!!)
|
||||
}
|
||||
|
||||
inner class VersionJSONDownloadTask(val gameVersion: String): Task() {
|
||||
private class VersionJSONDownloadTask(val gameVersion: String, val dependencyManager: DefaultDependencyManager, val id: String): Task() {
|
||||
override val dependents: MutableCollection<Task> = LinkedList()
|
||||
override val dependencies: MutableCollection<Task> = LinkedList()
|
||||
var httpTask: GetTask? = null
|
||||
val result: String? get() = httpTask?.result
|
||||
|
||||
val gameVersionList: VersionList<*> = dependencyManager.getVersionList("game")
|
||||
private val gameVersionList: VersionList<*> = dependencyManager.getVersionList("game")
|
||||
init {
|
||||
if (!gameVersionList.loaded)
|
||||
dependents += gameVersionList.refreshAsync(downloadProvider)
|
||||
dependents += gameVersionList.refreshAsync(dependencyManager.downloadProvider)
|
||||
}
|
||||
|
||||
override fun execute() {
|
||||
val remoteVersion = gameVersionList.getVersions(gameVersion).firstOrNull()
|
||||
?: throw Error("Cannot find specific version $gameVersion in remote repository")
|
||||
|
||||
val jsonURL = downloadProvider.injectURL(remoteVersion.url)
|
||||
httpTask = GetTask(jsonURL.toURL(), proxy = dependencyManager.proxy)
|
||||
dependencies += httpTask!!
|
||||
val jsonURL = dependencyManager.downloadProvider.injectURL(remoteVersion.url)
|
||||
dependencies += GetTask(jsonURL.toURL(), proxy = dependencyManager.proxy, id = id)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,11 +38,11 @@ class ForgeInstallTask(private val dependencyManager: DefaultDependencyManager,
|
||||
lateinit var remote: RemoteVersion<*>
|
||||
override val dependents = mutableListOf<Task>()
|
||||
override val dependencies = mutableListOf<Task>()
|
||||
override val id = ID
|
||||
override val id = "version"
|
||||
|
||||
init {
|
||||
if (!forgeVersionList.loaded)
|
||||
dependents += forgeVersionList.refreshAsync(dependencyManager.downloadProvider) then {
|
||||
dependents += forgeVersionList.refreshAsync(dependencyManager.downloadProvider).then {
|
||||
remote = forgeVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote forge version $gameVersion, $remoteVersion not found")
|
||||
FileDownloadTask(remote.url.toURL(), installer)
|
||||
}
|
||||
@ -76,8 +76,4 @@ class ForgeInstallTask(private val dependencyManager: DefaultDependencyManager,
|
||||
|
||||
check(installer.delete(), { "Unable to delete installer file $installer" })
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ID = "forge_install_task"
|
||||
}
|
||||
}
|
@ -37,11 +37,11 @@ class LiteLoaderInstallTask(private val dependencyManager: DefaultDependencyMana
|
||||
lateinit var remote: RemoteVersion<LiteLoaderRemoteVersionTag>
|
||||
override val dependents = mutableListOf<Task>()
|
||||
override val dependencies = mutableListOf<Task>()
|
||||
override val id = ID
|
||||
override val id = "version"
|
||||
|
||||
init {
|
||||
if (!liteLoaderVersionList.loaded)
|
||||
dependents += LiteLoaderVersionList.refreshAsync(dependencyManager.downloadProvider) then {
|
||||
dependents += LiteLoaderVersionList.refreshAsync(dependencyManager.downloadProvider).then {
|
||||
remote = liteLoaderVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote LiteLoader version $gameVersion, $remoteVersion not found")
|
||||
null
|
||||
}
|
||||
@ -70,8 +70,4 @@ class LiteLoaderInstallTask(private val dependencyManager: DefaultDependencyMana
|
||||
)
|
||||
dependencies += GameLibrariesTask(dependencyManager, tempVersion)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ID = "lite_loader_install_task"
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@ class OptiFineInstallTask(private val dependencyManager: DefaultDependencyManage
|
||||
lateinit var remote: RemoteVersion<*>
|
||||
override val dependents = mutableListOf<Task>()
|
||||
override val dependencies = mutableListOf<Task>()
|
||||
override val id = ID
|
||||
override val id = "version"
|
||||
|
||||
init {
|
||||
if (!optiFineVersionList.loaded)
|
||||
@ -75,8 +75,4 @@ class OptiFineInstallTask(private val dependencyManager: DefaultDependencyManage
|
||||
result = version.copy(libraries = merge(version.libraries, libraries), mainClass = mainClass, minecraftArguments = arg)
|
||||
dependencies += GameLibrariesTask(dependencyManager, version.copy(libraries = libraries))
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ID = "optifine_install_task"
|
||||
}
|
||||
}
|
@ -17,14 +17,16 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.task
|
||||
|
||||
internal class CoupleTask<P: Task>(private val pred: P, private val succ: Task.(P) -> Task?, override val reliant: Boolean) : Task() {
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap
|
||||
|
||||
internal class CoupleTask<P: Task>(pred: P, private val succ: (AutoTypingMap<String>) -> Task?, override val reliant: Boolean) : Task() {
|
||||
override val hidden: Boolean = true
|
||||
|
||||
override val dependents: Collection<Task> = listOf(pred)
|
||||
override val dependencies: MutableCollection<Task> = mutableListOf()
|
||||
|
||||
override fun execute() {
|
||||
val task = this.succ(pred)
|
||||
val task = this.succ(variables!!)
|
||||
if (task != null)
|
||||
dependencies += task
|
||||
}
|
||||
@ -33,9 +35,9 @@ internal class CoupleTask<P: Task>(private val pred: P, private val succ: Task.(
|
||||
/**
|
||||
* @param b A runnable that decides what to do next, You can also do something here.
|
||||
*/
|
||||
infix fun <T: Task> T.then(b: Task.(T) -> Task?): Task = CoupleTask(this, b, true)
|
||||
infix fun <T: Task> T.then(b: (AutoTypingMap<String>) -> Task?): Task = CoupleTask(this, b, true)
|
||||
|
||||
/**
|
||||
* @param b A runnable that decides what to do next, You can also do something here.
|
||||
*/
|
||||
infix fun <T: Task> T.with(b: Task.(T) -> Task?): Task = CoupleTask(this, b, false)
|
||||
infix fun <T: Task> T.with(b: (AutoTypingMap<String>) -> Task?): Task = CoupleTask(this, b, false)
|
@ -25,9 +25,8 @@ import java.net.Proxy
|
||||
import java.net.URL
|
||||
import java.nio.charset.Charset
|
||||
|
||||
class GetTask @JvmOverloads constructor(val url: URL, val encoding: Charset = Charsets.UTF_8, private val retry: Int = 5, private val proxy: Proxy = Proxy.NO_PROXY): TaskResult<String>() {
|
||||
class GetTask @JvmOverloads constructor(val url: URL, val encoding: Charset = Charsets.UTF_8, private val retry: Int = 5, private val proxy: Proxy = Proxy.NO_PROXY, override val id: String = ID): TaskResult<String>() {
|
||||
override val scheduler: Scheduler = Scheduler.IO
|
||||
override val id = ID
|
||||
|
||||
override fun execute() {
|
||||
var exception: IOException? = null
|
||||
|
@ -81,11 +81,15 @@ abstract class Task {
|
||||
protected fun updateProgress(progress: Double) {
|
||||
val now = System.currentTimeMillis()
|
||||
if (now - lastTime >= progressInterval) {
|
||||
progressPropertyImpl.updateAsync(progress, progressUpdate)
|
||||
updateProgressImmediately(progress)
|
||||
lastTime = now
|
||||
}
|
||||
}
|
||||
|
||||
protected fun updateProgressImmediately(progress: Double) {
|
||||
progressPropertyImpl.updateAsync(progress, progressUpdate)
|
||||
}
|
||||
|
||||
private val messageUpdate = AtomicReference<String>()
|
||||
private val messagePropertyImpl = ReadOnlyStringWrapper(this, "message", null)
|
||||
val messageProperty: ReadOnlyStringProperty = messagePropertyImpl.readOnlyProperty
|
||||
|
@ -49,13 +49,13 @@ class TaskExecutor() {
|
||||
* Start the subscription and run all registered tasks asynchronously.
|
||||
*/
|
||||
fun start() {
|
||||
workerQueue.add(Scheduler.Schedulers.NEW_THREAD.schedule(Callable {
|
||||
workerQueue.add(Scheduler.NEW_THREAD.schedule {
|
||||
totTask.addAndGet(taskQueue.size)
|
||||
while (!taskQueue.isEmpty()) {
|
||||
if (canceled) break
|
||||
val task = taskQueue.poll()
|
||||
if (task != null) {
|
||||
val future = task.scheduler.schedule(Callable { executeTask(task); Unit })
|
||||
val future = task.scheduler.schedule { executeTask(task) }
|
||||
try {
|
||||
future?.get()
|
||||
} catch (e: InterruptedException) {
|
||||
@ -66,7 +66,9 @@ class TaskExecutor() {
|
||||
}
|
||||
if (canceled || Thread.interrupted())
|
||||
taskListener?.onTerminate()
|
||||
}))
|
||||
else
|
||||
taskListener?.end()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,8 +20,9 @@ package org.jackhuang.hmcl.task
|
||||
import java.util.*
|
||||
|
||||
interface TaskListener : EventListener {
|
||||
fun onReady(task: Task)
|
||||
fun onFinished(task: Task)
|
||||
fun onFailed(task: Task)
|
||||
fun onTerminate()
|
||||
fun onReady(task: Task) {}
|
||||
fun onFinished(task: Task) {}
|
||||
fun onFailed(task: Task) {}
|
||||
fun onTerminate() {}
|
||||
fun end() {}
|
||||
}
|
@ -26,14 +26,14 @@ import java.util.logging.*
|
||||
import java.util.logging.Formatter
|
||||
|
||||
val LOG = Logger.getLogger("HMCL").apply {
|
||||
level = Level.FINEST
|
||||
level = Level.FINER
|
||||
useParentHandlers = false
|
||||
addHandler(FileHandler("hmcl.log").apply {
|
||||
level = Level.FINEST
|
||||
level = Level.FINER
|
||||
formatter = DefaultFormatter
|
||||
})
|
||||
addHandler(ConsoleHandler().apply {
|
||||
level = Level.FINEST
|
||||
level = Level.FINER
|
||||
formatter = DefaultFormatter
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user