Launching progress

This commit is contained in:
huangyuhui
2017-08-19 21:51:46 +08:00
parent 27939c6b61
commit 383453f9af
28 changed files with 413 additions and 185 deletions

View File

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

View File

@@ -28,53 +28,48 @@ class DefaultGameBuilder(val dependencyManager: DefaultDependencyManager): GameB
override fun buildAsync(): Task {
val gameVersion = gameVersion
return VersionJSONDownloadTask(gameVersion = gameVersion) then a@{ task ->
var version = GSON.fromJson<Version>(task.result!!) ?: return@a null
version = version.copy(id = name, jar = null)
var result = ParallelTask(
GameAssetDownloadTask(dependencyManager, version),
GameLoggingDownloadTask(dependencyManager, version),
GameDownloadTask(version),
GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
) then VersionJSONSaveTask(dependencyManager, version)
return VersionJSONDownloadTask(gameVersion, dependencyManager, "raw_version_json")
.then {
var version = GSON.fromJson<Version>(it["raw_version_json"])!!
it["version"] = version
version = version.copy(id = name, jar = null)
var result = ParallelTask(
GameAssetDownloadTask(dependencyManager, version),
GameLoggingDownloadTask(dependencyManager, version),
GameDownloadTask(version),
GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
) then VersionJSONSaveTask(dependencyManager, version)
if (toolVersions.containsKey("forge"))
result = result then libraryTaskHelper(gameVersion, version, "forge")
if (toolVersions.containsKey("liteloader"))
result = result then libraryTaskHelper(gameVersion, version, "liteloader")
if (toolVersions.containsKey("optifine"))
result = result then libraryTaskHelper(gameVersion, version, "optifine")
result
}
if (toolVersions.containsKey("forge"))
result = result then libraryTaskHelper(gameVersion, "forge")
if (toolVersions.containsKey("liteloader"))
result = result then libraryTaskHelper(gameVersion, "liteloader")
if (toolVersions.containsKey("optifine"))
result = result then libraryTaskHelper(gameVersion, "optifine")
result
}
}
private fun libraryTaskHelper(gameVersion: String, version: Version, libraryId: String): Task.(Task) -> Task = { prev ->
var thisVersion = version
if (prev is TaskResult<*> && prev.result is Version) {
thisVersion = prev.result as Version
}
dependencyManager.installLibraryAsync(gameVersion, thisVersion, libraryId, toolVersions[libraryId]!!)
private fun libraryTaskHelper(gameVersion: String, libraryId: String): (AutoTypingMap<String>) -> Task = {
dependencyManager.installLibraryAsync(gameVersion, it["version"], libraryId, toolVersions[libraryId]!!)
}
inner class VersionJSONDownloadTask(val gameVersion: String): Task() {
private class VersionJSONDownloadTask(val gameVersion: String, val dependencyManager: DefaultDependencyManager, val id: String): Task() {
override val dependents: MutableCollection<Task> = LinkedList()
override val dependencies: MutableCollection<Task> = LinkedList()
var httpTask: GetTask? = null
val result: String? get() = httpTask?.result
val gameVersionList: VersionList<*> = dependencyManager.getVersionList("game")
private val gameVersionList: VersionList<*> = dependencyManager.getVersionList("game")
init {
if (!gameVersionList.loaded)
dependents += gameVersionList.refreshAsync(downloadProvider)
dependents += gameVersionList.refreshAsync(dependencyManager.downloadProvider)
}
override fun execute() {
val remoteVersion = gameVersionList.getVersions(gameVersion).firstOrNull()
?: throw Error("Cannot find specific version $gameVersion in remote repository")
val jsonURL = downloadProvider.injectURL(remoteVersion.url)
httpTask = GetTask(jsonURL.toURL(), proxy = dependencyManager.proxy)
dependencies += httpTask!!
val jsonURL = dependencyManager.downloadProvider.injectURL(remoteVersion.url)
dependencies += GetTask(jsonURL.toURL(), proxy = dependencyManager.proxy, id = id)
}
}

View File

@@ -38,11 +38,11 @@ class ForgeInstallTask(private val dependencyManager: DefaultDependencyManager,
lateinit var remote: RemoteVersion<*>
override val dependents = mutableListOf<Task>()
override val dependencies = mutableListOf<Task>()
override val id = ID
override val id = "version"
init {
if (!forgeVersionList.loaded)
dependents += forgeVersionList.refreshAsync(dependencyManager.downloadProvider) then {
dependents += forgeVersionList.refreshAsync(dependencyManager.downloadProvider).then {
remote = forgeVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote forge version $gameVersion, $remoteVersion not found")
FileDownloadTask(remote.url.toURL(), installer)
}
@@ -76,8 +76,4 @@ class ForgeInstallTask(private val dependencyManager: DefaultDependencyManager,
check(installer.delete(), { "Unable to delete installer file $installer" })
}
companion object {
const val ID = "forge_install_task"
}
}

View File

@@ -37,11 +37,11 @@ class LiteLoaderInstallTask(private val dependencyManager: DefaultDependencyMana
lateinit var remote: RemoteVersion<LiteLoaderRemoteVersionTag>
override val dependents = mutableListOf<Task>()
override val dependencies = mutableListOf<Task>()
override val id = ID
override val id = "version"
init {
if (!liteLoaderVersionList.loaded)
dependents += LiteLoaderVersionList.refreshAsync(dependencyManager.downloadProvider) then {
dependents += LiteLoaderVersionList.refreshAsync(dependencyManager.downloadProvider).then {
remote = liteLoaderVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote LiteLoader version $gameVersion, $remoteVersion not found")
null
}
@@ -70,8 +70,4 @@ class LiteLoaderInstallTask(private val dependencyManager: DefaultDependencyMana
)
dependencies += GameLibrariesTask(dependencyManager, tempVersion)
}
companion object {
const val ID = "lite_loader_install_task"
}
}

View File

@@ -34,7 +34,7 @@ class OptiFineInstallTask(private val dependencyManager: DefaultDependencyManage
lateinit var remote: RemoteVersion<*>
override val dependents = mutableListOf<Task>()
override val dependencies = mutableListOf<Task>()
override val id = ID
override val id = "version"
init {
if (!optiFineVersionList.loaded)
@@ -75,8 +75,4 @@ class OptiFineInstallTask(private val dependencyManager: DefaultDependencyManage
result = version.copy(libraries = merge(version.libraries, libraries), mainClass = mainClass, minecraftArguments = arg)
dependencies += GameLibrariesTask(dependencyManager, version.copy(libraries = libraries))
}
companion object {
const val ID = "optifine_install_task"
}
}

View File

@@ -17,14 +17,16 @@
*/
package org.jackhuang.hmcl.task
internal class CoupleTask<P: Task>(private val pred: P, private val succ: Task.(P) -> Task?, override val reliant: Boolean) : Task() {
import org.jackhuang.hmcl.util.AutoTypingMap
internal class CoupleTask<P: Task>(pred: P, private val succ: (AutoTypingMap<String>) -> Task?, override val reliant: Boolean) : Task() {
override val hidden: Boolean = true
override val dependents: Collection<Task> = listOf(pred)
override val dependencies: MutableCollection<Task> = mutableListOf()
override fun execute() {
val task = this.succ(pred)
val task = this.succ(variables!!)
if (task != null)
dependencies += task
}
@@ -33,9 +35,9 @@ internal class CoupleTask<P: Task>(private val pred: P, private val succ: Task.(
/**
* @param b A runnable that decides what to do next, You can also do something here.
*/
infix fun <T: Task> T.then(b: Task.(T) -> Task?): Task = CoupleTask(this, b, true)
infix fun <T: Task> T.then(b: (AutoTypingMap<String>) -> Task?): Task = CoupleTask(this, b, true)
/**
* @param b A runnable that decides what to do next, You can also do something here.
*/
infix fun <T: Task> T.with(b: Task.(T) -> Task?): Task = CoupleTask(this, b, false)
infix fun <T: Task> T.with(b: (AutoTypingMap<String>) -> Task?): Task = CoupleTask(this, b, false)

View File

@@ -25,9 +25,8 @@ import java.net.Proxy
import java.net.URL
import java.nio.charset.Charset
class GetTask @JvmOverloads constructor(val url: URL, val encoding: Charset = Charsets.UTF_8, private val retry: Int = 5, private val proxy: Proxy = Proxy.NO_PROXY): TaskResult<String>() {
class GetTask @JvmOverloads constructor(val url: URL, val encoding: Charset = Charsets.UTF_8, private val retry: Int = 5, private val proxy: Proxy = Proxy.NO_PROXY, override val id: String = ID): TaskResult<String>() {
override val scheduler: Scheduler = Scheduler.IO
override val id = ID
override fun execute() {
var exception: IOException? = null

View File

@@ -81,11 +81,15 @@ abstract class Task {
protected fun updateProgress(progress: Double) {
val now = System.currentTimeMillis()
if (now - lastTime >= progressInterval) {
progressPropertyImpl.updateAsync(progress, progressUpdate)
updateProgressImmediately(progress)
lastTime = now
}
}
protected fun updateProgressImmediately(progress: Double) {
progressPropertyImpl.updateAsync(progress, progressUpdate)
}
private val messageUpdate = AtomicReference<String>()
private val messagePropertyImpl = ReadOnlyStringWrapper(this, "message", null)
val messageProperty: ReadOnlyStringProperty = messagePropertyImpl.readOnlyProperty

View File

@@ -49,13 +49,13 @@ class TaskExecutor() {
* Start the subscription and run all registered tasks asynchronously.
*/
fun start() {
workerQueue.add(Scheduler.Schedulers.NEW_THREAD.schedule(Callable {
workerQueue.add(Scheduler.NEW_THREAD.schedule {
totTask.addAndGet(taskQueue.size)
while (!taskQueue.isEmpty()) {
if (canceled) break
val task = taskQueue.poll()
if (task != null) {
val future = task.scheduler.schedule(Callable { executeTask(task); Unit })
val future = task.scheduler.schedule { executeTask(task) }
try {
future?.get()
} catch (e: InterruptedException) {
@@ -66,7 +66,9 @@ class TaskExecutor() {
}
if (canceled || Thread.interrupted())
taskListener?.onTerminate()
}))
else
taskListener?.end()
})
}
/**

View File

@@ -20,8 +20,9 @@ package org.jackhuang.hmcl.task
import java.util.*
interface TaskListener : EventListener {
fun onReady(task: Task)
fun onFinished(task: Task)
fun onFailed(task: Task)
fun onTerminate()
fun onReady(task: Task) {}
fun onFinished(task: Task) {}
fun onFailed(task: Task) {}
fun onTerminate() {}
fun end() {}
}

View File

@@ -26,14 +26,14 @@ import java.util.logging.*
import java.util.logging.Formatter
val LOG = Logger.getLogger("HMCL").apply {
level = Level.FINEST
level = Level.FINER
useParentHandlers = false
addHandler(FileHandler("hmcl.log").apply {
level = Level.FINEST
level = Level.FINER
formatter = DefaultFormatter
})
addHandler(ConsoleHandler().apply {
level = Level.FINEST
level = Level.FINER
formatter = DefaultFormatter
})
}