Massive performance improvement thanks to:
* not mapping out the uniques every tile * saving tech uniques and units uniques specific to movement between tiles
This commit is contained in:
parent
30734c7287
commit
2923dc80c9
7 changed files with 60 additions and 19 deletions
Binary file not shown.
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.6 KiB |
|
@ -21,7 +21,7 @@ android {
|
||||||
applicationId "com.unciv.game"
|
applicationId "com.unciv.game"
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 181
|
versionCode 182
|
||||||
versionName "2.11.0"
|
versionName "2.11.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ class UnCivGame : Game() {
|
||||||
val viewEntireMapForDebug = false
|
val viewEntireMapForDebug = false
|
||||||
|
|
||||||
// For when you need to test something in an advanced game and don't have time to faff around
|
// For when you need to test something in an advanced game and don't have time to faff around
|
||||||
val superchargedForDebug = true
|
val superchargedForDebug = false
|
||||||
|
|
||||||
lateinit var worldScreen: WorldScreen
|
lateinit var worldScreen: WorldScreen
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,12 @@ import java.util.*
|
||||||
class TechManager {
|
class TechManager {
|
||||||
@Transient lateinit var civInfo: CivilizationInfo
|
@Transient lateinit var civInfo: CivilizationInfo
|
||||||
@Transient var researchedTechnologies=ArrayList<Technology>()
|
@Transient var researchedTechnologies=ArrayList<Technology>()
|
||||||
|
@Transient private var researchedTechUniques=ArrayList<String>()
|
||||||
|
|
||||||
|
// MapUnit.canPassThrough is the most called function in the game, and having these extremey specific booleans is or way of improving the time cost
|
||||||
|
@Transient var unitsCanEmbark=false
|
||||||
|
@Transient var embarkedUnitsCanEnterOcean=false
|
||||||
|
|
||||||
|
|
||||||
var freeTechs = 0
|
var freeTechs = 0
|
||||||
var techsResearched = HashSet<String>()
|
var techsResearched = HashSet<String>()
|
||||||
|
@ -56,7 +62,7 @@ class TechManager {
|
||||||
return GameBasics.Technologies[TechName]!!.prerequisites.all { isResearched(it) }
|
return GameBasics.Technologies[TechName]!!.prerequisites.all { isResearched(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUniques() = researchedTechnologies.flatMap { it.uniques }
|
fun getUniques() = researchedTechUniques
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
@ -103,7 +109,11 @@ class TechManager {
|
||||||
techsResearched.add(techName)
|
techsResearched.add(techName)
|
||||||
|
|
||||||
// this is to avoid concurrent modification problems
|
// this is to avoid concurrent modification problems
|
||||||
researchedTechnologies = researchedTechnologies.withItem(GameBasics.Technologies[techName]!!)
|
val newTech = GameBasics.Technologies[techName]!!
|
||||||
|
researchedTechnologies = researchedTechnologies.withItem(newTech)
|
||||||
|
for(unique in newTech.uniques)
|
||||||
|
researchedTechUniques = researchedTechUniques.withItem(unique)
|
||||||
|
updateTransientBooleans()
|
||||||
|
|
||||||
civInfo.addNotification("Research of [$techName] has completed!", null, Color.BLUE)
|
civInfo.addNotification("Research of [$techName] has completed!", null, Color.BLUE)
|
||||||
|
|
||||||
|
@ -144,7 +154,13 @@ class TechManager {
|
||||||
techsToResearch.remove("Mass Media")
|
techsToResearch.remove("Mass Media")
|
||||||
|
|
||||||
researchedTechnologies.addAll(techsResearched.map { GameBasics.Technologies[it]!! })
|
researchedTechnologies.addAll(techsResearched.map { GameBasics.Technologies[it]!! })
|
||||||
|
researchedTechUniques.addAll(researchedTechnologies.flatMap { it.uniques })
|
||||||
|
updateTransientBooleans()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
fun updateTransientBooleans(){
|
||||||
|
if(researchedTechUniques.contains("Enables embarkation for land units")) unitsCanEmbark=true
|
||||||
|
if(researchedTechUniques.contains("Enables embarked units to enter ocean tiles")) embarkedUnitsCanEnterOcean=true
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,13 @@ class MapUnit {
|
||||||
@Transient lateinit var baseUnit: BaseUnit
|
@Transient lateinit var baseUnit: BaseUnit
|
||||||
@Transient internal lateinit var currentTile :TileInfo
|
@Transient internal lateinit var currentTile :TileInfo
|
||||||
|
|
||||||
|
// These are for performance improvements to getMovementCostBetweenAdjacentTiles,
|
||||||
|
// a major component of getDistanceToTilesWithinTurn,
|
||||||
|
// which in turn is a component of getShortestPath and canReach
|
||||||
|
@Transient var ignoresTerrainCost = false
|
||||||
|
@Transient var roughTerrainPenalty = false
|
||||||
|
@Transient var doubleMovementInCoast = false
|
||||||
|
|
||||||
lateinit var owner: String
|
lateinit var owner: String
|
||||||
lateinit var name: String
|
lateinit var name: String
|
||||||
var currentMovement: Float = 0f
|
var currentMovement: Float = 0f
|
||||||
|
@ -81,6 +88,10 @@ class MapUnit {
|
||||||
uniques.addAll(baseUnit.uniques)
|
uniques.addAll(baseUnit.uniques)
|
||||||
uniques.addAll(promotions.promotions.map { GameBasics.UnitPromotions[it]!!.effect })
|
uniques.addAll(promotions.promotions.map { GameBasics.UnitPromotions[it]!!.effect })
|
||||||
tempUniques = uniques
|
tempUniques = uniques
|
||||||
|
|
||||||
|
if("Ignores terrain cost" in uniques) ignoresTerrainCost=true
|
||||||
|
if("Rough terrain penalty" in uniques) roughTerrainPenalty=true
|
||||||
|
if("Double movement in coast" in uniques) doubleMovementInCoast=true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasUnique(unique:String): Boolean {
|
fun hasUnique(unique:String): Boolean {
|
||||||
|
@ -116,23 +127,26 @@ class MapUnit {
|
||||||
return "$name - $owner"
|
return "$name - $owner"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is the most called function in the entire game,
|
||||||
|
// so multiple callees of this function have been optimized,
|
||||||
|
// because optimization on this function results in massive benefits!
|
||||||
fun canPassThrough(tile: TileInfo):Boolean{
|
fun canPassThrough(tile: TileInfo):Boolean{
|
||||||
val tileOwner = tile.getOwner()
|
val tileOwner = tile.getOwner()
|
||||||
|
|
||||||
if(tile.getBaseTerrain().impassable) return false
|
if(tile.getBaseTerrain().impassable) return false
|
||||||
val isOcean = tile.baseTerrain == "Ocean" // profiling showed that 3.5% of all nextTurn time is taken up by string equals in this function =|
|
|
||||||
if(tile.isWater() && type.isLandUnit()){
|
|
||||||
val techUniques = civInfo.tech.getUniques()
|
|
||||||
if(!techUniques.contains("Enables embarkation for land units"))
|
|
||||||
return false
|
|
||||||
if(isOcean && !techUniques.contains("Enables embarked units to enter ocean tiles"))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if(tile.isLand() && type.isWaterUnit())
|
if(tile.isLand() && type.isWaterUnit())
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
val isOcean = tile.baseTerrain == "Ocean"
|
||||||
|
if(tile.isWater() && type.isLandUnit()){
|
||||||
|
if(!civInfo.tech.unitsCanEmbark) return false
|
||||||
|
if(isOcean && !civInfo.tech.embarkedUnitsCanEnterOcean)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if(isOcean && baseUnit.uniques.contains("Cannot enter ocean tiles")) return false
|
||||||
if(isOcean && baseUnit.uniques.contains("Cannot enter ocean tiles until Astronomy")
|
if(isOcean && baseUnit.uniques.contains("Cannot enter ocean tiles until Astronomy")
|
||||||
&& !civInfo.tech.isResearched("Astronomy"))
|
&& !civInfo.tech.isResearched("Astronomy"))
|
||||||
return false
|
return false
|
||||||
if(isOcean && baseUnit.uniques.contains("Cannot enter ocean tiles")) return false
|
|
||||||
if(tileOwner!=null && tileOwner.civName!=owner
|
if(tileOwner!=null && tileOwner.civName!=owner
|
||||||
&& (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner))) return false
|
&& (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner))) return false
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -92,8 +92,19 @@ class TileMap {
|
||||||
fun getViewableTiles(position: Vector2, sightDistance: Int): MutableList<TileInfo> {
|
fun getViewableTiles(position: Vector2, sightDistance: Int): MutableList<TileInfo> {
|
||||||
val viewableTiles = getTilesInDistance(position, 1).toMutableList()
|
val viewableTiles = getTilesInDistance(position, 1).toMutableList()
|
||||||
for (i in 1..sightDistance) { // in each layer,
|
for (i in 1..sightDistance) { // in each layer,
|
||||||
getTilesAtDistance(position, i).filterTo(viewableTiles) // take only tiles which have a visible neighbor, which is lower than the tile
|
// This is so we don't use tiles in the same distance to "see over",
|
||||||
{ tile -> tile.neighbors.any{viewableTiles.contains(it) && (it.getHeight() ==0 || it.getHeight() < tile.getHeight())} }
|
// that is to say, the "viewableTiles.contains(it) check will return false for neighbors from the same distance
|
||||||
|
val tilesToAddInDistanceI = ArrayList<TileInfo>()
|
||||||
|
|
||||||
|
for (tile in getTilesAtDistance(position, i)) { // for each tile in that layer,
|
||||||
|
val tileHeight = tile.getHeight()
|
||||||
|
val containsViewableNeighborThatCanSeeOver = tile.neighbors.any {
|
||||||
|
val neighborHeight = it.getHeight()
|
||||||
|
viewableTiles.contains(it) && (neighborHeight == 0 || neighborHeight < tileHeight)
|
||||||
|
}
|
||||||
|
if (containsViewableNeighborThatCanSeeOver) tilesToAddInDistanceI.add(tile)
|
||||||
|
}
|
||||||
|
viewableTiles.addAll(tilesToAddInDistanceI)
|
||||||
}
|
}
|
||||||
|
|
||||||
return viewableTiles
|
return viewableTiles
|
||||||
|
|
|
@ -19,13 +19,13 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
|
||||||
if (unit.civInfo.tech.getUniques().contains("Improves movement speed on roads")) return 1 / 3f
|
if (unit.civInfo.tech.getUniques().contains("Improves movement speed on roads")) return 1 / 3f
|
||||||
else return 1 / 2f
|
else return 1 / 2f
|
||||||
}
|
}
|
||||||
if (unit.hasUnique("Ignores terrain cost")) return 1f
|
if (unit.ignoresTerrainCost) return 1f
|
||||||
|
|
||||||
if (unit.hasUnique("Rough terrain penalty")
|
if (unit.roughTerrainPenalty
|
||||||
&& (to.baseTerrain == "Hill" || to.terrainFeature == "Forest" || to.terrainFeature == "Jungle"))
|
&& (to.baseTerrain == "Hill" || to.terrainFeature == "Forest" || to.terrainFeature == "Jungle"))
|
||||||
return 4f
|
return 4f
|
||||||
|
|
||||||
if(unit.hasUnique("Double movement in coast") && to.baseTerrain=="Coast")
|
if(unit.doubleMovementInCoast && to.baseTerrain=="Coast")
|
||||||
return 1/2f
|
return 1/2f
|
||||||
|
|
||||||
return to.getLastTerrain().movementCost.toFloat() // no road
|
return to.getLastTerrain().movementCost.toFloat() // no road
|
||||||
|
|
Loading…
Reference in a new issue