mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-10 02:24:05 +09:00
596 lines
26 KiB
Kotlin
596 lines
26 KiB
Kotlin
package net.torvald.terrarum.modulebasegame.ui
|
|
|
|
import com.badlogic.gdx.Gdx
|
|
import com.badlogic.gdx.Input.Keys
|
|
import com.badlogic.gdx.graphics.Color
|
|
import com.badlogic.gdx.graphics.OrthographicCamera
|
|
import com.badlogic.gdx.graphics.Texture
|
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
|
import net.torvald.terrarum.App
|
|
import net.torvald.terrarum.CommonResourcePool
|
|
import net.torvald.terrarum.TerrarumAppConfiguration
|
|
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
|
import net.torvald.terrarum.langpack.Lang
|
|
import net.torvald.terrarum.modulebasegame.serialise.LoadSavegame
|
|
import net.torvald.terrarum.savegame.ByteArray64Reader
|
|
import net.torvald.terrarum.savegame.DiskSkimmer
|
|
import net.torvald.terrarum.savegame.VDFileID
|
|
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
|
import net.torvald.terrarum.serialise.Common
|
|
import net.torvald.terrarum.tryDispose
|
|
import net.torvald.terrarum.ui.Toolkit
|
|
import net.torvald.terrarum.ui.UICanvas
|
|
import net.torvald.terrarum.ui.UIItemTextButton
|
|
import net.torvald.terrarum.ui.UIItemTextLineInput
|
|
import net.torvald.terrarum.utils.JsonFetcher
|
|
import net.torvald.terrarum.utils.forEachSiblings
|
|
import net.torvald.unicode.EMDASH
|
|
import java.time.Instant
|
|
import java.time.format.DateTimeFormatter
|
|
import java.util.*
|
|
|
|
/**
|
|
* Created by minjaesong on 2023-07-05.
|
|
*/
|
|
class UILoadManage(val full: UILoadSavegame) : UICanvas() {
|
|
|
|
init {
|
|
handler.allowESCtoClose = false
|
|
}
|
|
|
|
override var width: Int = Toolkit.drawWidth
|
|
override var height: Int = App.scr.height
|
|
|
|
private val buttonHeight = full.buttonHeight
|
|
private val buttonGap = full.buttonGap
|
|
private val buttonWidth = full.buttonWidth
|
|
private val drawX = full.drawX
|
|
private val hx = Toolkit.hdrawWidth
|
|
|
|
private val buttonX1third = hx - (buttonWidth * 1.5).toInt() - buttonGap
|
|
private val buttonXcentre = hx - (buttonWidth / 2)
|
|
private val buttonX3third = hx + (buttonWidth / 2) + buttonGap
|
|
|
|
private val buttonXleft = drawX + (240 - buttonWidth) / 2
|
|
private val buttonXright = drawX + 240 + (240 - buttonWidth) / 2
|
|
|
|
private val buttonRowY = full.buttonRowY - buttonHeight
|
|
private val buttonRowY2 = buttonRowY - buttonHeight - buttonGap
|
|
|
|
private var altDown = false
|
|
|
|
private val mainGoButton = UIItemTextButton(this,
|
|
{ if (altDown && savegameIsNotNew) Lang["MENU_LABEL_PREV_SAVES"] else Lang["MENU_IO_LOAD_GAME"] }, buttonX1third, buttonRowY2, buttonWidth * 3 + buttonGap * 2, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {
|
|
it.clickOnceListener = { _,_ ->
|
|
App.printdbg(this, "Load playerUUID: ${UILoadGovernor.playerUUID}, worldUUID: ${UILoadGovernor.worldUUID}")
|
|
|
|
/*if (full.loadables.moreRecentAutosaveAvailable()) {
|
|
full.bringAutosaveSelectorUp()
|
|
full.changePanelTo(2)
|
|
}
|
|
else */
|
|
|
|
if (altDown && savegameIsNotNew) {
|
|
mode = MODE_PREV_SAVES
|
|
loadPrevGameInfo()
|
|
}
|
|
else {
|
|
if (full.loadables.saveAvaliable()) {
|
|
if (full.loadables.newerSaveIsDamaged) {
|
|
UILoadGovernor.previousSaveWasLoaded = true
|
|
}
|
|
|
|
// full.takeAutosaveSelectorDown()
|
|
full.loadManageSelectedGame = full.loadables.getLoadableSave()!!
|
|
|
|
mode = MODE_LOAD
|
|
|
|
full.interruptListGenerator()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
private val mainNoGoButton = UIItemTextButton(this,
|
|
{ Lang["ERROR_SAVE_CORRUPTED"].replace(".","") }, buttonX1third, buttonRowY2, buttonWidth * 3 + buttonGap * 2, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {
|
|
it.isEnabled = false
|
|
}
|
|
private val mainNoGoButtonSaveFromNewerVersion = UIItemTextButton(this,
|
|
{ if (altDown && savegameIsNotNew) Lang["MENU_LABEL_PREV_SAVES"] else Lang["ERROR_SAVE_IS_FROM_NEWER_VERSION"].replace(".","") }, buttonX1third, buttonRowY2, buttonWidth * 3 + buttonGap * 2, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {
|
|
it.isEnabled = false
|
|
it.clickOnceListener = { _,_ ->
|
|
App.printdbg(this, "Load playerUUID: ${UILoadGovernor.playerUUID}, worldUUID: ${UILoadGovernor.worldUUID}")
|
|
|
|
if (altDown && savegameIsNotNew) {
|
|
mode = MODE_PREV_SAVES
|
|
loadPrevGameInfo()
|
|
}
|
|
}
|
|
it.updateListener = { _ ->
|
|
it.isEnabled = altDown
|
|
}
|
|
}
|
|
private val mainImportedPlayerCreateNewWorldButton = UIItemTextButton(this,
|
|
{ Lang["CONTEXT_WORLD_NEW"].replace(".","") }, buttonX1third, buttonRowY2, buttonWidth * 3 + buttonGap * 2, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {
|
|
it.clickOnceListener = { _,_ ->
|
|
val playerDisk = full.loadables.getImportedPlayer()!!
|
|
full.remoCon.openUI(UINewWorld(full.remoCon, playerDisk))
|
|
}
|
|
}
|
|
private val mainRenameButton = UIItemTextButton(this,
|
|
{ if (altDown && savegameIsNotNew) Lang["MENU_MODULES"] else Lang["MENU_LABEL_RENAME"] }, buttonX1third, buttonRowY, buttonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {
|
|
it.clickOnceListener = { _,_ ->
|
|
if (altDown && savegameIsNotNew) {
|
|
mode = MODE_SHOW_LOAD_ORDER
|
|
}
|
|
else {
|
|
mode = MODE_RENAME
|
|
}
|
|
}
|
|
}
|
|
private val mainBackButton = UIItemTextButton(this,
|
|
{ Lang["MENU_LABEL_BACK"] }, buttonXcentre, buttonRowY, buttonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {
|
|
it.clickOnceListener = { _,_ ->
|
|
full.resetScroll()
|
|
full.changePanelTo(0)
|
|
full.playerButtonSelected?.forceUnhighlight = false
|
|
}
|
|
}
|
|
private val mainDeleteButton = UIItemTextButton(this,
|
|
{ Lang["CONTEXT_CHARACTER_DELETE"] }, buttonX3third, buttonRowY, buttonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true, inactiveCol = Toolkit.Theme.COL_RED, activeCol = Toolkit.Theme.COL_REDD).also {
|
|
it.clickOnceListener = { _,_ ->
|
|
mode = MODE_DELETE
|
|
}
|
|
}
|
|
|
|
private val confirmDeleteButton = UIItemTextButton(this,
|
|
{ Lang["MENU_LABEL_DELETE"] }, buttonXleft, buttonRowY, buttonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true, inactiveCol = Toolkit.Theme.COL_RED, activeCol = Toolkit.Theme.COL_REDD).also {
|
|
it.clickOnceListener = { _,_ ->
|
|
val pu = full.playerButtonSelected!!.playerUUID
|
|
val wu = full.playerButtonSelected!!.worldUUID
|
|
App.savegamePlayers[pu]?.moveToRecycle(App.recycledPlayersDir)?.let {
|
|
App.sortedPlayers.remove(pu)
|
|
App.savegamePlayers.remove(pu)
|
|
App.savegamePlayersName.remove(pu)
|
|
}
|
|
// don't delete the world please
|
|
full.remoCon.openUI(UILoadSavegame(full.remoCon))
|
|
}
|
|
}
|
|
private val confirmCancelButton = UIItemTextButton(this,
|
|
{ Lang["MENU_LABEL_CANCEL"] }, buttonXright, buttonRowY, buttonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {
|
|
it.clickOnceListener = { _,_ ->
|
|
mode = MODE_INIT
|
|
}
|
|
}
|
|
|
|
private val renameInput = UIItemTextLineInput(this, buttonXleft, App.scr.halfh, 240 + buttonWidth)
|
|
private val renameCancelButton = UIItemTextButton(this,
|
|
{ Lang["MENU_LABEL_CANCEL"] }, buttonXleft, buttonRowY, buttonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {
|
|
it.clickOnceListener = { _,_ ->
|
|
mode = MODE_INIT
|
|
}
|
|
}
|
|
private val renameRenameButton = UIItemTextButton(this,
|
|
{ Lang["MENU_LABEL_RENAME"] }, buttonXright, buttonRowY, buttonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {
|
|
it.clickOnceListener = { _,_ ->
|
|
val newName = renameInput.getText().trim()
|
|
if (newName.isNotBlank()) {
|
|
full.playerButtonSelected!!.playerUUID.let { uuid ->
|
|
App.savegamePlayersName[uuid] = newName
|
|
App.savegamePlayers[uuid]!!.renamePlayer(newName)
|
|
full.playerButtonSelected!!.playerName = newName
|
|
}
|
|
}
|
|
|
|
mode = MODE_INIT
|
|
}
|
|
}
|
|
|
|
private val modulesBackButton = UIItemTextButton(this,
|
|
{ Lang["MENU_LABEL_BACK"] }, buttonXcentre, buttonRowY, buttonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {
|
|
it.clickOnceListener = { _,_ ->
|
|
mode = MODE_INIT
|
|
}
|
|
}
|
|
|
|
private var mode = 0
|
|
|
|
private var mainButtons0 = listOf(mainGoButton, mainBackButton, mainRenameButton, mainDeleteButton)
|
|
private var mainButtonsNoGoSaveCorrupted = listOf(mainNoGoButton, mainBackButton, mainRenameButton, mainDeleteButton)
|
|
private var mainButtonsNoGoSaveFromNewer = listOf(mainNoGoButtonSaveFromNewerVersion, mainBackButton, mainRenameButton, mainDeleteButton)
|
|
private var mainButtons2 = listOf(mainImportedPlayerCreateNewWorldButton, mainBackButton, mainRenameButton, mainDeleteButton)
|
|
private var delButtons = listOf(confirmCancelButton, confirmDeleteButton)
|
|
private var renameButtons = listOf(renameRenameButton, renameCancelButton)
|
|
|
|
private val savegameHasError: Boolean
|
|
get() = (!full.loadables.saveAvaliable() && !full.loadables.isImported)
|
|
private val savegameIsNotNew: Boolean
|
|
get() = full.loadables.saveAvaliable()
|
|
|
|
private val mainButtons: List<UIItemTextButton>
|
|
get() =
|
|
if (full.playerButtonSelected?.isNewerVersion == true)
|
|
mainButtonsNoGoSaveFromNewer
|
|
else if (full.loadables.saveAvaliable())
|
|
mainButtons0
|
|
else if (full.loadables.isImported)
|
|
mainButtons2
|
|
else
|
|
mainButtonsNoGoSaveCorrupted
|
|
|
|
private val MODE_INIT = 0
|
|
private val MODE_DELETE = 16 // are you sure?
|
|
private val MODE_RENAME = 32 // show rename dialogue
|
|
private val MODE_PREV_SAVES = 48
|
|
private val MODE_SHOW_LOAD_ORDER = 64
|
|
private val MODE_LOAD = 256 // is needed to make the static loading screen
|
|
|
|
init {
|
|
|
|
}
|
|
|
|
private var screencap: TextureRegion? = null
|
|
private val screencapW = SAVE_THUMBNAIL_MAIN_WIDTH
|
|
private val screencapH = SAVE_THUMBNAIL_MAIN_HEIGHT
|
|
|
|
override fun doOpening(delta: Float) {
|
|
full.playerButtonSelected?.forceUnhighlight = true
|
|
full.playerButtonSelected?.let { button ->
|
|
screencap?.texture?.tryDispose()
|
|
button.savegameThumbnailPixmap?.let {
|
|
Texture(it).also {
|
|
it.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
|
|
screencap = TextureRegion(it)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun doClosing(delta: Float) {
|
|
full.playerButtonSelected?.forceUnhighlight = false
|
|
}
|
|
|
|
|
|
private val modulesBoxBaseY = full.titleTopGradEnd + 48
|
|
private val modulesTextboxW = 280
|
|
private val boxTextMargin = 3
|
|
private val listGap = 10
|
|
private val playerModTextboxX = Toolkit.drawWidth / 2 - (2 * boxTextMargin + listGap) - modulesTextboxW
|
|
private val worldModTextboxX = Toolkit.drawWidth / 2 + (2 * boxTextMargin + listGap)
|
|
|
|
|
|
private lateinit var sortedPlayerWorldList: List<Pair<SavegameMeta?, SavegameMeta?>>
|
|
private lateinit var loadOrderPlayer: List<String>
|
|
private lateinit var loadOrderWorld: List<String>
|
|
private var playerName = ""
|
|
private var px64 = 0
|
|
private var wx64 = 0
|
|
private var px48 = 0
|
|
private var wx48 = 0
|
|
private var totalTBH48 = 0
|
|
private var totalTBH64 = 0
|
|
|
|
override fun show() {
|
|
super.show()
|
|
}
|
|
|
|
private fun loadPrevGameInfo() {
|
|
val players = App.savegamePlayers[full.playerButtonSelected!!.playerUUID]!!.files
|
|
val worlds = App.savegameWorlds[full.playerButtonSelected!!.worldUUID]!!.files
|
|
val playerSavesInfo = players.map { it.getSavegameMeta() }.sortedByDescending { it.lastPlayTime }
|
|
val worldSavesInfo = worlds.map { it.getSavegameMeta() }.sortedByDescending { it.lastPlayTime }
|
|
|
|
sortedPlayerWorldList = getChronologicalPair(playerSavesInfo, worldSavesInfo)
|
|
|
|
px48 = playerModTextboxX + (modulesTextboxW - tbw48) / 2
|
|
wx48 = worldModTextboxX + (modulesTextboxW - tbw48) / 2
|
|
totalTBH48 = sortedPlayerWorldList.size * 32
|
|
}
|
|
|
|
internal fun loadSavegameInfo() {
|
|
playerName = App.savegamePlayersName[full.playerButtonSelected!!.playerUUID] ?: "Player"
|
|
|
|
loadOrderPlayer =
|
|
App.savegamePlayers[full.playerButtonSelected!!.playerUUID]!!.files[selectedRevision].getFile(
|
|
VDFileID.LOADORDER
|
|
)?.getContent()?.toByteArray()?.toString(Common.CHARSET)?.split('\n')?.let {
|
|
it.mapIndexed { index, s -> "${(index+1).toString().padStart(it.size.fastLen())}. $s" }
|
|
} ?: listOf("$EMDASH")
|
|
loadOrderWorld =
|
|
App.savegameWorlds[full.playerButtonSelected!!.worldUUID]?.files?.get(selectedRevision)?.getFile( // it's null for freshly-imported avatars
|
|
VDFileID.LOADORDER
|
|
)?.getContent()?.toByteArray()?.toString(Common.CHARSET)?.split('\n')?.let {
|
|
it.mapIndexed { index, s -> "${(index+1).toString().padStart(it.size.fastLen())}. $s" }
|
|
} ?: listOf("$EMDASH")
|
|
|
|
val playerTBW64 = loadOrderPlayer.maxOfOrNull { App.fontGame.getWidth(it) } ?: 0
|
|
val worldTBW64 = loadOrderWorld.maxOfOrNull { App.fontGame.getWidth(it) } ?: 0
|
|
px64 = playerModTextboxX + (modulesTextboxW - playerTBW64) / 2
|
|
wx64 = worldModTextboxX + (modulesTextboxW - worldTBW64) / 2
|
|
totalTBH64 = maxOf(loadOrderPlayer.size, loadOrderWorld.size) * App.fontGame.lineHeight.toInt()
|
|
}
|
|
|
|
override fun updateImpl(delta: Float) {
|
|
altDown = Gdx.input.isKeyPressed(Keys.ALT_LEFT) || Gdx.input.isKeyPressed(Keys.ALT_RIGHT)
|
|
|
|
when (mode) {
|
|
MODE_INIT -> {
|
|
mainButtons.forEach { it.update(delta) }
|
|
}
|
|
MODE_DELETE -> {
|
|
delButtons.forEach { it.update(delta) }
|
|
}
|
|
MODE_RENAME -> {
|
|
renameButtons.forEach { it.update(delta) }
|
|
renameInput.update(delta)
|
|
}
|
|
MODE_SHOW_LOAD_ORDER, MODE_PREV_SAVES -> {
|
|
modulesBackButton.update(delta)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun inputStrobed(e: TerrarumKeyboardEvent) {
|
|
when (mode) {
|
|
MODE_RENAME -> {
|
|
renameInput.inputStrobed(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
private var loadFiredFrameCounter = 0
|
|
|
|
private var selectedRevision = 0 // 0: most recent, 1: second most recent, etc.
|
|
|
|
private val icons = CommonResourcePool.getAsTextureRegionPack("inventory_category")
|
|
|
|
override fun renderImpl(frameDelta: Float, batch: SpriteBatch, camera: OrthographicCamera) {
|
|
if (mode != MODE_SHOW_LOAD_ORDER) {
|
|
val buttonYdelta = (full.titleTopGradEnd) - full.playerButtonSelected!!.posY
|
|
full.playerButtonSelected!!.render(frameDelta, batch, camera, 0, buttonYdelta)
|
|
}
|
|
|
|
when (mode) {
|
|
MODE_INIT -> {
|
|
mainButtons.forEach { it.render(frameDelta, batch, camera) }
|
|
|
|
// draw thumbnails of the most recent game
|
|
// val tex = screencap ?: CommonResourcePool.getAsTextureRegion("terrarum-defaultsavegamethumb")
|
|
|
|
|
|
if (screencap != null) {
|
|
val tx = (Toolkit.drawWidth - screencapW) / 2
|
|
val tys = full.titleTopGradEnd + SAVE_CELL_HEIGHT + buttonGap
|
|
val tye = buttonRowY2 - buttonGap
|
|
val ty = tys + (tye - tys - SAVE_THUMBNAIL_MAIN_HEIGHT) / 2
|
|
|
|
batch.color = Toolkit.Theme.COL_INACTIVE
|
|
Toolkit.drawBoxBorder(batch, tx - 1, ty - 1, screencapW + 2, screencapH + 2)
|
|
batch.color = UIInventoryFull.CELL_COL
|
|
Toolkit.fillArea(batch, tx, ty, screencapW, screencapH)
|
|
|
|
batch.color = Color.WHITE
|
|
batch.draw(screencap, tx.toFloat(), ty.toFloat(), screencapW.toFloat(), screencapH.toFloat())
|
|
}
|
|
|
|
}
|
|
MODE_DELETE -> {
|
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_LABEL_SAVE_WILL_BE_DELETED"], Toolkit.drawWidth, 0, full.titleTopGradEnd + full.cellInterval + SAVE_CELL_HEIGHT + 36)
|
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_LABEL_ARE_YOU_SURE"], Toolkit.drawWidth, 0, full.titleTopGradEnd + full.cellInterval + SAVE_CELL_HEIGHT + 36 + 24)
|
|
|
|
delButtons.forEach { it.render(frameDelta, batch, camera) }
|
|
}
|
|
MODE_RENAME -> {
|
|
renameInput.render(frameDelta, batch, camera)
|
|
renameButtons.forEach { it.render(frameDelta, batch, camera) }
|
|
}
|
|
MODE_LOAD -> {
|
|
loadFiredFrameCounter += 1
|
|
StaticLoadScreenSubstitute(batch)
|
|
if (loadFiredFrameCounter == 2) LoadSavegame(full.loadManageSelectedGame)
|
|
}
|
|
MODE_SHOW_LOAD_ORDER -> {
|
|
Toolkit.drawTextCentered(batch, App.fontUITitle, Lang["MENU_MODULES"], Toolkit.drawWidth, 0, full.titleTopGradEnd)
|
|
|
|
batch.color = Toolkit.Theme.COL_CELL_FILL
|
|
Toolkit.fillArea(batch, playerModTextboxX, modulesBoxBaseY - 4, modulesTextboxW, 36 + totalTBH64)
|
|
Toolkit.fillArea(batch, worldModTextboxX, modulesBoxBaseY - 4, modulesTextboxW, 36 + totalTBH64)
|
|
batch.color = Toolkit.Theme.COL_INACTIVE
|
|
Toolkit.drawBoxBorder(batch, playerModTextboxX - 1, modulesBoxBaseY - 4 - 1, modulesTextboxW + 2, 36 + totalTBH64 + 2)
|
|
Toolkit.drawBoxBorder(batch, worldModTextboxX - 1, modulesBoxBaseY - 4 - 1, modulesTextboxW + 2, 36 + totalTBH64 + 2)
|
|
|
|
batch.color = Toolkit.Theme.COL_INVENTORY_CELL_BORDER
|
|
for (i in 0 until maxOf(loadOrderPlayer.size, loadOrderWorld.size)) {
|
|
Toolkit.drawStraightLine(batch, playerModTextboxX + boxTextMargin, modulesBoxBaseY + 32 + App.fontGame.lineHeight.toInt() * i, playerModTextboxX + modulesTextboxW - boxTextMargin, 1, false)
|
|
Toolkit.drawStraightLine(batch, worldModTextboxX + boxTextMargin, modulesBoxBaseY + 32 + App.fontGame.lineHeight.toInt() * i, worldModTextboxX + modulesTextboxW - boxTextMargin, 1, false)
|
|
}
|
|
|
|
|
|
batch.color = Color.WHITE
|
|
Toolkit.drawTextCentered(batch, App.fontGame, playerName, modulesTextboxW, playerModTextboxX, modulesBoxBaseY + 1)
|
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_LABEL_WORLD"], modulesTextboxW, worldModTextboxX, modulesBoxBaseY + 1)
|
|
|
|
loadOrderPlayer.forEachIndexed { index, s ->
|
|
App.fontGame.draw(batch, s, px64, modulesBoxBaseY + 32 + App.fontGame.lineHeight.toInt() * index)
|
|
}
|
|
loadOrderWorld.forEachIndexed { index, s ->
|
|
App.fontGame.draw(batch, s, wx64, modulesBoxBaseY + 32 + App.fontGame.lineHeight.toInt() * index)
|
|
}
|
|
|
|
modulesBackButton.render(frameDelta, batch, camera)
|
|
}
|
|
MODE_PREV_SAVES -> {
|
|
val modulesBoxBaseY2 = full.titleTopGradEnd + SAVE_CELL_HEIGHT + listGap + 4
|
|
|
|
batch.color = Toolkit.Theme.COL_CELL_FILL
|
|
Toolkit.fillArea(batch, playerModTextboxX, modulesBoxBaseY2 - 4, modulesTextboxW, 36 + totalTBH48)
|
|
Toolkit.fillArea(batch, worldModTextboxX, modulesBoxBaseY2 - 4, modulesTextboxW, 36 + totalTBH48)
|
|
batch.color = Toolkit.Theme.COL_INACTIVE
|
|
Toolkit.drawBoxBorder(batch, playerModTextboxX - 1, modulesBoxBaseY2 - 4 - 1, modulesTextboxW + 2, 36 + totalTBH48 + 2)
|
|
Toolkit.drawBoxBorder(batch, worldModTextboxX - 1, modulesBoxBaseY2 - 4 - 1, modulesTextboxW + 2, 36 + totalTBH48 + 2)
|
|
|
|
batch.color = Toolkit.Theme.COL_INVENTORY_CELL_BORDER
|
|
for (i in 0 until sortedPlayerWorldList.size) {
|
|
Toolkit.drawStraightLine(batch, playerModTextboxX + boxTextMargin, modulesBoxBaseY2 + 32 + 32 * i, playerModTextboxX + modulesTextboxW - boxTextMargin, 1, false)
|
|
Toolkit.drawStraightLine(batch, worldModTextboxX + boxTextMargin, modulesBoxBaseY2 + 32 + 32 * i, worldModTextboxX + modulesTextboxW - boxTextMargin, 1, false)
|
|
}
|
|
|
|
batch.color = Color.WHITE
|
|
Toolkit.drawTextCentered(batch, App.fontGame, playerName, modulesTextboxW, playerModTextboxX, modulesBoxBaseY2 + 1)
|
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_LABEL_WORLD"], modulesTextboxW, worldModTextboxX, modulesBoxBaseY2 + 1)
|
|
sortedPlayerWorldList.forEachIndexed { index, (pmeta, wmeta) ->
|
|
if (pmeta != null) {
|
|
if (pmeta.isAuto) batch.draw(icons.get(24,1), playerModTextboxX + 4f, modulesBoxBaseY2 + 38f + 32 * index)
|
|
App.fontGame.draw(batch, "$pmeta", px48, modulesBoxBaseY2 + 36 + 32 * index)
|
|
}
|
|
if (wmeta != null) {
|
|
if (wmeta.isAuto) batch.draw(icons.get(24,1), worldModTextboxX + 4f, modulesBoxBaseY2 + 38f + 32 * index)
|
|
App.fontGame.draw(batch, "$wmeta", wx48, modulesBoxBaseY2 + 36 + 32 * index)
|
|
}
|
|
}
|
|
|
|
modulesBackButton.render(frameDelta, batch, camera)
|
|
}
|
|
}
|
|
}
|
|
|
|
val tbw48 = App.fontGame.getWidth("8888-88-88 88:88:88 (8.8.88)")
|
|
|
|
|
|
private data class SavegameMeta(
|
|
val lastPlayTime: Long,
|
|
val genver: String,
|
|
val isAuto: Boolean,
|
|
) {
|
|
private val lastPlayTimeS = Instant.ofEpochSecond(lastPlayTime)
|
|
.atZone(TimeZone.getDefault().toZoneId())
|
|
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
|
|
|
override fun toString() = "$lastPlayTimeS\u3000($genver)"
|
|
}
|
|
|
|
private fun DiskSkimmer.getSavegameMeta(): SavegameMeta {
|
|
if (!this.initialised) this.rebuild()
|
|
this.getFile(SAVEGAMEINFO)!!.bytes.let {
|
|
var lastPlayTime = 0L
|
|
var genver = ""
|
|
val isAuto = (this.getSaveMode() and 0b10 != 0)
|
|
JsonFetcher.readFromJsonString(ByteArray64Reader(it, Common.CHARSET)).forEachSiblings { name, value ->
|
|
if (name == "lastPlayTime") lastPlayTime = value.asLong()
|
|
if (name == "genver") genver = value.asLong().let { "${it.ushr(48)}.${it.ushr(24).and(0xFFFFFF)}.${it.and(0xFFFFFF)}" }
|
|
}
|
|
val snap = this.getSaveSnapshotVersion()?.toString()
|
|
|
|
val versionString = if (snap != null) "$snap" else TerrarumAppConfiguration.convertVersionNumberToReadableShort(genver)
|
|
|
|
return SavegameMeta(
|
|
lastPlayTime,
|
|
versionString,
|
|
isAuto
|
|
)
|
|
}
|
|
}
|
|
|
|
private fun getChronologicalPair(ps: List<SavegameMeta>, ws: List<SavegameMeta>): List<Pair<SavegameMeta?, SavegameMeta?>> {
|
|
val li = ArrayList<Pair<SavegameMeta?, SavegameMeta?>>()
|
|
var pc = 0
|
|
var wc = 0
|
|
var breakStatus = -1 // 0: ps ran out, 1: ws ran out
|
|
while (true) {
|
|
if (ps.size == pc) {
|
|
breakStatus = 0
|
|
break
|
|
}
|
|
else if (ws.size == wc) {
|
|
breakStatus = 1
|
|
break
|
|
}
|
|
|
|
if (ps[pc].lastPlayTime == ws[wc].lastPlayTime) {
|
|
li.add(ps[pc] to ws[wc])
|
|
pc++; wc++
|
|
}
|
|
else if (ps[pc].lastPlayTime > ws[wc].lastPlayTime) {
|
|
li.add(ps[pc] to null)
|
|
pc++
|
|
}
|
|
else {
|
|
li.add(null to ws[wc])
|
|
wc++
|
|
}
|
|
}
|
|
|
|
val remainder = if (breakStatus == 0) ws else ps
|
|
var rc = if (breakStatus == 0) wc else pc
|
|
while (rc < remainder.size) {
|
|
if (breakStatus == 0)
|
|
li.add(null to ws[rc])
|
|
else
|
|
li.add(ps[pc] to null)
|
|
|
|
rc++
|
|
}
|
|
|
|
return li
|
|
}
|
|
|
|
override fun dispose() {
|
|
screencap?.texture?.tryDispose()
|
|
}
|
|
|
|
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
|
when (mode) {
|
|
MODE_INIT -> {
|
|
mainButtons.forEach { it.touchDown(screenX, screenY, pointer, button) }
|
|
}
|
|
MODE_DELETE -> {
|
|
delButtons.forEach { it.touchDown(screenX, screenY, pointer, button) }
|
|
}
|
|
MODE_RENAME -> {
|
|
renameInput.touchDown(screenX, screenY, pointer, button)
|
|
renameButtons.forEach { it.touchDown(screenX, screenY, pointer, button) }
|
|
}
|
|
MODE_SHOW_LOAD_ORDER, MODE_PREV_SAVES -> {
|
|
modulesBackButton.touchDown(screenX, screenY, pointer, button)
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
|
when (mode) {
|
|
MODE_INIT -> {
|
|
mainButtons.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
|
}
|
|
MODE_DELETE -> {
|
|
delButtons.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
|
}
|
|
MODE_RENAME -> {
|
|
renameInput.touchUp(screenX, screenY, pointer, button)
|
|
renameButtons.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
|
}
|
|
MODE_SHOW_LOAD_ORDER, MODE_PREV_SAVES -> {
|
|
modulesBackButton.touchUp(screenX, screenY, pointer, button)
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
private fun Int.fastLen(): Int {
|
|
return if (this < 0) 1 + this.unaryMinus().fastLen()
|
|
else if (this < 10) 1
|
|
else if (this < 100) 2
|
|
else if (this < 1000) 3
|
|
else if (this < 10000) 4
|
|
else if (this < 100000) 5
|
|
else if (this < 1000000) 6
|
|
else if (this < 10000000) 7
|
|
else if (this < 100000000) 8
|
|
else if (this < 1000000000) 9
|
|
else 10
|
|
}
|
|
|
|
} |