Mod loader resilience (#2211)

* For #2200: Avoid MacOS tripping us

* Second hidden test in packImages

* Clearer message for a specific mod error, UI message for savegames missing mods

* Fixed obsolete imports from rejected experiments

* Tiny lint issue

* Irrelevant change to test push after rebase
This commit is contained in:
rh-github-2015 2020-03-22 21:43:39 +01:00 committed by GitHub
parent 3734f39101
commit 4fb7e11354
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 12 deletions

View file

@ -366,6 +366,12 @@ Upload map = Karte hochladen
Could not upload map! = Kann Karte nicht hochladen!
Map uploaded successfully! = Karte hochladen war erfolgreich!
Saving... = Speichern...
It looks like your saved game can't be loaded! = Dieser Spielstand kann nicht geladen werden!
If you could copy your game data ("Copy saved game to clipboard" - = Wenn Sie die Spieldaten kopieren ("Gespeichertes Spiel in die Zwischenablage kopieren"),
paste into an email to yairm210@hotmail.com) = und in eine mail an mich (yairm210@hotmail.com) einfügen,
I could maybe help you figure out what went wrong, since this isn't supposed to happen! = dann kann ich eventuell helfen den Grund zu finden - das sollte nicht passieren!
Missing mods: [mods] = Der Spielstand benötigt das/die mod(s) [mods], diese sind aber nicht verfügbar.
# Options

View file

@ -366,6 +366,11 @@ Upload map =
Could not upload map! =
Map uploaded successfully! =
Saving... =
It looks like your saved game can't be loaded! =
If you could copy your game data ("Copy saved game to clipboard" - =
paste into an email to yairm210@hotmail.com) =
I could maybe help you figure out what went wrong, since this isn't supposed to happen! =
Missing mods: [mods] =
# Options

View file

@ -17,6 +17,8 @@ import com.unciv.models.ruleset.RulesetCache
import java.util.*
import kotlin.collections.ArrayList
class UncivShowableException(missingMods: String) : Exception(missingMods)
class GameInfo {
@Transient lateinit var difficultyObject: Difficulty // Since this is static game-wide, and was taking a large part of nextTurn
@Transient lateinit var currentPlayerCiv:CivilizationInfo // this is called thousands of times, no reason to search for it with a find{} every time
@ -219,6 +221,15 @@ class GameInfo {
fun setTransients() {
tileMap.gameInfo = this
ruleSet = RulesetCache.getComplexRuleset(gameParameters.mods)
// any mod the saved game lists that is currently not installed causes null pointer
// exceptions in this routine unless it contained no new objects or was very simple.
// Player's fault, so better complain early:
val missingMods = gameParameters.mods
.filterNot { it in ruleSet.mods }
.joinToString(limit = 120) { it }
if (missingMods.isNotEmpty()) {
throw UncivShowableException("Missing mods: [$missingMods]")
}
// Renames as of version 3.1.8, because of translation conflicts with the property "Range" and the difficulty "Immortal"
// Needs to be BEFORE tileMap.setTransients, because the units' setTransients is called from there
@ -370,3 +381,4 @@ class GameInfo {
}
}

View file

@ -3,6 +3,7 @@ package com.unciv.models.ruleset
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.files.FileHandle
import com.unciv.JsonParser
import com.unciv.logic.UncivShowableException
import com.unciv.models.ruleset.tech.TechColumn
import com.unciv.models.ruleset.tech.Technology
import com.unciv.models.ruleset.tile.Terrain
@ -91,10 +92,11 @@ class Ruleset() {
if(buildingsFile.exists()) {
buildings += createHashmap(jsonParser.getFromJson(Array<Building>::class.java, buildingsFile))
for (building in buildings.values) {
if (building.requiredTech == null) continue
val column = technologies[building.requiredTech!!]!!.column
if (building.cost == 0)
building.cost = if (building.isWonder || building.isNationalWonder) column!!.wonderCost else column!!.buildingCost
if (building.cost == 0) {
val column = technologies[building.requiredTech]?.column
?: throw UncivShowableException("Building (${building.name}) must either have an explicit cost or a required tech in the same mod")
building.cost = if (building.isWonder || building.isNationalWonder) column.wonderCost else column.buildingCost
}
}
}
@ -149,14 +151,18 @@ object RulesetCache :HashMap<String,Ruleset>(){
this[""] = Ruleset().apply { load(Gdx.files.internal("jsons")) }
for(modFolder in Gdx.files.local("mods").list()){
if (modFolder.name().startsWith('.')) continue
try{
val modRuleset = Ruleset()
modRuleset.load(modFolder.child("jsons"))
modRuleset.name = modFolder.name()
this[modRuleset.name] = modRuleset
println ("Mod loaded successfully: " + modRuleset.name)
}
catch (ex:Exception){
println( "Exception loading " + modFolder.name() + ": " + ex.message )
println ("Exception loading mod '${modFolder.name()}':")
println (" ${ex.localizedMessage}")
println (" (Source file ${ex.stackTrace[0].fileName} line ${ex.stackTrace[0].lineNumber})")
}
}
}

View file

@ -10,6 +10,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener
import com.unciv.UncivGame
import com.unciv.logic.GameSaver
import com.unciv.logic.UncivShowableException
import com.unciv.models.translations.tr
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.utils.disable
@ -44,11 +45,17 @@ class LoadGameScreen : PickerScreen() {
catch (ex:Exception){
val cantLoadGamePopup = Popup(this)
cantLoadGamePopup.addGoodSizedLabel("It looks like your saved game can't be loaded!").row()
cantLoadGamePopup.addGoodSizedLabel("If you could copy your game data (\"Copy saved game to clipboard\" - ").row()
cantLoadGamePopup.addGoodSizedLabel(" paste into an email to yairm210@hotmail.com)").row()
cantLoadGamePopup.addGoodSizedLabel("I could maybe help you figure out what went wrong, since this isn't supposed to happen!").row()
cantLoadGamePopup.open()
ex.printStackTrace()
if (ex is UncivShowableException && ex.localizedMessage != null) {
// thrown exceptions are our own tests and can be shown to the user
cantLoadGamePopup.addGoodSizedLabel(ex.localizedMessage).row()
cantLoadGamePopup.open()
} else {
cantLoadGamePopup.addGoodSizedLabel("If you could copy your game data (\"Copy saved game to clipboard\" - ").row()
cantLoadGamePopup.addGoodSizedLabel(" paste into an email to yairm210@hotmail.com)").row()
cantLoadGamePopup.addGoodSizedLabel("I could maybe help you figure out what went wrong, since this isn't supposed to happen!").row()
cantLoadGamePopup.open()
ex.printStackTrace()
}
}
}

View file

@ -61,7 +61,8 @@ internal object DesktopLauncher {
val modDirectory = File("mods")
if(modDirectory.exists()) {
for (mod in modDirectory.listFiles()!!){
TexturePacker.process(settings, mod.path + "/Images", mod.path, "game")
if (!mod.isHidden && File(mod.path + "/Images").exists())
TexturePacker.process(settings, mod.path + "/Images", mod.path, "game")
}
}
@ -97,6 +98,6 @@ internal object DesktopLauncher {
presence.details=currentPlayerCiv.nation.getLeaderDisplayName().tr()
presence.largeImageKey = "logo" // The actual image is uploaded to the discord app / applications webpage
presence.largeImageText ="Turn".tr()+" " + currentPlayerCiv.gameInfo.turns
DiscordRPC.INSTANCE.Discord_UpdatePresence(presence);
DiscordRPC.INSTANCE.Discord_UpdatePresence(presence)
}
}