diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/Events.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/Events.kt index 38ab439b0..9aa72f8f9 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/Events.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/Events.kt @@ -18,7 +18,7 @@ package org.jackhuang.hmcl import org.jackhuang.hmcl.setting.Profile -import java.util.EventObject +import java.util.* /** * This event gets fired when the selected profile changed. diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt index 3e05f48c3..c2abc6373 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt @@ -20,7 +20,6 @@ package org.jackhuang.hmcl import javafx.application.Application import javafx.application.Platform import javafx.stage.Stage -import javafx.stage.StageStyle import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.task.Scheduler import org.jackhuang.hmcl.ui.Controllers @@ -29,7 +28,6 @@ import org.jackhuang.hmcl.util.DEFAULT_USER_AGENT import org.jackhuang.hmcl.util.LOG import org.jackhuang.hmcl.util.OS import java.io.File -import java.util.concurrent.Callable import java.util.logging.Level fun i18n(key: String): String { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLGameRepository.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLGameRepository.kt index 7e8729634..149165976 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLGameRepository.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLGameRepository.kt @@ -23,7 +23,6 @@ import org.jackhuang.hmcl.setting.EnumGameDirectory import org.jackhuang.hmcl.setting.Profile import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.setting.VersionSetting -import org.jackhuang.hmcl.util.GSON import org.jackhuang.hmcl.util.LOG import org.jackhuang.hmcl.util.fromJson import java.io.File diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/LauncherHelper.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/LauncherHelper.kt index b829ac30d..d3a3386fb 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/LauncherHelper.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/LauncherHelper.kt @@ -29,15 +29,15 @@ import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.setting.VersionSetting import org.jackhuang.hmcl.task.* import org.jackhuang.hmcl.ui.* -import org.jackhuang.hmcl.util.JavaProcess import org.jackhuang.hmcl.util.Log4jLevel +import org.jackhuang.hmcl.util.ManagedProcess import java.util.* import java.util.concurrent.ConcurrentLinkedQueue object LauncherHelper { private val launchingStepsPane = LaunchingStepsPane() - val PROCESS = ConcurrentLinkedQueue() + val PROCESS = ConcurrentLinkedQueue() fun launch() { val profile = Settings.selectedProfile @@ -119,11 +119,11 @@ object LauncherHelper { authInfo.username to "" ) private val launcherVisibility = setting.launcherVisibility - private lateinit var process: JavaProcess + private lateinit var process: ManagedProcess private var lwjgl = false private var logWindow: LogWindow? = null private val logs = LinkedList>() - override fun setProcess(process: JavaProcess) { + override fun setProcess(process: ManagedProcess) { this.process = process if (setting.showLogs) { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Config.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Config.kt index d9dfc112a..4702fbab6 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Config.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Config.kt @@ -20,8 +20,7 @@ package org.jackhuang.hmcl.setting import com.google.gson.annotations.SerializedName import org.jackhuang.hmcl.Main import org.jackhuang.hmcl.util.JavaVersion -import java.io.File -import java.util.TreeMap +import java.util.* class Config { @SerializedName("last") diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Profile.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Profile.kt index ca7241fbd..1c3e395eb 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Profile.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Profile.kt @@ -22,9 +22,10 @@ import javafx.beans.InvalidationListener import org.jackhuang.hmcl.download.DefaultDependencyManager import org.jackhuang.hmcl.game.HMCLGameRepository import org.jackhuang.hmcl.mod.ModManager -import org.jackhuang.hmcl.util.* -import org.jackhuang.hmcl.util.property.ImmediateObjectProperty -import org.jackhuang.hmcl.util.property.ImmediateStringProperty +import org.jackhuang.hmcl.util.ImmediateObjectProperty +import org.jackhuang.hmcl.util.ImmediateStringProperty +import org.jackhuang.hmcl.util.getValue +import org.jackhuang.hmcl.util.setValue import java.io.File import java.lang.reflect.Type diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Settings.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Settings.kt index 49e53d6df..89f02c5ae 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Settings.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Settings.kt @@ -20,26 +20,23 @@ package org.jackhuang.hmcl.setting import com.google.gson.GsonBuilder import javafx.beans.InvalidationListener import javafx.scene.text.Font -import java.io.IOException import org.jackhuang.hmcl.Main +import org.jackhuang.hmcl.ProfileChangedEvent +import org.jackhuang.hmcl.ProfileLoadingEvent +import org.jackhuang.hmcl.auth.Account import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider import org.jackhuang.hmcl.download.DownloadProvider import org.jackhuang.hmcl.download.MojangDownloadProvider -import org.jackhuang.hmcl.util.LOG -import java.io.File -import java.util.logging.Level -import org.jackhuang.hmcl.ProfileLoadingEvent -import org.jackhuang.hmcl.ProfileChangedEvent -import org.jackhuang.hmcl.auth.Account -import org.jackhuang.hmcl.util.* import org.jackhuang.hmcl.event.EVENT_BUS -import org.jackhuang.hmcl.util.property.ImmediateObjectProperty -import org.jackhuang.hmcl.util.property.ImmediateStringProperty +import org.jackhuang.hmcl.util.* +import java.io.File +import java.io.IOException import java.net.Authenticator import java.net.InetSocketAddress import java.net.PasswordAuthentication import java.net.Proxy import java.util.* +import java.util.logging.Level object Settings { val GSON = GsonBuilder() diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/VersionSetting.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/VersionSetting.kt index 0237b56d1..a526ae1a8 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/VersionSetting.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/VersionSetting.kt @@ -22,7 +22,6 @@ import javafx.beans.InvalidationListener import org.jackhuang.hmcl.Main import org.jackhuang.hmcl.game.LaunchOptions import org.jackhuang.hmcl.util.* -import org.jackhuang.hmcl.util.property.* import java.io.File import java.io.IOException import java.lang.reflect.Type 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 59729710d..642c8f585 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt @@ -19,15 +19,14 @@ package org.jackhuang.hmcl.ui import com.jfoenix.controls.* import javafx.application.Platform -import javafx.fxml.FXML -import javafx.scene.Node -import javafx.scene.control.ScrollPane -import javafx.scene.layout.StackPane import javafx.beans.property.SimpleStringProperty import javafx.beans.property.StringProperty -import javafx.beans.value.ChangeListener +import javafx.fxml.FXML +import javafx.scene.Node import javafx.scene.control.Label +import javafx.scene.control.ScrollPane import javafx.scene.control.ToggleGroup +import javafx.scene.layout.StackPane import org.jackhuang.hmcl.auth.Account import org.jackhuang.hmcl.auth.OfflineAccount import org.jackhuang.hmcl.auth.yggdrasil.InvalidCredentialsException @@ -37,6 +36,7 @@ import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.task.Scheduler import org.jackhuang.hmcl.task.taskResult import org.jackhuang.hmcl.ui.wizard.DecoratorPage +import org.jackhuang.hmcl.util.onChange class AccountsPage() : StackPane(), DecoratorPage { override val titleProperty: StringProperty = SimpleStringProperty(this, "title", "Accounts") @@ -50,14 +50,6 @@ class AccountsPage() : StackPane(), DecoratorPage { @FXML lateinit var cboType: JFXComboBox @FXML lateinit var progressBar: JFXProgressBar - val listener = ChangeListener { _, _, newValue -> - masonryPane.children.forEach { - if (it is AccountItem) { - it.chkSelected.isSelected = newValue?.username == it.lblUser.text - } - } - } - init { loadFXML("/assets/fxml/account.fxml") children.remove(dialog) @@ -75,8 +67,8 @@ class AccountsPage() : StackPane(), DecoratorPage { } txtPassword.validate() - cboType.selectionModel.selectedIndexProperty().addListener { _, _, newValue -> - val visible = newValue != 0 + cboType.selectionModel.selectedIndexProperty().onChange { + val visible = it != 0 txtPassword.isVisible = visible } cboType.selectionModel.select(0) @@ -84,7 +76,13 @@ class AccountsPage() : StackPane(), DecoratorPage { txtPassword.setOnAction { onCreationAccept() } txtUsername.setOnAction { onCreationAccept() } - Settings.selectedAccountProperty.addListener(listener) + Settings.selectedAccountProperty.setChangedListener { account -> + masonryPane.children.forEach { node -> + if (node is AccountItem) { + node.chkSelected.isSelected = account?.username == node.lblUser.text + } + } + } loadAccounts() @@ -92,10 +90,6 @@ class AccountsPage() : StackPane(), DecoratorPage { addNewAccount() } - override fun onClose() { - Settings.selectedAccountProperty.removeListener(listener) - } - fun loadAccounts() { val children = mutableListOf() var i = 0 @@ -103,9 +97,9 @@ class AccountsPage() : StackPane(), DecoratorPage { for ((_, account) in Settings.getAccounts()) { children += buildNode(++i, account, group) } - group.selectedToggleProperty().addListener { _, _, newValue -> - if (newValue != null) - Settings.selectedAccount = newValue.properties["account"] as Account + group.selectedToggleProperty().onChange { + if (it != null) + Settings.selectedAccount = it.properties["account"] as Account } masonryPane.resetChildren(children) Platform.runLater { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/Decorator.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/Decorator.kt index 07dc60b41..d9080dfc5 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/Decorator.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/Decorator.kt @@ -23,7 +23,7 @@ import com.jfoenix.controls.JFXDrawer import com.jfoenix.controls.JFXHamburger import com.jfoenix.effects.JFXDepthManager import com.jfoenix.svg.SVGGlyph -import javafx.animation.* +import javafx.animation.Timeline import javafx.application.Platform import javafx.beans.property.BooleanProperty import javafx.beans.property.ObjectProperty @@ -36,7 +36,6 @@ import javafx.geometry.Insets import javafx.scene.Cursor import javafx.scene.Node import javafx.scene.control.Label -import javafx.scene.control.ScrollPane import javafx.scene.control.Tooltip import javafx.scene.input.MouseEvent import javafx.scene.layout.* @@ -49,7 +48,8 @@ import org.jackhuang.hmcl.ui.animation.AnimationProducer import org.jackhuang.hmcl.ui.animation.ContainerAnimations import org.jackhuang.hmcl.ui.animation.TransitionHandler import org.jackhuang.hmcl.ui.wizard.* -import org.jackhuang.hmcl.util.* +import org.jackhuang.hmcl.util.getValue +import org.jackhuang.hmcl.util.setValue import java.util.* import java.util.concurrent.ConcurrentLinkedQueue 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 e766b4742..f76c9b615 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LeftPaneController.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LeftPaneController.kt @@ -18,13 +18,11 @@ package org.jackhuang.hmcl.ui import com.jfoenix.controls.JFXComboBox -import javafx.scene.layout.* -import org.jackhuang.hmcl.auth.Account +import javafx.scene.layout.VBox 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() diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LogWindow.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LogWindow.kt index 73a1b4bfe..cd994b7f6 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LogWindow.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LogWindow.kt @@ -35,6 +35,7 @@ import org.jackhuang.hmcl.i18n import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.util.Log4jLevel import org.jackhuang.hmcl.util.inc +import org.jackhuang.hmcl.util.onChange import org.jackhuang.hmcl.util.readFullyAsString import org.w3c.dom.Document import org.w3c.dom.Node @@ -90,8 +91,8 @@ class LogWindow : Stage() { engine = webView.engine engine.loadContent(javaClass.getResourceAsStream("/assets/log-window-content.html").readFullyAsString().replace("\${FONT}", "${Settings.font.size}px \"${Settings.font.family}\"")) - engine.loadWorker.stateProperty().addListener { _, _, newValue -> - if (newValue == Worker.State.SUCCEEDED) { + engine.loadWorker.stateProperty().onChange { + if (it == Worker.State.SUCCEEDED) { document = engine.document body = document.getElementsByTagName("body").item(0) engine.executeScript("limitedLogs=${Settings.logLines};") @@ -105,8 +106,8 @@ class LogWindow : Stage() { flag = true } } - cboLines.selectionModel.selectedItemProperty().addListener { _, _, newValue -> - Settings.logLines = newValue.toInt() + cboLines.selectionModel.selectedItemProperty().onChange { + Settings.logLines = it?.toInt() ?: 100 engine.executeScript("limitedLogs=${Settings.logLines};") } if (!flag) { 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 85da57a68..fd72fa5e8 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/MainPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/MainPage.kt @@ -38,6 +38,7 @@ import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.ui.construct.RipplerContainer import org.jackhuang.hmcl.ui.download.DownloadWizardProvider import org.jackhuang.hmcl.ui.wizard.DecoratorPage +import org.jackhuang.hmcl.util.onChange /** * @see /assets/fxml/main.fxml @@ -104,9 +105,9 @@ class MainPage : StackPane(), DecoratorPage { profile.repository.getVersions().forEach { version -> children += buildNode(++i, profile, version.id, minecraftVersion(profile.repository.getVersionJar(version.id)) ?: "Unknown", group) } - group.selectedToggleProperty().addListener { _, _, newValue -> - if (newValue != null) - profile.selectedVersion = newValue.properties["version"] as String + group.selectedToggleProperty().onChange { + if (it != null) + profile.selectedVersion = it.properties["version"] as String } masonryPane.resetChildren(children) } diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/ModController.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/ModController.kt index e45d519b8..bbd6cc48d 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/ModController.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/ModController.kt @@ -28,6 +28,7 @@ import org.jackhuang.hmcl.i18n import org.jackhuang.hmcl.mod.ModManager import org.jackhuang.hmcl.task.Scheduler import org.jackhuang.hmcl.task.task +import org.jackhuang.hmcl.util.onChange class ModController { @FXML lateinit var scrollPane: ScrollPane @@ -71,8 +72,8 @@ class ModController { JFXDepthManager.setDepth(this, 1) style += "-fx-background-radius: 2; -fx-background-color: white; -fx-padding: 8;" - modInfo.activeProperty.addListener { _, _, newValue -> - if (newValue) + modInfo.activeProperty.onChange { + if (it) styleClass -= "disabled" else styleClass += "disabled" diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/ModItem.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/ModItem.kt index 02b993c97..a5d0e2be1 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/ModItem.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/ModItem.kt @@ -22,6 +22,7 @@ import javafx.fxml.FXML import javafx.scene.control.Label import javafx.scene.layout.BorderPane import org.jackhuang.hmcl.mod.ModInfo +import org.jackhuang.hmcl.util.onChange class ModItem(info: ModInfo, private val deleteCallback: (ModItem) -> Unit) : BorderPane() { @FXML lateinit var lblModFileName: Label @@ -34,8 +35,8 @@ class ModItem(info: ModInfo, private val deleteCallback: (ModItem) -> Unit) : Bo lblModFileName.text = info.fileName lblModAuthor.text = "${info.name}, Version: ${info.version}, Game Version: ${info.mcversion}, Authors: ${info.authors}" chkEnabled.isSelected = info.isActive - chkEnabled.selectedProperty().addListener { _, _, newValue -> - info.activeProperty.set(newValue) + chkEnabled.selectedProperty().onChange { + info.activeProperty.set(it) } } 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 c590775e0..55d0e045c 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/SVG.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/SVG.kt @@ -21,7 +21,6 @@ import javafx.fxml.FXMLLoader import javafx.scene.Group import javafx.scene.Node import javafx.scene.shape.SVGPath -import kotlin.coroutines.experimental.EmptyCoroutineContext.plus object SVG { val svgNames = setOf("gear") diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/SettingsPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/SettingsPage.kt index b2960fb6e..f2324e833 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/SettingsPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/SettingsPage.kt @@ -35,6 +35,7 @@ import org.jackhuang.hmcl.ui.construct.FileItem import org.jackhuang.hmcl.ui.construct.FontComboBox import org.jackhuang.hmcl.ui.construct.Validator import org.jackhuang.hmcl.ui.wizard.DecoratorPage +import org.jackhuang.hmcl.util.onChange class SettingsPage : StackPane(), DecoratorPage { override val titleProperty: StringProperty = SimpleStringProperty(this, "title", i18n("launcher.title.launcher")) @@ -59,41 +60,33 @@ class SettingsPage : StackPane(), DecoratorPage { cboDownloadSource.limitWidth(400.0) txtProxyHost.text = Settings.proxyHost - txtProxyHost.textProperty().addListener { _, _, newValue -> - Settings.proxyHost = newValue - } + txtProxyHost.textProperty().onChange { Settings.proxyHost = it } txtProxyPort.text = Settings.proxyPort - txtProxyPort.textProperty().addListener { _, _, newValue -> - Settings.proxyPort = newValue - } + txtProxyPort.textProperty().onChange { Settings.proxyPort = it } txtProxyUsername.text = Settings.proxyUser - txtProxyUsername.textProperty().addListener { _, _, newValue -> - Settings.proxyUser = newValue - } + txtProxyUsername.textProperty().onChange { Settings.proxyUser = it } txtProxyPassword.text = Settings.proxyPass - txtProxyPassword.textProperty().addListener { _, _, newValue -> - Settings.proxyPass = newValue - } + txtProxyPassword.textProperty().onChange { Settings.proxyPass = it } cboDownloadSource.selectionModel.select(DownloadProviders.DOWNLOAD_PROVIDERS.indexOf(Settings.downloadProvider)) - cboDownloadSource.selectionModel.selectedIndexProperty().addListener { _, _, newValue -> - Settings.downloadProvider = DownloadProviders.getDownloadProvider(newValue.toInt()) + cboDownloadSource.selectionModel.selectedIndexProperty().onChange { + Settings.downloadProvider = DownloadProviders.getDownloadProvider(it) } cboFont.selectionModel.select(Settings.font.family) - cboFont.valueProperty().addListener { _, _, newValue -> - val font = Font.font(newValue, Settings.font.size) + cboFont.valueProperty().onChange { + val font = Font.font(it, Settings.font.size) Settings.font = font lblDisplay.style = "-fx-font: ${Settings.font.size} \"${font.family}\";" } txtFontSize.text = Settings.font.size.toString() txtFontSize.validators += Validator { it.toDoubleOrNull() != null } - txtFontSize.textProperty().addListener { _, _, newValue -> + txtFontSize.textProperty().onChange { if (txtFontSize.validate()) { - val font = Font.font(Settings.font.family, newValue.toDouble()) + val font = Font.font(Settings.font.family, it!!.toDouble()) Settings.font = font lblDisplay.style = "-fx-font: ${font.size} \"${Settings.font.family}\";" } @@ -106,13 +99,13 @@ class SettingsPage : StackPane(), DecoratorPage { } cboLanguage.items = list cboLanguage.selectionModel.select(Locales.LOCALES.indexOf(Settings.locale)) - cboLanguage.selectionModel.selectedIndexProperty().addListener { _, _, newValue -> - Settings.locale = Locales.getLocale(newValue.toInt()) + cboLanguage.selectionModel.selectedIndexProperty().onChange { + Settings.locale = Locales.getLocale(it) } cboProxyType.selectionModel.select(Proxies.PROXIES.indexOf(Settings.proxyType)) - cboProxyType.selectionModel.selectedIndexProperty().addListener { _, _, newValue -> - Settings.proxyType = Proxies.getProxyType(newValue.toInt()) + cboProxyType.selectionModel.selectedIndexProperty().onChange { + Settings.proxyType = Proxies.getProxyType(it) } fileCommonLocation.setProperty(Settings.commonPathProperty) 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 486d283a0..7e61b50c6 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionItem.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionItem.kt @@ -18,9 +18,7 @@ package org.jackhuang.hmcl.ui import com.jfoenix.controls.JFXButton -import com.jfoenix.controls.JFXCheckBox import com.jfoenix.controls.JFXRadioButton -import com.jfoenix.effects.JFXDepthManager import javafx.beans.binding.Bindings import javafx.fxml.FXML import javafx.scene.control.Label diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionListItem.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionListItem.kt index 4b8ae6c4a..a987d99fc 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionListItem.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionListItem.kt @@ -20,10 +20,7 @@ package org.jackhuang.hmcl.ui import javafx.fxml.FXML import javafx.scene.control.Button import javafx.scene.control.Label -import javafx.scene.control.Tooltip -import javafx.scene.layout.BorderPane import javafx.scene.layout.StackPane -import org.jackhuang.hmcl.setting.VersionSetting class VersionListItem(val versionName: String, val gameVersion: String) : StackPane() { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionPage.kt index deb7fb258..3f0b61da8 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionPage.kt @@ -17,13 +17,15 @@ */ package org.jackhuang.hmcl.ui -import com.jfoenix.controls.* +import com.jfoenix.controls.JFXButton +import com.jfoenix.controls.JFXListView +import com.jfoenix.controls.JFXPopup import javafx.beans.property.SimpleStringProperty import javafx.beans.property.StringProperty import javafx.fxml.FXML import javafx.scene.control.Alert -import javafx.scene.layout.* -import org.jackhuang.hmcl.download.GameAssetIndexDownloadTask +import javafx.scene.layout.StackPane +import org.jackhuang.hmcl.download.game.GameAssetIndexDownloadTask import org.jackhuang.hmcl.i18n import org.jackhuang.hmcl.setting.Profile import org.jackhuang.hmcl.ui.wizard.DecoratorPage 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 1dc4b8a8d..411d0cd71 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionSettingsController.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionSettingsController.kt @@ -19,15 +19,15 @@ package org.jackhuang.hmcl.ui import com.jfoenix.controls.* import javafx.beans.InvalidationListener -import javafx.beans.binding.Bindings import javafx.beans.value.ChangeListener import javafx.fxml.FXML -import javafx.geometry.Pos import javafx.scene.control.Label import javafx.scene.control.ScrollPane import javafx.scene.control.Toggle import javafx.scene.control.ToggleGroup -import javafx.scene.layout.* +import javafx.scene.layout.BorderPane +import javafx.scene.layout.Pane +import javafx.scene.layout.VBox import javafx.stage.DirectoryChooser import org.jackhuang.hmcl.i18n import org.jackhuang.hmcl.setting.VersionSetting diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/TransitionHandler.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/TransitionHandler.kt index 48bca6ce8..4abdac73a 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/TransitionHandler.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/TransitionHandler.kt @@ -26,9 +26,7 @@ import javafx.scene.SnapshotParameters import javafx.scene.image.ImageView import javafx.scene.image.WritableImage import javafx.scene.layout.StackPane -import javafx.scene.shape.Rectangle import javafx.util.Duration -import org.jackhuang.hmcl.ui.setOverflowHidden import org.jackhuang.hmcl.ui.takeSnapshot /** diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/ComponentList.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/ComponentList.kt index 3dcc44e7f..5459821f0 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/ComponentList.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/ComponentList.kt @@ -19,7 +19,6 @@ package org.jackhuang.hmcl.ui.construct import javafx.beans.DefaultProperty import javafx.beans.property.SimpleIntegerProperty -import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleStringProperty import javafx.collections.FXCollections import javafx.collections.ListChangeListener @@ -27,7 +26,10 @@ import javafx.collections.ObservableList import javafx.scene.Node import javafx.scene.layout.StackPane import javafx.scene.layout.VBox -import org.jackhuang.hmcl.util.* +import org.jackhuang.hmcl.util.getValue +import org.jackhuang.hmcl.util.setValue +import kotlin.collections.plusAssign +import kotlin.collections.set @DefaultProperty("content") class ComponentList: StackPane() { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/ComponentListCell.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/ComponentListCell.kt index d51e4f90a..13bc827de 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/ComponentListCell.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/ComponentListCell.kt @@ -18,14 +18,14 @@ package org.jackhuang.hmcl.ui.construct import com.jfoenix.controls.JFXButton -import javafx.animation.* +import javafx.animation.Animation +import javafx.animation.KeyFrame +import javafx.animation.KeyValue +import javafx.animation.Timeline import javafx.beans.property.SimpleBooleanProperty -import javafx.geometry.Insets import javafx.geometry.Pos import javafx.scene.Node import javafx.scene.control.Label -import javafx.scene.layout.HBox -import javafx.scene.layout.Priority import javafx.scene.layout.StackPane import javafx.scene.layout.VBox import javafx.scene.shape.Rectangle @@ -33,7 +33,9 @@ import javafx.util.Duration import org.jackhuang.hmcl.ui.SINE import org.jackhuang.hmcl.ui.SVG import org.jackhuang.hmcl.ui.limitHeight -import org.jackhuang.hmcl.util.* +import org.jackhuang.hmcl.util.getValue +import org.jackhuang.hmcl.util.onChange +import org.jackhuang.hmcl.util.setValue class ComponentListCell(private val content: Node) : StackPane() { @@ -146,8 +148,8 @@ class ComponentListCell(private val content: Node) : StackPane() { expandAnimation?.play() } - expandedProperty.addListener { _, _, newValue -> - if (newValue) { + expandedProperty.onChange { + if (it) { expandIcon.rotate = 180.0 } else { expandIcon.rotate = 0.0 diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/FileItem.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/FileItem.kt index 5dcc15011..682af6baa 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/FileItem.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/FileItem.kt @@ -27,7 +27,8 @@ import javafx.scene.layout.VBox import javafx.stage.DirectoryChooser import org.jackhuang.hmcl.ui.Controllers import org.jackhuang.hmcl.ui.SVG -import org.jackhuang.hmcl.util.* +import org.jackhuang.hmcl.util.getValue +import org.jackhuang.hmcl.util.setValue class FileItem : BorderPane() { val nameProperty = SimpleStringProperty(this, "name") diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/FontComboBox.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/FontComboBox.kt index 63d496724..d4bab6a1c 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/FontComboBox.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/FontComboBox.kt @@ -23,12 +23,13 @@ import javafx.collections.FXCollections import javafx.scene.control.ListCell import javafx.scene.text.Font import javafx.util.Callback +import org.jackhuang.hmcl.util.onChange class FontComboBox(@NamedArg("fontSize") fontSize: Double = 12.0, @NamedArg("enableStyle") enableStyle: Boolean = false) : JFXComboBox(FXCollections.observableArrayList(Font.getFamilies())) { init { - valueProperty().addListener { _, _, newValue -> + valueProperty().onChange { if (enableStyle) - style = "-fx-font-family: \"$newValue\";" + style = "-fx-font-family: \"$it\";" } cellFactory = Callback { object : ListCell() { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/RipplerContainer.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/RipplerContainer.kt index c02d8dadd..88304cab2 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/RipplerContainer.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/RipplerContainer.kt @@ -26,11 +26,15 @@ import javafx.beans.property.SimpleBooleanProperty import javafx.beans.property.SimpleObjectProperty import javafx.geometry.Insets import javafx.scene.Node -import javafx.scene.layout.* +import javafx.scene.layout.Background +import javafx.scene.layout.BackgroundFill +import javafx.scene.layout.CornerRadii +import javafx.scene.layout.StackPane import javafx.scene.paint.Color import javafx.scene.paint.Paint import javafx.scene.shape.Rectangle import org.jackhuang.hmcl.util.getValue +import org.jackhuang.hmcl.util.onChange import org.jackhuang.hmcl.util.setValue import java.util.concurrent.Callable @@ -92,8 +96,8 @@ open class RipplerContainer(@NamedArg("container") container: Node): StackPane() } } - focusedProperty().addListener { _, _, newVal -> - if (newVal) { + focusedProperty().onChange { + if (it) { if (!isPressed) { this.buttonRippler.showOverlay() } @@ -125,7 +129,7 @@ open class RipplerContainer(@NamedArg("container") container: Node): StackPane() return@Callable background } }, backgroundProperty())) - ripplerFillProperty.addListener { _, _, newVal -> this.buttonRippler.ripplerFill = newVal } + ripplerFillProperty.onChange { this.buttonRippler.ripplerFill = it } if (background == null || this.isJavaDefaultBackground(background)) { background = Background(BackgroundFill(Color.TRANSPARENT, this.defaultRadii, null)) } diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/UTF8Control.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/UTF8Control.kt index 7a57f571b..2a47804fa 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/UTF8Control.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/UTF8Control.kt @@ -17,12 +17,10 @@ */ package org.jackhuang.hmcl.ui.construct -import java.io.InputStreamReader -import java.util.PropertyResourceBundle -import java.util.ResourceBundle import java.io.IOException import java.io.InputStream -import java.util.Locale +import java.io.InputStreamReader +import java.util.* object UTF8Control : ResourceBundle.Control() { @Throws(IllegalAccessException::class, InstantiationException::class, IOException::class) diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/InstallersPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/InstallersPage.kt index 890c2dd05..fb9a6fdae 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/InstallersPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/InstallersPage.kt @@ -26,6 +26,7 @@ import org.jackhuang.hmcl.download.DownloadProvider 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 downloadProvider: DownloadProvider): StackPane(), WizardPage { @@ -42,9 +43,9 @@ class InstallersPage(private val controller: WizardController, private val downl val gameVersion = controller.settings["game"] as String txtName.text = gameVersion - list.selectionModel.selectedIndexProperty().addListener { _, _, newValue -> - controller.settings[INSTALLER_TYPE] = newValue - controller.onNext(when (newValue){ + 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) } diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/ModpackPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/ModpackPage.kt index 01ce2f8b6..0bb31e6e9 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/ModpackPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/ModpackPage.kt @@ -28,7 +28,6 @@ import javafx.stage.FileChooser import org.jackhuang.hmcl.i18n import org.jackhuang.hmcl.mod.readCurseForgeModpackManifest import org.jackhuang.hmcl.setting.Profile -import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.ui.Controllers import org.jackhuang.hmcl.ui.construct.Validator import org.jackhuang.hmcl.ui.loadFXML diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/VersionsPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/VersionsPage.kt index d04c58c95..7225a3739 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/VersionsPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/VersionsPage.kt @@ -21,8 +21,8 @@ import com.jfoenix.controls.JFXListView import com.jfoenix.controls.JFXSpinner import javafx.fxml.FXML import javafx.scene.layout.StackPane -import org.jackhuang.hmcl.download.RemoteVersion import org.jackhuang.hmcl.download.DownloadProvider +import org.jackhuang.hmcl.download.RemoteVersion import org.jackhuang.hmcl.task.Scheduler import org.jackhuang.hmcl.task.TaskExecutor import org.jackhuang.hmcl.ui.animation.ContainerAnimations @@ -31,6 +31,7 @@ import org.jackhuang.hmcl.ui.loadFXML import org.jackhuang.hmcl.ui.wizard.Refreshable import org.jackhuang.hmcl.ui.wizard.WizardController import org.jackhuang.hmcl.ui.wizard.WizardPage +import org.jackhuang.hmcl.util.onChange class VersionsPage(private val controller: WizardController, private val gameVersion: String, private val downloadProvider: DownloadProvider, private val libraryId: String, private val callback: () -> Unit): StackPane(), WizardPage, Refreshable { @@ -44,8 +45,8 @@ class VersionsPage(private val controller: WizardController, private val gameVer init { loadFXML("/assets/fxml/download/versions.fxml") children.setAll(spinner) - list.selectionModel.selectedItemProperty().addListener { _, _, newValue -> - controller.settings[libraryId] = newValue.remoteVersion.selfVersion + list.selectionModel.selectedItemProperty().onChange { + controller.settings[libraryId] = it!!.remoteVersion.selfVersion callback() } refresh() diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/VersionsPageItem.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/VersionsPageItem.kt index 845cfeeb0..10d65b526 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/VersionsPageItem.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/VersionsPageItem.kt @@ -19,7 +19,6 @@ package org.jackhuang.hmcl.ui.download import javafx.fxml.FXML import javafx.scene.control.Label -import javafx.scene.layout.BorderPane import javafx.scene.layout.StackPane import org.jackhuang.hmcl.download.RemoteVersion import org.jackhuang.hmcl.ui.loadFXML diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.kt index 604290ff3..8ed42732f 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.kt @@ -20,7 +20,6 @@ package org.jackhuang.hmcl.ui.wizard import com.jfoenix.concurrency.JFXUtilities import com.jfoenix.controls.JFXProgressBar import javafx.application.Platform -import javafx.scene.Node import javafx.scene.control.Label import javafx.scene.layout.StackPane import javafx.scene.layout.VBox diff --git a/HMCL/src/main/resources/assets/fxml/decorator.fxml b/HMCL/src/main/resources/assets/fxml/decorator.fxml index 622f4012f..f3cec60b5 100644 --- a/HMCL/src/main/resources/assets/fxml/decorator.fxml +++ b/HMCL/src/main/resources/assets/fxml/decorator.fxml @@ -1,7 +1,6 @@ - @@ -60,7 +59,11 @@
diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/GameProfile.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/GameProfile.kt index c5836b594..c753e37ce 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/GameProfile.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/GameProfile.kt @@ -19,9 +19,7 @@ package org.jackhuang.hmcl.auth.yggdrasil import com.google.gson.* import java.lang.reflect.Type -import com.google.gson.JsonObject -import java.util.UUID -import com.google.gson.JsonParseException +import java.util.* data class GameProfile( val id: UUID? = null, diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/PropertyMap.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/PropertyMap.kt index 32194005f..071af44e9 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/PropertyMap.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/auth/yggdrasil/PropertyMap.kt @@ -20,13 +20,6 @@ package org.jackhuang.hmcl.auth.yggdrasil import com.google.gson.* import java.lang.reflect.Type import java.util.* -import com.google.gson.JsonObject -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import kotlin.collections.HashMap -import com.google.gson.JsonPrimitive -import com.google.gson.JsonSerializationContext - class PropertyMap: HashMap() { 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 06cdbed72..63311ccd1 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 @@ -21,9 +21,6 @@ import com.google.gson.GsonBuilder import com.google.gson.JsonParseException import org.jackhuang.hmcl.auth.* import org.jackhuang.hmcl.util.* -import org.jackhuang.hmcl.util.doGet -import org.jackhuang.hmcl.util.doPost -import org.jackhuang.hmcl.util.toURL import java.io.IOException import java.net.Proxy import java.net.URL diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/AbstractDependencyManager.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/AbstractDependencyManager.kt index 114342f30..132fa4ade 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/AbstractDependencyManager.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/AbstractDependencyManager.kt @@ -17,11 +17,11 @@ */ package org.jackhuang.hmcl.download -import org.jackhuang.hmcl.game.* +import org.jackhuang.hmcl.game.GameRepository import java.net.Proxy -abstract class AbstractDependencyManager(repository: GameRepository, proxy: Proxy) - : DependencyManager(repository, proxy) { +abstract class AbstractDependencyManager + : DependencyManager { abstract val downloadProvider: DownloadProvider fun getVersions(id: String, selfVersion: String) = diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.kt index fbd931e86..1e159a38e 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.kt @@ -17,6 +17,14 @@ */ package org.jackhuang.hmcl.download +import org.jackhuang.hmcl.download.forge.ForgeVersionList +import org.jackhuang.hmcl.download.game.GameVersionList +import org.jackhuang.hmcl.download.liteloader.LiteLoaderVersionList +import org.jackhuang.hmcl.download.optifine.OptiFineBMCLVersionList + +/** + * @see {@link http://bmclapi2.bangbang93.com} + */ object BMCLAPIDownloadProvider : DownloadProvider() { override val libraryBaseURL: String = "http://bmclapi2.bangbang93.com/libraries/" override val versionListURL: String = "http://bmclapi2.bangbang93.com/mc/game/version_manifest.json" diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DefaultDependencyManager.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DefaultDependencyManager.kt index 279c0fa1a..93e945b0f 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DefaultDependencyManager.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DefaultDependencyManager.kt @@ -17,6 +17,13 @@ */ package org.jackhuang.hmcl.download +import org.jackhuang.hmcl.download.forge.ForgeInstallTask +import org.jackhuang.hmcl.download.game.GameAssetDownloadTask +import org.jackhuang.hmcl.download.game.GameLibrariesTask +import org.jackhuang.hmcl.download.game.GameLoggingDownloadTask +import org.jackhuang.hmcl.download.game.VersionJSONSaveTask +import org.jackhuang.hmcl.download.liteloader.LiteLoaderInstallTask +import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask import org.jackhuang.hmcl.game.DefaultGameRepository import org.jackhuang.hmcl.game.Version import org.jackhuang.hmcl.task.ParallelTask @@ -27,8 +34,8 @@ import java.net.Proxy /** * This class has no state. */ -class DefaultDependencyManager(override val repository: DefaultGameRepository, override var downloadProvider: DownloadProvider, proxy: Proxy = Proxy.NO_PROXY) - : AbstractDependencyManager(repository, proxy) { +class DefaultDependencyManager(override val repository: DefaultGameRepository, override var downloadProvider: DownloadProvider, override val proxy: Proxy = Proxy.NO_PROXY) + : AbstractDependencyManager() { override fun gameBuilder(): GameBuilder = DefaultGameBuilder(this) diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DefaultGameBuilder.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DefaultGameBuilder.kt index c8a4e7a0c..7ea7a6b82 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DefaultGameBuilder.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DefaultGameBuilder.kt @@ -17,9 +17,16 @@ */ package org.jackhuang.hmcl.download -import org.jackhuang.hmcl.game.* +import org.jackhuang.hmcl.download.game.GameAssetDownloadTask +import org.jackhuang.hmcl.download.game.GameLibrariesTask +import org.jackhuang.hmcl.download.game.GameLoggingDownloadTask +import org.jackhuang.hmcl.download.game.VersionJSONSaveTask +import org.jackhuang.hmcl.game.Version import org.jackhuang.hmcl.task.* -import org.jackhuang.hmcl.util.* +import org.jackhuang.hmcl.util.AutoTypingMap +import org.jackhuang.hmcl.util.GSON +import org.jackhuang.hmcl.util.fromJson +import org.jackhuang.hmcl.util.toURL import java.util.* class DefaultGameBuilder(val dependencyManager: DefaultDependencyManager): GameBuilder() { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DependencyManager.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DependencyManager.kt index fcd91ca67..32495bb63 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DependencyManager.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DependencyManager.kt @@ -22,27 +22,51 @@ import org.jackhuang.hmcl.game.Version import org.jackhuang.hmcl.task.Task import java.net.Proxy -abstract class DependencyManager(open val repository: GameRepository, open val proxy: Proxy) { +/** + * Do everything that will connect to Internet. + * Downloading Minecraft files. + */ +interface DependencyManager { + /** + * The relied game repository. + */ + val repository: GameRepository + + /** + * The proxy that all network operations should go through. + */ + val proxy: Proxy /** * Check if the game is complete. * Check libraries, assets, logging files and so on. * - * @return + * @return the task to check game completion. */ - abstract fun checkGameCompletionAsync(version: Version): Task + fun checkGameCompletionAsync(version: Version): Task /** * The builder to build a brand new game then libraries such as Forge, LiteLoader and OptiFine. */ - abstract fun gameBuilder(): GameBuilder + fun gameBuilder(): GameBuilder - abstract fun installLibraryAsync(gameVersion: String, version: Version, libraryId: String, libraryVersion: String): Task + /** + * Install a library to a version. + * **Note**: Installing a library may change the version.json. + * + * @param gameVersion the Minecraft version that the library relies on. + * @param version the version.json. + * @param libraryId the type of being installed library. i.e. "forge", "liteloader", "optifine" + * @param libraryVersion the version of being installed library. + * @return the task to install the specific library. + */ + fun installLibraryAsync(gameVersion: String, version: Version, libraryId: String, libraryVersion: String): Task /** * Get registered version list. + * * @param id the id of version list. i.e. game, forge, liteloader, optifine * @throws IllegalArgumentException if the version list of specific id is not found. */ - abstract fun getVersionList(id: String): VersionList<*> + fun getVersionList(id: String): VersionList<*> } \ No newline at end of file diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DownloadProvider.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DownloadProvider.kt index dfeb348ba..934ad5011 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DownloadProvider.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/DownloadProvider.kt @@ -17,14 +17,31 @@ */ package org.jackhuang.hmcl.download -import org.jackhuang.hmcl.download.VersionList - +/** + * The service provider that provides Minecraft online file downloads. + */ abstract class DownloadProvider { abstract val libraryBaseURL: String abstract val versionListURL: String abstract val versionBaseURL: String abstract val assetIndexBaseURL: String abstract val assetBaseURL: String + + /** + * Inject into original URL provided by Mojang and Forge. + * + * Since there are many provided URLs that are written in JSONs and are unmodifiable, + * this method provides a way to change them. + * + * @param baseURL original URL provided by Mojang and Forge. + * @return the URL that is equivalent to [baseURL], but belongs to your own service provider. + */ abstract fun injectURL(baseURL: String): String + + /** + * the specific version list that this download provider provides. i.e. "forge", "liteloader", "game", "optifine" + * @param id the id of specific version list that this download provider provides. i.e. "forge", "liteloader", "game", "optifine" + * @return the version list + */ abstract fun getVersionListById(id: String): VersionList<*> } \ No newline at end of file diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameBuilder.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameBuilder.kt index eb406b16f..897ea6c64 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameBuilder.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameBuilder.kt @@ -19,12 +19,20 @@ package org.jackhuang.hmcl.download import org.jackhuang.hmcl.task.Task - +/** + * The builder which provide a task to build Minecraft environment. + * + * @author huangyuhui + */ abstract class GameBuilder { var name: String = "" protected var gameVersion: String = "" protected var toolVersions = HashMap() + /** + * The new game version name, for .minecraft/. + * @param name the name of new game version. + */ fun name(name: String): GameBuilder { this.name = name return this @@ -35,10 +43,17 @@ abstract class GameBuilder { return this } + /** + * @param id the core library id. i.e. "forge", "liteloader", "optifine" + * @param version the version of the core library. For documents, you can first try [VersionList.versions] + */ fun version(id: String, version: String): GameBuilder { toolVersions[id] = version return this } + /** + * @return the task that can build thw whole Minecraft environment + */ abstract fun buildAsync(): Task } \ No newline at end of file diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/MojangDownloadProvider.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/MojangDownloadProvider.kt index d074dcc06..481d1e42f 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/MojangDownloadProvider.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/MojangDownloadProvider.kt @@ -17,8 +17,15 @@ */ package org.jackhuang.hmcl.download +import org.jackhuang.hmcl.download.forge.ForgeVersionList +import org.jackhuang.hmcl.download.game.GameVersionList +import org.jackhuang.hmcl.download.liteloader.LiteLoaderVersionList +import org.jackhuang.hmcl.download.optifine.OptiFineVersionList import java.util.* +/** + * @see {@link http://wiki.vg} + */ object MojangDownloadProvider : DownloadProvider() { override val libraryBaseURL: String = "https://libraries.minecraft.net/" override val versionBaseURL: String = "http://s3.amazonaws.com/Minecraft.Download/versions/" @@ -37,15 +44,6 @@ object MojangDownloadProvider : DownloadProvider() { } override fun injectURL(baseURL: String): String { - /**if (baseURL.contains("scala-swing") || baseURL.contains("scala-xml") || baseURL.contains("scala-parser-combinators")) - return baseURL.replace("http://files.minecraftforge.net/maven", "http://ftb.cursecdn.com/FTB2/maven/"); - else if (baseURL.contains("typesafe") || baseURL.contains("scala")) - if (Locale.getDefault() == Locale.CHINA) - return baseURL.replace("http://files.minecraftforge.net/maven", "http://maven.aliyun.com/nexus/content/groups/public"); - else - return baseURL.replace("http://files.minecraftforge.net/maven", "http://repo1.maven.org/maven2"); - else - return baseURL; */ if (baseURL.endsWith("net/minecraftforge/forge/json")) return baseURL else if (Locale.getDefault() == Locale.CHINA) diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/RemoteVersion.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/RemoteVersion.kt index be0391629..b1f760058 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/RemoteVersion.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/RemoteVersion.kt @@ -19,14 +19,18 @@ package org.jackhuang.hmcl.download import org.jackhuang.hmcl.util.VersionNumber import java.util.* -import kotlin.Comparator +/** + * The remote version. + * + * @param gameVersion the Minecraft version that this remote version suits. + * @param selfVersion the version string of the remote version. + * @param url the installer or universal jar URL. + * @param tag some necessary information for Installer Task. + */ data class RemoteVersion ( val gameVersion: String, val selfVersion: String, - /** - * The file of remote version, may be an installer or an universal jar. - */ val url: String, val tag: T ): Comparable> { @@ -39,6 +43,7 @@ data class RemoteVersion ( } override fun compareTo(other: RemoteVersion): Int { + // newer versions are smaller than older versions return -selfVersion.compareTo(other.selfVersion) } diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/VersionList.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/VersionList.kt index b5178e2c3..d62f8dbeb 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/VersionList.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/VersionList.kt @@ -22,20 +22,37 @@ import org.jackhuang.hmcl.util.SimpleMultimap import java.util.* import kotlin.collections.HashMap +/** + * The remote version list. + * @param T The type of RemoteVersion, the type of tags. + */ abstract class VersionList { - @JvmField + /** + * the remote version list. + * key: game version. + * values: corresponding remote versions. + */ protected val versions = SimpleMultimap>(::HashMap, ::TreeSet) + /** + * True if the version list has been loaded. + */ val loaded = versions.isNotEmpty + /** + * @param downloadProvider DownloadProvider + * @return the task to reload the remote version list. + */ abstract fun refreshAsync(downloadProvider: DownloadProvider): Task - protected open fun getVersionsImpl(gameVersion: String): Collection> { + private fun getVersionsImpl(gameVersion: String): Collection> { val ans = versions[gameVersion] return if (ans.isEmpty()) versions.values else ans } /** + * Get the remote versions that specifics Minecraft version. + * * @param gameVersion the Minecraft version that remote versions belong to * @return the collection of specific remote versions */ @@ -43,6 +60,13 @@ abstract class VersionList { return Collections.unmodifiableCollection(getVersionsImpl(gameVersion)) } + /** + * Get the specific remote version. + * + * @param gameVersion the Minecraft version that remote versions belong to + * @param remoteVersion the version of the remote version. + * @return the specific remote version, null if it is not found. + */ fun getVersion(gameVersion: String, remoteVersion: String): RemoteVersion? { var result : RemoteVersion? = null versions[gameVersion].forEach { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/ForgeInstallTask.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/forge/ForgeInstallTask.kt similarity index 89% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/ForgeInstallTask.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/forge/ForgeInstallTask.kt index 55af35e0e..1249a8cbc 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/ForgeInstallTask.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/forge/ForgeInstallTask.kt @@ -15,8 +15,11 @@ * 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.download +package org.jackhuang.hmcl.download.forge +import org.jackhuang.hmcl.download.DefaultDependencyManager +import org.jackhuang.hmcl.download.RemoteVersion +import org.jackhuang.hmcl.download.game.GameLibrariesTask import org.jackhuang.hmcl.game.Library import org.jackhuang.hmcl.game.SimpleVersionProvider import org.jackhuang.hmcl.game.Version @@ -30,9 +33,9 @@ import java.io.IOException import java.util.zip.ZipFile class ForgeInstallTask(private val dependencyManager: DefaultDependencyManager, - private val gameVersion: String, - private val version: Version, - private val remoteVersion: String) : TaskResult() { + private val gameVersion: String, + private val version: Version, + private val remoteVersion: String) : TaskResult() { private val forgeVersionList = dependencyManager.getVersionList("forge") private val installer: File = File("forge-installer.jar").absoluteFile lateinit var remote: RemoteVersion<*> diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/ForgeRemote.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/forge/ForgeRemote.kt similarity index 98% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/ForgeRemote.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/forge/ForgeRemote.kt index 66d747d98..6bb2c186d 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/ForgeRemote.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/forge/ForgeRemote.kt @@ -15,7 +15,7 @@ * 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.download +package org.jackhuang.hmcl.download.forge import com.google.gson.annotations.SerializedName import org.jackhuang.hmcl.game.Version diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/ForgeVersionList.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/forge/ForgeVersionList.kt similarity index 93% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/ForgeVersionList.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/forge/ForgeVersionList.kt index 6fc6fa86b..801f90c3a 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/ForgeVersionList.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/forge/ForgeVersionList.kt @@ -15,8 +15,11 @@ * 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.download +package org.jackhuang.hmcl.download.forge +import org.jackhuang.hmcl.download.DownloadProvider +import org.jackhuang.hmcl.download.RemoteVersion +import org.jackhuang.hmcl.download.VersionList import org.jackhuang.hmcl.task.GetTask import org.jackhuang.hmcl.task.Task import org.jackhuang.hmcl.util.* diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameDownloadTasks.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/game/GameDownloadTasks.kt similarity index 80% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameDownloadTasks.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/game/GameDownloadTasks.kt index e8fe34365..adf3c5b80 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameDownloadTasks.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/game/GameDownloadTasks.kt @@ -15,8 +15,11 @@ * 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.download +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 @@ -30,13 +33,12 @@ import java.io.IOException import java.util.* import java.util.logging.Level - /** * This task is to download game libraries. * This task should be executed last(especially after game downloading, Forge, LiteLoader and OptiFine install task) * @param resolvedVersion the resolved version */ -class GameLibrariesTask(private val dependencyManager: DefaultDependencyManager, private val resolvedVersion: Version): Task() { +class GameLibrariesTask(private val dependencyManager: AbstractDependencyManager, private val resolvedVersion: Version): Task() { override val dependencies = LinkedList() override fun execute() { for (library in resolvedVersion.libraries) @@ -49,7 +51,12 @@ class GameLibrariesTask(private val dependencyManager: DefaultDependencyManager, } -class GameLoggingDownloadTask(private val dependencyManager: DefaultDependencyManager, private val version: Version) : Task() { +/** + * This task is to download log4j configuration file provided in minecraft.json. + * @param dependencyManager the dependency manager that can provides proxy settings and [GameRepository] + * @param version the **resolved** version + */ +class GameLoggingDownloadTask(private val dependencyManager: DependencyManager, private val version: Version) : Task() { override val dependencies = LinkedList() override fun execute() { val logging = version.logging?.get(DownloadType.CLIENT) ?: return @@ -59,6 +66,11 @@ class GameLoggingDownloadTask(private val dependencyManager: DefaultDependencyMa } } +/** + * This task is to download asset index file provided in minecraft.json. + * @param dependencyManager the dependency manager that can provides proxy settings and [GameRepository] + * @param version the **resolved** version + */ class GameAssetIndexDownloadTask(private val dependencyManager: DefaultDependencyManager, private val version: Version) : Task() { override val dependencies = LinkedList() override fun execute() { @@ -72,6 +84,11 @@ class GameAssetIndexDownloadTask(private val dependencyManager: DefaultDependenc } } +/** + * This task is to extract all asset objects described in asset index json. + * @param dependencyManager the dependency manager that can provides proxy settings and [GameRepository] + * @param version the **resolved** version + */ class GameAssetRefreshTask(private val dependencyManager: DefaultDependencyManager, private val version: Version) : TaskResult>>() { private val assetIndexTask = GameAssetIndexDownloadTask(dependencyManager, version) private val assetIndexInfo = version.actualAssetIndex @@ -100,6 +117,11 @@ class GameAssetRefreshTask(private val dependencyManager: DefaultDependencyManag } } +/** + * This task is to download all asset objects provided in asset index json. + * @param dependencyManager the dependency manager that can provides proxy settings and [GameRepository] + * @param version the **resolved** version + */ class GameAssetDownloadTask(private val dependencyManager: DefaultDependencyManager, private val version: Version) : Task() { private val refreshTask = GameAssetRefreshTask(dependencyManager, version) override val dependents = listOf(refreshTask) @@ -140,6 +162,11 @@ 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 version the **resolved** version + */ class VersionJSONSaveTask(private val dependencyManager: DefaultDependencyManager, private val version: Version): Task() { override fun execute() { val json = dependencyManager.repository.getVersionJson(version.id).absoluteFile diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameRemoteVersions.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/game/GameRemote.kt similarity index 98% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameRemoteVersions.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/game/GameRemote.kt index 934b321ba..e37d4e1c9 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameRemoteVersions.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/game/GameRemote.kt @@ -15,7 +15,7 @@ * 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.download +package org.jackhuang.hmcl.download.game import com.google.gson.annotations.SerializedName import org.jackhuang.hmcl.game.ReleaseType diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameVersionList.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/game/GameVersionList.kt similarity index 91% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameVersionList.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/game/GameVersionList.kt index a74e95be8..dfc9cb3fa 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/GameVersionList.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/game/GameVersionList.kt @@ -15,13 +15,16 @@ * 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.download +package org.jackhuang.hmcl.download.game +import org.jackhuang.hmcl.download.DownloadProvider +import org.jackhuang.hmcl.download.RemoteVersion +import org.jackhuang.hmcl.download.VersionList +import org.jackhuang.hmcl.task.GetTask +import org.jackhuang.hmcl.task.Task import org.jackhuang.hmcl.util.GSON import org.jackhuang.hmcl.util.asVersion import org.jackhuang.hmcl.util.fromJson -import org.jackhuang.hmcl.task.GetTask -import org.jackhuang.hmcl.task.Task import org.jackhuang.hmcl.util.toURL diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/LiteLoaderInstallTask.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.kt similarity index 86% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/LiteLoaderInstallTask.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.kt index 5259b8ebf..f91467080 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/LiteLoaderInstallTask.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.kt @@ -15,8 +15,11 @@ * 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.download +package org.jackhuang.hmcl.download.liteloader +import org.jackhuang.hmcl.download.DefaultDependencyManager +import org.jackhuang.hmcl.download.RemoteVersion +import org.jackhuang.hmcl.download.game.GameLibrariesTask import org.jackhuang.hmcl.game.LibrariesDownloadInfo import org.jackhuang.hmcl.game.Library import org.jackhuang.hmcl.game.LibraryDownloadInfo @@ -27,12 +30,12 @@ import org.jackhuang.hmcl.task.then import org.jackhuang.hmcl.util.merge /** - * LiteLoader must be installed after Forge. + * Note: LiteLoader must be installed after Forge. */ class LiteLoaderInstallTask(private val dependencyManager: DefaultDependencyManager, - private val gameVersion: String, - private val version: Version, - private val remoteVersion: String): TaskResult() { + private val gameVersion: String, + private val version: Version, + private val remoteVersion: String): TaskResult() { private val liteLoaderVersionList = dependencyManager.getVersionList("liteloader") as LiteLoaderVersionList lateinit var remote: RemoteVersion override val dependents = mutableListOf() diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/LiteLoaderRemote.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/liteloader/LiteLoaderRemote.kt similarity index 98% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/LiteLoaderRemote.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/liteloader/LiteLoaderRemote.kt index 40ad1213e..9bdfb5aab 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/LiteLoaderRemote.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/liteloader/LiteLoaderRemote.kt @@ -15,7 +15,7 @@ * 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.download +package org.jackhuang.hmcl.download.liteloader import com.google.gson.annotations.SerializedName import org.jackhuang.hmcl.game.Library diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/LiteLoaderVersionList.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.kt similarity index 94% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/LiteLoaderVersionList.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.kt index ff762e4ba..aab772359 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/LiteLoaderVersionList.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.kt @@ -15,13 +15,16 @@ * 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.download +package org.jackhuang.hmcl.download.liteloader +import org.jackhuang.hmcl.download.DownloadProvider +import org.jackhuang.hmcl.download.RemoteVersion +import org.jackhuang.hmcl.download.VersionList +import org.jackhuang.hmcl.task.GetTask +import org.jackhuang.hmcl.task.Task import org.jackhuang.hmcl.util.GSON import org.jackhuang.hmcl.util.asVersion import org.jackhuang.hmcl.util.fromJson -import org.jackhuang.hmcl.task.GetTask -import org.jackhuang.hmcl.task.Task import org.jackhuang.hmcl.util.toURL object LiteLoaderVersionList : VersionList() { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineBMCLVersionList.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.kt similarity index 92% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineBMCLVersionList.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.kt index 17cf0164e..4ac869d2b 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineBMCLVersionList.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.kt @@ -15,15 +15,17 @@ * 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.download +package org.jackhuang.hmcl.download.optifine +import org.jackhuang.hmcl.download.DownloadProvider +import org.jackhuang.hmcl.download.RemoteVersion +import org.jackhuang.hmcl.download.VersionList import org.jackhuang.hmcl.task.GetTask import org.jackhuang.hmcl.task.Task import org.jackhuang.hmcl.util.GSON import org.jackhuang.hmcl.util.asVersion import org.jackhuang.hmcl.util.toURL import org.jackhuang.hmcl.util.typeOf -import java.util.TreeSet object OptiFineBMCLVersionList : VersionList() { override fun refreshAsync(downloadProvider: DownloadProvider): Task { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineDownloadFormatter.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineDownloadFormatter.kt similarity index 94% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineDownloadFormatter.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineDownloadFormatter.kt index fd3d2fa12..2a58a620a 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineDownloadFormatter.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineDownloadFormatter.kt @@ -15,7 +15,7 @@ * 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.download +package org.jackhuang.hmcl.download.optifine object Opt \ No newline at end of file diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineInstallTask.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.kt similarity index 87% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineInstallTask.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.kt index 3c63b1054..62f7f1285 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineInstallTask.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.kt @@ -15,8 +15,11 @@ * 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.download +package org.jackhuang.hmcl.download.optifine +import org.jackhuang.hmcl.download.DefaultDependencyManager +import org.jackhuang.hmcl.download.RemoteVersion +import org.jackhuang.hmcl.download.game.GameLibrariesTask import org.jackhuang.hmcl.game.LibrariesDownloadInfo import org.jackhuang.hmcl.game.Library import org.jackhuang.hmcl.game.LibraryDownloadInfo @@ -26,10 +29,13 @@ import org.jackhuang.hmcl.task.TaskResult import org.jackhuang.hmcl.task.then import org.jackhuang.hmcl.util.merge +/** + * **Note**: OptiFine should be installed in the end. + */ class OptiFineInstallTask(private val dependencyManager: DefaultDependencyManager, - private val gameVersion: String, - private val version: Version, - private val remoteVersion: String): TaskResult() { + private val gameVersion: String, + private val version: Version, + private val remoteVersion: String): TaskResult() { private val optiFineVersionList = dependencyManager.getVersionList("optifine") lateinit var remote: RemoteVersion<*> override val dependents = mutableListOf() diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineRemotes.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineRemote.kt similarity index 96% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineRemotes.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineRemote.kt index 98dcc2784..1a57792c1 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineRemotes.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineRemote.kt @@ -15,7 +15,7 @@ * 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.download +package org.jackhuang.hmcl.download.optifine import com.google.gson.annotations.SerializedName diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineVersionList.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineVersionList.kt similarity index 94% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineVersionList.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineVersionList.kt index e8cb524e6..de156de12 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/OptiFineVersionList.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/download/optifine/OptiFineVersionList.kt @@ -15,15 +15,18 @@ * 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.download +package org.jackhuang.hmcl.download.optifine +import org.jackhuang.hmcl.download.DownloadProvider +import org.jackhuang.hmcl.download.RemoteVersion +import org.jackhuang.hmcl.download.VersionList import org.jackhuang.hmcl.task.GetTask import org.jackhuang.hmcl.task.Task import org.jackhuang.hmcl.util.toURL import org.w3c.dom.Element import java.io.ByteArrayInputStream -import javax.xml.parsers.DocumentBuilderFactory import java.util.regex.Pattern +import javax.xml.parsers.DocumentBuilderFactory object OptiFineVersionList : VersionList() { private val pattern = Pattern.compile("OptiFine (.*?) ") diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/event/Events.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/event/Events.kt index 471d0b64f..c775c7fbe 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/event/Events.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/event/Events.kt @@ -17,8 +17,8 @@ */ package org.jackhuang.hmcl.event -import org.jackhuang.hmcl.util.JavaProcess -import java.util.EventObject +import org.jackhuang.hmcl.util.ManagedProcess +import java.util.* /** * This event gets fired when loading versions in a .minecraft folder. @@ -59,7 +59,7 @@ class LoadedOneVersionEvent(source: Any, val version: String) : EventObject(sour * @param JavaProcess The process that exited abnormally. * @author huangyuhui */ -class JavaProcessExitedAbnormallyEvent(source: Any, val value: JavaProcess) : EventObject(source) +class JavaProcessExitedAbnormallyEvent(source: Any, val value: ManagedProcess) : EventObject(source) /** * This event gets fired when minecraft process exited successfully and the exit code is 0. @@ -69,7 +69,7 @@ class JavaProcessExitedAbnormallyEvent(source: Any, val value: JavaProcess) : Ev * @param JavaProcess minecraft process * @author huangyuhui */ -class JavaProcessStoppedEvent(source: Any, val value: JavaProcess) : EventObject(source) +class JavaProcessStoppedEvent(source: Any, val value: ManagedProcess) : EventObject(source) /** * This event gets fired when we launch the JVM and it got crashed. @@ -79,4 +79,4 @@ class JavaProcessStoppedEvent(source: Any, val value: JavaProcess) : EventObject * @param JavaProcess the crashed process. * @author huangyuhui */ -class JVMLaunchFailedEvent(source: Any, val value: JavaProcess) : EventObject(source) +class JVMLaunchFailedEvent(source: Any, val value: ManagedProcess) : EventObject(source) diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/AssetIndexInfo.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/AssetIndexInfo.kt index 35878df33..682c30f29 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/AssetIndexInfo.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/AssetIndexInfo.kt @@ -18,7 +18,6 @@ package org.jackhuang.hmcl.game import jdk.nashorn.internal.ir.annotations.Immutable -import java.net.URL @Immutable class AssetIndexInfo( diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/ClassicVersion.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/ClassicVersion.kt index 284802208..a66e877fb 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/ClassicVersion.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/ClassicVersion.kt @@ -20,6 +20,9 @@ package org.jackhuang.hmcl.game import org.jackhuang.hmcl.util.Immutable import java.io.File +/** + * The Minecraft version for 1.5.x and earlier. + */ @Immutable class ClassicVersion : Version( mainClass = "net.minecraft.client.Minecraft", @@ -41,6 +44,9 @@ class ClassicVersion : Version( ) companion object { + /** + * Check if this directory is an old style Minecraft repository. + */ fun hasClassicVersion(baseDirectory: File): Boolean { val file = File(baseDirectory, "bin") if (!file.exists()) return false diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/DefaultGameRepository.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/DefaultGameRepository.kt index d7d463b21..cb8e3fa1e 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/DefaultGameRepository.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/DefaultGameRepository.kt @@ -18,7 +18,10 @@ package org.jackhuang.hmcl.game import com.google.gson.JsonSyntaxException -import org.jackhuang.hmcl.event.* +import org.jackhuang.hmcl.event.EVENT_BUS +import org.jackhuang.hmcl.event.LoadedOneVersionEvent +import org.jackhuang.hmcl.event.RefreshedVersionsEvent +import org.jackhuang.hmcl.event.RefreshingVersionsEvent import org.jackhuang.hmcl.util.GSON import org.jackhuang.hmcl.util.LOG import org.jackhuang.hmcl.util.fromJson @@ -28,6 +31,9 @@ import java.io.IOException import java.util.* import java.util.logging.Level +/** + * An implementation of classic Minecraft game repository. + */ open class DefaultGameRepository(var baseDirectory: File): GameRepository { protected val versions: MutableMap = TreeMap() @@ -44,6 +50,11 @@ open class DefaultGameRepository(var baseDirectory: File): GameRepository { val id = v.jar ?: v.id return getVersionRoot(id).resolve("$id.jar") } + + /** + * {@inheritsDoc} + * @return something like ".minecraft/versions//-natives" + */ override fun getNativeDirectory(id: String) = File(getVersionRoot(id), "$id-natives") override fun getVersionRoot(id: String) = File(baseDirectory, "versions/$id") open fun getVersionJson(id: String) = File(getVersionRoot(id), "$id.json") @@ -83,7 +94,6 @@ open class DefaultGameRepository(var baseDirectory: File): GameRepository { } protected open fun refreshVersionsImpl() { - versions.clear() if (ClassicVersion.hasClassicVersion(baseDirectory)) { @@ -167,7 +177,7 @@ open class DefaultGameRepository(var baseDirectory: File): GameRepository { return assetDir.resolve("objects/${obj.location}") } - open fun getIndexFile(version: String, assetId: String): File = + override fun getIndexFile(version: String, assetId: String): File = getAssetDirectory(version, assetId).resolve("indexes/$assetId.json") override fun getLoggingObject(version: String, assetId: String, loggingInfo: LoggingInfo): File = @@ -176,9 +186,8 @@ open class DefaultGameRepository(var baseDirectory: File): GameRepository { @Throws(IOException::class, JsonSyntaxException::class) protected open fun reconstructAssets(version: String, assetId: String): File { val assetsDir = getAssetDirectory(version, assetId) - val assetVersion = assetId - val indexFile: File = getIndexFile(version, assetVersion) - val virtualRoot = assetsDir.resolve("virtual").resolve(assetVersion) + val indexFile: File = getIndexFile(version, assetId) + val virtualRoot = assetsDir.resolve("virtual").resolve(assetId) if (!indexFile.isFile) { return assetsDir diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/GameRepository.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/GameRepository.kt index 426a51992..2daeda6e0 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/GameRepository.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/GameRepository.kt @@ -18,13 +18,15 @@ package org.jackhuang.hmcl.game import java.io.File +import java.io.IOException /** * Supports operations on versioning. * - * Note that game repository will not do any tasks that connect to Internet. + * Note that game repository will not do any tasks that connect to Internet, if do, see [org.jackhuang.hmcl.download.DependencyManager] */ interface GameRepository : VersionProvider { + /** * Does the version of id exist? * @param id the id of version @@ -126,7 +128,8 @@ interface GameRepository : VersionProvider { * Will reconstruct assets or do some blocking tasks if necessary. * You'd better create a new thread to invoke this method. * - * @param assetId the asset id, [AssetIndexInfo.id] [Version.assets] + * @param version the id of specific version that is relevant to [assetId] + * @param assetId the asset id, you can find it in [AssetIndexInfo.id] [Version.actualAssetIndex.id] * @throws java.io.IOException if I/O operation fails. * @return the actual asset directory */ @@ -134,24 +137,31 @@ interface GameRepository : VersionProvider { /** * Get the asset directory according to the asset id. + * + * @param version the id of specific version that is relevant to [assetId] + * @param assetId the asset id, you can find it in [AssetIndexInfo.id] [Version.actualAssetIndex.id] + * @return the asset directory */ fun getAssetDirectory(version: String, assetId: String): File /** * Get the file that given asset object refers to * - * @param assetId the asset id, [AssetIndexInfo.id] [Version.assets] - * @param name the asset object name, [AssetIndex.objects.key] + * @param version the id of specific version that is relevant to [assetId] + * @param assetId the asset id, you can find it in [AssetIndexInfo.id] [Version.actualAssetIndex.id] + * @param name the asset object name, you can find it in [AssetIndex.objects.keys] * @throws java.io.IOException if I/O operation fails. * @return the file that given asset object refers to */ + @Throws(IOException::class) fun getAssetObject(version: String, assetId: String, name: String): File /** * Get the file that given asset object refers to * - * @param assetId the asset id, [AssetIndexInfo.id] [Version.assets] - * @param obj the asset object, [AssetIndex.objects] + * @param version the id of specific version that is relevant to [assetId] + * @param assetId the asset id, you can find it in [AssetIndexInfo.id] [Version.actualAssetIndex.id] + * @param obj the asset object, you can find it in [AssetIndex.objects] * @return the file that given asset object refers to */ fun getAssetObject(version: String, assetId: String, obj: AssetObject): File @@ -159,17 +169,28 @@ interface GameRepository : VersionProvider { /** * Get asset index that assetId represents * - * @param assetId the asset id, [AssetIndexInfo.id] [Version.assets] + * @param version the id of specific version that is relevant to [assetId] + * @param assetId the asset id, you can find it in [AssetIndexInfo.id] [Version.actualAssetIndex.id] * @return the asset index */ fun getAssetIndex(version: String, assetId: String): AssetIndex + /** + * Get the asset_index.json which includes asset objects information. + * + * @param version the id of specific version that is relevant to [assetId] + * @param assetId the asset id, you can find it in [AssetIndexInfo.id] [Version.actualAssetIndex.id] + */ + fun getIndexFile(version: String, assetId: String): File + /** * Get logging object * - * @param assetId the asset id, [AssetIndexInfo.id] [Version.assets] + * @param version the id of specific version that is relevant to [assetId] + * @param assetId the asset id, you can find it in [AssetIndexInfo.id] [Version.assets] * @param loggingInfo the logging info * @return the file that loggingInfo refers to */ fun getLoggingObject(version: String, assetId: String, loggingInfo: LoggingInfo): File + } \ No newline at end of file diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/GameVersion.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/GameVersion.kt index 1ed29157e..4c8b715b3 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/GameVersion.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/GameVersion.kt @@ -19,10 +19,10 @@ package org.jackhuang.hmcl.game import org.jackhuang.hmcl.util.closeQuietly import org.jackhuang.hmcl.util.readFullyAsByteArray +import java.io.File import java.io.IOException import java.util.zip.ZipEntry import java.util.zip.ZipFile -import java.io.File private fun lessThan32(b: ByteArray, startIndex: Int): Int { for (i in startIndex until b.size) diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/LoggingInfo.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/LoggingInfo.kt index 267a51be7..f37e26bf0 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/LoggingInfo.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/LoggingInfo.kt @@ -17,7 +17,6 @@ */ package org.jackhuang.hmcl.game -import com.google.gson.JsonSyntaxException import com.google.gson.annotations.SerializedName import org.jackhuang.hmcl.util.Immutable import org.jackhuang.hmcl.util.Validation diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/VersionProvider.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/VersionProvider.kt index 0351f776d..21a89014b 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/VersionProvider.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/game/VersionProvider.kt @@ -23,6 +23,7 @@ package org.jackhuang.hmcl.game * @see Version.resolve */ interface VersionProvider { + /** * Does the version of id exist? * @param id the id of version @@ -36,4 +37,5 @@ interface VersionProvider { * @return the version you want */ fun getVersion(id: String): Version + } \ No newline at end of file diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/DefaultLauncher.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/DefaultLauncher.kt index b2ba95912..b0e9d42d2 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/DefaultLauncher.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/DefaultLauncher.kt @@ -18,14 +18,16 @@ package org.jackhuang.hmcl.launch import org.jackhuang.hmcl.auth.AuthInfo -import org.jackhuang.hmcl.game.* +import org.jackhuang.hmcl.game.DownloadType +import org.jackhuang.hmcl.game.GameException +import org.jackhuang.hmcl.game.GameRepository +import org.jackhuang.hmcl.game.LaunchOptions import org.jackhuang.hmcl.task.TaskResult import org.jackhuang.hmcl.util.* import java.io.File import java.io.IOException import java.util.* import kotlin.concurrent.thread -import kotlin.coroutines.experimental.EmptyCoroutineContext.plus /** * @param versionId The version to be launched. @@ -220,7 +222,7 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun } } - override fun launch(): JavaProcess { + override fun launch(): ManagedProcess { // To guarantee that when failed to generate code, we will not call precalled command val builder = ProcessBuilder(rawCommandLine) @@ -237,7 +239,7 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun builder.directory(repository.getRunDirectory(version.id)) .environment().put("APPDATA", options.gameDir.absoluteFile.parent) - val p = JavaProcess(builder.start(), rawCommandLine) + val p = ManagedProcess(builder.start(), rawCommandLine) if (listener == null) startMonitors(p) else @@ -245,8 +247,8 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun return p } - fun launchAsync(): TaskResult { - return object : TaskResult() { + fun launchAsync(): TaskResult { + return object : TaskResult() { override val id = LAUNCH_ASYNC_ID override fun execute() { result = launch() @@ -279,20 +281,20 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun return scriptFile } - private fun startMonitors(javaProcess: JavaProcess) { - javaProcess.relatedThreads += thread(name = "stdout-pump", isDaemon = true, block = StreamPump(javaProcess.process.inputStream)::run) - javaProcess.relatedThreads += thread(name = "stderr-pump", isDaemon = true, block = StreamPump(javaProcess.process.errorStream)::run) + private fun startMonitors(managedProcess: ManagedProcess) { + managedProcess.relatedThreads += thread(name = "stdout-pump", isDaemon = true, block = StreamPump(managedProcess.process.inputStream)::run) + managedProcess.relatedThreads += thread(name = "stderr-pump", isDaemon = true, block = StreamPump(managedProcess.process.errorStream)::run) } - private fun startMonitors(javaProcess: JavaProcess, processListener: ProcessListener, isDaemon: Boolean = true) { - processListener.setProcess(javaProcess) - val logHandler = Log4jHandler { line, level -> processListener.onLog(line, level); javaProcess.lines += line }.apply { start() } - javaProcess.relatedThreads += logHandler - val stdout = thread(name = "stdout-pump", isDaemon = isDaemon, block = StreamPump(javaProcess.process.inputStream, { logHandler.newLine(it) } )::run) - javaProcess.relatedThreads += stdout - val stderr = thread(name = "stderr-pump", isDaemon = isDaemon, block = StreamPump(javaProcess.process.errorStream, { processListener.onLog(it + OS.LINE_SEPARATOR, Log4jLevel.ERROR); javaProcess.lines += it })::run) - javaProcess.relatedThreads += stderr - javaProcess.relatedThreads += thread(name = "exit-waiter", isDaemon = isDaemon, block = ExitWaiter(javaProcess, listOf(stdout, stderr), { exitCode, exitType -> logHandler.onStopped(); processListener.onExit(exitCode, exitType) })::run) + private fun startMonitors(managedProcess: ManagedProcess, processListener: ProcessListener, isDaemon: Boolean = true) { + processListener.setProcess(managedProcess) + val logHandler = Log4jHandler { line, level -> processListener.onLog(line, level); managedProcess.lines += line }.apply { start() } + managedProcess.relatedThreads += logHandler + val stdout = thread(name = "stdout-pump", isDaemon = isDaemon, block = StreamPump(managedProcess.process.inputStream, { logHandler.newLine(it) } )::run) + managedProcess.relatedThreads += stdout + val stderr = thread(name = "stderr-pump", isDaemon = isDaemon, block = StreamPump(managedProcess.process.errorStream, { processListener.onLog(it + OS.LINE_SEPARATOR, Log4jLevel.ERROR); managedProcess.lines += it })::run) + managedProcess.relatedThreads += stderr + managedProcess.relatedThreads += thread(name = "exit-waiter", isDaemon = isDaemon, block = ExitWaiter(managedProcess, listOf(stdout, stderr), { exitCode, exitType -> logHandler.onStopped(); processListener.onExit(exitCode, exitType) })::run) } companion object { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/ExitWaiter.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/ExitWaiter.kt index ad8d7ef1d..043f431fe 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/ExitWaiter.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/ExitWaiter.kt @@ -21,16 +21,15 @@ import org.jackhuang.hmcl.event.EVENT_BUS import org.jackhuang.hmcl.event.JVMLaunchFailedEvent import org.jackhuang.hmcl.event.JavaProcessExitedAbnormallyEvent import org.jackhuang.hmcl.event.JavaProcessStoppedEvent -import org.jackhuang.hmcl.util.JavaProcess +import org.jackhuang.hmcl.util.ManagedProcess import org.jackhuang.hmcl.util.containsOne import org.jackhuang.hmcl.util.guessLogLineError -import java.util.* /** * @param process the process to wait for * @param watcher the callback that will be called after process stops. */ -internal class ExitWaiter(val process: JavaProcess, val joins: Collection, val watcher: (Int, ProcessListener.ExitType) -> Unit) : Runnable { +internal class ExitWaiter(val process: ManagedProcess, val joins: Collection, val watcher: (Int, ProcessListener.ExitType) -> Unit) : Runnable { override fun run() { try { process.process.waitFor() diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/Launcher.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/Launcher.kt index 8907219f2..973b67459 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/Launcher.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/Launcher.kt @@ -21,7 +21,7 @@ import org.jackhuang.hmcl.auth.AuthInfo import org.jackhuang.hmcl.game.GameRepository import org.jackhuang.hmcl.game.LaunchOptions import org.jackhuang.hmcl.game.Version -import org.jackhuang.hmcl.util.JavaProcess +import org.jackhuang.hmcl.util.ManagedProcess import java.io.File abstract class Launcher( @@ -34,7 +34,7 @@ abstract class Launcher( val version: Version = repository.getVersion(versionId).resolve(repository) abstract val rawCommandLine: List - abstract fun launch(): JavaProcess + abstract fun launch(): ManagedProcess /** * @param file The file path without extension diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/Log4jHandler.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/Log4jHandler.kt index e506f3ed5..9e2e14d6d 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/Log4jHandler.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/Log4jHandler.kt @@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicBoolean /** * This class is to parse log4j classic XML layout logging, since only vanilla Minecraft will enable this layout. + * Also supports plain logs. */ internal class Log4jHandler(val callback: (String, Log4jLevel) -> Unit) : Thread() { val reader = XMLReaderFactory.createXMLReader().apply { @@ -53,6 +54,9 @@ internal class Log4jHandler(val callback: (String, Log4jLevel) -> Unit) : Thread } } + /** + * Should be called to stop [Log4jHandler] manually. + */ fun onStopped() { if (interrupted.get()) return @@ -66,7 +70,7 @@ internal class Log4jHandler(val callback: (String, Log4jLevel) -> Unit) : Thread } /** - * Should be called in [ProcessListener.onErrorLog] and [ProcessListener.onLog] manually. + * New XML line. */ fun newLine(content: String) = Scheduler.COMPUTATION.schedule { @@ -102,6 +106,7 @@ internal class Log4jHandler(val callback: (String, Log4jLevel) -> Unit) : Thread l = Log4jLevel.ERROR } "log4j_Message" -> readingMessage = true + "log4j_Throwable" -> {} } } diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/ProcessListener.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/ProcessListener.kt index 29a15708d..b31dfd204 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/ProcessListener.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/ProcessListener.kt @@ -17,15 +17,15 @@ */ package org.jackhuang.hmcl.launch -import org.jackhuang.hmcl.util.JavaProcess import org.jackhuang.hmcl.util.Log4jLevel +import org.jackhuang.hmcl.util.ManagedProcess interface ProcessListener { /** * When a game launched, this method will be called to get the new process. * You should not override this method when your ProcessListener is shared with all processes. */ - fun setProcess(process: JavaProcess) {} + fun setProcess(process: ManagedProcess) {} /** * Called when receiving a log from stdout/stderr. diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/StreamPump.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/StreamPump.kt index 6a7f7977e..5f21e21bc 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/StreamPump.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/launch/StreamPump.kt @@ -23,6 +23,12 @@ import java.io.IOException import java.io.InputStream import java.util.logging.Level +/** + * Pump the given input stream. + * @param inputStream the input stream to pump + * @param callback receives each line + * + */ internal class StreamPump @JvmOverloads constructor( private val inputStream: InputStream, private val callback: (String) -> Unit = {} diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/CurseForgeModpack.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/CurseForgeModpack.kt index e09582d00..09fc796f6 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/CurseForgeModpack.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/CurseForgeModpack.kt @@ -99,14 +99,27 @@ class CurseForgeModpackManifestFile ( val url: URL get() = "https://minecraft.curseforge.com/projects/$projectID/files/$fileID/download".toURL() } +/** + * @param f the CurseForge modpack file. + * @return the manifest. + */ fun readCurseForgeModpackManifest(f: File): CurseForgeModpackManifest { ZipFile(f).use { zipFile -> - val entry = zipFile.getEntry("manifest.json") ?: throw IOException("Manifest.json not found. Not a valid CurseForge modpack.") + val entry = zipFile.getEntry("manifest.json") ?: throw IOException("`manifest.json` not found. Not a valid CurseForge modpack.") val json = zipFile.getInputStream(entry).readFullyAsString() - return GSON.fromJson(json) ?: throw JsonParseException("Manifest.json not found. Not a valid CurseForge modpack.") + return GSON.fromJson(json) ?: throw JsonParseException("`manifest.json` not found. Not a valid CurseForge modpack.") } } +/** + * Install a downloaded CurseForge modpack. + * + * @param dependencyManager the dependency manager. + * @param zipFile the CurseForge modpack file. + * @param manifest The manifest content of given CurseForge modpack. + * @param name the new version name + * @see readCurseForgeModpackManifest + */ class CurseForgeModpackInstallTask(private val dependencyManager: DefaultDependencyManager, private val zipFile: File, private val manifest: CurseForgeModpackManifest, private val name: String): Task() { val repository = dependencyManager.repository init { @@ -136,7 +149,8 @@ class CurseForgeModpackInstallTask(private val dependencyManager: DefaultDepende f.fileName = f.url.detectFileName(dependencyManager.proxy) dependencies += FileDownloadTask(f.url, run.resolve("mods").resolve(f.fileName), proxy = dependencyManager.proxy) } catch (e: IOException) { - // ignore it and retry next time. + // Because in China, the CurseForge is too difficult to visit. + // So if failed, ignore it and retry next time. } ++finished updateProgress(1.0 * finished / manifest.files.size) @@ -146,6 +160,12 @@ class CurseForgeModpackInstallTask(private val dependencyManager: DefaultDepende } } +/** + * Complete the CurseForge version. + * + * @param dependencyManager the dependency manager. + * @param version the existent and physical version. + */ class CurseForgeModpackCompletionTask(dependencyManager: DependencyManager, version: String): Task() { val repository = dependencyManager.repository val run = repository.getRunDirectory(version) @@ -161,6 +181,8 @@ class CurseForgeModpackCompletionTask(dependencyManager: DependencyManager, vers else { manifest = GSON.fromJson(repository.getVersionRoot(version).resolve("manifest.json").readText())!! + // Because in China, the CurseForge is too difficult to visit. + // So caching the file name is necessary. for (f in manifest!!.files) { if (f.fileName.isBlank()) dependents += task { f.fileName = f.url.detectFileName(proxy) } diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/ForgeModMetadata.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/ForgeModMetadata.kt index 92347d442..8c93066a0 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/ForgeModMetadata.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/ForgeModMetadata.kt @@ -26,7 +26,7 @@ import org.jackhuang.hmcl.util.typeOf import java.io.File import java.util.zip.ZipFile -class ForgeModMetadata( +class ForgeModMetadata @JvmOverloads internal constructor( @SerializedName("modid") val modId: String = "", val name: String = "", @@ -42,6 +42,9 @@ class ForgeModMetadata( ) { companion object { + /** + * Read Forge mod ModInfo. + */ fun fromFile(modFile: File): ModInfo { ZipFile(modFile).use { val entry = it.getEntry("mcmod.info") ?: throw JsonParseException("File $modFile is not a Forge mod.") diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/LiteModMetadata.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/LiteModMetadata.kt index 03fd49f2d..54af4f0dc 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/LiteModMetadata.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/LiteModMetadata.kt @@ -18,11 +18,13 @@ package org.jackhuang.hmcl.mod import com.google.gson.JsonParseException -import org.jackhuang.hmcl.util.* +import org.jackhuang.hmcl.util.GSON +import org.jackhuang.hmcl.util.fromJson +import org.jackhuang.hmcl.util.readFullyAsString import java.io.File import java.util.zip.ZipFile -class LiteModMetadata ( +class LiteModMetadata @JvmOverloads internal constructor( val name: String = "", val version: String = "", val mcversion: String = "", @@ -37,6 +39,9 @@ class LiteModMetadata ( ) { companion object { + /** + * Read LiteLoader mod ModInfo. + */ fun fromFile(modFile: File): ModInfo { ZipFile(modFile).use { val entry = it.getEntry("litemod.json") diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/ModInfo.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/ModInfo.kt index 1096f3e63..6f8727da4 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/ModInfo.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/ModInfo.kt @@ -17,9 +17,9 @@ */ package org.jackhuang.hmcl.mod -import com.google.gson.JsonParseException -import org.jackhuang.hmcl.util.property.ImmediateBooleanProperty -import org.jackhuang.hmcl.util.* +import org.jackhuang.hmcl.util.ImmediateBooleanProperty +import org.jackhuang.hmcl.util.getValue +import org.jackhuang.hmcl.util.setValue import java.io.File class ModInfo ( diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/Modpack.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/Modpack.kt index d86685ef7..f28badc84 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/Modpack.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/mod/Modpack.kt @@ -17,8 +17,6 @@ */ package org.jackhuang.hmcl.mod -import org.jackhuang.hmcl.download.DefaultDependencyManager -import org.jackhuang.hmcl.task.Task import java.io.File class Modpack(val file: File) { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/CoupleTask.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/CoupleTask.kt index 361d4187a..2e9c2d5a0 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/CoupleTask.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/CoupleTask.kt @@ -19,6 +19,13 @@ package org.jackhuang.hmcl.task import org.jackhuang.hmcl.util.AutoTypingMap +/** + * A task that combines two tasks and make sure [pred] runs before [succ]. + * + * @param pred the task that runs before [succ] + * @param succ a callback that returns the task runs after [pred], [succ] will be executed asynchronously. You can do something that relies on the result of [pred]. + * @param reliant true if this task chain will be broken when task [pred] fails. + */ internal class CoupleTask(pred: P, private val succ: (AutoTypingMap) -> Task?, override val reliant: Boolean) : Task() { override val hidden: Boolean = true 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 4337d8013..7e3413156 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/FileDownloadTask.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/FileDownloadTask.kt @@ -19,28 +19,39 @@ package org.jackhuang.hmcl.task import org.jackhuang.hmcl.event.EventManager import org.jackhuang.hmcl.event.FailedEvent -import org.jackhuang.hmcl.util.LOG -import org.jackhuang.hmcl.util.closeQuietly -import org.jackhuang.hmcl.util.DigestUtils -import org.jackhuang.hmcl.util.makeDirectory -import org.jackhuang.hmcl.util.createConnection +import org.jackhuang.hmcl.util.* import java.io.File import java.io.IOException import java.io.InputStream import java.io.RandomAccessFile +import java.math.BigInteger import java.net.Proxy import java.net.URL -import java.math.BigInteger import java.util.logging.Level +/** + * A task that can download a file online. + * + * @param url the URL of remote file. + * @param file the location that download to. + * @param hash the SHA-1 hash code of remote file, null if the hash is unknown or it is no need to check the hash code. + * @param retry the times for retrying if downloading fails. + * @param proxy the proxy. + * + * @author huangyuhui + */ 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 + /** + * Once downloading fails, this event will be fired to gain the substitute URL. + */ var onFailed = EventManager>() + private var rFile: RandomAccessFile? = null private var stream: InputStream? = null - fun closeFiles() { + private fun closeFiles() { rFile?.closeQuietly() rFile = null stream?.closeQuietly() 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 4eecf5ab4..2e6ce7058 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/GetTask.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/GetTask.kt @@ -25,6 +25,17 @@ import java.net.Proxy import java.net.URL import java.nio.charset.Charset +/** + * A task that can read the content of a remote text file. + * + * @param url the URL of remote text file. + * @param encoding the encoding/charset of the remote text file. + * @param retry the times for retrying if downloading fails. + * @param proxy the proxy. + * @param id the result variable id, see [Task.variables] + * + * @author huangyuhui + */ 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() { override val scheduler: Scheduler = Scheduler.IO @@ -65,6 +76,9 @@ class GetTask @JvmOverloads constructor(val url: URL, val encoding: Charset = Ch } companion object { + /** + * The default task result ID. + */ const val ID = "http_get" } } \ No newline at end of file diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/ParallelTask.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/ParallelTask.kt index 671dd92d2..57237df4d 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/ParallelTask.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/ParallelTask.kt @@ -17,6 +17,11 @@ */ package org.jackhuang.hmcl.task +/** + * The tasks that provides a way to execute tasks parallelly. + * + * @param tasks the tasks that can be executed parallelly. + */ class ParallelTask(vararg tasks: Task): Task() { override val hidden: Boolean = true override val dependents: Collection = listOf(*tasks) 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 03aa809ad..837cb4964 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Scheduler.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Scheduler.kt @@ -17,13 +17,25 @@ */ package org.jackhuang.hmcl.task -import javafx.application.Platform import java.util.concurrent.* import java.util.concurrent.atomic.AtomicReference -import javax.swing.SwingUtilities +/** + * Determines how a task is executed. + * + * @see [Task.scheduler] + */ interface Scheduler { + /** + * Schedules the given task. + * @return the future, null if future is not supported. + */ fun schedule(block: () -> Unit): Future<*>? = schedule(Callable { block() }) + + /** + * Schedules the given task. + * @return the future, null if future is not supported. + */ fun schedule(block: Callable): Future<*>? private class SchedulerImpl(val executor: (Runnable) -> Unit) : Scheduler { @@ -58,7 +70,7 @@ interface Scheduler { } private class SchedulerExecutorService(val executorService: ExecutorService) : Scheduler { - override fun schedule(block: Callable) = executorService.submit(block) + override fun schedule(block: Callable): Future<*> = executorService.submit(block) } companion object Schedulers { @@ -90,13 +102,44 @@ interface Scheduler { return null } } - val JAVAFX: Scheduler = SchedulerImpl(Platform::runLater) - val SWING: Scheduler = SchedulerImpl(SwingUtilities::invokeLater) + + /** + * A scheduler for JavaFX UI operations. + */ + val JAVAFX: Scheduler = SchedulerImpl(javafx.application.Platform::runLater) + + /** + * A scheduler for Swing UI operations. + */ + val SWING: Scheduler = SchedulerImpl(javax.swing.SwingUtilities::invokeLater) + + /** + * A scheduler that always create new threads to execute tasks. + * For tasks that do not do heavy operations. + */ val NEW_THREAD: Scheduler = SchedulerExecutorService(CACHED_EXECUTOR) + + /** + * A scheduler that exclusively executes tasks that do I/O operations. + * The number tasks that do I/O operations in the meantime cannot be larger then 6. + */ val IO: Scheduler = SchedulerExecutorService(IO_EXECUTOR) + + /** + * A scheduler that exclusively executes tasks that do computations. + * The best way to do computations is an event queue. + */ val COMPUTATION: Scheduler = SchedulerExecutorService(SINGLE_EXECUTOR) + + /** + * The default scheduler for tasks to be executed. + * @see [Task.scheduler] + */ val DEFAULT = NEW_THREAD + /** + * Shut down all executor services to guarantee that the application can stop implicitly. + */ fun shutdown() { CACHED_EXECUTOR.shutdown() IO_EXECUTOR.shutdown() diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/SilentException.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/SilentException.kt index 2f1f938da..331457f9e 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/SilentException.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/SilentException.kt @@ -17,8 +17,7 @@ */ package org.jackhuang.hmcl.task -class SilentException : Exception { - constructor() : super() {} - constructor(message: String) : super(message) {} - constructor(message: String, cause: Throwable) : super(message, cause) {} -} \ No newline at end of file +/** + * If a task throws [SilentException], the task will be marked as failure but do not log the stacktrace. + */ +class SilentException : Exception() \ No newline at end of file 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 9fe4a1b68..b41c07445 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Task.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/Task.kt @@ -22,12 +22,15 @@ import javafx.beans.property.ReadOnlyDoubleWrapper import javafx.beans.property.ReadOnlyStringProperty import javafx.beans.property.ReadOnlyStringWrapper import org.jackhuang.hmcl.event.EventManager -import org.jackhuang.hmcl.util.* +import org.jackhuang.hmcl.util.AutoTypingMap +import org.jackhuang.hmcl.util.updateAsync import java.util.concurrent.Callable import java.util.concurrent.atomic.AtomicReference /** * Disposable task. + * + * @see [TaskExecutor] */ abstract class Task { /** diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/TaskExecutor.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/TaskExecutor.kt index 8f5e7eb6b..b3ce3b8a2 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/TaskExecutor.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/TaskExecutor.kt @@ -19,11 +19,13 @@ package org.jackhuang.hmcl.task import org.jackhuang.hmcl.util.AutoTypingMap import org.jackhuang.hmcl.util.LOG -import java.util.concurrent.* +import java.util.concurrent.Callable +import java.util.concurrent.ConcurrentLinkedQueue +import java.util.concurrent.CountDownLatch +import java.util.concurrent.Future import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger import java.util.logging.Level -import kotlin.concurrent.thread class TaskExecutor() { var taskListener: TaskListener? = null diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/TaskResult.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/TaskResult.kt index c4ed957c4..2078f2563 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/TaskResult.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/task/TaskResult.kt @@ -17,6 +17,9 @@ */ package org.jackhuang.hmcl.task +/** + * A task that has a result. + */ abstract class TaskResult : Task() { open var result: V? = null diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Annotation.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Annotation.kt index 4288f42ee..ffe932f8e 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Annotation.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Annotation.kt @@ -17,6 +17,9 @@ */ package org.jackhuang.hmcl.util +/** + * Mark if the model is immutable. + */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.SOURCE) annotation class Immutable \ No newline at end of file diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/AutoTypingMap.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/AutoTypingMap.kt index 04ae0d505..4af694013 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/AutoTypingMap.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/AutoTypingMap.kt @@ -17,6 +17,9 @@ */ package org.jackhuang.hmcl.util +/** + * A map that support auto casting. + */ class AutoTypingMap(private val impl: MutableMap) { fun clear() = impl.clear() diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/FileUtils.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/FileUtils.kt index 381aff2d3..a3f43a6b5 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/FileUtils.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/FileUtils.kt @@ -18,10 +18,6 @@ package org.jackhuang.hmcl.util import java.io.File -import java.io.FileNotFoundException -import java.io.IOException -import java.nio.file.Files -import java.nio.file.StandardCopyOption fun File.makeDirectory(): Boolean = isDirectory || mkdirs() diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Gson.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Gson.kt index b43a8de55..826a5102c 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Gson.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Gson.kt @@ -20,15 +20,12 @@ package org.jackhuang.hmcl.util import com.google.gson.* import com.google.gson.reflect.TypeToken import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonWriter -import java.lang.reflect.Type import com.google.gson.stream.JsonToken -import java.io.IOException -import com.google.gson.TypeAdapter -import com.google.gson.Gson -import com.google.gson.TypeAdapterFactory +import com.google.gson.stream.JsonWriter import org.jackhuang.hmcl.game.Library import java.io.File +import java.io.IOException +import java.lang.reflect.Type import java.text.DateFormat import java.text.ParseException import java.text.SimpleDateFormat diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/IOUtils.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/IOUtils.kt index 1f6fd2d41..281b0e329 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/IOUtils.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/IOUtils.kt @@ -64,6 +64,10 @@ fun InputStream.copyToAndClose(dest: OutputStream) { } } +/** + * @param cmd the command line + * @return the final command line + */ fun makeCommand(cmd: List): String { val cmdbuf = StringBuilder(120) for (i in cmd.indices) { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/property/ImmediateStringProperty.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ImmediateProperties.kt similarity index 99% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/property/ImmediateStringProperty.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ImmediateProperties.kt index 61de32ccc..7d126a681 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/property/ImmediateStringProperty.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ImmediateProperties.kt @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.util.property +package org.jackhuang.hmcl.util import javafx.beans.property.* import javafx.beans.value.ChangeListener 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 1cd24913a..e0bf7e33f 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/JavaVersion.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/JavaVersion.kt @@ -24,12 +24,26 @@ import java.io.Serializable import java.util.* import java.util.regex.Pattern +/** + * Represents a Java installation. + */ data class JavaVersion internal constructor( @SerializedName("location") val binary: File, val longVersion: String, val platform: Platform) : Serializable { + /** + * The major version of Java installation. + * + * @see JAVA_X + * @see JAVA_9 + * @see JAVA_8 + * @see JAVA_7 + * @see JAVA_6 + * @see JAVA_5 + * @see UNKNOWN + */ val version = parseVersion(longVersion) companion object { @@ -110,10 +124,12 @@ data class JavaVersion internal constructor( return path.resolve("java") } - private val currentJava: JavaVersion = JavaVersion( - binary = getJavaFile(File(System.getProperty("java.home"))), - longVersion = System.getProperty("java.version"), - platform = Platform.PLATFORM) + private val currentJava: JavaVersion by lazy { + JavaVersion( + binary = getJavaFile(File(System.getProperty("java.home"))), + longVersion = System.getProperty("java.version"), + platform = Platform.PLATFORM) + } fun fromCurrentEnvironment() = currentJava init { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Lang.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Lang.kt index ba68bbd4d..47ea28928 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Lang.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Lang.kt @@ -18,12 +18,9 @@ package org.jackhuang.hmcl.util import javafx.beans.property.Property -import javafx.beans.value.ObservableValue import java.util.* import java.util.concurrent.atomic.AtomicReference import kotlin.collections.HashMap -import sun.text.normalizer.UTF16.append -import java.lang.reflect.Array.getLength inline fun ignoreException(func: () -> Unit) { try { 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 5dd7a5c11..409ee7024 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Logging.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Logging.kt @@ -18,13 +18,13 @@ @file:JvmName("HMCLog") package org.jackhuang.hmcl.util +import javafx.scene.paint.Color import java.io.ByteArrayOutputStream import java.io.PrintWriter import java.text.SimpleDateFormat import java.util.* import java.util.logging.* import java.util.logging.Formatter -import javafx.scene.paint.Color import java.util.regex.Pattern val LOG = Logger.getLogger("HMCL").apply { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/JavaProcess.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ManagedProcess.kt similarity index 61% rename from HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/JavaProcess.kt rename to HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ManagedProcess.kt index 1349839c5..7afef7570 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/JavaProcess.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ManagedProcess.kt @@ -20,25 +20,58 @@ package org.jackhuang.hmcl.util import java.util.* import java.util.concurrent.ConcurrentLinkedQueue -class JavaProcess( +/** + * The managed process. + * + * @param process the raw system process that this instance manages. + * @param commands the command line of [process]. + * @see [org.jackhuang.hmcl.launch.ExitWaiter] + * @see [org.jackhuang.hmcl.launch.StreamPump] + */ +class ManagedProcess( val process: Process, val commands: List ) { + /** + * To save some information you need. + */ val properties = mutableMapOf() + + /** + * The standard output/error lines. + */ val lines: Queue = ConcurrentLinkedQueue() + + /** + * The related threads. + * + * If a thread is monitoring this raw process, + * you are required to add the instance to [relatedThreads]. + */ val relatedThreads = mutableListOf() + + /** + * True if the managed process is running. + */ val isRunning: Boolean = try { process.exitValue() true } catch (ex: IllegalThreadStateException) { false } + + /** + * The exit code of raw process. + */ val exitCode: Int get() = process.exitValue() - override fun toString() = "JavaProcess[commands=$commands, isRunning=$isRunning]" - + /** + * Destroys the raw process and other related threads that are monitoring this raw process. + */ fun stop() { process.destroy() relatedThreads.forEach(Thread::interrupt) } + + override fun toString() = "ManagedProcess[commands=$commands, isRunning=$isRunning]" } \ No newline at end of file diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/NetUtils.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/NetUtils.kt index 29fd7bd19..cd4258803 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/NetUtils.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/NetUtils.kt @@ -19,20 +19,19 @@ package org.jackhuang.hmcl.util import java.io.IOException import java.io.InputStream +import java.io.OutputStream import java.net.HttpURLConnection import java.net.Proxy import java.net.URL import java.security.GeneralSecurityException import java.security.SecureRandom import java.security.cert.X509Certificate +import java.util.* +import java.util.logging.Level import javax.net.ssl.HostnameVerifier import javax.net.ssl.HttpsURLConnection import javax.net.ssl.SSLContext import javax.net.ssl.X509TrustManager -import java.io.OutputStream -import java.util.* -import java.util.logging.Level -import kotlin.text.Charsets private val XTM = object : X509TrustManager { override fun checkClientTrusted(chain: Array, authType: String) {} diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/OS.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/OS.kt index 446260fc6..00d98b9ac 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/OS.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/OS.kt @@ -25,17 +25,31 @@ import java.lang.management.ManagementFactory import java.nio.charset.Charset import java.util.* +/** + * Represents the operating system. + */ enum class OS { - @SerializedName("windows") + /** + * Microsoft Windows. + */ WINDOWS, - @SerializedName("linux") + /** + * Linux and Unix like OS, including Solaris. + */ LINUX, - @SerializedName("osx") + /** + * Mac OS X. + */ OSX, - @SerializedName("unknown") + /** + * Unknown operating system. + */ UNKNOWN; companion object { + /** + * The current operating system. + */ val CURRENT_OS: OS by lazy { System.getProperty("os.name").toLowerCase(Locale.US).run { when { @@ -47,12 +61,18 @@ enum class OS { } } - val TOTAL_MEMORY: Long by lazy { + /** + * The total memory/MB this computer have. + */ + val TOTAL_MEMORY: Int by lazy { val bytes = ReflectionHelper.invoke(ManagementFactory.getOperatingSystemMXBean(), "getTotalPhysicalMemorySize") if (bytes == null) 1024 - else bytes / 1024 / 1024 + else (bytes / 1024 / 1024).toInt() } + /** + * The suggested memory size/MB for Minecraft to allocate. + */ val SUGGESTED_MEMORY: Int by lazy { val memory = TOTAL_MEMORY / 4 (Math.round(1.0 * memory / 128.0) * 128).toInt() @@ -61,13 +81,27 @@ enum class OS { val PATH_SEPARATOR: String = File.pathSeparator val FILE_SEPARATOR: String = File.separator val LINE_SEPARATOR: String by lazy(System::lineSeparator) + + /** + * The system default encoding. + */ val ENCODING: String by lazy { System.getProperty("sun.jnu.encoding", Charset.defaultCharset().name()) } + /** + * The version of current operating system. + */ val SYSTEM_VERSION: String by lazy { System.getProperty("os.version") } + + /** + * The arch of current operating system. + */ val SYSTEM_ARCH: String by lazy { System.getProperty("os.arch") } + /** + * Set the content of clipboard. + */ fun setClipboard(string: String) { val clipboard = Clipboard.getSystemClipboard() clipboard.setContent(ClipboardContent().apply { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Platform.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Platform.kt index 44f64391b..b36fda8db 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Platform.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Platform.kt @@ -20,11 +20,18 @@ package org.jackhuang.hmcl.util import com.google.gson.* import java.lang.reflect.Type +/** + * The platform that indicates which the platform of operating system is, 64-bit or 32-bit. + * Of course, 128-bit and 16-bit is not supported. + */ enum class Platform(val bit: String) { BIT_32("32"), BIT_64("64"), UNKNOWN("unknown"); + /** + * The json serializer to [Platform] + */ companion object Serializer: JsonSerializer, JsonDeserializer { override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): Platform? { @@ -45,10 +52,16 @@ enum class Platform(val bit: String) { } } + /** + * The platform of current Java Environment. + */ val PLATFORM: Platform by lazy { if (IS_64_BIT) BIT_64 else BIT_32 } + /** + * True if current Java Environment is 64-bit. + */ val IS_64_BIT: Boolean by lazy { val arch = System.getProperty("sun.arch.data.model") ?: System.getProperty("os.arch") arch.contains("64") diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/RandomUserAgent.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/RandomUserAgent.kt index 82e3f1182..bc4377ae7 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/RandomUserAgent.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/RandomUserAgent.kt @@ -17,7 +17,7 @@ */ package org.jackhuang.hmcl.util -import java.util.HashMap +import java.util.* object RandomUserAgent { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ReflectionHelper.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ReflectionHelper.kt index 09f3937c3..57148d25e 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ReflectionHelper.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ReflectionHelper.kt @@ -17,11 +17,11 @@ */ package org.jackhuang.hmcl.util -import java.lang.reflect.AccessibleObject import sun.misc.Unsafe +import java.lang.reflect.AccessibleObject import java.lang.reflect.Method -import java.security.PrivilegedExceptionAction import java.security.AccessController +import java.security.PrivilegedExceptionAction object ReflectionHelper { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/SimpleMultimap.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/SimpleMultimap.kt index 51dc7bc26..73506a046 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/SimpleMultimap.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/SimpleMultimap.kt @@ -19,6 +19,10 @@ package org.jackhuang.hmcl.util import java.util.* +/** + * A simple implementation of Multimap. + * Just a combination of map and set. + */ class SimpleMultimap(val maper: () -> MutableMap>, val valuer: () -> MutableCollection) { private val map = HashMap>() private val valuesImpl: MutableCollection = valuer() diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/VersionNumber.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/VersionNumber.kt index a85704ecb..8aa1d5f43 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/VersionNumber.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/VersionNumber.kt @@ -19,6 +19,9 @@ package org.jackhuang.hmcl.util import java.util.* +/** + * The formatted version number represents a version string. + */ abstract class VersionNumber: Comparable { companion object { @JvmStatic @@ -47,6 +50,9 @@ abstract class VersionNumber: Comparable { } } +/** + * If a version string contains alphabets, a [StringVersionNumber] will be constructed. + */ class StringVersionNumber internal constructor(val version: String): VersionNumber() { override fun compareTo(other: VersionNumber): Int { if (other !is StringVersionNumber) return 0 @@ -64,6 +70,9 @@ class StringVersionNumber internal constructor(val version: String): VersionNumb } } +/** + * If a version string formats x.x.x.x, a [IntVersionNumber] will be generated. + */ class IntVersionNumber internal constructor(val version: List): VersionNumber() { override fun compareTo(other: VersionNumber): Int { diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ZipUtils.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ZipUtils.kt index 1c44323f7..4a848b6ab 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ZipUtils.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/ZipUtils.kt @@ -17,24 +17,19 @@ */ package org.jackhuang.hmcl.util -import java.util.zip.ZipEntry import java.io.File import java.io.IOException -import java.util.zip.ZipOutputStream +import java.util.zip.ZipEntry import java.util.zip.ZipInputStream +import java.util.zip.ZipOutputStream /** - * 功能:把 src 目录下的所有文件进行 zip 格式的压缩,保存为指定 zip 文件 - - * @param src 源文件夹 - * * - * @param destZip 压缩生成的zip文件路径。 - * * - * @param pathNameCallback callback(pathName, isDirectory) returns your - * * modified pathName - * * - * * - * @throws java.io.IOException 压缩失败或无法读取 + * Compress the given directory to a zip file. + * + * @param src the source directory or a file. + * @param destZip the location of dest zip file. + * @param pathNameCallback callback(pathName, isDirectory) returns your modified pathName + * @throws IOException */ @JvmOverloads @Throws(IOException::class) @@ -53,14 +48,11 @@ fun zip(src: File, destZip: File, pathNameCallback: ((String, Boolean) -> String /** * Zip file. - - * @param src 源文件夹 - * @param basePath file directory that will be compressed - * * - * @param zos zip文件的os - * * - * @param pathNameCallback callback(pathName, isDirectory) returns your - * * modified pathName, null if you dont want this file zipped + * @param src source directory to be compressed. + * @param basePath the file directory to be compressed, if [src] is a file, this is the parent directory of [src] + * @param zos the [ZipOutputStream] of dest zip file. + * @param pathNameCallback callback(pathName, isDirectory) returns your modified pathName, null if you dont want this file zipped + * @throws IOException */ @Throws(IOException::class) private fun zipFile(src: File, @@ -98,17 +90,11 @@ private fun zipFile(src: File, } /** - * 将文件压缩成zip文件 - - * @param zip zip文件路径 - * * - * @param dest 待压缩文件根目录 - * * - * @param callback will be called for every entry in the zip file, - * * returns false if you dont want this file unzipped. - * * - * * - * @throws java.io.IOException 解压失败或无法写入 + * Decompress the given zip file to a directory. + * @param zip the source zip file. + * @param dest the dest directory. + * @param callback will be called for every entry in the zip file, returns false if you dont want this file unzipped. + * @throws IOException */ @JvmOverloads @Throws(IOException::class) @@ -158,21 +144,16 @@ fun unzip(zip: File, dest: File, callback: ((String) -> Boolean)? = null, ignore } /** - * 将文件压缩成zip文件 - - * @param zip zip文件路径 - * * - * @param dest 待压缩文件根目录 - * * - * @param callback will be called for every entry in the zip file, - * * returns false if you dont want this file unzipped. - * * - * * - * @throws java.io.IOException 解压失败或无法写入 + * Decompress the subdirectory of given zip file. + * @param zip the source zip file. + * @param dest the dest directory. + * @param subDirectory the subdirectory of the zip file to be decompressed. + * @param ignoreExistentFile true if skip all existent files. + * @throws IOException */ @JvmOverloads @Throws(IOException::class) -fun unzipSubDirectory(zip: File, dest: File, subDirectory: String, ignoreExistsFile: Boolean = true) { +fun unzipSubDirectory(zip: File, dest: File, subDirectory: String, ignoreExistentFile: Boolean = true) { val buf = ByteArray(1024) dest.mkdirs() ZipInputStream(zip.inputStream()).use { zipFile -> @@ -204,7 +185,7 @@ fun unzipSubDirectory(zip: File, dest: File, subDirectory: String, ignoreExistsF if (!subdir.exists()) subdir.mkdir() } - if (ignoreExistsFile && File(strtemp).exists()) + if (ignoreExistentFile && File(strtemp).exists()) continue File(strtemp).outputStream().use({ fos -> zipFile.copyTo(fos, buf) diff --git a/HMCLCore/src/test/java/org/jackhuang/hmcl/Test.kt b/HMCLCore/src/test/java/org/jackhuang/hmcl/Test.kt index 408b4e9ff..2a2456d37 100644 --- a/HMCLCore/src/test/java/org/jackhuang/hmcl/Test.kt +++ b/HMCLCore/src/test/java/org/jackhuang/hmcl/Test.kt @@ -19,7 +19,7 @@ package org.jackhuang.hmcl import org.jackhuang.hmcl.auth.OfflineAccount import org.jackhuang.hmcl.download.DefaultDependencyManager -import org.jackhuang.hmcl.download.LiteLoaderVersionList +import org.jackhuang.hmcl.download.liteloader.LiteLoaderVersionList import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider import org.jackhuang.hmcl.download.MojangDownloadProvider import org.jackhuang.hmcl.game.DefaultGameRepository @@ -30,9 +30,6 @@ import org.jackhuang.hmcl.launch.ProcessListener import org.jackhuang.hmcl.util.makeCommand import org.jackhuang.hmcl.task.Task import org.jackhuang.hmcl.task.TaskListener -import org.jackhuang.hmcl.util.detectFileName -import org.jackhuang.hmcl.util.toURL -import org.junit.Test import java.io.File import java.net.InetSocketAddress import java.net.Proxy