Game can deal gracefully wth mods removing certain units and technologies

This commit is contained in:
Yair Morgenstern
2020-12-27 11:55:28 +02:00
parent 87c6819462
commit 599a1d8a91
4 changed files with 57 additions and 37 deletions

View File

@ -262,35 +262,7 @@ class GameInfo {
throw UncivShowableException("Missing mods: [$missingMods]")
}
// Mods can change, leading to things on the map that are no longer defined in the mod.
// So we remove them so the game doesn't crash when it tries to access them.
for (tile in tileMap.values) {
if (tile.resource != null && !ruleSet.tileResources.containsKey(tile.resource!!))
tile.resource = null
if (tile.improvement != null && !ruleSet.tileImprovements.containsKey(tile.improvement!!)
&& !tile.improvement!!.startsWith("StartingLocation ")) // To not remove the starting locations in GameStarter.startNewGame()
tile.improvement = null
for (unit in tile.getUnits())
for (promotion in unit.promotions.promotions.toList())
if (!ruleSet.unitPromotions.containsKey(promotion))
unit.promotions.promotions.remove(promotion)
for (city in civilizations.asSequence().flatMap { it.cities.asSequence() }) {
for (building in city.cityConstructions.builtBuildings.toHashSet())
if (!ruleSet.buildings.containsKey(building))
city.cityConstructions.builtBuildings.remove(building)
// Remove invalid buildings or units from the queue - don't just check buildings and units because it might be a special construction as well
for (construction in city.cityConstructions.constructionQueue.toList()) {
if (!ruleSet.buildings.containsKey(construction) && !ruleSet.units.containsKey(construction)
&& !PerpetualConstruction.perpetualConstructionsMap.containsKey(construction))
city.cityConstructions.constructionQueue.remove(construction)
}
}
}
removeMissingModReferences()
tileMap.setTransients(ruleSet)
@ -347,6 +319,46 @@ class GameInfo {
}
}
// Mods can change, leading to things on the map that are no longer defined in the mod.
// So we remove them so the game doesn't crash when it tries to access them.
private fun removeMissingModReferences() {
for (tile in tileMap.values) {
if (tile.resource != null && !ruleSet.tileResources.containsKey(tile.resource!!))
tile.resource = null
if (tile.improvement != null && !ruleSet.tileImprovements.containsKey(tile.improvement!!)
&& !tile.improvement!!.startsWith("StartingLocation ")) // To not remove the starting locations in GameStarter.startNewGame()
tile.improvement = null
for (unit in tile.getUnits()) {
if (!ruleSet.units.containsKey(unit.name)) tile.removeUnit(unit)
for (promotion in unit.promotions.promotions.toList())
if (!ruleSet.unitPromotions.containsKey(promotion))
unit.promotions.promotions.remove(promotion)
}
}
for (city in civilizations.asSequence().flatMap { it.cities.asSequence() }) {
for (building in city.cityConstructions.builtBuildings.toHashSet())
if (!ruleSet.buildings.containsKey(building))
city.cityConstructions.builtBuildings.remove(building)
// Remove invalid buildings or units from the queue - don't just check buildings and units because it might be a special construction as well
for (construction in city.cityConstructions.constructionQueue.toList()) {
if (!ruleSet.buildings.containsKey(construction) && !ruleSet.units.containsKey(construction)
&& !PerpetualConstruction.perpetualConstructionsMap.containsKey(construction))
city.cityConstructions.constructionQueue.remove(construction)
}
}
for (civinfo in civilizations) {
for (tech in civinfo.tech.techsResearched.toList())
if (!ruleSet.technologies.containsKey(tech))
civinfo.tech.techsResearched.remove(tech)
}
}
private fun changeBuildingName(cityConstructions: CityConstructions, oldBuildingName: String, newBuildingName: String) {
if (cityConstructions.builtBuildings.contains(oldBuildingName)) {
cityConstructions.builtBuildings.remove(oldBuildingName)

View File

@ -18,6 +18,7 @@ import kotlin.math.min
class TechManager {
@Transient
lateinit var civInfo: CivilizationInfo
/** This is the Transient list of Technologies */
@Transient
var researchedTechnologies = ArrayList<Technology>()
@Transient
@ -42,6 +43,7 @@ class TechManager {
/** For calculating Great Scientist yields - see https://civilization.fandom.com/wiki/Great_Scientist_(Civ5) */
var scienceOfLast8Turns = IntArray(8) { 0 }
var scienceFromResearchAgreements = 0
/** This is the lit of strings, which is serialized */
var techsResearched = HashSet<String>()
/** When moving towards a certain tech, the user doesn't have to manually pick every one. */

View File

@ -495,13 +495,7 @@ class MapUnit {
.forEach { unit -> unit.destroy() }
}
fun removeFromTile() {
when {
type.isAirUnit() -> currentTile.airUnits.remove(this)
type.isCivilian() -> getTile().civilianUnit = null
else -> getTile().militaryUnit = null
}
}
fun removeFromTile() = currentTile.removeUnit(this)
fun moveThroughTile(tile: TileInfo) {
if (tile.improvement == Constants.ancientRuins && civInfo.isMajorCiv())

View File

@ -483,7 +483,19 @@ open class TileInfo {
}
fun stripUnits() {
for (unit in this.getUnits()) unit.removeFromTile()
for (unit in this.getUnits()) removeUnit(unit)
}
/** If the unit isn't in the ruleset we can't even know what type of unit this is! So check each place
* This works with no transients so can be called from gameInfo.setTransients with no fear
*/
fun removeUnit(mapUnit: MapUnit){
when {
airUnits.contains(mapUnit) -> airUnits.remove(mapUnit)
civilianUnit == mapUnit -> civilianUnit = null
else -> militaryUnit = null
}
}
fun startWorkingOnImprovement(improvement: TileImprovement, civInfo: CivilizationInfo) {