This commit is contained in:
huangyuhui
2017-08-10 18:44:21 +08:00
parent da66102bc0
commit 9bd7071297
38 changed files with 878 additions and 414 deletions

View File

@@ -21,6 +21,12 @@ import org.jackhuang.hmcl.util.DigestUtils
import java.net.Proxy
class OfflineAccount private constructor(val uuid: String, override val username: String): Account() {
init {
if (username.isBlank())
throw IllegalArgumentException("Username cannot be blank")
}
override fun logIn(proxy: Proxy): AuthInfo {
if (username.isBlank() || uuid.isBlank())
throw AuthenticationException("Username cannot be empty")

View File

@@ -38,19 +38,19 @@ class DefaultDependencyManager(override val repository: DefaultGameRepository, o
return ParallelTask(*tasks)
}
override fun installLibraryAsync(version: Version, libraryId: String, libraryVersion: String): Task {
override fun installLibraryAsync(gameVersion: String, version: Version, libraryId: String, libraryVersion: String): Task {
if (libraryId == "forge")
return ForgeInstallTask(this, version, libraryVersion) then { task ->
return ForgeInstallTask(this, gameVersion, version, libraryVersion) then { task ->
val newVersion = task.result!!
VersionJSONSaveTask(this@DefaultDependencyManager, newVersion)
}
else if (libraryId == "liteloader")
return LiteLoaderInstallTask(this, version, libraryVersion) then { task ->
return LiteLoaderInstallTask(this, gameVersion, version, libraryVersion) then { task ->
val newVersion = task.result!!
VersionJSONSaveTask(this@DefaultDependencyManager, newVersion)
}
else if (libraryId == "optifine")
return OptiFineInstallTask(this, version, libraryVersion) then { task ->
return OptiFineInstallTask(this, gameVersion, version, libraryVersion) then { task ->
val newVersion = task.result!!
VersionJSONSaveTask(this@DefaultDependencyManager, newVersion)
}

View File

@@ -27,9 +27,10 @@ class DefaultGameBuilder(val dependencyManager: DefaultDependencyManager): GameB
val downloadProvider = dependencyManager.downloadProvider
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(jar = version.id, id = name)
version = version.copy(id = name)
var result = ParallelTask(
GameAssetDownloadTask(dependencyManager, version),
GameLoggingDownloadTask(dependencyManager, version),
@@ -38,21 +39,21 @@ class DefaultGameBuilder(val dependencyManager: DefaultDependencyManager): GameB
) then VersionJSONSaveTask(dependencyManager, version)
if (toolVersions.containsKey("forge"))
result = result then libraryTaskHelper(version, "forge")
result = result then libraryTaskHelper(gameVersion, version, "forge")
if (toolVersions.containsKey("liteloader"))
result = result then libraryTaskHelper(version, "liteloader")
result = result then libraryTaskHelper(gameVersion, version, "liteloader")
if (toolVersions.containsKey("optifine"))
result = result then libraryTaskHelper(version, "optifine")
result = result then libraryTaskHelper(gameVersion, version, "optifine")
result
}
}
private fun libraryTaskHelper(version: Version, libraryId: String): Task.(Task) -> Task = { prev ->
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(thisVersion, libraryId, toolVersions[libraryId]!!)
dependencyManager.installLibraryAsync(gameVersion, thisVersion, libraryId, toolVersions[libraryId]!!)
}
inner class VersionJSONDownloadTask(val gameVersion: String): Task() {

View File

@@ -36,7 +36,7 @@ abstract class DependencyManager(open val repository: GameRepository) {
*/
abstract fun gameBuilder(): GameBuilder
abstract fun installLibraryAsync(version: Version, libraryId: String, libraryVersion: String): Task
abstract fun installLibraryAsync(gameVersion: String, version: Version, libraryId: String, libraryVersion: String): Task
/**
* Get registered version list.

View File

@@ -30,8 +30,9 @@ import java.io.IOException
import java.util.zip.ZipFile
class ForgeInstallTask(private val dependencyManager: DefaultDependencyManager,
private val version: Version,
private val remoteVersion: String) : TaskResult<Version>() {
private val gameVersion: String,
private val version: Version,
private val remoteVersion: String) : TaskResult<Version>() {
private val forgeVersionList = dependencyManager.getVersionList("forge")
private val installer: File = File("forge-installer.jar").absoluteFile
lateinit var remote: RemoteVersion<*>
@@ -39,15 +40,13 @@ class ForgeInstallTask(private val dependencyManager: DefaultDependencyManager,
override val dependencies: MutableCollection<Task> = mutableListOf()
init {
if (version.jar == null)
throw IllegalArgumentException()
if (!forgeVersionList.loaded)
dependents += forgeVersionList.refreshAsync(dependencyManager.downloadProvider) then {
remote = forgeVersionList.getVersion(version.jar, remoteVersion) ?: throw IllegalArgumentException("Remote forge version ${version.jar}, $remoteVersion not found")
remote = forgeVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote forge version $gameVersion, $remoteVersion not found")
FileDownloadTask(remote.url.toURL(), installer)
}
else {
remote = forgeVersionList.getVersion(version.jar, remoteVersion) ?: throw IllegalArgumentException("Remote forge version ${version.jar}, $remoteVersion not found")
remote = forgeVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote forge version $gameVersion, $remoteVersion not found")
dependents += FileDownloadTask(remote.url.toURL(), installer)
}
}

View File

@@ -30,23 +30,22 @@ import org.jackhuang.hmcl.util.merge
* LiteLoader must be installed after Forge.
*/
class LiteLoaderInstallTask(private val dependencyManager: DefaultDependencyManager,
private val version: Version,
private val remoteVersion: String): TaskResult<Version>() {
private val gameVersion: String,
private val version: Version,
private val remoteVersion: String): TaskResult<Version>() {
private val liteLoaderVersionList = dependencyManager.getVersionList("liteloader") as LiteLoaderVersionList
lateinit var remote: RemoteVersion<LiteLoaderRemoteVersionTag>
override val dependents: MutableCollection<Task> = mutableListOf()
override val dependencies: MutableCollection<Task> = mutableListOf()
init {
if (version.jar == null)
throw IllegalArgumentException()
if (!liteLoaderVersionList.loaded)
dependents += LiteLoaderVersionList.refreshAsync(dependencyManager.downloadProvider) then {
remote = liteLoaderVersionList.getVersion(version.jar, remoteVersion) ?: throw IllegalArgumentException("Remote LiteLoader version ${version.jar}, $remoteVersion not found")
remote = liteLoaderVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote LiteLoader version $gameVersion, $remoteVersion not found")
null
}
else {
remote = liteLoaderVersionList.getVersion(version.jar, remoteVersion) ?: throw IllegalArgumentException("Remote LiteLoader version ${version.jar}, $remoteVersion not found")
remote = liteLoaderVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote LiteLoader version $gameVersion, $remoteVersion not found")
}
}

View File

@@ -27,23 +27,22 @@ import org.jackhuang.hmcl.task.then
import org.jackhuang.hmcl.util.merge
class OptiFineInstallTask(private val dependencyManager: DefaultDependencyManager,
private val version: Version,
private val remoteVersion: String): TaskResult<Version>() {
private val gameVersion: String,
private val version: Version,
private val remoteVersion: String): TaskResult<Version>() {
private val optiFineVersionList = dependencyManager.getVersionList("optifine")
lateinit var remote: RemoteVersion<*>
override val dependents: MutableCollection<Task> = mutableListOf()
override val dependencies: MutableCollection<Task> = mutableListOf()
init {
if (version.jar == null)
throw IllegalArgumentException()
if (!optiFineVersionList.loaded)
dependents += optiFineVersionList.refreshAsync(dependencyManager.downloadProvider) then {
remote = optiFineVersionList.getVersion(version.jar, remoteVersion) ?: throw IllegalArgumentException("Remote LiteLoader version $remoteVersion not found")
remote = optiFineVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote OptiFine version $gameVersion-$remoteVersion not found")
null
}
else {
remote = optiFineVersionList.getVersion(version.jar, remoteVersion) ?: throw IllegalArgumentException("Remote LiteLoader version $remoteVersion not found")
remote = optiFineVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote OptiFine version $gameVersion-$remoteVersion not found")
}
}
override fun execute() {

View File

@@ -41,7 +41,7 @@ open class DefaultGameRepository(var baseDirectory: File): GameRepository {
override fun getRunDirectory(id: String) = baseDirectory
override fun getVersionJar(version: Version): File {
val v = version.resolve(this)
val id = v.id
val id = v.jar ?: v.id
return getVersionRoot(id).resolve("$id.jar")
}
override fun getNativeDirectory(id: String) = File(getVersionRoot(id), "$id-natives")

View File

@@ -167,7 +167,7 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
res.add(options.width.toString())
}
if (options.serverIp != null) {
if (options.serverIp != null && options.serverIp.isNotBlank()) {
val args = options.serverIp.split(":")
res.add("--server")
res.add(args[0])

View File

@@ -18,19 +18,34 @@
package org.jackhuang.hmcl.mod
import com.google.gson.JsonParseException
import org.jackhuang.hmcl.util.property.ImmediateBooleanProperty
import org.jackhuang.hmcl.util.*
import java.io.File
class ModInfo (
val file: File,
var file: File,
val name: String,
val description: String = "",
val authors: String = "",
val version: String = "",
val mcversion: String = "",
val authors: String = "unknown",
val version: String = "unknown",
val mcversion: String = "unknown",
val url: String = ""
): Comparable<ModInfo> {
val isActive: Boolean
get() = file.extension != DISABLED_EXTENSION
val activeProperty = object : ImmediateBooleanProperty(this, "active", file.extension != DISABLED_EXTENSION) {
override fun invalidated() {
val f = file.absoluteFile
val newf: File
if (f.extension == DISABLED_EXTENSION)
newf = File(f.parentFile, f.nameWithoutExtension)
else
newf = File(f.parentFile, f.name + ".disabled")
if (f.renameTo(newf))
file = newf
}
}
@JvmName("activeProperty") get
var isActive: Boolean by activeProperty
val fileName: String = (if (isActive) file.name else file.nameWithoutExtension).substringBeforeLast(".")
@@ -53,22 +68,23 @@ class ModInfo (
val file = if (modFile.extension == DISABLED_EXTENSION)
modFile.absoluteFile.parentFile.resolve(modFile.nameWithoutExtension)
else modFile
var description = "Unrecognized mod file"
if (file.extension == "zip" || file.extension == "jar")
try {
return ForgeModMetadata.fromFile(modFile)
} catch (e: JsonParseException) {
throw e
} catch (ignore: Exception) {}
} catch (ignore: Exception) {
description = "May be Forge mod"
}
else if (file.extension == "litemod")
try {
return LiteModMetadata.fromFile(modFile)
} catch (e: JsonParseException) {
throw e
} catch (ignore: Exception) {}
} catch (ignore: Exception) {
description = "May be LiteLoader mod"
}
else throw IllegalArgumentException("File $modFile is not mod")
return ModInfo(file = modFile, name = modFile.nameWithoutExtension, description = "Unrecognized mod file")
return ModInfo(file = modFile, name = modFile.nameWithoutExtension, description = description)
}
}
}

View File

@@ -46,11 +46,13 @@ enum class OS {
}
val TOTAL_MEMORY: Long by lazy {
ReflectionHelper.get<Long>(ManagementFactory.getOperatingSystemMXBean(), "getTotalPhysicalMemorySize") ?: 1024L
val bytes = ReflectionHelper.invoke<Long>(ManagementFactory.getOperatingSystemMXBean(), "getTotalPhysicalMemorySize")
if (bytes == null) 1024
else bytes / 1024 / 1024
}
val SUGGESTED_MEMORY: Int by lazy {
val memory = TOTAL_MEMORY / 1024 / 1024 / 4
val memory = TOTAL_MEMORY / 4
(Math.round(1.0 * memory / 128.0) * 128).toInt()
}

View File

@@ -0,0 +1,173 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hmcl.util.property
import javafx.beans.property.*
import javafx.beans.value.ObservableValue
open class ImmediateStringProperty(bean: Any, name: String, initialValue: String): SimpleStringProperty(bean, name, initialValue) {
override fun set(newValue: String) {
super.get()
super.set(newValue)
}
protected fun superSet(newValue: String) {
super.set(newValue)
}
override fun bind(newObservable: ObservableValue<out String>) {
super.get()
super.bind(newObservable)
}
override fun unbind() {
super.get()
super.unbind()
}
public override fun fireValueChangedEvent() {
super.fireValueChangedEvent()
}
}
open class ImmediateNullableStringProperty(bean: Any, name: String, initialValue: String?): SimpleStringProperty(bean, name, initialValue) {
override fun set(newValue: String?) {
super.get()
super.set(newValue)
}
protected fun superSet(newValue: String?) {
super.set(newValue)
}
override fun bind(newObservable: ObservableValue<out String?>) {
super.get()
super.bind(newObservable)
}
override fun unbind() {
super.get()
super.unbind()
}
public override fun fireValueChangedEvent() {
super.fireValueChangedEvent()
}
}
open class ImmediateBooleanProperty(bean: Any, name: String, initialValue: Boolean): SimpleBooleanProperty(bean, name, initialValue) {
override fun set(newValue: Boolean) {
super.get()
super.set(newValue)
}
protected fun superSet(newValue: Boolean) {
super.set(newValue)
}
override fun bind(rawObservable: ObservableValue<out Boolean>?) {
super.get()
super.bind(rawObservable)
}
override fun unbind() {
super.get()
super.unbind()
}
public override fun fireValueChangedEvent() {
super.fireValueChangedEvent()
}
}
open class ImmediateIntegerProperty(bean: Any, name: String, initialValue: Int): SimpleIntegerProperty(bean, name, initialValue) {
override fun set(newValue: Int) {
super.get()
super.set(newValue)
}
protected fun superSet(newValue: Int) {
super.set(newValue)
}
override fun bind(rawObservable: ObservableValue<out Number>) {
super.get()
super.bind(rawObservable)
}
override fun unbind() {
super.get()
super.unbind()
}
public override fun fireValueChangedEvent() {
super.fireValueChangedEvent()
}
}
open class ImmediateDoubleProperty(bean: Any, name: String, initialValue: Double): SimpleDoubleProperty(bean, name, initialValue) {
override fun set(newValue: Double) {
super.get()
super.set(newValue)
}
protected fun superSet(newValue: Double) {
super.set(newValue)
}
override fun bind(rawObservable: ObservableValue<out Number>) {
super.get()
super.bind(rawObservable)
}
override fun unbind() {
super.get()
super.unbind()
}
public override fun fireValueChangedEvent() {
super.fireValueChangedEvent()
}
}
open class ImmediateObjectProperty<T>(bean: Any, name: String, initialValue: T): SimpleObjectProperty<T>(bean, name, initialValue) {
override fun set(newValue: T) {
super.get()
super.set(newValue)
}
override fun bind(rawObservable: ObservableValue<out T>) {
super.get()
super.bind(rawObservable)
}
override fun unbind() {
super.get()
super.unbind()
}
public override fun fireValueChangedEvent() {
super.fireValueChangedEvent()
}
}

View File

@@ -25,6 +25,7 @@ import org.jackhuang.hmcl.download.MojangDownloadProvider
import org.jackhuang.hmcl.game.DefaultGameRepository
import org.jackhuang.hmcl.launch.DefaultLauncher
import org.jackhuang.hmcl.game.LaunchOptions
import org.jackhuang.hmcl.game.minecraftVersion
import org.jackhuang.hmcl.launch.ProcessListener
import org.jackhuang.hmcl.util.makeCommand
import org.jackhuang.hmcl.task.Task
@@ -115,10 +116,11 @@ class Test {
fun installForge() {
val thread = Thread.currentThread()
val version = repository.getVersion("test").resolve(repository)
val minecraftVersion = minecraftVersion(repository.getVersionJar(version)) ?: ""
// optifine HD_U_C4
// forge 14.21.1.2426
// liteloader 1.12-SNAPSHOT-4
dependency.installLibraryAsync(version, "liteloader", "1.12-SNAPSHOT-4").executor().apply {
dependency.installLibraryAsync(minecraftVersion, version, "liteloader", "1.12-SNAPSHOT-4").executor().apply {
taskListener = taskListener(thread)
}.start()
try {