mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-30 14:48:56 +07:00
Console: Simplified input validation, with exception throwing
This commit is contained in:
@ -12,9 +12,18 @@ interface ConsoleCommand {
|
||||
fun autocomplete(params: List<String>): String? = ""
|
||||
}
|
||||
|
||||
class ConsoleHintException(val hint:String):Exception()
|
||||
class ConsoleErrorException(val error:String):Exception()
|
||||
|
||||
class ConsoleAction(val action: (console: DevConsolePopup, params: List<String>) -> DevConsoleResponse) : ConsoleCommand {
|
||||
override fun handle(console: DevConsolePopup, params: List<String>): DevConsoleResponse {
|
||||
return action(console, params)
|
||||
return try {
|
||||
action(console, params)
|
||||
} catch (hintException: ConsoleHintException) {
|
||||
DevConsoleResponse.hint(hintException.hint)
|
||||
} catch (errorException: ConsoleErrorException) {
|
||||
DevConsoleResponse.error(errorException.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,16 +65,22 @@ class ConsoleCommandRoot : ConsoleCommandNode {
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun validateFormat(format: String, params:List<String>){
|
||||
val allParams = format.split(" ")
|
||||
val requiredParamsAmount = allParams.count { it.startsWith('<') }
|
||||
val optionalParamsAmount = allParams.count { it.startsWith('[') }
|
||||
if (params.size < requiredParamsAmount || params.size > requiredParamsAmount + optionalParamsAmount)
|
||||
throw ConsoleHintException("Format: $format")
|
||||
}
|
||||
|
||||
class ConsoleUnitCommands : ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
|
||||
"add" to ConsoleAction { console, params ->
|
||||
if (params.size != 2)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: unit add <civName> <unitName>")
|
||||
val selectedTile = console.screen.mapHolder.selectedTile
|
||||
?: return@ConsoleAction DevConsoleResponse.error("No tile selected")
|
||||
validateFormat("unit add <civName> <unitName>", params)
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val civ = console.getCivByName(params[0])
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown civ")
|
||||
val baseUnit = console.gameInfo.ruleset.units.values.firstOrNull { it.name.toCliInput() == params[1] }
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown unit")
|
||||
civ.units.placeUnitNearTile(selectedTile.position, baseUnit)
|
||||
@ -73,19 +88,15 @@ class ConsoleUnitCommands : ConsoleCommandNode {
|
||||
},
|
||||
|
||||
"remove" to ConsoleAction { console, params ->
|
||||
if (params.isNotEmpty())
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: unit remove")
|
||||
validateFormat("unit remove", params)
|
||||
val unit = console.getSelectedUnit()
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Select tile with unit")
|
||||
unit.destroy()
|
||||
return@ConsoleAction DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"addpromotion" to ConsoleAction { console, params ->
|
||||
if (params.size != 1)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: unit addpromotion <promotionName>")
|
||||
validateFormat("unit addpromotion <promotionName>", params)
|
||||
val unit = console.getSelectedUnit()
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Select tile with unit")
|
||||
val promotion = console.gameInfo.ruleset.unitPromotions.values.firstOrNull { it.name.toCliInput() == params[0] }
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown promotion")
|
||||
unit.promotions.addPromotion(promotion.name, true)
|
||||
@ -93,10 +104,8 @@ class ConsoleUnitCommands : ConsoleCommandNode {
|
||||
},
|
||||
|
||||
"removepromotion" to ConsoleAction { console, params ->
|
||||
if (params.size != 1)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: unit removepromotion <promotionName>")
|
||||
validateFormat("unit removepromotion <promotionName>", params)
|
||||
val unit = console.getSelectedUnit()
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Select tile with unit")
|
||||
val promotion = unit.promotions.getPromotions().firstOrNull { it.name.toCliInput() == params[0] }
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Promotion not found on unit")
|
||||
// No such action in-game so we need to manually update
|
||||
@ -107,12 +116,10 @@ class ConsoleUnitCommands : ConsoleCommandNode {
|
||||
},
|
||||
|
||||
"setmovement" to ConsoleAction { console, params ->
|
||||
if (params.size != 1)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: unit setmovement <amount>")
|
||||
validateFormat("unit setmovement <amount>", params)
|
||||
val movement = params[0].toFloatOrNull()
|
||||
if (movement == null || movement < 0) return@ConsoleAction DevConsoleResponse.error("Invalid number")
|
||||
val unit = console.getSelectedUnit()
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Select tile with unit")
|
||||
unit.currentMovement = movement
|
||||
return@ConsoleAction DevConsoleResponse.OK
|
||||
}
|
||||
@ -123,12 +130,9 @@ class ConsoleCityCommands : ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
|
||||
"add" to ConsoleAction { console, params ->
|
||||
if (params.size != 1)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: city add <civName>")
|
||||
validateFormat("city add <civName>", params)
|
||||
val civ = console.getCivByName(params[0])
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown civ")
|
||||
val selectedTile = console.screen.mapHolder.selectedTile
|
||||
?: return@ConsoleAction DevConsoleResponse.error("No tile selected")
|
||||
val selectedTile = console.getSelectedTile()
|
||||
if (selectedTile.isCityCenter())
|
||||
return@ConsoleAction DevConsoleResponse.error("Tile already contains a city center")
|
||||
civ.addCity(selectedTile.position)
|
||||
@ -136,34 +140,25 @@ class ConsoleCityCommands : ConsoleCommandNode {
|
||||
},
|
||||
|
||||
"remove" to ConsoleAction { console, params ->
|
||||
if (params.isNotEmpty())
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: city remove")
|
||||
val selectedTile = console.screen.mapHolder.selectedTile
|
||||
?: return@ConsoleAction DevConsoleResponse.error("No tile selected")
|
||||
val city = selectedTile.getCity()
|
||||
?: return@ConsoleAction DevConsoleResponse.error("No city in selected tile")
|
||||
validateFormat("city remove", params)
|
||||
val city = console.getSelectedCity()
|
||||
city.destroyCity(overrideSafeties = true)
|
||||
return@ConsoleAction DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setpop" to ConsoleAction { console, params ->
|
||||
if (params.size != 2)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: city setpop <cityName> <amount>")
|
||||
val newPop = params[1].toIntOrNull() ?: return@ConsoleAction DevConsoleResponse.error("Invalid amount " + params[1])
|
||||
if (newPop < 1) return@ConsoleAction DevConsoleResponse.error("Invalid amount $newPop")
|
||||
val city = console.gameInfo.getCities().firstOrNull { it.name.toCliInput() == params[0] }
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown city")
|
||||
validateFormat("city setpop <amount>", params)
|
||||
val city = console.getSelectedCity()
|
||||
val newPop = console.getInt(params[0])
|
||||
if (newPop < 1) return@ConsoleAction DevConsoleResponse.error("Population must be at least 1")
|
||||
city.population.setPopulation(newPop)
|
||||
return@ConsoleAction DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"addtile" to ConsoleAction { console, params ->
|
||||
if (params.size != 1)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: city addtile <cityName>")
|
||||
val selectedTile = console.screen.mapHolder.selectedTile
|
||||
?: return@ConsoleAction DevConsoleResponse.error("No tile selected")
|
||||
val city = console.gameInfo.getCities().firstOrNull { it.name.toCliInput() == params[0] }
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown city")
|
||||
validateFormat("city addtile <cityName>", params)
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val city = console.getCity(params[0])
|
||||
if (selectedTile.neighbors.none { it.getCity() == city })
|
||||
return@ConsoleAction DevConsoleResponse.error("Tile is not adjacent to any tile already owned by the city")
|
||||
city.expansion.takeOwnership(selectedTile)
|
||||
@ -171,24 +166,19 @@ class ConsoleCityCommands : ConsoleCommandNode {
|
||||
},
|
||||
|
||||
"removetile" to ConsoleAction { console, params ->
|
||||
if (params.isNotEmpty())
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: city removetile")
|
||||
val selectedTile = console.screen.mapHolder.selectedTile
|
||||
?: return@ConsoleAction DevConsoleResponse.error("No tile selected")
|
||||
val city = selectedTile.getCity() ?: return@ConsoleAction DevConsoleResponse.error("No city for selected tile")
|
||||
validateFormat("city removetile", params)
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val city = console.getSelectedCity()
|
||||
city.expansion.relinquishOwnership(selectedTile)
|
||||
return@ConsoleAction DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"religion" to ConsoleAction { console, params ->
|
||||
if (params.size != 2)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: city religion <name> <±pressure>")
|
||||
val city = console.screen.bottomUnitTable.selectedCity
|
||||
?: return@ConsoleAction DevConsoleResponse.hint("Select a city first")
|
||||
validateFormat("city religion <name> <±pressure>", params)
|
||||
val city = console.getSelectedCity()
|
||||
val religion = city.civ.gameInfo.religions.keys.firstOrNull { it.toCliInput() == params[0] }
|
||||
?: return@ConsoleAction DevConsoleResponse.error("'${params[0]}' is not a known religion")
|
||||
val pressure = params[1].toIntOrNull()
|
||||
?: return@ConsoleAction DevConsoleResponse.error("'${params[1]}' is not an integer")
|
||||
val pressure = console.getInt(params[1])
|
||||
city.religion.addPressure(religion, pressure.coerceAtLeast(-city.religion.getPressures()[religion]))
|
||||
city.religion.updatePressureOnPopulationChange(0)
|
||||
return@ConsoleAction DevConsoleResponse.OK
|
||||
@ -200,36 +190,29 @@ class ConsoleTileCommands: ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
|
||||
"setimprovement" to ConsoleAction { console, params ->
|
||||
if (params.size != 1 && params.size != 2)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: tile setimprovement <improvementName> [<civName>]")
|
||||
val selectedTile = console.screen.mapHolder.selectedTile
|
||||
?: return@ConsoleAction DevConsoleResponse.error("No tile selected")
|
||||
validateFormat("tile setimprovement <improvementName> [civName]", params)
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val improvement = console.gameInfo.ruleset.tileImprovements.values.firstOrNull {
|
||||
it.name.toCliInput() == params[0]
|
||||
} ?: return@ConsoleAction DevConsoleResponse.error("Unknown improvement")
|
||||
var civ:Civilization? = null
|
||||
var civ: Civilization? = null
|
||||
if (params.size == 2){
|
||||
civ = console.getCivByName(params[1])
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown civ")
|
||||
}
|
||||
selectedTile.improvementFunctions.changeImprovement(improvement.name, civ)
|
||||
return@ConsoleAction DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removeimprovement" to ConsoleAction { console, params ->
|
||||
if (params.isNotEmpty())
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: tile removeimprovement")
|
||||
val selectedTile = console.screen.mapHolder.selectedTile
|
||||
?: return@ConsoleAction DevConsoleResponse.error("No tile selected")
|
||||
validateFormat("tile removeimprovement", params)
|
||||
val selectedTile = console.getSelectedTile()
|
||||
selectedTile.improvementFunctions.changeImprovement(null)
|
||||
return@ConsoleAction DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"addfeature" to ConsoleAction { console, params ->
|
||||
if (params.size != 1)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: tile addfeature <featureName>")
|
||||
val selectedTile = console.screen.mapHolder.selectedTile
|
||||
?: return@ConsoleAction DevConsoleResponse.error("No tile selected")
|
||||
validateFormat("tile addfeature <featureName>", params)
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val feature = console.gameInfo.ruleset.terrains.values
|
||||
.firstOrNull { it.type == TerrainType.TerrainFeature && it.name.toCliInput() == params[0] }
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown feature")
|
||||
@ -238,10 +221,8 @@ class ConsoleTileCommands: ConsoleCommandNode {
|
||||
},
|
||||
|
||||
"removefeature" to ConsoleAction { console, params ->
|
||||
if (params.size != 1)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: tile addfeature <featureName>")
|
||||
val selectedTile = console.screen.mapHolder.selectedTile
|
||||
?: return@ConsoleAction DevConsoleResponse.error("No tile selected")
|
||||
validateFormat("tile addfeature <featureName>", params)
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val feature = console.gameInfo.ruleset.terrains.values
|
||||
.firstOrNull { it.type == TerrainType.TerrainFeature && it.name.toCliInput() == params[0] }
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown feature")
|
||||
@ -255,16 +236,13 @@ class ConsoleCivCommands : ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
"add" to ConsoleAction { console, params ->
|
||||
var statPos = 0
|
||||
if (params.size !in 2..3)
|
||||
return@ConsoleAction DevConsoleResponse.hint("Format: civ add [civ] <stat> <amount>")
|
||||
validateFormat("civ add [civ] <stat> <amount>", params)
|
||||
val civ = if (params.size == 2) console.screen.selectedCiv
|
||||
else {
|
||||
statPos++
|
||||
console.getCivByName(params[0])
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown civ")
|
||||
}
|
||||
val amount = params[statPos+1].toIntOrNull()
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Whut? \"${params[statPos+1]}\" is not a number!")
|
||||
val amount = console.getInt(params[statPos+1])
|
||||
val stat = Stat.safeValueOf(params[statPos].replaceFirstChar(Char::titlecase))
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Whut? \"${params[statPos]}\" is not a Stat!")
|
||||
if (stat !in Stat.statsWithCivWideField)
|
||||
@ -274,10 +252,8 @@ class ConsoleCivCommands : ConsoleCommandNode {
|
||||
},
|
||||
|
||||
"setplayertype" to ConsoleAction { console, params ->
|
||||
if (params.size != 2) return@ConsoleAction DevConsoleResponse.hint("Format: civ setplayertype <civName> <ai/human>")
|
||||
|
||||
validateFormat("civ setplayertype <civName> <ai/human>", params)
|
||||
val civ = console.getCivByName(params[0])
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Unknown civ")
|
||||
val playerType = PlayerType.values().firstOrNull { it.name.lowercase() == params[1].lowercase() }
|
||||
?: return@ConsoleAction DevConsoleResponse.error("Invalid player type, valid options are 'ai' or 'human'")
|
||||
civ.playerType = playerType
|
||||
|
@ -85,14 +85,25 @@ class DevConsolePopup(val screen: WorldScreen) : Popup(screen) {
|
||||
}
|
||||
|
||||
internal fun getCivByName(name: String) = gameInfo.civilizations.firstOrNull { it.civName.toCliInput() == name }
|
||||
?: throw ConsoleErrorException("Unknown civ: $name")
|
||||
|
||||
internal fun getSelectedUnit(): MapUnit? {
|
||||
val selectedTile = screen.mapHolder.selectedTile ?: return null
|
||||
if (selectedTile.getFirstUnit() == null) return null
|
||||
internal fun getSelectedTile() = screen.mapHolder.selectedTile ?: throw ConsoleErrorException("Select tile")
|
||||
|
||||
/** Gets city by selected tile */
|
||||
internal fun getSelectedCity() = getSelectedTile().getCity() ?: throw ConsoleErrorException("Select tile belonging to city")
|
||||
|
||||
internal fun getCity(cityName:String) = gameInfo.getCities().firstOrNull { it.name.toCliInput() == cityName }
|
||||
?: throw ConsoleErrorException("Unknown city: $cityName")
|
||||
|
||||
internal fun getSelectedUnit(): MapUnit {
|
||||
val selectedTile = getSelectedTile()
|
||||
if (selectedTile.getFirstUnit() == null) throw ConsoleErrorException("Select tile with units")
|
||||
val units = selectedTile.getUnits().toList()
|
||||
val selectedUnit = screen.bottomUnitTable.selectedUnit
|
||||
return if (selectedUnit != null && selectedUnit.getTile() == selectedTile) selectedUnit
|
||||
else units.first()
|
||||
}
|
||||
|
||||
internal fun getInt(param: String) = param.toIntOrNull() ?: throw ConsoleErrorException("$param is not a valid number")
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user