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"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 28
|
||||
versionCode 181
|
||||
versionCode 182
|
||||
versionName "2.11.0"
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class UnCivGame : Game() {
|
|||
val viewEntireMapForDebug = false
|
||||
|
||||
// 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
|
||||
|
||||
|
|
|
@ -12,6 +12,12 @@ import java.util.*
|
|||
class TechManager {
|
||||
@Transient lateinit var civInfo: CivilizationInfo
|
||||
@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 techsResearched = HashSet<String>()
|
||||
|
@ -56,7 +62,7 @@ class TechManager {
|
|||
return GameBasics.Technologies[TechName]!!.prerequisites.all { isResearched(it) }
|
||||
}
|
||||
|
||||
fun getUniques() = researchedTechnologies.flatMap { it.uniques }
|
||||
fun getUniques() = researchedTechUniques
|
||||
|
||||
//endregion
|
||||
|
||||
|
@ -103,7 +109,11 @@ class TechManager {
|
|||
techsResearched.add(techName)
|
||||
|
||||
// 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)
|
||||
|
||||
|
@ -144,7 +154,13 @@ class TechManager {
|
|||
techsToResearch.remove("Mass Media")
|
||||
|
||||
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 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 name: String
|
||||
var currentMovement: Float = 0f
|
||||
|
@ -81,6 +88,10 @@ class MapUnit {
|
|||
uniques.addAll(baseUnit.uniques)
|
||||
uniques.addAll(promotions.promotions.map { GameBasics.UnitPromotions[it]!!.effect })
|
||||
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 {
|
||||
|
@ -116,23 +127,26 @@ class MapUnit {
|
|||
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{
|
||||
val tileOwner = tile.getOwner()
|
||||
|
||||
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())
|
||||
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")
|
||||
&& !civInfo.tech.isResearched("Astronomy"))
|
||||
return false
|
||||
if(isOcean && baseUnit.uniques.contains("Cannot enter ocean tiles")) return false
|
||||
if(tileOwner!=null && tileOwner.civName!=owner
|
||||
&& (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner))) return false
|
||||
return true
|
||||
|
|
|
@ -92,8 +92,19 @@ class TileMap {
|
|||
fun getViewableTiles(position: Vector2, sightDistance: Int): MutableList<TileInfo> {
|
||||
val viewableTiles = getTilesInDistance(position, 1).toMutableList()
|
||||
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
|
||||
{ tile -> tile.neighbors.any{viewableTiles.contains(it) && (it.getHeight() ==0 || it.getHeight() < tile.getHeight())} }
|
||||
// This is so we don't use tiles in the same distance to "see over",
|
||||
// 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
|
||||
|
|
|
@ -19,13 +19,13 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
|
|||
if (unit.civInfo.tech.getUniques().contains("Improves movement speed on roads")) return 1 / 3f
|
||||
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"))
|
||||
return 4f
|
||||
|
||||
if(unit.hasUnique("Double movement in coast") && to.baseTerrain=="Coast")
|
||||
if(unit.doubleMovementInCoast && to.baseTerrain=="Coast")
|
||||
return 1/2f
|
||||
|
||||
return to.getLastTerrain().movementCost.toFloat() // no road
|
||||
|
|
Loading…
Reference in a new issue