Better mod download and error display (#4396)

* Better mod download and error display

* Fix Android Studio Insubordinations
This commit is contained in:
SomeTroglodyte
2021-07-06 18:33:05 +02:00
committed by GitHub
parent 3df83b1a75
commit 7875ec4896
5 changed files with 48 additions and 12 deletions

View File

@ -2,6 +2,7 @@ package com.unciv.ui.newgamescreen
import com.badlogic.gdx.scenes.scene2d.ui.CheckBox
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.Ruleset.CheckModLinksResult
import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.translations.tr
@ -39,21 +40,19 @@ class ModCheckboxTable(val mods:LinkedHashSet<String>, val screen: CameraStageBa
mods.remove(oldBaseRuleset)
mods.add(mod.name)
var isCompatibleWithCurrentRuleset = true
var complexModLinkCheck = CheckModLinksResult()
try {
val newRuleset = RulesetCache.getComplexRuleset(mods)
newRuleset.modOptions.isBaseRuleset = true // This is so the checkModLinks finds all connections
complexModLinkCheck = newRuleset.checkModLinks()
isCompatibleWithCurrentRuleset = !complexModLinkCheck.isError()
} catch (x: Exception) {
} catch (ex: Exception) {
// This happens if a building is dependent on a tech not in the base ruleset
// because newRuleset.updateBuildingCosts() in getComplexRuleset() throws an error
isCompatibleWithCurrentRuleset = false
complexModLinkCheck = CheckModLinksResult(Ruleset.CheckModLinksStatus.Error, ex.localizedMessage)
}
if (!isCompatibleWithCurrentRuleset) {
ToastPopup("The mod you selected is incompatible with the defined ruleset!\n\n$complexModLinkCheck", screen)
if (complexModLinkCheck.isError()) {
ToastPopup("{The mod you selected is incompatible with the defined ruleset!}\n\n{$complexModLinkCheck}", screen)
checkBox.isChecked = false
mods.clear()
mods.addAll(previousMods)

View File

@ -317,13 +317,14 @@ class ModManagementScreen: PickerScreen(disableScroll = true) {
val downloadButton = "Download mod from URL".toTextButton()
downloadButton.onClick {
val popup = Popup(this)
popup.addGoodSizedLabel("Please enter the mod repository -or- archive zip url:").row()
val textArea = TextArea("https://github.com/...", skin)
popup.add(textArea).width(stage.width / 2).row()
val actualDownloadButton = "Download".toTextButton()
actualDownloadButton.onClick {
actualDownloadButton.setText("Downloading...".tr())
actualDownloadButton.disable()
downloadMod(Github.Repo().apply { html_url = textArea.text; default_branch = "master" }) { popup.close() }
downloadMod(Github.Repo().parseUrl(textArea.text)) { popup.close() }
}
popup.add(actualDownloadButton).row()
popup.addCloseButton()
@ -354,13 +355,13 @@ class ModManagementScreen: PickerScreen(disableScroll = true) {
addModInfoToActionTable(repo)
}
/** Download and install a mod in the background, called from the right-bottom button */
/** Download and install a mod in the background, called both from the right-bottom button and the URL entry popup */
private fun downloadMod(repo: Github.Repo, postAction: () -> Unit = {}) {
thread(name="DownloadMod") { // to avoid ANRs - we've learnt our lesson from previous download-related actions
try {
val modFolder = Github.downloadAndExtract(repo.html_url, repo.default_branch,
Gdx.files.local("mods"))
?: return@thread
?: throw Exception() // downloadAndExtract returns null for 404 errors and the like -> display something!
rewriteModOptions(repo, modFolder)
Gdx.app.postRunnable {
ToastPopup("Downloaded!", this)

View File

@ -57,7 +57,7 @@ object Github {
defaultBranch: String,
folderFileHandle: FileHandle
): FileHandle? {
// Initiate download - the helper returns null when it fails
// Initiate download - the helper returns null when it fails
val zipUrl = "$gitRepoUrl/archive/$defaultBranch.zip"
val inputStream = download(zipUrl) ?: return null
@ -247,6 +247,38 @@ object Github {
//var stargazers_url = ""
//var homepage: String? = null // might use instead of go to repo?
//var has_wiki = false // a wiki could mean proper documentation for the mod?
/**
* Initialize `this` with an url, extracting all possible fields from it.
*
* Allows basic repo url or complete 'zip' url from github's code->download zip menu
*
* @return `this` to allow chaining
*/
fun parseUrl(url: String): Repo {
// Allow url formats
// https://github.com/author/repoName
// or
// https://github.com/author/repoName/archive/refs/heads/branchName.zip
// and extract author, repoName, branchName
html_url = url
default_branch = "master"
val matchZip = Regex("""^(.*/(.*)/(.*))/archive/(?:.*/)?([^.]+).zip$""").matchEntire(url)
if (matchZip != null && matchZip.groups.size > 3) {
html_url = matchZip.groups[1]!!.value
owner.login = matchZip.groups[2]!!.value
name = matchZip.groups[3]!!.value
default_branch = matchZip.groups[4]!!.value
} else {
val matchRepo = Regex("""^.*/(.*)/(.*)/?$""").matchEntire(url)
if (matchRepo != null && matchRepo.groups.size > 2) {
owner.login = matchRepo.groups[1]!!.value
name = matchRepo.groups[2]!!.value
}
}
return this
}
}
/** Part of [Repo] in Github API response */