Solved rare pillage-related crash

This commit is contained in:
Yair Morgenstern 2023-12-31 22:42:19 +02:00
parent 1bf75844a3
commit 15dfb892a7
5 changed files with 23 additions and 230640 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -14,10 +14,8 @@ import com.unciv.logic.civilization.NotificationCategory
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.tile.Tile
import com.unciv.models.UnitActionType
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActions
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsPillage
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsUpgrade
@ -379,7 +377,9 @@ object UnitAutomation {
if (unit.getTile() != tileToPillage)
unit.movement.moveToTile(tileToPillage)
UnitActions.invokeUnitAction(unit, UnitActionType.Pillage)
// We CANNOT use invokeUnitAction, since the default unit action contains a popup, which - when automated -
// runs a UI action on a side thread leading to crash!
UnitActionsPillage.getPillageAction(unit, unit.currentTile)?.action?.invoke()
return unit.currentMovement == 0f
}

View File

@ -18,8 +18,9 @@ import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.tile.RoadStatus
import com.unciv.logic.map.tile.Tile
import com.unciv.logic.map.tile.TileStatFunctions
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.logic.map.tile.toStats
import com.unciv.models.UnitActionType
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.Terrain
import com.unciv.models.ruleset.tile.TileImprovement
import com.unciv.models.ruleset.unique.LocalUniqueCache
@ -28,7 +29,6 @@ import com.unciv.ui.screens.worldscreen.unit.actions.UnitActions
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsFromUniques
import com.unciv.utils.Log
import com.unciv.utils.debug
import kotlin.IllegalStateException
private object WorkerAutomationConst {
/** BFS max size is determined by the aerial distance of two cities to connect, padded with this */
@ -129,8 +129,8 @@ class WorkerAutomation(
* The improvementPriority and bestImprovement are by default not set.
* Once improvementPriority is set we have already checked for the best improvement, repairImprovement.
*/
data class TileImprovementRank(val tilePriority: Float, var improvementPriority: Float? = null,
var bestImprovement: TileImprovement? = null,
data class TileImprovementRank(val tilePriority: Float, var improvementPriority: Float? = null,
var bestImprovement: TileImprovement? = null,
var repairImprovment: Boolean? = null)
private val tileRankings = HashMap<Tile, TileImprovementRank>()
@ -273,14 +273,14 @@ class WorkerAutomation(
*/
fun automateWorkerAction(unit: MapUnit, dangerousTiles: HashSet<Tile>) {
val currentTile = unit.getTile()
// Shortcut, we are working a good tile (like resource) and don't need to check for other tiles to work
if (!dangerousTiles.contains(currentTile) && getFullPriority(unit.getTile(), unit) >= 10
&& currentTile.improvementInProgress != null) {
return
}
val tileToWork = findTileToWork(unit, dangerousTiles)
// If we have < 20 GPT lets not spend time connecting roads
if (civInfo.stats.statsForNextTurn.gold >= 20
&& tryConnectingCities(unit, getImprovementPriority(tileToWork, unit))) return
@ -332,14 +332,14 @@ class WorkerAutomation(
throw IllegalStateException("We didn't find anything to improve on this tile even though there was supposed to be something to improve!")
}
}
if (unit.cache.hasUniqueToCreateWaterImprovements) {
// Support Alpha Frontier-Style Workers that _also_ have the "May create improvements on water resources" unique
if (automateWorkBoats(unit)) return
}
//Lets check again if we want to build roads because we don't have a tile nearby to improve
if (civInfo.stats.statsForNextTurn.gold > 15 && tryConnectingCities(unit, 0f)) return
if (civInfo.stats.statsForNextTurn.gold > 15 && tryConnectingCities(unit, 0f)) return
val citiesToNumberOfUnimprovedTiles = HashMap<String, Int>()
for (city in unit.civ.cities) {
@ -360,7 +360,7 @@ class WorkerAutomation(
}
// Nothing to do, try again to connect cities
if (civInfo.stats.statsForNextTurn.gold > 10 && tryConnectingCities(unit, 0f)) return
if (civInfo.stats.statsForNextTurn.gold > 10 && tryConnectingCities(unit, 0f)) return
debug("WorkerAutomation: %s -> nothing to do", unit.label())
@ -386,7 +386,7 @@ class WorkerAutomation(
else -> 20
}
if (maxDistanceWanted < 0) return false
// Since further away cities take longer to get to and - most importantly - the canReach() to them is very long,
// we order cities by their closeness to the worker first, and then check for each one whether there's a viable path
// it can take to an existing connected city.
@ -476,7 +476,7 @@ class WorkerAutomation(
// Search through each group by priority
// If we can find an eligible best tile in the group lets return that
// under the assumption that best tile is better than tiles in all lower groups
// under the assumption that best tile is better than tiles in all lower groups
for (tilePriorityGroup in workableTilesPrioritized) {
var bestTile: Tile? = null
for (tileInGroup in tilePriorityGroup.value.sortedBy { unit.getTile().aerialDistanceTo(it) }) {
@ -494,19 +494,19 @@ class WorkerAutomation(
}
return currentTile
}
/**
* Calculate a priority for the tile without accounting for the improvement it'self
* This is a cheap guess on how helpful it might be to do work on this tile
*/
fun getBasePriority(tile: Tile, unit: MapUnit): Float {
val unitSpecificPriority = 2 - (tile.aerialDistanceTo(unit.getTile()) / 2.0f).coerceIn(0f, 2f)
if (tileRankings.containsKey(tile))
if (tileRankings.containsKey(tile))
return tileRankings[tile]!!.tilePriority + unitSpecificPriority
var priority = 0f
if (tile.getOwner() == civInfo) {
priority += Automation.rankStatsValue(tile.stats.getTerrainStats(), civInfo)
priority += Automation.rankStatsValue(tile.stats.getTerrainStatsBreakdown().toStats(), civInfo)
if (tile.providesYield()) priority += 2
if (tile.isPillaged()) priority += 1
// TODO: Removing fallout is hardcoded for now, but what if we want to have other bad features on tiles?
@ -519,8 +519,8 @@ class WorkerAutomation(
if (priority <= 0 && tile.hasViewableResource(civInfo)) {
priority += 1
// New Resources are great!
if (tile.tileResource.resourceType != ResourceType.Bonus
&& !civInfo.hasResource(tile.resource!!))
if (tile.tileResource.resourceType != ResourceType.Bonus
&& !civInfo.hasResource(tile.resource!!))
priority += 2
}
tileRankings[tile] = TileImprovementRank(priority)
@ -566,7 +566,7 @@ class WorkerAutomation(
return rank.improvementPriority!!
}
/**
* Calculates the full priority of the tile
*/
@ -579,7 +579,7 @@ class WorkerAutomation(
*/
private fun tileHasWorkToDo(tile: Tile, unit: MapUnit): Boolean {
if (getImprovementPriority(tile, unit) <= 0) return false
if (!(tileRankings[tile]!!.bestImprovement != null || tileRankings[tile]!!.repairImprovment!!))
if (!(tileRankings[tile]!!.bestImprovement != null || tileRankings[tile]!!.repairImprovment!!))
throw IllegalStateException("There was an improvementPriority > 0 and nothing to do")
return true
}