Try to asynchronize some time-costly tasks

This commit is contained in:
huangyuhui 2017-08-26 10:53:05 +08:00
parent 008f07cacc
commit c775e8368e
12 changed files with 82 additions and 70 deletions

View File

@ -42,15 +42,19 @@ fun i18n(key: String): String {
class Main : Application() { class Main : Application() {
override fun start(stage: Stage) { override fun start(stage: Stage) {
println(System.currentTimeMillis())
// When launcher visibility is set to "hide and reopen" without [Platform.implicitExit] = false, // When launcher visibility is set to "hide and reopen" without [Platform.implicitExit] = false,
// Stage.show() cannot work again because JavaFX Toolkit have already shut down. // Stage.show() cannot work again because JavaFX Toolkit have already shut down.
Platform.setImplicitExit(false) Platform.setImplicitExit(false)
Controllers.initialize(stage) Controllers.initialize(stage)
println("Showing stage: " + System.currentTimeMillis())
stage.isResizable = false stage.isResizable = false
stage.scene = Controllers.scene stage.scene = Controllers.scene
stage.show() stage.show()
println("Showed stage: " + System.currentTimeMillis())
} }
companion object { companion object {

View File

@ -23,6 +23,7 @@ import org.jackhuang.hmcl.setting.EnumGameDirectory
import org.jackhuang.hmcl.setting.Profile import org.jackhuang.hmcl.setting.Profile
import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.setting.Settings
import org.jackhuang.hmcl.setting.VersionSetting import org.jackhuang.hmcl.setting.VersionSetting
import org.jackhuang.hmcl.task.Scheduler
import org.jackhuang.hmcl.util.LOG import org.jackhuang.hmcl.util.LOG
import org.jackhuang.hmcl.util.fromJson import org.jackhuang.hmcl.util.fromJson
import java.io.File import java.io.File
@ -68,30 +69,29 @@ class HMCLGameRepository(val profile: Profile, baseDirectory: File)
return File(Settings.commonPath).resolve("libraries/${lib.path}") return File(Settings.commonPath).resolve("libraries/${lib.path}")
} }
@Synchronized
override fun refreshVersionsImpl() { override fun refreshVersionsImpl() {
versionSettings.clear() Scheduler.NEW_THREAD.schedule {
versionSettings.clear()
super.refreshVersionsImpl() super.refreshVersionsImpl()
versions.keys.forEach(this::loadVersionSetting) versions.keys.forEach(this::loadVersionSetting)
checkModpack() checkModpack()
try { try {
val file = baseDirectory.resolve("launcher_profiles.json") val file = baseDirectory.resolve("launcher_profiles.json")
if (!file.exists() && versions.isNotEmpty()) if (!file.exists() && versions.isNotEmpty())
file.writeText(PROFILE) file.writeText(PROFILE)
} catch (ex: IOException) { } catch (ex: IOException) {
LOG.log(Level.WARNING, "Unable to create launcher_profiles.json, Forge/LiteLoader installer will not work.", ex) LOG.log(Level.WARNING, "Unable to create launcher_profiles.json, Forge/LiteLoader installer will not work.", ex)
}
} }
} }
fun changeDirectory(newDir: File) { fun changeDirectory(newDir: File) {
baseDirectory = newDir baseDirectory = newDir
refreshVersions() refreshVersions()
} }

View File

@ -47,11 +47,7 @@ class Profile(name: String = "Default", initialGameDir: File = File(".minecraft"
var modManager = ModManager(repository) var modManager = ModManager(repository)
init { init {
gameDirProperty.onChange { newGameDir -> gameDirProperty.onChange { repository.changeDirectory(it!!) }
repository.baseDirectory = newGameDir!!
repository.refreshVersions()
}
selectedVersionProperty.addListener { _ -> verifySelectedVersion() } selectedVersionProperty.addListener { _ -> verifySelectedVersion() }
EVENT_BUS.channel<RefreshedVersionsEvent>() += { event -> if (event.source == repository) verifySelectedVersion() } EVENT_BUS.channel<RefreshedVersionsEvent>() += { event -> if (event.source == repository) verifySelectedVersion() }
} }

View File

@ -191,7 +191,7 @@ class VersionSetting() {
return null // Custom Java Directory not found, return null // Custom Java Directory not found,
} }
} else if (java.isNotBlank()) { } else if (java.isNotBlank()) {
val c = JavaVersion.JAVAS[java] val c = JavaVersion.getJREs()[java]
if (c == null) { if (c == null) {
java = "Default" java = "Default"
return JavaVersion.fromCurrentEnvironment() return JavaVersion.fromCurrentEnvironment()

View File

@ -25,14 +25,16 @@ import javafx.scene.layout.Region
import javafx.stage.Stage import javafx.stage.Stage
import org.jackhuang.hmcl.Main import org.jackhuang.hmcl.Main
import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.setting.Settings
import org.jackhuang.hmcl.task.task
import org.jackhuang.hmcl.util.JavaVersion
object Controllers { object Controllers {
lateinit var scene: Scene private set lateinit var scene: Scene private set
lateinit var stage: Stage private set lateinit var stage: Stage private set
val mainPane = MainPage() val mainPane = MainPage()
val settingsPane = SettingsPage() val settingsPane by lazy { SettingsPage() }
val versionPane = VersionPage() val versionPane by lazy { VersionPage() }
lateinit var leftPaneController: LeftPaneController lateinit var leftPaneController: LeftPaneController
@ -46,6 +48,7 @@ object Controllers {
leftPaneController = LeftPaneController(decorator.leftPane) leftPaneController = LeftPaneController(decorator.leftPane)
Settings.onProfileLoading() Settings.onProfileLoading()
task { JavaVersion.initialize() }.start()
decorator.isCustomMaximize = false decorator.isCustomMaximize = false

View File

@ -17,21 +17,38 @@
*/ */
package org.jackhuang.hmcl.ui package org.jackhuang.hmcl.ui
import com.jfoenix.controls.JFXButton
import com.jfoenix.controls.JFXCheckBox import com.jfoenix.controls.JFXCheckBox
import com.jfoenix.effects.JFXDepthManager import com.jfoenix.effects.JFXDepthManager
import javafx.fxml.FXML import javafx.geometry.Pos
import javafx.scene.control.Label import javafx.scene.control.Label
import javafx.scene.layout.BorderPane import javafx.scene.layout.BorderPane
import javafx.scene.layout.VBox
import org.jackhuang.hmcl.mod.ModInfo import org.jackhuang.hmcl.mod.ModInfo
import org.jackhuang.hmcl.util.onChange import org.jackhuang.hmcl.util.onChange
class ModItem(info: ModInfo, private val deleteCallback: (ModItem) -> Unit) : BorderPane() { class ModItem(info: ModInfo, private val deleteCallback: (ModItem) -> Unit) : BorderPane() {
@FXML lateinit var lblModFileName: Label val lblModFileName = Label().apply { style = "-fx-font-size: 15;" }
@FXML lateinit var lblModAuthor: Label val lblModAuthor = Label().apply { style = "-fx-font-size: 10;" }
@FXML lateinit var chkEnabled: JFXCheckBox val chkEnabled = JFXCheckBox().apply { BorderPane.setAlignment(this, Pos.CENTER) }
init { init {
loadFXML("/assets/fxml/version/mod-item.fxml") left = chkEnabled
center = VBox().apply {
BorderPane.setAlignment(this, Pos.CENTER)
children += lblModFileName
children += lblModAuthor
}
right = JFXButton().apply {
setOnMouseClicked { onDelete() }
styleClass += "toggle-icon4"
BorderPane.setAlignment(this, Pos.CENTER)
graphic = SVG.close("black", 15.0, 15.0)
}
style = "-fx-background-radius: 2; -fx-background-color: white; -fx-padding: 8;" style = "-fx-background-radius: 2; -fx-background-color: white; -fx-padding: 8;"
JFXDepthManager.setDepth(this, 1) JFXDepthManager.setDepth(this, 1)

View File

@ -20,6 +20,7 @@ package org.jackhuang.hmcl.ui
import com.jfoenix.controls.* import com.jfoenix.controls.*
import javafx.beans.value.ChangeListener import javafx.beans.value.ChangeListener
import javafx.fxml.FXML import javafx.fxml.FXML
import javafx.scene.Node
import javafx.scene.control.Label import javafx.scene.control.Label
import javafx.scene.control.ScrollPane import javafx.scene.control.ScrollPane
import javafx.scene.control.Toggle import javafx.scene.control.Toggle
@ -106,16 +107,22 @@ class VersionSettingsController {
txtMetaspace.setValidators(validator(true)) txtMetaspace.setValidators(validator(true))
txtMetaspace.setValidateWhileTextChanged() txtMetaspace.setValidateWhileTextChanged()
javaPane.children.clear()
javaPane.children += createJavaPane(JavaVersion.fromCurrentEnvironment(), javaGroup)
JavaVersion.JAVAS.values.forEach { javaVersion ->
javaPane.children += createJavaPane(javaVersion, javaGroup)
}
javaPane.children += javaPaneCustom
javaPaneCustom.limitHeight(20.0) javaPaneCustom.limitHeight(20.0)
radioCustom.toggleGroup = javaGroup radioCustom.toggleGroup = javaGroup
txtJavaDir.disableProperty().bind(radioCustom.selectedProperty().not()) txtJavaDir.disableProperty().bind(radioCustom.selectedProperty().not())
btnJavaSelect.disableProperty().bind(radioCustom.selectedProperty().not()) btnJavaSelect.disableProperty().bind(radioCustom.selectedProperty().not())
task {
val list = mutableListOf<Node>()
list += createJavaPane(JavaVersion.fromCurrentEnvironment(), javaGroup)
JavaVersion.getJREs().values.forEach { javaVersion ->
list += createJavaPane(javaVersion, javaGroup)
}
list += javaPaneCustom
it["list"] = list
}.subscribe(Scheduler.JAVAFX) {
javaPane.children.setAll(it.get<List<Node>>("list"))
}
} }
private fun createJavaPane(java: JavaVersion, group: ToggleGroup): Pane { private fun createJavaPane(java: JavaVersion, group: ToggleGroup): Pane {

View File

@ -35,7 +35,7 @@ class InstallWizardProvider(val profile: Profile, val gameVersion: String, val v
if (settings.containsKey("optifine")) if (settings.containsKey("optifine"))
ret = ret with profile.dependency.installLibraryAsync(gameVersion, version, "optifine", settings["optifine"] as String) ret = ret with profile.dependency.installLibraryAsync(gameVersion, version, "optifine", settings["optifine"] as String)
return ret with task(Scheduler.JAVAFX) { profile.repository.refreshVersions() } return ret with task { profile.repository.refreshVersions() }
} }
override fun createPage(controller: WizardController, step: Int, settings: MutableMap<String, Any>): Node { override fun createPage(controller: WizardController, step: Int, settings: MutableMap<String, Any>): Node {

View File

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

View File

@ -12,7 +12,7 @@
<JFXSpinner style="-fx-radius:16" styleClass="materialDesign-purple, first-spinner" /> <JFXSpinner style="-fx-radius:16" styleClass="materialDesign-purple, first-spinner" />
<StackPane fx:id="contentPane"> <StackPane fx:id="contentPane">
<ScrollPane fx:id="scrollPane" fitToWidth="true" fitToHeight="true"> <ScrollPane fx:id="scrollPane" fitToWidth="true" fitToHeight="true">
<VBox fx:id="modPane" spacing="10" style="-fx-padding: 20;"> <VBox fx:id="modPane" spacing="10" style="-fx-padding: 20 20 70 20;">
</VBox> </VBox>
</ScrollPane> </ScrollPane>

View File

@ -140,7 +140,6 @@ open class DefaultGameRepository(var baseDirectory: File): GameRepository {
isLoaded = true isLoaded = true
} }
@Synchronized
final override fun refreshVersions() { final override fun refreshVersions() {
EVENT_BUS.fireEvent(RefreshingVersionsEvent(this)) EVENT_BUS.fireEvent(RefreshingVersionsEvent(this))
refreshVersionsImpl() refreshVersionsImpl()

View File

@ -18,10 +18,12 @@
package org.jackhuang.hmcl.util package org.jackhuang.hmcl.util
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import org.jackhuang.hmcl.game.Version
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.io.Serializable import java.io.Serializable
import java.util.* import java.util.*
import java.util.concurrent.CountDownLatch
import java.util.regex.Pattern import java.util.regex.Pattern
/** /**
@ -49,8 +51,6 @@ data class JavaVersion internal constructor(
companion object { companion object {
private val regex = Pattern.compile("java version \"(?<version>[1-9]*\\.[1-9]*\\.[0-9]*(.*?))\"") private val regex = Pattern.compile("java version \"(?<version>[1-9]*\\.[1-9]*\\.[0-9]*(.*?))\"")
val JAVAS: Map<String, JavaVersion>
val UNKNOWN: Int = -1 val UNKNOWN: Int = -1
val JAVA_5: Int = 50 val JAVA_5: Int = 50
val JAVA_6: Int = 60 val JAVA_6: Int = 60
@ -132,7 +132,22 @@ data class JavaVersion internal constructor(
} }
fun fromCurrentEnvironment() = currentJava fun fromCurrentEnvironment() = currentJava
init { private var javas: Map<String, JavaVersion>? = null
private val await = CountDownLatch(1)
/**
* This method will block until [initialize] succeeds.
*/
fun getJREs(): Map<String, JavaVersion> {
if (javas != null) return javas!!
await.await()
return javas!!
}
@Synchronized
fun initialize() {
if (javas != null)
throw IllegalStateException("JavaVersions have already been initialized.")
val temp = mutableMapOf<String, JavaVersion>() val temp = mutableMapOf<String, JavaVersion>()
(when (OS.CURRENT_OS) { (when (OS.CURRENT_OS) {
OS.WINDOWS -> queryWindows() OS.WINDOWS -> queryWindows()
@ -141,7 +156,8 @@ data class JavaVersion internal constructor(
}).forEach { javaVersion -> }).forEach { javaVersion ->
temp.put(javaVersion.longVersion, javaVersion) temp.put(javaVersion.longVersion, javaVersion)
} }
JAVAS = temp javas = temp
await.countDown()
} }
private fun queryMacintosh() = LinkedList<JavaVersion>().apply { private fun queryMacintosh() = LinkedList<JavaVersion>().apply {