diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt index fda28db92..0347a3176 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt @@ -54,6 +54,7 @@ class Main : Application() { val VERSION = "@HELLO_MINECRAFT_LAUNCHER_VERSION_FOR_GRADLE_REPLACING@" val NAME = "HMCL" val TITLE = "$NAME $VERSION" + val APPDATA = getWorkingDirectory("hmcl") lateinit var PRIMARY_STAGE: Stage @JvmStatic diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/AccountSkin.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/AccountSkin.kt new file mode 100644 index 000000000..d89570d86 --- /dev/null +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/AccountSkin.kt @@ -0,0 +1,76 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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.setting + +import javafx.scene.image.Image +import org.jackhuang.hmcl.Main +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.util.toURL +import java.net.Proxy + +object AccountSkin { + val SKIN_DIR = Main.APPDATA.resolve("skins") + + fun loadSkins(proxy: Proxy = Settings.proxy) { + for (account in Settings.getAccounts().values) { + if (account is YggdrasilAccount) { + SkinLoadTask(account, proxy, false).start() + } + } + } + + fun loadSkinAsync(account: YggdrasilAccount, proxy: Proxy = Settings.proxy): Task = + SkinLoadTask(account, proxy, false) + + fun refreshSkinAsync(account: YggdrasilAccount, proxy: Proxy = Settings.proxy): Task = + SkinLoadTask(account, proxy, true) + + private class SkinLoadTask(val account: YggdrasilAccount, val proxy: Proxy, val refresh: Boolean = false): Task() { + override val scheduler = Scheduler.IO + override val dependencies = mutableListOf() + + override fun execute() { + if (account.canLogIn && (account.selectedProfile == null || refresh)) + account.logIn(proxy) + val profile = account.selectedProfile ?: return + val name = profile.name ?: return + val url = "http://skins.minecraft.net/MinecraftSkins/$name.png" + val file = getSkinFile(name) + if (!refresh && file.exists()) + return + dependencies += FileDownloadTask(url.toURL(), file, proxy = proxy) + } + } + + private fun getSkinFile(name: String) = SKIN_DIR.resolve("$name.png") + private val DEFAULT_IMAGE = Image("/assets/img/icon.png") + + fun getSkin(account: YggdrasilAccount, scaleRatio: Double = 1.0): Image { + if (account.selectedProfile == null) return DEFAULT_IMAGE + val name = account.selectedProfile?.name ?: return DEFAULT_IMAGE + val file = getSkinFile(name) + if (file.exists()) { + val original = Image("file:" + file.absolutePath) + return Image("file:" + file.absolutePath, original.width * scaleRatio, original.height * scaleRatio, false, false) + } + else return DEFAULT_IMAGE + } +} \ No newline at end of file diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountItem.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountItem.kt index a218b409b..f58e331a8 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountItem.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountItem.kt @@ -19,48 +19,81 @@ 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 import javafx.scene.control.Label import javafx.scene.control.ToggleGroup import javafx.scene.effect.BlurType import javafx.scene.effect.DropShadow +import javafx.scene.image.ImageView 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.yggdrasil.YggdrasilAccount +import org.jackhuang.hmcl.setting.AccountSkin +import org.jackhuang.hmcl.setting.Settings +import org.jackhuang.hmcl.task.Scheduler import java.util.concurrent.Callable -class AccountItem(i: Int, group: ToggleGroup) : StackPane() { +class AccountItem(i: Int, val account: Account, group: ToggleGroup) : StackPane() { @FXML lateinit var icon: Pane @FXML lateinit var content: VBox @FXML lateinit var header: StackPane @FXML lateinit var body: StackPane @FXML lateinit var btnDelete: JFXButton + @FXML lateinit var btnRefresh: JFXButton @FXML lateinit var lblUser: Label @FXML lateinit var chkSelected: JFXRadioButton @FXML lateinit var lblType: Label + @FXML lateinit var pgsSkin: JFXProgressBar + @FXML lateinit var portraitView: ImageView init { loadFXML("/assets/fxml/account-item.fxml") - limitWidth(150.0) - limitHeight(140.0) + limitWidth(160.0) + limitHeight(156.0) effect = DropShadow(BlurType.GAUSSIAN, Color.rgb(0, 0, 0, 0.26), 5.0, 0.12, -0.5, 1.0) chkSelected.toggleGroup = group - btnDelete.graphic = SVG.delete("white", 15.0, 15.0) + btnDelete.graphic = SVG.delete("black", 15.0, 15.0) + btnRefresh.graphic = SVG.refresh("black", 15.0, 15.0) // create content val headerColor = getDefaultColor(i % 12) header.style = "-fx-background-radius: 2 2 0 0; -fx-background-color: " + headerColor - body.minHeight = Math.random() * 20 + 50 // create image view icon.translateYProperty().bind(Bindings.createDoubleBinding(Callable { header.boundsInParent.height - icon.height / 2 }, header.boundsInParentProperty(), icon.heightProperty())) + + chkSelected.properties["account"] = account + chkSelected.isSelected = Settings.selectedAccount == account + lblUser.text = account.username + lblType.text = accountType(account) + + if (account is YggdrasilAccount) + btnRefresh.setOnMouseClicked { + pgsSkin.isVisible = true + AccountSkin.refreshSkinAsync(account).subscribe(Scheduler.JAVAFX) { loadSkin() } + } + } + + fun loadSkin() { + if (account !is YggdrasilAccount) + return + pgsSkin.isVisible = false + val size = 8.0 * 4 + portraitView.viewport = Rectangle2D(size, size, size, size) + portraitView.image = AccountSkin.getSkin(account, 4.0) + portraitView.fitHeight = 32.0 + portraitView.fitWidth = 32.0 } private fun getDefaultColor(i: Int): String { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt index 017d8cf21..ef15ea8ea 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt @@ -32,6 +32,7 @@ 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 @@ -111,15 +112,16 @@ class AccountsPage() : StackPane(), DecoratorPage { } private fun buildNode(i: Int, account: Account, group: ToggleGroup): Node { - return AccountItem(i, group).apply { - chkSelected.properties["account"] = account - chkSelected.isSelected = Settings.selectedAccount == account - lblUser.text = account.username - lblType.text = accountType(account) + return AccountItem(i, account, group).apply { btnDelete.setOnMouseClicked { Settings.deleteAccount(account.username) Platform.runLater(this@AccountsPage::loadAccounts) } + + if (account is YggdrasilAccount) + AccountSkin.loadSkinAsync(account).subscribe(Scheduler.JAVAFX) { + loadSkin() + } } } diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LeftPaneController.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LeftPaneController.kt index f82748491..e766b4742 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LeftPaneController.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LeftPaneController.kt @@ -19,10 +19,12 @@ package org.jackhuang.hmcl.ui import com.jfoenix.controls.JFXComboBox import javafx.scene.layout.* +import org.jackhuang.hmcl.auth.Account import org.jackhuang.hmcl.i18n import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.ui.construct.IconedItem import org.jackhuang.hmcl.ui.construct.RipplerContainer +import javax.swing.event.ChangeListener class LeftPaneController(private val leftPane: AdvancedListBox) { val versionsPane = VBox() @@ -63,16 +65,15 @@ class LeftPaneController(private val leftPane: AdvancedListBox) { } Controllers.mainPane.buttonLaunch.setOnMouseClicked { LauncherHelper.launch() }*/ - Settings.selectedAccountProperty.addListener { _, _, newValue -> - if (newValue == null) { + Settings.selectedAccountProperty.setChangedListener { + if (it == null) { accountItem.lblVersionName.text = "mojang@mojang.com" accountItem.lblGameVersion.text = "Yggdrasil" } else { - accountItem.lblVersionName.text = newValue.username - accountItem.lblGameVersion.text = accountType(newValue) + accountItem.lblVersionName.text = it.username + accountItem.lblGameVersion.text = accountType(it) } } - Settings.selectedAccountProperty.fireValueChangedEvent() if (Settings.getAccounts().isEmpty()) Controllers.navigate(AccountsPage()) diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/MainPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/MainPage.kt index d85c693d4..85da57a68 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/MainPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/MainPage.kt @@ -91,10 +91,9 @@ class MainPage : StackPane(), DecoratorPage { fun onProfileChanged(event: ProfileChangedEvent) { val profile = event.value - profile.selectedVersionProperty.addListener { _ -> + profile.selectedVersionProperty.setChangedListener { versionChanged(profile.selectedVersion) } - profile.selectedVersionProperty.fireValueChangedEvent() } private fun loadVersions() { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/SVG.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/SVG.kt index 3056b19b3..c590775e0 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/SVG.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/SVG.kt @@ -61,5 +61,5 @@ object SVG { fun navigate(fill: String = "white", width: Double = 20.0, height: Double = 20.0) = createSVGPath("M14,3V5H17.59L7.76,14.83L9.17,16.24L19,6.41V10H21V3M19,19H5V5H12V3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19Z", fill, width, height) fun launch(fill: String = "white", width: Double = 20.0, height: Double = 20.0) = createSVGPath("M1008 6.286q18.857 13.714 15.429 36.571l-146.286 877.714q-2.857 16.571-18.286 25.714-8 4.571-17.714 4.571-6.286 0-13.714-2.857l-258.857-105.714-138.286 168.571q-10.286 13.143-28 13.143-7.429 0-12.571-2.286-10.857-4-17.429-13.429t-6.571-20.857v-199.429l493.714-605.143-610.857 528.571-225.714-92.571q-21.143-8-22.857-31.429-1.143-22.857 18.286-33.714l950.857-548.571q8.571-5.143 18.286-5.14311.429 0 20.571 6.286z", fill, width, height) fun pencil(fill: String = "white", width: Double = 20.0, height: Double = 20.0) = createSVGPath("M20.71,4.04C21.1,3.65 21.1,3 20.71,2.63L18.37,0.29C18,-0.1 17.35,-0.1 16.96,0.29L15,2.25L18.75,6M17.75,7L14,3.25L4,13.25V17H7.75L17.75,7Z", fill, width, height) - + fun refresh(fill: String = "white", width: Double = 20.0, height: Double = 20.0) = createSVGPath("M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z", fill, width, height) } \ No newline at end of file diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionItem.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionItem.kt index e51c90e91..486d283a0 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionItem.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionItem.kt @@ -47,7 +47,7 @@ class VersionItem(i: Int, group: ToggleGroup) : StackPane() { init { loadFXML("/assets/fxml/version-item.fxml") - limitWidth(190.0) + limitWidth(160.0) limitHeight(156.0) effect = DropShadow(BlurType.GAUSSIAN, Color.rgb(0, 0, 0, 0.26), 5.0, 0.12, -1.0, 1.0) diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionSettingsController.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionSettingsController.kt index 892e70540..d6ede55ea 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionSettingsController.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionSettingsController.kt @@ -60,7 +60,7 @@ class VersionSettingsController { @FXML lateinit var chkNoGameCheck: JFXToggleButton @FXML lateinit var componentJava: ComponentList @FXML lateinit var javaPane: VBox - @FXML lateinit var javaPaneCustom: HBox + @FXML lateinit var javaPaneCustom: BorderPane @FXML lateinit var radioCustom: JFXRadioButton @FXML lateinit var btnJavaSelect: JFXButton @@ -100,21 +100,21 @@ class VersionSettingsController { javaPane.children += createJavaPane(javaVersion, javaGroup) } javaPane.children += javaPaneCustom + javaPaneCustom.limitHeight(20.0) radioCustom.toggleGroup = javaGroup txtJavaDir.disableProperty().bind(radioCustom.selectedProperty().not()) btnJavaSelect.disableProperty().bind(radioCustom.selectedProperty().not()) } private fun createJavaPane(java: JavaVersion, group: ToggleGroup): Pane { - return HBox().apply { + return BorderPane().apply { style = "-fx-padding: 3;" - spacing = 8.0 - alignment = Pos.CENTER_LEFT - children += JFXRadioButton(java.longVersion).apply { + limitHeight(20.0) + left = JFXRadioButton(java.longVersion).apply { toggleGroup = group userData = java } - children += Label(java.binary.absolutePath).apply { + right = Label(java.binary.absolutePath).apply { styleClass += "subtitle-label" style += "-fx-font-size: 10;" } diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/RenderedPartlyTexture.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/RenderedPartlyTexture.kt deleted file mode 100644 index c5acf5c4b..000000000 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/RenderedPartlyTexture.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2017 huangyuhui - * - * 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.construct - -import javafx.scene.canvas.GraphicsContext -import javafx.scene.paint.Color - -object RenderedPartlyTexture { - - fun renderAvatar(ctx: GraphicsContext, skinScale: Int, skinImg: Array>, width: Double) { - val helmBs = width / (1.0 * skinScale) - val headBs = (width - 1.0 * helmBs) / (1.0 * skinScale) - val headOffset = helmBs / 2.0 - - // render head.front - renderRange(ctx, skinImg, head_front_x * skinScale, head_front_y * skinScale, head_front_w * skinScale, head_front_h * skinScale, headOffset, headOffset, headBs) - - // render helm.front - renderRange(ctx, skinImg, helm_front_x * skinScale, helm_front_y * skinScale, helm_front_w * skinScale, helm_front_h * skinScale, 0.0, 0.0, helmBs) - } - - private fun renderRange(ctx: GraphicsContext, img: Array>, x0: Int, y0: Int, w: Int, h: Int, tx0: Double, ty0: Double, bs: Double) { - var x: Int - var y: Int - var tx: Double - var ty: Double - for (dx in 0..w - 1) { - for (dy in 0..h - 1) { - x = x0 + dx - y = y0 + dy - tx = tx0 + bs * dx - ty = ty0 + bs * dy - ctx.fill = img[x][y] - ctx.fillRect(tx, ty, bs, bs) - } - } - } - - /* - * The specification of skin can be found at https://github.com/minotar/skin-spec - */ - - internal val head_front_x = 1 - internal val head_front_y = 1 - internal val head_front_w = 1 - internal val head_front_h = 1 - - internal val helm_front_x = 5 - internal val helm_front_y = 1 - internal val helm_front_w = 1 - internal val helm_front_h = 1 - -} \ No newline at end of file diff --git a/HMCL/src/main/resources/assets/fxml/account-item.fxml b/HMCL/src/main/resources/assets/fxml/account-item.fxml index 782111f5a..9c206bdb0 100644 --- a/HMCL/src/main/resources/assets/fxml/account-item.fxml +++ b/HMCL/src/main/resources/assets/fxml/account-item.fxml @@ -8,6 +8,7 @@ + @@ -16,23 +17,34 @@ - +
- +
- - + + + + + + + + + + + + + - + diff --git a/HMCL/src/main/resources/assets/fxml/account.fxml b/HMCL/src/main/resources/assets/fxml/account.fxml index 6b2ec1d61..cb79dfecc 100644 --- a/HMCL/src/main/resources/assets/fxml/account.fxml +++ b/HMCL/src/main/resources/assets/fxml/account.fxml @@ -18,7 +18,7 @@ xmlns:fx="http://javafx.com/fxml" type="StackPane"> - + diff --git a/HMCL/src/main/resources/assets/fxml/main.fxml b/HMCL/src/main/resources/assets/fxml/main.fxml index 1e4b3eb24..b76221ec5 100644 --- a/HMCL/src/main/resources/assets/fxml/main.fxml +++ b/HMCL/src/main/resources/assets/fxml/main.fxml @@ -8,7 +8,7 @@ styleClass="transparent" type="StackPane" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1"> - + diff --git a/HMCL/src/main/resources/assets/fxml/version-settings.fxml b/HMCL/src/main/resources/assets/fxml/version-settings.fxml index 61d90f282..b9b900888 100644 --- a/HMCL/src/main/resources/assets/fxml/version-settings.fxml +++ b/HMCL/src/main/resources/assets/fxml/version-settings.fxml @@ -22,16 +22,22 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/AuthenticationException.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/AuthenticationException.kt index 6ce2b0257..1faede083 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/AuthenticationException.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/AuthenticationException.kt @@ -17,7 +17,7 @@ */ package org.jackhuang.hmcl.auth -class AuthenticationException : Exception { +open class AuthenticationException : Exception { constructor() : super() {} constructor(message: String) : super(message) {} constructor(message: String, cause: Throwable) : super(message, cause) {} diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/Exceptions.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/Exceptions.kt new file mode 100644 index 000000000..34ab880a7 --- /dev/null +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/Exceptions.kt @@ -0,0 +1,24 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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.auth.yggdrasil + +import org.jackhuang.hmcl.auth.AuthenticationException + +class InvalidTokenException(val account: YggdrasilAccount) : AuthenticationException() + +class InvalidCredentialsException(val account: YggdrasilAccount) : AuthenticationException() \ No newline at end of file diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilAccount.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilAccount.kt index 45ac93a79..39958b377 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilAccount.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/YggdrasilAccount.kt @@ -36,7 +36,8 @@ class YggdrasilAccount private constructor(override val username: String): Accou private var clientToken: String = UUID.randomUUID().toString() private var isOnline: Boolean = false private var userProperties = PropertyMap() - private var selectedProfile: GameProfile? = null + var selectedProfile: GameProfile? = null + private set private var profiles: Array? = null private var userType: UserType = UserType.LEGACY @@ -166,7 +167,11 @@ class YggdrasilAccount private constructor(override val username: String): Accou if (response.error?.isNotBlank() ?: false) { LOG.severe("Failed to log in, the auth server returned an error: " + response.error + ", message: " + response.errorMessage + ", cause: " + response.cause) - throw AuthenticationException("Request error: ${response.errorMessage}") + throw when (response.errorMessage) { + "Invalid token." -> InvalidTokenException(this) + "Invalid credentials. Invalid username or password." -> InvalidCredentialsException(this) + else -> AuthenticationException("Request error: ${response.errorMessage}") + } } return response diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/FileDownloadTask.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/FileDownloadTask.kt index 528ce2496..4337d8013 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/FileDownloadTask.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/FileDownloadTask.kt @@ -34,7 +34,7 @@ import java.math.BigInteger import java.util.logging.Level class FileDownloadTask @JvmOverloads constructor(val url: URL, val file: File, val hash: String? = null, val retry: Int = 5, val proxy: Proxy = Proxy.NO_PROXY): Task() { - override val scheduler: Scheduler = Scheduler.IO_THREAD + override val scheduler: Scheduler = Scheduler.IO var onFailed = EventManager>() private var rFile: RandomAccessFile? = null diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/GetTask.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/GetTask.kt index 71d9ff184..6cd6f1363 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/GetTask.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/GetTask.kt @@ -26,7 +26,7 @@ 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() { - override val scheduler: Scheduler = Scheduler.IO_THREAD + override val scheduler: Scheduler = Scheduler.IO override val id = ID override fun execute() { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Scheduler.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Scheduler.kt index 43daea8b7..2af5d4140 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Scheduler.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Scheduler.kt @@ -62,7 +62,7 @@ interface Scheduler { val NEW_THREAD: Scheduler = object : Scheduler { override fun schedule(block: Callable) = CACHED_EXECUTOR.submit(block) } - val IO_THREAD: Scheduler = object : Scheduler { + val IO: Scheduler = object : Scheduler { override fun schedule(block: Callable) = IO_EXECUTOR.submit(block) } val DEFAULT = NEW_THREAD diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Task.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Task.kt index 18671a7a7..457d99ed1 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Task.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Task.kt @@ -58,7 +58,6 @@ abstract class Task { @Throws(Exception::class) abstract fun execute() - infix fun parallel(couple: Task): Task = ParallelTask(this, couple) infix fun then(b: Task): Task = CoupleTask(this, { b }, true) infix fun with(b: Task): Task = CoupleTask(this, { b }, false) @@ -116,7 +115,7 @@ abstract class Task { fun executor() = TaskExecutor().submit(this) fun executor(taskListener: TaskListener) = TaskExecutor().submit(this).apply { this.taskListener = taskListener } - + fun start() = executor().start() fun subscribe(subscriber: Task) = executor().apply { submit(subscriber).start() } diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/JavaVersion.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/JavaVersion.kt index 8a899c35f..1cd24913a 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/JavaVersion.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/JavaVersion.kt @@ -82,7 +82,7 @@ data class JavaVersion internal constructor( val parsedVersion = parseVersion(thisVersion) if (parsedVersion == UNKNOWN) throw IOException("Java version '$thisVersion' can not be recognized") - return JavaVersion(file.parentFile, thisVersion, platform) + return JavaVersion(file, thisVersion, platform) } private fun fromExecutable(file: File, version: String) = diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Logging.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Logging.kt index 257fd6258..45d66a5d1 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Logging.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Logging.kt @@ -26,14 +26,14 @@ import java.util.logging.* import java.util.logging.Formatter val LOG = Logger.getLogger("HMCL").apply { - level = Level.FINER + level = Level.FINEST useParentHandlers = false addHandler(FileHandler("hmcl.log").apply { - level = Level.FINER + level = Level.FINEST formatter = DefaultFormatter }) addHandler(ConsoleHandler().apply { - level = Level.FINER + level = Level.FINEST formatter = DefaultFormatter }) } diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/property/ImmediateStringProperty.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/property/ImmediateStringProperty.kt index 984884828..61de32ccc 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/property/ImmediateStringProperty.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/property/ImmediateStringProperty.kt @@ -50,10 +50,6 @@ open class ImmediateStringProperty(bean: Any, name: String, initialValue: String init { addListener(changeListener) } - - public override fun fireValueChangedEvent() { - super.fireValueChangedEvent() - } } open class ImmediateBooleanProperty(bean: Any, name: String, initialValue: Boolean): SimpleBooleanProperty(bean, name, initialValue) { @@ -85,10 +81,6 @@ open class ImmediateBooleanProperty(bean: Any, name: String, initialValue: Boole init { addListener(changeListener) } - - public override fun fireValueChangedEvent() { - super.fireValueChangedEvent() - } } open class ImmediateIntegerProperty(bean: Any, name: String, initialValue: Int): SimpleIntegerProperty(bean, name, initialValue) { @@ -120,10 +112,6 @@ open class ImmediateIntegerProperty(bean: Any, name: String, initialValue: Int): init { addListener(changeListener) } - - public override fun fireValueChangedEvent() { - super.fireValueChangedEvent() - } } open class ImmediateDoubleProperty(bean: Any, name: String, initialValue: Double): SimpleDoubleProperty(bean, name, initialValue) { @@ -155,10 +143,6 @@ open class ImmediateDoubleProperty(bean: Any, name: String, initialValue: Double init { addListener(changeListener) } - - public override fun fireValueChangedEvent() { - super.fireValueChangedEvent() - } } open class ImmediateObjectProperty(bean: Any, name: String, initialValue: T): SimpleObjectProperty(bean, name, initialValue) { @@ -185,13 +169,10 @@ open class ImmediateObjectProperty(bean: Any, name: String, initialValue: T): fun setChangedListener(listener: (T) -> Unit) { myListener = listener + listener(get()) } init { addListener(changeListener) } - - public override fun fireValueChangedEvent() { - super.fireValueChangedEvent() - } } \ No newline at end of file