Inceptum/launcher-gtk/src/main/kotlin/io/gitlab/jfronny/inceptum/gtk/window/create/NewInstanceWindow.kt

183 lines
7.7 KiB
Kotlin

package io.gitlab.jfronny.inceptum.gtk.window.create
import io.gitlab.jfronny.commons.StringFormatter
import io.gitlab.jfronny.commons.io.JFiles
import io.gitlab.jfronny.inceptum.common.InceptumConfig
import io.gitlab.jfronny.inceptum.common.MetaHolder
import io.gitlab.jfronny.inceptum.gtk.control.KDropDown
import io.gitlab.jfronny.inceptum.gtk.control.KEntry
import io.gitlab.jfronny.inceptum.gtk.control.assistant.KAssistant
import io.gitlab.jfronny.inceptum.gtk.schedule
import io.gitlab.jfronny.inceptum.gtk.util.I18n
import io.gitlab.jfronny.inceptum.gtk.util.Log
import io.gitlab.jfronny.inceptum.gtk.util.toTypedArray
import io.gitlab.jfronny.inceptum.gtk.window.dialog.ProcessStateWatcherDialog
import io.gitlab.jfronny.inceptum.launcher.api.FabricMetaApi
import io.gitlab.jfronny.inceptum.launcher.api.McApi
import io.gitlab.jfronny.inceptum.launcher.model.fabric.FabricVersionLoaderInfo
import io.gitlab.jfronny.inceptum.launcher.model.mojang.VersionsListInfo
import io.gitlab.jfronny.inceptum.launcher.system.instance.InstanceNameTool
import io.gitlab.jfronny.inceptum.launcher.system.instance.LoaderInfo
import io.gitlab.jfronny.inceptum.launcher.system.setup.SetupStepInfo
import io.gitlab.jfronny.inceptum.launcher.system.setup.Steps
import org.gnome.glib.GLib
import org.gnome.gtk.*
import java.io.IOException
class NewInstanceWindow(app: Application) : KAssistant(app) {
companion object {
private val VERSIONS = McApi.getVersions()
}
init {
var gameVersion: VersionsListInfo? = null
var useFabric = false
var fabricVersion: FabricVersionLoaderInfo? = null
var name = "New Instance"
var failureMessage = "Unknown error, please look at the log!"
var isFailure = false
page("Welcome", AssistantPageType.INTRO) {
append(Label("This assistant will guide you through the process of setting up a Minecraft instance.\nTo begin, please choose the game version you want to use"))
val versions = VERSIONS.versions.stream()
.filter { InceptumConfig.snapshots || it.type == "release" }
.toTypedArray()
val def = versions.withIndex().firstOrNull { it.value.id == VERSIONS.latest.release }?.index ?: 0
gameVersion = versions[def]
append(KDropDown(versions, { it.id }, def).apply {
onChange { gameVersion = versions[it] }
})
setComplete(true)
}
page("Loader", AssistantPageType.CONTENT) {
append(Label("Select a mod loader if you want to use mods in this instance. This can be changed later."))
var lastGameVersion: VersionsListInfo? = null
var versions = arrayOf<FabricVersionLoaderInfo>()
var def = 0
val none = CheckButton.newWithLabel("None")
val fabric = CheckButton.newWithLabel("Fabric")
none.onToggled { useFabric = false }
none.onToggled { useFabric = true }
fabric.setGroup(none)
append(none)
val fabricVersionDropdown = KDropDown(versions, { it.loader.version }, def)
fabricVersionDropdown.onChange { fabricVersion = versions[it] }
append(Box(Orientation.HORIZONTAL, 8).apply {
append(fabric)
append(fabricVersionDropdown)
})
onOpen {
if (lastGameVersion == null || lastGameVersion != gameVersion) {
versions = FabricMetaApi.getLoaderVersions(gameVersion!!).toTypedArray()
def = versions.withIndex().firstOrNull { it.value.loader.stable }?.index ?: 0
fabricVersionDropdown.updateOptions(versions, def)
lastGameVersion = gameVersion
none.active = true
fabric.active = false
useFabric = false
}
if (versions.isEmpty()) {
none.active = true
fabric.active = false
useFabric = false
fabric.sensitive = false
}
}
setComplete(true)
}
page("Name", AssistantPageType.CONTENT) {
append(Label(I18n["instance.settings.general.name.placeholder"]))
val entry = KEntry(name)
entry.placeholderText = I18n["instance.settings.general.name.placeholder"]
entry.valign
entry.onChange { name = InstanceNameTool.getNextValid(it) }
append(entry)
onOpen {
name = InstanceNameTool.getDefaultName(gameVersion!!.id, useFabric)
entry.text = name
}
setComplete(true)
}
page("Creating", AssistantPageType.PROGRESS) {
append(Label("Creating Instance"))
val progress = ProgressBar()
append(progress)
val stage = Label("")
append(stage)
onOpen {
commit()
val pState = Steps.createProcessState()
val state = SetupStepInfo(
McApi.getVersionInfo(gameVersion),
if (useFabric) LoaderInfo(fabricVersion!!.loader) else LoaderInfo.NONE,
name,
pState
)
var finished = false
var cachedState: ProcessStateWatcherDialog.State? = null
addTickCallback { widget, _ ->
if (finished) return@addTickCallback GLib.SOURCE_REMOVE
val nc = ProcessStateWatcherDialog.State(pState)
if (nc != cachedState) {
cachedState = nc
stage.setMarkup(cachedState!!.msg)
progress.fraction = cachedState!!.progress.coerceAtMost(1f).toDouble()
widget.queueDraw()
}
GLib.SOURCE_CONTINUE
}
onClose { pState.cancel() }
onCancel { pState.cancel() }
pState.updateStep("Starting install process")
Thread {
try {
for (step in Steps.STEPS) {
if (state.isCancelled) {
try {
JFiles.deleteRecursive(MetaHolder.INSTANCE_DIR.resolve(state.name))
} catch (e: IOException) {
Log.error("Could not delete instance dir", e)
}
return@Thread
}
pState.incrementStep(step.name)
step.execute(state)
}
} catch (e: Throwable) {
pState.cancel()
Log.error("Could not create instance")
failureMessage = StringFormatter.toString(e)
isFailure = true
} finally {
finished = true
schedule { setComplete(true) }
schedule { nextPage() }
}
}.start()
}
}
page("Done", AssistantPageType.SUMMARY) {
val status = Label("")
onOpen {
if (isFailure) {
status.setMarkup("Something went wrong while creating the instance.\n\n$failureMessage")
} else {
status.setMarkup("The instance was successfully created. You can now launch it using the main menu")
}
}
setComplete(true)
}
}
}