mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-05 15:59:50 +07:00
Map editor update - concurrency, resource amounts, file double-click (#9461)
This commit is contained in:
@ -501,6 +501,7 @@ Map copy and paste =
|
||||
Position: [param] =
|
||||
Starting location(s): [param] =
|
||||
Continent: [param] ([amount] tiles) =
|
||||
Resource abundance =
|
||||
Change map to fit selected ruleset? =
|
||||
Area: [amount] tiles, [amount2] continents/islands =
|
||||
Area: [amount] tiles, [amount2]% water, [amount3] continents/islands =
|
||||
|
@ -8,9 +8,11 @@ import com.unciv.logic.city.City
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.logic.map.HexMath
|
||||
import com.unciv.logic.map.MapParameters // Kdoc only
|
||||
import com.unciv.logic.map.MapResources
|
||||
import com.unciv.logic.map.TileMap
|
||||
import com.unciv.logic.map.mapunit.MapUnit
|
||||
import com.unciv.logic.map.mapunit.UnitMovement // Kdoc only
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
import com.unciv.models.ruleset.tile.Terrain
|
||||
@ -676,7 +678,7 @@ open class Tile : IsPartOfGameInfoSerialization {
|
||||
|
||||
/**
|
||||
* @returns whether units of [civInfo] can pass through this tile, considering only civ-wide filters.
|
||||
* Use [UnitMovementAlgorithms.canPassThrough] to check whether a specific unit can pass through a tile.
|
||||
* Use [UnitMovement.canPassThrough] to check whether a specific unit can pass through a tile.
|
||||
*/
|
||||
fun canCivPassThrough(civInfo: Civilization): Boolean {
|
||||
val tileOwner = getOwner()
|
||||
@ -785,7 +787,10 @@ open class Tile : IsPartOfGameInfoSerialization {
|
||||
fun setTileResource(newResource: TileResource, majorDeposit: Boolean? = null, rng: Random = Random.Default) {
|
||||
resource = newResource.name
|
||||
|
||||
if (newResource.resourceType != ResourceType.Strategic) return
|
||||
if (newResource.resourceType != ResourceType.Strategic) {
|
||||
resourceAmount = 0
|
||||
return
|
||||
}
|
||||
|
||||
for (unique in newResource.getMatchingUniques(UniqueType.ResourceAmountOnTiles, StateForConditionals(tile = this))) {
|
||||
if (matchesTerrainFilter(unique.params[0])) {
|
||||
|
@ -83,6 +83,7 @@ class TileLayerMisc(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, si
|
||||
private var hexOutlineIcon: Actor? = null
|
||||
|
||||
private var resourceName: String? = null
|
||||
private var resourceAmount: Int = -1
|
||||
private var resourceIcon: Actor? = null
|
||||
|
||||
private var workedIcon: Actor? = null
|
||||
@ -168,15 +169,16 @@ class TileLayerMisc(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, si
|
||||
}
|
||||
|
||||
// If resource has changed (e.g. tech researched) - force new icon next time it's needed
|
||||
if (resourceName != tile().resource) {
|
||||
if (resourceName != tile().resource || resourceAmount != tile().resourceAmount) {
|
||||
resourceName = tile().resource
|
||||
resourceAmount = tile().resourceAmount
|
||||
resourceIcon?.remove()
|
||||
resourceIcon = null
|
||||
}
|
||||
|
||||
// Get a fresh Icon if and only if necessary
|
||||
if (resourceName != null && effectiveVisible && resourceIcon == null) {
|
||||
val icon = ImageGetter.getResourcePortrait(resourceName!!, 20f, tile().resourceAmount)
|
||||
val icon = ImageGetter.getResourcePortrait(resourceName!!, 20f, resourceAmount)
|
||||
icon.center(tileGroup)
|
||||
icon.x -= 22 // left
|
||||
icon.y += 10 // top
|
||||
|
@ -12,13 +12,15 @@ import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
import com.unciv.ui.components.extensions.keyShortcuts
|
||||
import com.unciv.ui.components.extensions.onClick
|
||||
import com.unciv.ui.components.extensions.onDoubleClick
|
||||
import com.unciv.ui.components.extensions.pad
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
|
||||
class MapEditorFilesTable(
|
||||
initWidth: Float,
|
||||
private val includeMods: Boolean = false,
|
||||
private val onSelect: (FileHandle) -> Unit
|
||||
private val onSelect: (FileHandle) -> Unit,
|
||||
private val onDoubleClick: () -> Unit
|
||||
): Table(BaseScreen.skin) {
|
||||
private var selectedIndex = -1
|
||||
|
||||
@ -41,7 +43,7 @@ class MapEditorFilesTable(
|
||||
onSelect(sortedFiles[row].file)
|
||||
}
|
||||
|
||||
fun moveSelection(delta: Int) {
|
||||
private fun moveSelection(delta: Int) {
|
||||
selectedIndex = when {
|
||||
selectedIndex + delta in sortedFiles.indices ->
|
||||
selectedIndex + delta
|
||||
@ -92,6 +94,10 @@ class MapEditorFilesTable(
|
||||
mapButton.onClick {
|
||||
markSelection(mapButton, index)
|
||||
}
|
||||
mapButton.onDoubleClick {
|
||||
markSelection(mapButton, index)
|
||||
onDoubleClick()
|
||||
}
|
||||
add(mapButton).row()
|
||||
}
|
||||
layout()
|
||||
|
@ -22,12 +22,15 @@ import com.unciv.ui.components.KeyCharAndCode
|
||||
import com.unciv.ui.components.KeyboardPanningListener
|
||||
import com.unciv.ui.screens.basescreen.RecreateOnResize
|
||||
import com.unciv.ui.screens.worldscreen.ZoomButtonPair
|
||||
import com.unciv.utils.Concurrency
|
||||
import com.unciv.utils.Dispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
|
||||
//todo normalize properly
|
||||
|
||||
//todo Remove "Area: [amount] tiles, [amount2] continents/islands = " after 2022-07-01
|
||||
//todo Direct Strategic Resource abundance control
|
||||
//todo functional Tab for Units (empty Tab is prepared but commented out in MapEditorEditTab.AllEditSubTabs)
|
||||
//todo copy/paste tile areas? (As tool tab, brush sized, floodfill forbidden, tab displays copied area)
|
||||
//todo Synergy with Civilopedia for drawing loose tiles / terrain icons
|
||||
@ -73,6 +76,9 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen(), RecreateOnResize {
|
||||
|
||||
private val highlightedTileGroups = mutableListOf<TileGroup>()
|
||||
|
||||
// Control of background jobs - make them cancel on context changes like exit editor or resize screen
|
||||
private val jobs = ArrayDeque<Job>(3)
|
||||
|
||||
init {
|
||||
if (map == null) {
|
||||
ruleset = RulesetCache[BaseRuleset.Civ_V_GnK.fullName]!!
|
||||
@ -189,6 +195,7 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen(), RecreateOnResize {
|
||||
"Do you want to leave without saving the recent changes?",
|
||||
"Leave"
|
||||
) {
|
||||
cancelJobs()
|
||||
game.popScreen()
|
||||
}
|
||||
}
|
||||
@ -216,5 +223,32 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen(), RecreateOnResize {
|
||||
highlightTile(tile, color)
|
||||
}
|
||||
|
||||
override fun recreate(): BaseScreen = MapEditorScreen(tileMap)
|
||||
override fun recreate(): BaseScreen {
|
||||
cancelJobs()
|
||||
return MapEditorScreen(tileMap)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
cancelJobs()
|
||||
super.dispose()
|
||||
}
|
||||
|
||||
fun startBackgroundJob(
|
||||
name: String,
|
||||
isDaemon: Boolean = true,
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
) {
|
||||
val scope = CoroutineScope(if (isDaemon) Dispatcher.DAEMON else Dispatcher.NON_DAEMON)
|
||||
val newJob = Concurrency.run(name, scope, block)
|
||||
jobs.add(newJob)
|
||||
newJob.invokeOnCompletion {
|
||||
jobs.remove(newJob)
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelJobs() {
|
||||
for (job in jobs)
|
||||
job.cancel()
|
||||
jobs.clear()
|
||||
}
|
||||
}
|
||||
|
@ -156,6 +156,7 @@ class MapEditorEditResourcesTab(
|
||||
add(eraser.render(0f).apply { onClick {
|
||||
editTab.setBrush("Remove resource", eraserIcon, true) { tile ->
|
||||
tile.resource = null
|
||||
tile.resourceAmount = 0
|
||||
}
|
||||
} }).padBottom(0f).row()
|
||||
add(
|
||||
@ -165,7 +166,10 @@ class MapEditorEditResourcesTab(
|
||||
) { resourceName ->
|
||||
val resource = ruleset.tileResources[resourceName]!!
|
||||
editTab.setBrush(resourceName, resource.makeLink()) {
|
||||
it.setTileResource(resource, rng = editTab.randomness.RNG)
|
||||
if (it.resource == resourceName && resource.resourceType == ResourceType.Strategic)
|
||||
it.resourceAmount = (it.resourceAmount + 1).coerceAtMost(42)
|
||||
else
|
||||
it.setTileResource(resource, rng = editTab.randomness.RNG)
|
||||
}
|
||||
}).padTop(0f).row()
|
||||
}
|
||||
|
@ -11,26 +11,19 @@ import com.unciv.logic.map.mapgenerator.RiverGenerator
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditFeaturesTab
|
||||
import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditImprovementsTab
|
||||
import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditResourcesTab
|
||||
import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditRiversTab
|
||||
import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditStartsTab
|
||||
import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditTerrainTab
|
||||
import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditWondersTab
|
||||
import com.unciv.ui.screens.mapeditorscreen.MapEditorScreen
|
||||
import com.unciv.ui.screens.mapeditorscreen.TileInfoNormalizer
|
||||
import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorOptionsTab.TileMatchFuzziness
|
||||
import com.unciv.ui.popups.ToastPopup
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
import com.unciv.ui.components.KeyCharAndCode
|
||||
import com.unciv.ui.components.TabbedPager
|
||||
import com.unciv.ui.components.UncivSlider
|
||||
import com.unciv.ui.components.extensions.addSeparator
|
||||
import com.unciv.ui.components.extensions.keyShortcuts
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.popups.ToastPopup
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||
import com.unciv.ui.screens.mapeditorscreen.MapEditorScreen
|
||||
import com.unciv.ui.screens.mapeditorscreen.TileInfoNormalizer
|
||||
import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorOptionsTab.TileMatchFuzziness
|
||||
import com.unciv.utils.Log
|
||||
|
||||
class MapEditorEditTab(
|
||||
@ -190,7 +183,7 @@ class MapEditorEditTab(
|
||||
editorScreen.tileClickHandler = null
|
||||
}
|
||||
|
||||
fun tileClickHandler(tile: Tile) {
|
||||
private fun tileClickHandler(tile: Tile) {
|
||||
if (brushSize < -1 || brushSize > 5 || brushHandlerType == BrushHandlerType.None) return
|
||||
if (editorScreen.mapHolder.isPanning || editorScreen.mapHolder.isZooming()) return
|
||||
editorScreen.hideSelection()
|
||||
|
@ -29,8 +29,8 @@ import com.unciv.ui.components.extensions.onClick
|
||||
import com.unciv.ui.components.extensions.toCheckBox
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.ui.components.extensions.toTextButton
|
||||
import com.unciv.utils.Concurrency
|
||||
import com.unciv.utils.Log
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class MapEditorGenerateTab(
|
||||
private val editorScreen: MapEditorScreen
|
||||
@ -73,7 +73,7 @@ class MapEditorGenerateTab(
|
||||
val mapParameters = editorScreen.newMapParameters.clone() // this clone is very important here
|
||||
val message = mapParameters.mapSize.fixUndesiredSizes(mapParameters.worldWrap)
|
||||
if (message != null) {
|
||||
Gdx.app.postRunnable {
|
||||
Concurrency.runOnGLThread {
|
||||
ToastPopup( message, editorScreen, 4000 )
|
||||
newTab.mapParametersTable.run { mapParameters.mapSize.also {
|
||||
customMapSizeRadius.text = it.radius.toString()
|
||||
@ -113,7 +113,7 @@ class MapEditorGenerateTab(
|
||||
}
|
||||
|
||||
// Map generation can take a while and we don't want ANRs
|
||||
thread(name = "MapGenerator", isDaemon = true) {
|
||||
editorScreen.startBackgroundJob("MapEditor.MapGenerator") {
|
||||
try {
|
||||
val (newRuleset, generator) = if (step > MapGeneratorSteps.Landmass) null to null
|
||||
else {
|
||||
@ -124,7 +124,7 @@ class MapEditorGenerateTab(
|
||||
MapGeneratorSteps.All -> {
|
||||
val generatedMap = generator!!.generateMap(mapParameters)
|
||||
val savedScale = editorScreen.mapHolder.scaleX
|
||||
Gdx.app.postRunnable {
|
||||
Concurrency.runOnGLThread {
|
||||
freshMapCompleted(generatedMap, mapParameters, newRuleset!!, selectPage = 0)
|
||||
editorScreen.mapHolder.zoom(savedScale)
|
||||
}
|
||||
@ -136,7 +136,7 @@ class MapEditorGenerateTab(
|
||||
mapParameters.type = editorScreen.newMapParameters.type
|
||||
generator.generateSingleStep(generatedMap, step)
|
||||
val savedScale = editorScreen.mapHolder.scaleX
|
||||
Gdx.app.postRunnable {
|
||||
Concurrency.runOnGLThread {
|
||||
freshMapCompleted(generatedMap, mapParameters, newRuleset!!, selectPage = 1)
|
||||
editorScreen.mapHolder.zoom(savedScale)
|
||||
}
|
||||
@ -144,14 +144,14 @@ class MapEditorGenerateTab(
|
||||
else -> {
|
||||
editorScreen.tileMap.mapParameters.seed = mapParameters.seed
|
||||
MapGenerator(editorScreen.ruleset).generateSingleStep(editorScreen.tileMap, step)
|
||||
Gdx.app.postRunnable {
|
||||
Concurrency.runOnGLThread {
|
||||
stepCompleted(step)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
Log.error("Exception while generating map", exception)
|
||||
Gdx.app.postRunnable {
|
||||
Concurrency.runOnGLThread {
|
||||
setButtonsEnabled(true)
|
||||
Gdx.input.inputProcessor = editorScreen.stage
|
||||
Popup(editorScreen).apply {
|
||||
|
@ -22,8 +22,10 @@ import com.unciv.ui.components.extensions.isEnabled
|
||||
import com.unciv.ui.components.extensions.keyShortcuts
|
||||
import com.unciv.ui.components.extensions.onActivation
|
||||
import com.unciv.ui.components.extensions.toTextButton
|
||||
import com.unciv.utils.Concurrency
|
||||
import com.unciv.utils.Log
|
||||
import kotlin.concurrent.thread
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.isActive
|
||||
|
||||
class MapEditorLoadTab(
|
||||
private val editorScreen: MapEditorScreen,
|
||||
@ -32,7 +34,9 @@ class MapEditorLoadTab(
|
||||
private val mapFiles = MapEditorFilesTable(
|
||||
initWidth = editorScreen.getToolsWidth() - 20f,
|
||||
includeMods = true,
|
||||
this::selectFile)
|
||||
this::selectFile,
|
||||
this::loadHandler
|
||||
)
|
||||
|
||||
private val loadButton = "Load map".toTextButton()
|
||||
private val deleteButton = "Delete map".toTextButton()
|
||||
@ -53,7 +57,7 @@ class MapEditorLoadTab(
|
||||
val fileTableHeight = editorScreen.stage.height - headerHeight - buttonTable.height - 2f
|
||||
val scrollPane = AutoScrollPane(mapFiles, skin)
|
||||
scrollPane.setOverscroll(false, true)
|
||||
add(scrollPane).height(fileTableHeight).width(editorScreen.getToolsWidth() - 20f).row()
|
||||
add(scrollPane).size(editorScreen.getToolsWidth() - 20f, fileTableHeight).padTop(10f).row()
|
||||
add(buttonTable).row()
|
||||
}
|
||||
|
||||
@ -63,7 +67,7 @@ class MapEditorLoadTab(
|
||||
"Do you want to load another map without saving the recent changes?",
|
||||
"Load map"
|
||||
) {
|
||||
thread(name = "MapLoader", isDaemon = true, block = this::loaderThread)
|
||||
editorScreen.startBackgroundJob("MapLoader") { loaderThread() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,18 +93,18 @@ class MapEditorLoadTab(
|
||||
pager.setScrollDisabled(false)
|
||||
}
|
||||
|
||||
fun selectFile(file: FileHandle?) {
|
||||
private fun selectFile(file: FileHandle?) {
|
||||
chosenMap = file
|
||||
loadButton.isEnabled = (file != null)
|
||||
deleteButton.isEnabled = (file != null)
|
||||
deleteButton.color = if (file != null) Color.SCARLET else Color.BROWN
|
||||
}
|
||||
|
||||
fun loaderThread() {
|
||||
private fun CoroutineScope.loaderThread() {
|
||||
var popup: Popup? = null
|
||||
var needPopup = true // loadMap can fail faster than postRunnable runs
|
||||
Gdx.app.postRunnable {
|
||||
if (!needPopup) return@postRunnable
|
||||
Concurrency.runOnGLThread {
|
||||
if (!needPopup) return@runOnGLThread
|
||||
popup = Popup(editorScreen).apply {
|
||||
addGoodSizedLabel(Constants.loading)
|
||||
open()
|
||||
@ -108,6 +112,7 @@ class MapEditorLoadTab(
|
||||
}
|
||||
try {
|
||||
val map = MapSaver.loadMap(chosenMap!!)
|
||||
if (!isActive) return
|
||||
|
||||
val missingMods = map.mapParameters.mods.filter { it !in RulesetCache }.toMutableList()
|
||||
// [TEMPORARY] conversion of old maps with a base ruleset contained in the mods
|
||||
@ -117,12 +122,12 @@ class MapEditorLoadTab(
|
||||
if (map.mapParameters.baseRuleset !in RulesetCache) missingMods += map.mapParameters.baseRuleset
|
||||
|
||||
if (missingMods.isNotEmpty()) {
|
||||
Gdx.app.postRunnable {
|
||||
Concurrency.runOnGLThread {
|
||||
needPopup = false
|
||||
popup?.close()
|
||||
ToastPopup("Missing mods: [${missingMods.joinToString()}]", editorScreen)
|
||||
}
|
||||
} else Gdx.app.postRunnable {
|
||||
} else Concurrency.runOnGLThread {
|
||||
Gdx.input.inputProcessor = null // This is to stop ANRs happening here, until the map editor screen sets up.
|
||||
try {
|
||||
// For deprecated maps, set the base ruleset field if it's still saved in the mods field
|
||||
@ -155,7 +160,7 @@ class MapEditorLoadTab(
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
needPopup = false
|
||||
Gdx.app.postRunnable {
|
||||
Concurrency.runOnGLThread {
|
||||
popup?.close()
|
||||
Log.error("Error loading map \"$chosenMap\"", ex)
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.unciv.ui.screens.mapeditorscreen.tabs
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
@ -25,8 +24,10 @@ import com.unciv.ui.components.extensions.onActivation
|
||||
import com.unciv.ui.components.extensions.onChange
|
||||
import com.unciv.ui.components.extensions.onClick
|
||||
import com.unciv.ui.components.extensions.toTextButton
|
||||
import com.unciv.utils.Concurrency
|
||||
import com.unciv.utils.Log
|
||||
import kotlin.concurrent.thread
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.isActive
|
||||
|
||||
class MapEditorSaveTab(
|
||||
private val editorScreen: MapEditorScreen,
|
||||
@ -35,7 +36,9 @@ class MapEditorSaveTab(
|
||||
private val mapFiles = MapEditorFilesTable(
|
||||
initWidth = editorScreen.getToolsWidth() - 40f,
|
||||
includeMods = false,
|
||||
this::selectFile)
|
||||
this::selectFile,
|
||||
this::saveHandler
|
||||
)
|
||||
|
||||
private val saveButton = "Save map".toTextButton()
|
||||
private val deleteButton = "Delete map".toTextButton()
|
||||
@ -76,11 +79,17 @@ class MapEditorSaveTab(
|
||||
add(buttonTable).row()
|
||||
}
|
||||
|
||||
private fun setSaveButton(enabled: Boolean) {
|
||||
saveButton.isEnabled = enabled
|
||||
saveButton.setText((if (enabled) "Save map" else "Working...").tr())
|
||||
}
|
||||
|
||||
private fun saveHandler() {
|
||||
if (mapNameTextField.text.isBlank()) return
|
||||
editorScreen.tileMap.mapParameters.name = mapNameTextField.text
|
||||
editorScreen.tileMap.mapParameters.type = MapGeneratedMainType.custom
|
||||
thread(name = "MapSaver", block = this::saverThread)
|
||||
setSaveButton(false)
|
||||
editorScreen.startBackgroundJob("MapSaver", false) { saverThread() }
|
||||
}
|
||||
|
||||
private fun deleteHandler() {
|
||||
@ -106,7 +115,7 @@ class MapEditorSaveTab(
|
||||
stage.keyboardFocus = null
|
||||
}
|
||||
|
||||
fun selectFile(file: FileHandle?) {
|
||||
private fun selectFile(file: FileHandle?) {
|
||||
chosenMap = file
|
||||
mapNameTextField.text = file?.name() ?: editorScreen.tileMap.mapParameters.name
|
||||
if (mapNameTextField.text.isBlank()) mapNameTextField.text = "My new map".tr()
|
||||
@ -117,22 +126,26 @@ class MapEditorSaveTab(
|
||||
deleteButton.color = if (file != null) Color.SCARLET else Color.BROWN
|
||||
}
|
||||
|
||||
private fun saverThread() {
|
||||
private fun CoroutineScope.saverThread() {
|
||||
try {
|
||||
val mapToSave = editorScreen.getMapCloneForSave()
|
||||
if (!isActive) return
|
||||
mapToSave.assignContinents(TileMap.AssignContinentsMode.Reassign)
|
||||
if (!isActive) return
|
||||
MapSaver.saveMap(mapNameTextField.text, mapToSave)
|
||||
Gdx.app.postRunnable {
|
||||
Concurrency.runOnGLThread {
|
||||
ToastPopup("Map saved successfully!", editorScreen)
|
||||
}
|
||||
editorScreen.isDirty = false
|
||||
setSaveButton(true)
|
||||
} catch (ex: Exception) {
|
||||
Log.error("Failed to save map", ex)
|
||||
Gdx.app.postRunnable {
|
||||
Concurrency.runOnGLThread {
|
||||
val cantLoadGamePopup = Popup(editorScreen)
|
||||
cantLoadGamePopup.addGoodSizedLabel("It looks like your map can't be saved!").row()
|
||||
cantLoadGamePopup.addCloseButton()
|
||||
cantLoadGamePopup.open(force = true)
|
||||
setSaveButton(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.unciv.ui.screens.mapeditorscreen.tabs
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Cell
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.GameInfo
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
@ -12,15 +13,18 @@ import com.unciv.logic.map.tile.TileDescription
|
||||
import com.unciv.models.Counter
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.nation.Nation
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.components.ExpanderTab
|
||||
import com.unciv.ui.components.TabbedPager
|
||||
import com.unciv.ui.components.UncivSlider
|
||||
import com.unciv.ui.components.WrappableLabel
|
||||
import com.unciv.ui.components.extensions.addSeparator
|
||||
import com.unciv.ui.components.extensions.darken
|
||||
import com.unciv.ui.components.extensions.onClick
|
||||
import com.unciv.ui.components.extensions.pad
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.ui.components.extensions.toTextButton
|
||||
import com.unciv.ui.popups.ToastPopup
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
@ -43,6 +47,8 @@ class MapEditorViewTab(
|
||||
|
||||
init {
|
||||
top()
|
||||
// Note on width: max expander content width + 2 * expander.defaultPad + 2 * the following horizontal pad
|
||||
// should not exceed editorScreen.getToolsWidth() or the page will scroll horizontally!
|
||||
defaults().pad(5f, 20f)
|
||||
update()
|
||||
}
|
||||
@ -72,7 +78,8 @@ class MapEditorViewTab(
|
||||
val headerText = tileMap.mapParameters.name.ifEmpty { "New map" }
|
||||
add(ExpanderTab(
|
||||
headerText,
|
||||
startsOutOpened = false
|
||||
startsOutOpened = false,
|
||||
defaultPad = 0f // See note in init
|
||||
) {
|
||||
val mapParameterText = tileMap.mapParameters.toString()
|
||||
.replace("\"${tileMap.mapParameters.name}\" ", "")
|
||||
@ -196,7 +203,7 @@ class MapEditorViewTab(
|
||||
lines += FormattedLine("Continent: [$continent] ([${tile.tileMap.continentSizes[continent]}] tiles)", link = "continent")
|
||||
}
|
||||
|
||||
tileDataCell?.setActor(MarkupRenderer.render(lines, labelWidth) {
|
||||
val renderedInfo = MarkupRenderer.render(lines, labelWidth) {
|
||||
if (it == "continent") {
|
||||
// Visualize the continent this tile is on
|
||||
editorScreen.hideSelection()
|
||||
@ -209,7 +216,25 @@ class MapEditorViewTab(
|
||||
// This needs CivilopediaScreen to be able to work without a GameInfo!
|
||||
UncivGame.Current.pushScreen(CivilopediaScreen(tile.ruleset, link = it))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (tile.resource != null && (tile.resourceAmount > 0 || tile.tileResource.resourceType == ResourceType.Strategic)) {
|
||||
renderedInfo.addSeparator(Color.GRAY)
|
||||
renderedInfo.add(Table().apply {
|
||||
add("Resource abundance".toLabel(alignment = Align.left)).left().growX()
|
||||
val slider = UncivSlider(0f, 42f, 1f,
|
||||
initial = tile.resourceAmount.toFloat()
|
||||
) {
|
||||
tile.resourceAmount = it.toInt()
|
||||
editorScreen.updateTile(tile)
|
||||
editorScreen.isDirty = true
|
||||
}
|
||||
slider.setSnapToValues(floatArrayOf(0f,1f,2f,3f,4f,5f,6f,7f,8f,9f,10f,12f,15f,20f,30f,40f), 5f)
|
||||
add(slider).right().minWidth(80f).fillX().padTop(15f)
|
||||
}).fillX()
|
||||
}
|
||||
|
||||
tileDataCell?.setActor(renderedInfo)
|
||||
|
||||
editorScreen.hideSelection()
|
||||
editorScreen.highlightTile(tile, Color.CORAL)
|
||||
|
Reference in New Issue
Block a user