Performance: Added transient builtBuildingObjects list in cittyConstructions, so we won't have to get the list every time we want to calculate, well, loads of stuff

This commit is contained in:
Yair Morgenstern 2018-11-27 23:31:40 +02:00
parent ea68a70823
commit 324176d098
8 changed files with 71 additions and 32 deletions

View File

@ -143,14 +143,14 @@ class Battle(val gameInfo:GameInfo) {
}
if(city.cityConstructions.isBuilt("Palace")){
city.cityConstructions.builtBuildings.remove("Palace")
city.cityConstructions.removeBuilding("Palace")
if(enemyCiv.isDefeated()) {
gameInfo.getPlayerCivilization()
.addNotification("The civilization of [${enemyCiv.civName}] has been destroyed!", null, Color.RED)
enemyCiv.getCivUnits().forEach { it.destroy() }
}
else if(enemyCiv.cities.isNotEmpty()){
enemyCiv.cities.first().cityConstructions.builtBuildings.add("Palace") // relocate palace
enemyCiv.cities.first().cityConstructions.addBuilding("Palace") // relocate palace
}
}

View File

@ -6,12 +6,15 @@ import com.unciv.models.gamebasics.Building
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.stats.Stats
import com.unciv.ui.utils.tr
import com.unciv.ui.utils.withItem
import com.unciv.ui.utils.withoutItem
import java.util.*
import kotlin.collections.ArrayList
class CityConstructions {
@Transient
lateinit var cityInfo: CityInfo
@Transient lateinit var cityInfo: CityInfo
@Transient private var builtBuildingObjects=ArrayList<Building>()
var builtBuildings = ArrayList<String>()
private val inProgressConstructions = HashMap<String, Int>()
@ -89,7 +92,7 @@ class CityConstructions {
throw NotBuildingOrUnitException("$constructionName is not a building or a unit!")
}
internal fun getBuiltBuildings(): List<Building> = builtBuildings.toList().map { GameBasics.Buildings[it]!! } // toList os to avoid concurrency problems
internal fun getBuiltBuildings(): List<Building> = builtBuildingObjects // toList os to avoid concurrency problems
fun containsBuildingOrEquivalent(building: String): Boolean =
isBuilt(building) || getBuiltBuildings().any{it.replaces==building}
@ -113,9 +116,13 @@ class CityConstructions {
//endregion
//region state changing functions
fun addConstruction(constructionToAdd: Int) {
fun setTransients(){
builtBuildingObjects = ArrayList(builtBuildings.map { GameBasics.Buildings[it]!! })
}
fun addProduction(productionToAdd: Int) {
if (!inProgressConstructions.containsKey(currentConstruction)) inProgressConstructions[currentConstruction] = 0
inProgressConstructions[currentConstruction] = inProgressConstructions[currentConstruction]!! + constructionToAdd
inProgressConstructions[currentConstruction] = inProgressConstructions[currentConstruction]!! + productionToAdd
}
fun nextTurn(cityStats: Stats) {
@ -136,26 +143,41 @@ class CityConstructions {
var productionToAdd = cityStats.production
if(!cityInfo.civInfo.isPlayerCivilization())
productionToAdd *= cityInfo.civInfo.gameInfo.getPlayerCivilization().getDifficulty().aiConstructionModifier
addConstruction(Math.round(cityStats.production))
addProduction(Math.round(cityStats.production))
val productionCost = construction.getProductionCost(cityInfo.civInfo.policies.adoptedPolicies)
if (inProgressConstructions[currentConstruction]!! >= productionCost) {
construction.postBuildEvent(this)
inProgressConstructions.remove(currentConstruction)
if(construction is Building && construction.isWonder && construction.requiredBuildingInAllCities==null) {
val playerCiv = cityInfo.civInfo.gameInfo.getPlayerCivilization()
val builtLocation = if(playerCiv.exploredTiles.contains(cityInfo.location)) cityInfo.name else "a faraway land"
playerCiv.addNotification("[$currentConstruction] has been built in [$builtLocation]", cityInfo.location, Color.BROWN)
}
else
cityInfo.civInfo.addNotification("[$currentConstruction] has been built in [" + cityInfo.name+"]", cityInfo.location, Color.BROWN)
currentConstruction=""
Automation().chooseNextConstruction(this)
constructionComplete(construction)
}
}
fun constructionComplete(construction: IConstruction) {
construction.postBuildEvent(this)
inProgressConstructions.remove(currentConstruction)
if (construction is Building && construction.isWonder && construction.requiredBuildingInAllCities == null) {
val playerCiv = cityInfo.civInfo.gameInfo.getPlayerCivilization()
val builtLocation = if (playerCiv.exploredTiles.contains(cityInfo.location)) cityInfo.name else "a faraway land"
playerCiv.addNotification("[$currentConstruction] has been built in [$builtLocation]", cityInfo.location, Color.BROWN)
} else
cityInfo.civInfo.addNotification("[$currentConstruction] has been built in [" + cityInfo.name + "]", cityInfo.location, Color.BROWN)
currentConstruction = ""
Automation().chooseNextConstruction(this)
}
fun addBuilding(buildingName:String){
val buildingObject = GameBasics.Buildings[buildingName]!!
builtBuildingObjects = builtBuildingObjects.withItem(buildingObject)
builtBuildings.add(buildingName)
}
fun removeBuilding(buildingName:String){
val buildingObject = GameBasics.Buildings[buildingName]!!
builtBuildingObjects = builtBuildingObjects.withoutItem(buildingObject)
builtBuildings.remove(buildingName)
}
fun purchaseBuilding(buildingName: String) {
cityInfo.civInfo.gold -= getConstruction(buildingName).getGoldCost(cityInfo.civInfo.policies.adoptedPolicies)
getConstruction(buildingName).postBuildEvent(this)

View File

@ -54,7 +54,7 @@ class CityInfo {
civInfo.addNotification("[$name] has been founded!", cityLocation, Color.PURPLE)
if (civInfo.policies.isAdopted("Legalism") && civInfo.cities.size <= 4) cityConstructions.addCultureBuilding()
if (civInfo.cities.size == 1) {
cityConstructions.builtBuildings.add("Palace")
cityConstructions.addBuilding("Palace")
cityConstructions.currentConstruction = "Worker" // Default for first city only!
}
@ -159,7 +159,7 @@ class CityInfo {
expansion.setTransients()
cityStats.cityInfo = this
cityConstructions.cityInfo = this
cityConstructions.setTransients()
}
fun endTurn() {
@ -178,7 +178,7 @@ class CityInfo {
civInfo.addNotification("[$name] has been razed to the ground!",location, Color.RED)
destroyCity()
if(isCapital() && civInfo.cities.isNotEmpty()) // Yes, we actually razed the capital. Some people do this.
civInfo.cities.first().cityConstructions.builtBuildings.add("Palace")
civInfo.cities.first().cityConstructions.addBuilding("Palace")
}
}
else population.nextTurn(stats.food)
@ -206,7 +206,7 @@ class CityInfo {
// Remove all national wonders
for(building in cityConstructions.getBuiltBuildings().filter { it.requiredBuildingInAllCities!=null })
cityConstructions.builtBuildings.remove(building.name)
cityConstructions.removeBuilding(building.name)
isBeingRazed=false
}
//endregion

View File

@ -210,7 +210,7 @@ class CityStats {
stats.production += 5f
if(policies.contains("Warrior Code") && currentConstruction is BaseUnit && currentConstruction.unitType.isMelee())
stats.production += 20
if (policies.contains("Reformation") && cityConstructions.builtBuildings.any { GameBasics.Buildings[it]!!.isWonder })
if (policies.contains("Reformation") && cityConstructions.getBuiltBuildings().any { it.isWonder })
stats.culture += 33f
if (policies.contains("Commerce") && cityInfo.isCapital())
stats.gold += 25f

View File

@ -6,6 +6,7 @@ import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tech.Technology
import com.unciv.models.gamebasics.unit.BaseUnit
import com.unciv.ui.utils.tr
import com.unciv.ui.utils.withItem
import java.util.*
class TechManager {
@ -77,9 +78,7 @@ class TechManager {
techsResearched.add(currentTechnology)
// this is to avoid concurrent modification problems
val newResearchedTechnologies = ArrayList(researchedTechnologies)
newResearchedTechnologies.add(GameBasics.Technologies[currentTechnology]!!)
researchedTechnologies = newResearchedTechnologies
researchedTechnologies = researchedTechnologies.withItem(GameBasics.Technologies[currentTechnology]!!)
civInfo.addNotification("Research of [$currentTechnology] has completed!", null, Color.BLUE)

View File

@ -214,10 +214,10 @@ class Building : NamedStats(), IConstruction{
civInfo.scienceVictory.currentParts.add(name, 1)
return
}
construction.builtBuildings.add(name)
construction.addBuilding(name)
if (providesFreeBuilding != null && !construction.builtBuildings.contains(providesFreeBuilding!!))
construction.builtBuildings.add(providesFreeBuilding!!)
construction.addBuilding(providesFreeBuilding!!)
when {
"Empire enters golden age" in uniques-> civInfo.goldenAges.enterGoldenAge()
"Free Great Artist Appears" in uniques-> civInfo.addGreatPerson("Great Artist")

View File

@ -203,4 +203,22 @@ fun Table.addSeparator(): Cell<Image> {
val cell = add(image).colspan(columns).fill()
row()
return cell
}
/**
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
*/
fun <T> ArrayList<T>.withItem(item:T): ArrayList<T> {
val newArrayList = ArrayList(this)
newArrayList.add(item)
return newArrayList
}
/**
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
*/
fun <T> ArrayList<T>.withoutItem(item:T): ArrayList<T> {
val newArrayList = ArrayList(this)
newArrayList.remove(item)
return newArrayList
}

View File

@ -168,7 +168,7 @@ class UnitActions {
if (unit.name == "Great Engineer" && !unit.isEmbarked()) {
actionList += UnitAction( "Hurry Wonder",
{
tile.getCity()!!.cityConstructions.addConstruction(300 + 30 * tile.getCity()!!.population.population) //http://civilization.wikia.com/wiki/Great_engineer_(Civ5)
tile.getCity()!!.cityConstructions.addProduction(300 + 30 * tile.getCity()!!.population.population) //http://civilization.wikia.com/wiki/Great_engineer_(Civ5)
unit.destroy()
},
unit.currentMovement != 0f &&