From 2d359415c8d3ca3805fee73c39598af8a19c9779 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Tue, 12 Oct 2021 00:17:44 +0900 Subject: [PATCH] player load ui --- SAVE_FORMAT.md | 2 + .../spriteanimation/HasAssembledSprite.kt | 4 +- .../torvald/spriteassembler/ADProperties.kt | 10 +- src/net/torvald/terrarum/App.java | 2 + src/net/torvald/terrarum/Terrarum.kt | 31 +++- .../terrarum/modulebasegame/TerrarumIngame.kt | 4 +- .../modulebasegame/gameactors/IngamePlayer.kt | 2 +- .../modulebasegame/ui/GraphicsControlPanel.kt | 5 +- .../modulebasegame/ui/UIInventoryFull.kt | 2 + .../ui/UIItemInventoryEquippedView.kt | 6 +- .../ui/UIItemInventoryItemGrid.kt | 4 +- .../modulebasegame/ui/UIItemPlayerInfoCell.kt | 129 ------------- .../ui/UIItemSavegameInfoCell.kt | 32 ---- .../modulebasegame/ui/UILoadDemoSavefiles.kt | 169 ++++++++++++++++-- .../ui/UITitleCharactersList.kt | 73 -------- .../torvald/terrarum/serialise/WriteActor.kt | 3 + work_files/UI/character_cell.kra | 4 +- 17 files changed, 212 insertions(+), 270 deletions(-) delete mode 100644 src/net/torvald/terrarum/modulebasegame/ui/UIItemPlayerInfoCell.kt delete mode 100644 src/net/torvald/terrarum/modulebasegame/ui/UIItemSavegameInfoCell.kt delete mode 100644 src/net/torvald/terrarum/modulebasegame/ui/UITitleCharactersList.kt diff --git a/SAVE_FORMAT.md b/SAVE_FORMAT.md index 81fc0565b..a9ece66bd 100644 --- a/SAVE_FORMAT.md +++ b/SAVE_FORMAT.md @@ -16,6 +16,7 @@ The main game directory is composed of following directories: } *if file -1025 is not there, read bodyparts from assets directory *optionally encrypt the files other than -1 + *disk name is player's name encoded in UTF-8 + Shared - , TEVD { * } - @@ -26,6 +27,7 @@ The main game directory is composed of following directories: [0x1_0000_0000L or (layerNumber shl 24) or chunkNumber] chunk data, [-2] screenshot.tga.gz taken by the last player } + *disk name is world's name encoded in UTF-8 ``` (TEVD stands for Terrarum Virtual Disk spec version 3, TVDA stands for spec version 254; both have MAGIC header of `TEVd`) diff --git a/src/net/torvald/spriteanimation/HasAssembledSprite.kt b/src/net/torvald/spriteanimation/HasAssembledSprite.kt index 84468f2ad..38b873149 100644 --- a/src/net/torvald/spriteanimation/HasAssembledSprite.kt +++ b/src/net/torvald/spriteanimation/HasAssembledSprite.kt @@ -1,10 +1,8 @@ package net.torvald.spriteanimation -import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.Texture import net.torvald.spriteassembler.ADProperties import net.torvald.spriteassembler.AssembleSheetPixmap -import net.torvald.terrarum.tvda.DiskSkimmer import net.torvald.terrarum.tvda.SimpleFileSystem import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack @@ -71,7 +69,7 @@ interface HasAssembledSprite { private fun _rebuild(disk: SimpleFileSystem, ad: ADProperties, sprite: SpriteAnimation) { // TODO injecting held item/armour pictures? Would it be AssembleSheetPixmap's job? - val pixmap = AssembleSheetPixmap.fromVirtualDisk(disk, ad) + val pixmap = if (disk.getEntry(-1025) != null) AssembleSheetPixmap.fromVirtualDisk(disk, ad) else AssembleSheetPixmap.fromAssetsDir(ad) val texture = Texture(pixmap) texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest) pixmap.dispose() diff --git a/src/net/torvald/spriteassembler/ADProperties.kt b/src/net/torvald/spriteassembler/ADProperties.kt index f27708920..63b9b9558 100644 --- a/src/net/torvald/spriteassembler/ADProperties.kt +++ b/src/net/torvald/spriteassembler/ADProperties.kt @@ -5,6 +5,7 @@ import net.torvald.terrarum.linearSearchBy import net.torvald.terrarum.serialise.Common import java.io.InputStream import java.io.Reader +import java.io.StringReader import java.util.* internal data class Joint(val name: String, val position: ADPropertyObject.Vector2i) { @@ -79,30 +80,29 @@ class ADProperties { constructor(gdxFile: FileHandle) { fileFrom = gdxFile.path() adlString = gdxFile.readString(Common.CHARSET.name()) - javaProp.load(gdxFile.read()) continueLoad() } constructor(reader: Reader) { adlString = reader.readText() - javaProp.load(reader) continueLoad() } constructor(inputStream: InputStream) { adlString = inputStream.readAllBytes().toString(Common.CHARSET) - javaProp.load(inputStream) continueLoad() } private fun continueLoad() { + javaProp.load(StringReader(adlString)) + // sanity check reservedProps.forEach { try { javaProp[it]!! } catch (e: NullPointerException) { - throw IllegalArgumentException("Prop '$it' not found from ${fileFrom.ifBlank { "(path unavailable)" }}", e) + throw IllegalArgumentException("Prop '$it' not found from ${fileFrom.ifBlank { "'${adlString.substring(0, 1024)}'" }}", e) } } @@ -210,7 +210,7 @@ class ADProperties { if (it.name.isBlank()) throw IllegalArgumentException("Empty Bodypart name on BODYPARTS; try removing trailing semicolon (';')?") else - throw IllegalArgumentException("Bodyparts definition for '${it.name}' not found from ${fileFrom.ifBlank { "(path unavailable)" }}", e) + throw IllegalArgumentException("Bodyparts definition for '${it.name}' not found from ${fileFrom.ifBlank { "'${adlString.substring(0, 1024)}'" }}", e) } } diff --git a/src/net/torvald/terrarum/App.java b/src/net/torvald/terrarum/App.java index fc5dea69e..b66ab77c7 100644 --- a/src/net/torvald/terrarum/App.java +++ b/src/net/torvald/terrarum/App.java @@ -189,7 +189,9 @@ public class App implements ApplicationListener { * Sorted by the lastplaytime, in reverse order (index 0 is the most recent game played) */ public static TreeMap savegameWorlds = new TreeMap<>(); + public static TreeMap savegameWorldsName = new TreeMap<>(); public static TreeMap savegamePlayers = new TreeMap<>(); + public static TreeMap savegamePlayersName = new TreeMap<>(); public static void updateListOfSavegames() { AppUpdateListOfSavegames(); diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 7f69098c6..5abdf2806 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -19,6 +19,7 @@ import net.torvald.terrarum.App.* import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.WireCodex +import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameactors.Actor import net.torvald.terrarum.gameactors.ActorID import net.torvald.terrarum.gameactors.faction.FactionCodex @@ -682,7 +683,9 @@ class Codex : KVHashMap() { fun AppUpdateListOfSavegames() { App.savegamePlayers.clear() + App.savegamePlayersName.clear() App.savegameWorlds.clear() + App.savegameWorldsName.clear() println("listing savegames...") @@ -692,7 +695,7 @@ fun AppUpdateListOfSavegames() { DiskSkimmer(file, Common.CHARSET, true) } catch (e: Throwable) { - System.err.println("Unable to load a savefile ${file.absolutePath}") + System.err.println("Unable to load a world file ${file.absolutePath}") e.printStackTrace() null } @@ -705,9 +708,33 @@ fun AppUpdateListOfSavegames() { val json = JsonReader().parse(ByteArray64Reader(jsonFile.bytes, Common.CHARSET).readText()) val worldUUID = UUID.fromString(json.get("worldIndex")!!.asString()) App.savegameWorlds[worldUUID] = it + App.savegameWorldsName[worldUUID] = it.getDiskName(Common.CHARSET) + } + + + // create list of players + (File(App.playersDir).listFiles().filter { !it.isDirectory && !it.name.contains('.') }.map { file -> + try { + DiskSkimmer(file, Common.CHARSET, true) + } + catch (e: Throwable) { + System.err.println("Unable to load a player file ${file.absolutePath}") + e.printStackTrace() + null + } + }.filter { it != null }.sortedByDescending { it!!.diskFile.lastModified() } as List).forEach { + println(it.diskFile.absolutePath) + it.rebuild() // disk skimmer was created without initialisation, so do it now + + // TODO write simple and dumb SAX parser for JSON + val jsonFile = it.getFile(-1L)!! + val json = JsonReader().parse(ByteArray64Reader(jsonFile.bytes, Common.CHARSET).readText()) + val playerUUID = UUID.fromString(json.get("uuid")!!.asString()) + App.savegamePlayers[playerUUID] = it +// App.savegamePlayersName[playerUUID] = it.getDiskName(Common.CHARSET) + App.savegamePlayersName[playerUUID] = json.get("actorValue")?.getChild(AVKey.NAME)?.asString() ?: "" } - // TODO: savegamePlayers } /** diff --git a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt index c42bc481b..bdf4c3cd8 100644 --- a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt +++ b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt @@ -333,13 +333,13 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { worldDisk = VDUtil.createNewDisk( 1L shl 60, - worldSavefileName, + savegameNickname, Common.CHARSET ) playerDisk = VDUtil.createNewDisk( 1L shl 60, - playerSavefileName, + actorGamer.actorValue.getAsString(AVKey.NAME) ?: "", Common.CHARSET ) diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/IngamePlayer.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/IngamePlayer.kt index 78919f956..5d42657bc 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/IngamePlayer.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/IngamePlayer.kt @@ -119,7 +119,7 @@ class IngamePlayer : ActorHumanoid { private fun _rebuild(disk: SimpleFileSystem, ad: ADProperties, sprite: SpriteAnimation) { // TODO injecting held item/armour pictures? Would it be AssembleSheetPixmap's job? - val pixmap = AssembleSheetPixmap.fromVirtualDisk(disk, ad) + val pixmap = if (disk.getEntry(-1025) != null) AssembleSheetPixmap.fromVirtualDisk(disk, ad) else AssembleSheetPixmap.fromAssetsDir(ad) val texture = Texture(pixmap) texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest) pixmap.dispose() diff --git a/src/net/torvald/terrarum/modulebasegame/ui/GraphicsControlPanel.kt b/src/net/torvald/terrarum/modulebasegame/ui/GraphicsControlPanel.kt index 722a27b27..6376a5e9e 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/GraphicsControlPanel.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/GraphicsControlPanel.kt @@ -5,9 +5,8 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.g2d.SpriteBatch import net.torvald.TIMES import net.torvald.terrarum.App -import net.torvald.terrarum.CommonResourcePool import net.torvald.terrarum.langpack.Lang -import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory.CELLCOLOUR_BLACK +import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELL_COL import net.torvald.terrarum.ui.Toolkit import net.torvald.terrarum.ui.UICanvas import net.torvald.terrarum.ui.UIItemTextButton @@ -63,7 +62,7 @@ class GraphicsControlPanel : UICanvas() { batch.color = Color.WHITE Toolkit.drawBoxBorder(batch, drawX, drawY, width, height) - batch.color = CELLCOLOUR_BLACK + batch.color = CELL_COL Toolkit.fillArea(batch, drawX, drawY, width, height) batch.color = Color.WHITE diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryFull.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryFull.kt index 167b009d1..caf97faaa 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryFull.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryFull.kt @@ -34,6 +34,8 @@ class UIInventoryFull( override var openCloseTime: Second = 0.0f companion object { + val CELL_COL = Color(0x28282888) + const val INVEN_DEBUG_MODE = false const val REQUIRED_MARGIN: Int = 138 // hard-coded value. Don't know the details. Range: [91-146]. I chose MAX-8 because cell gap is 8 diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryEquippedView.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryEquippedView.kt index f76af5548..8eb9eb860 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryEquippedView.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryEquippedView.kt @@ -5,8 +5,8 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.g2d.SpriteBatch import net.torvald.terrarum.* import net.torvald.terrarum.gameitem.GameItem -import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory.CELLCOLOUR_BLACK import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory.CELLCOLOUR_BLACK_ACTIVE +import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELL_COL import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.itemListHeight import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryItemGrid.Companion.createInvCellGenericKeyDownFun import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryItemGrid.Companion.createInvCellGenericTouchDownFun @@ -43,7 +43,7 @@ class UIItemInventoryEquippedView( lateinit var inventorySortList: Array private var rebuildList = true - val spriteViewBackCol: Color = CELLCOLOUR_BLACK + val spriteViewBackCol: Color = CELL_COL private val equipPosIcon = CommonResourcePool.getAsTextureRegionPack("inventory_category") private val cellToIcon = intArrayOf(0,1,2,3,4,5,6,7,6,7,6,7) @@ -59,7 +59,7 @@ class UIItemInventoryEquippedView( itemImage = null, mouseoverBackCol = Color(CELLCOLOUR_BLACK_ACTIVE), mouseoverBackBlendMode = BlendMode.SCREEN, - backCol = CELLCOLOUR_BLACK, + backCol = CELL_COL, backBlendMode = BlendMode.NORMAL, drawBackOnNull = true, keyDownFun = createInvCellGenericKeyDownFun(), diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryItemGrid.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryItemGrid.kt index 77796a097..831fe5c25 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryItemGrid.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryItemGrid.kt @@ -13,8 +13,8 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory import net.torvald.terrarum.modulebasegame.gameactors.InventoryPair -import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory.CELLCOLOUR_BLACK import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory.CELLCOLOUR_BLACK_ACTIVE +import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELL_COL import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVEN_DEBUG_MODE import net.torvald.terrarum.ui.UICanvas import net.torvald.terrarum.ui.UIItem @@ -55,7 +55,7 @@ class UIItemInventoryItemGrid( override val width = horizontalCells * UIItemInventoryElemSimple.height + (horizontalCells - 1) * listGap override val height = verticalCells * UIItemInventoryElemSimple.height + (verticalCells - 1) * listGap - val backColour = CELLCOLOUR_BLACK + val backColour = CELL_COL init { CommonResourcePool.addToLoadingList("inventory_walletnumberfont") { diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIItemPlayerInfoCell.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIItemPlayerInfoCell.kt deleted file mode 100644 index 30fcd41f8..000000000 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIItemPlayerInfoCell.kt +++ /dev/null @@ -1,129 +0,0 @@ -package net.torvald.terrarum.modulebasegame.ui - -import com.badlogic.gdx.graphics.Camera -import com.badlogic.gdx.graphics.g2d.SpriteBatch -import com.badlogic.gdx.utils.JsonValue -import net.torvald.terrarum.* -import net.torvald.terrarum.langpack.Lang -import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer -import net.torvald.terrarum.ui.UICanvas -import net.torvald.terrarum.ui.UIItem -import java.util.* - -/** - * Created by minjaesong on 2019-02-05. - * - * If ingamePlayer is specified, sprite of current ingamePlayer will be drawn, instead of the SaveMetaData's thumbnail. - */ -class UIItemPlayerInfoCell( - parent: UICanvas, - val saveInfo: JsonValue, - override val width: Int, - initialX: Int, - initialY: Int, - var highlightable: Boolean, - var ingamePlayer: IngamePlayer? = null -) : UIItem(parent, initialX, initialY) { - - override val height = HEIGHT - - companion object { - const val HEIGHT = 64 - } - - private val spriteAreaWidth = 56 - private val spriteToNameAreaGap = 8 - private val edgeGap = 8 - - private val backColInactive = ItemSlotImageFactory.CELLCOLOUR_BLACK - private val backColActive = ItemSlotImageFactory.CELLCOLOUR_BLACK_ACTIVE - - private val textRow1 = (((height / 2) - App.fontGame.lineHeight) / 2).toFloat() - private val textRow2 = textRow1 + (height / 2) - - private val creationTimeStr: String - private val modificationTimeStr: String - - private val worldCountStr: String - private val worldCountStrWidth: Int - - init { - val cal = Calendar.getInstance() - - cal.timeInMillis = saveInfo.getLong("creation_t") * 1000 - creationTimeStr = "${cal[Calendar.YEAR]}-" + - "${cal[Calendar.MONTH].toString().padStart(2,'0')}-" + - "${cal[Calendar.DATE].toString().padStart(2,'0')}" - - cal.timeInMillis = saveInfo.getLong("lastplay_t") * 1000 - modificationTimeStr = "${cal[Calendar.YEAR]}-" + - "${cal[Calendar.MONTH].toString().padStart(2,'0')}-" + - "${cal[Calendar.DATE].toString().padStart(2,'0')}" - - - worldCountStr = Lang["CONTEXT_WORLD_COUNT"] + saveInfo.get("worlds").asIntArray().size - worldCountStrWidth = App.fontGame.getWidth(worldCountStr) - } - - override fun render(batch: SpriteBatch, camera: Camera) { - // background - if (highlightable && mouseUp) { - batch.color = backColActive - blendScreen(batch) - } - else { - batch.color = backColInactive - blendNormal(batch) - } - - batch.fillRect(posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat()) - - - blendNormal(batch) - /*batch.color = SPRITE_DRAW_COL - - // character sprite image - if (ingamePlayer != null) { - val spriteImage = ingamePlayer?.sprite?.textureRegion?.get(0,0) - batch.draw(spriteImage, - ((spriteImage?.regionWidth ?: 2) - spriteAreaWidth).div(2).toFloat(), - ((spriteImage?.regionHeight ?: 2) - height).div(2).toFloat() - ) - } - else { - val spriteImage = saveInfo.thumbnail - batch.draw(spriteImage, - (spriteImage.width - spriteAreaWidth).div(2).toFloat(), - (spriteImage.height - height).div(2).toFloat() - ) - } - - // texts // - - // name - batch.color = Color.WHITE - AppLoader.fontGame.draw(batch, saveInfo.playerName, spriteAreaWidth + spriteToNameAreaGap.toFloat(), textRow1) - // creation and modification time - AppLoader.fontGame.draw(batch, "$creationTimeStr/$modificationTimeStr", spriteAreaWidth + spriteToNameAreaGap.toFloat(), textRow2) - // world count - AppLoader.fontGame.draw(batch, worldCountStr, width - (edgeGap + worldCountStrWidth).toFloat(), textRow1) - // wallet - val walletStr = "ยค " + (ingamePlayer?.inventory?.wallet ?: saveInfo.playerWallet) - val walletStrWidth = AppLoader.fontGame.getWidth(walletStr) - AppLoader.fontGame.draw(batch, walletStr, width - (edgeGap + walletStrWidth).toFloat(), textRow2) - */ - } - - override fun update(delta: Float) { - super.update(delta) - - - - oldPosX = posX - oldPosY = posY - } - - override fun dispose() { - - } -} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIItemSavegameInfoCell.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIItemSavegameInfoCell.kt deleted file mode 100644 index 006cc6335..000000000 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIItemSavegameInfoCell.kt +++ /dev/null @@ -1,32 +0,0 @@ -package net.torvald.terrarum.modulebasegame.ui - -import com.badlogic.gdx.graphics.Camera -import com.badlogic.gdx.graphics.g2d.SpriteBatch -import net.torvald.terrarum.App -import net.torvald.terrarum.ui.UICanvas -import net.torvald.terrarum.ui.UIItem -import java.io.File - -/** - * @param savefile TEVd file - * - * Created by minjaesong on 2018-09-15. - */ -class UIItemSavegameInfoCell( - parent: UICanvas, - savefile: File, - override val width: Int, - initialX: Int, - initialY: Int -) : UIItem(parent, initialX, initialY) { - - override val height: Int = App.fontGame.lineHeight.toInt() * 2 - - override fun render(batch: SpriteBatch, camera: Camera) { - - } - - override fun dispose() { - - } -} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UILoadDemoSavefiles.kt b/src/net/torvald/terrarum/modulebasegame/ui/UILoadDemoSavefiles.kt index 6286f4935..0a8114661 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UILoadDemoSavefiles.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UILoadDemoSavefiles.kt @@ -8,12 +8,18 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.graphics.glutils.ShapeRenderer import com.badlogic.gdx.utils.JsonReader +import com.jme3.math.FastMath +import net.torvald.EMDASH import net.torvald.getKeycapConsole import net.torvald.getKeycapPC +import net.torvald.spriteanimation.SpriteAnimation +import net.torvald.spriteassembler.ADProperties import net.torvald.terrarum.* import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.langpack.Lang +import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELL_COL import net.torvald.terrarum.serialise.Common +import net.torvald.terrarum.serialise.ReadPlayer import net.torvald.terrarum.tvda.ByteArray64InputStream import net.torvald.terrarum.tvda.ByteArray64Reader import net.torvald.terrarum.tvda.DiskSkimmer @@ -97,6 +103,15 @@ class UILoadDemoSavefiles : UICanvas() { private var showSpinner = false + // used by UIItem*Cells + internal var playerDisk: DiskSkimmer? = null + internal var worldDisk: DiskSkimmer? = null + + private val worldCells = ArrayList() + private val playerCells = ArrayList() + + var mode = 0 // 0: show players, 1: show worlds + override fun show() { printdbg(this, "savefiles show()") @@ -109,19 +124,31 @@ class UILoadDemoSavefiles : UICanvas() { Thread { // read savegames var savegamesCount = 0 - App.savegameWorlds.forEach { (uuid, skimmer) -> + App.savegameWorlds.forEach { (_, skimmer) -> val x = uiX + if (App.getConfigBoolean("fx_streamerslayout")) App.scr.chatWidth / 2 else 0 val y = titleTopGradEnd + cellInterval * savegamesCount try { - addUIitem(UIItemWorldCells(this, x, y, skimmer)) + worldCells.add(UIItemWorldCells(this, x, y, skimmer)) savegamesCount += 1 } catch (e: Throwable) { System.err.println("[UILoadDemoSavefiles] Error while loading World '${skimmer.diskFile.absolutePath}'") e.printStackTrace() } + } - + savegamesCount = 0 + App.savegamePlayers.forEach { (_, skimmer) -> + val x = uiX + if (App.getConfigBoolean("fx_streamerslayout")) App.scr.chatWidth / 2 else 0 + val y = titleTopGradEnd + cellInterval * savegamesCount + try { + playerCells.add(UIItemPlayerCells(this, x, y, skimmer)) + savegamesCount += 1 + } + catch (e: Throwable) { + System.err.println("[UILoadDemoSavefiles] Error while loading Player '${skimmer.diskFile.absolutePath}'") + e.printStackTrace() + } } @@ -134,10 +161,14 @@ class UILoadDemoSavefiles : UICanvas() { } override fun hide() { - uiItems.forEach { it.dispose() } - uiItems.clear() + worldCells.forEach { it.dispose() } + worldCells.clear() + playerCells.forEach { it.dispose() } + playerCells.clear() } + private fun getCells() = if (mode == 0) playerCells else worldCells + override fun updateUI(delta: Float) { if (scrollTarget != listScroll) { @@ -156,8 +187,10 @@ class UILoadDemoSavefiles : UICanvas() { } } - for (index in 0 until uiItems.size) { - val it = uiItems[index] + val cells = getCells() + + for (index in 0 until cells.size) { + val it = cells[index] if (index in listScroll - 2 until listScroll + savesVisible + 2) { // re-position it.posY = (it.initialY - uiScroll).roundToInt() @@ -172,6 +205,8 @@ class UILoadDemoSavefiles : UICanvas() { batch.end() + val cells = getCells() + lateinit var savePixmap: Pixmap sliderFBO.inAction(camera as OrthographicCamera, batch) { gdxClearAndSetBlend(0f,0f,0f,0f) @@ -179,8 +214,8 @@ class UILoadDemoSavefiles : UICanvas() { setCameraPosition(batch, camera, 0f, 0f) batch.color = Color.WHITE batch.inUse { - for (index in 0 until uiItems.size) { - val it = uiItems[index] + for (index in 0 until cells.size) { + val it = cells[index] if (index in listScroll - 2 until listScroll + savesVisible + 2) { it.render(batch, camera) } @@ -240,12 +275,14 @@ class UILoadDemoSavefiles : UICanvas() { override fun keyDown(keycode: Int): Boolean { if (this.isVisible) { + val cells = getCells() + if ((keycode == Input.Keys.UP || keycode == App.getConfigInt("control_key_up")) && scrollTarget > 0) { scrollFrom = listScroll scrollTarget -= 1 scrollAnimCounter = 0f } - else if ((keycode == Input.Keys.DOWN || keycode == App.getConfigInt("control_key_down")) && scrollTarget < uiItems.size - savesVisible) { + else if ((keycode == Input.Keys.DOWN || keycode == App.getConfigInt("control_key_down")) && scrollTarget < cells.size - savesVisible) { scrollFrom = listScroll scrollTarget += 1 scrollAnimCounter = 0f @@ -256,12 +293,14 @@ class UILoadDemoSavefiles : UICanvas() { override fun scrolled(amountX: Float, amountY: Float): Boolean { if (this.isVisible) { + val cells = getCells() + if (amountY <= -1f && scrollTarget > 0) { scrollFrom = listScroll scrollTarget -= 1 scrollAnimCounter = 0f } - else if (amountY >= 1f && scrollTarget < uiItems.size - savesVisible) { + else if (amountY >= 1f && scrollTarget < cells.size - savesVisible) { scrollFrom = listScroll scrollTarget += 1 scrollAnimCounter = 0f @@ -323,9 +362,109 @@ class UIItemPlayerCells( override val width = SAVE_CELL_WIDTH override val height = SAVE_CELL_HEIGHT + private var thumbPixmap: Pixmap? = null + private var thumb: TextureRegion? = null + override var clickOnceListener: ((Int, Int, Int) -> Unit)? = { _: Int, _: Int, _: Int -> + parent.playerDisk = skimmer + } + + private var playerName: String = "$EMDASH" + private var worldName: String = "$EMDASH" + private var lastPlayTime: String = "--h--m--s" + private var totalPlayTime: String = "--:--:--" + + init { + skimmer.getFile(-1L)?.bytes?.let { + val json = JsonReader().parse(ByteArray64Reader(it, Common.CHARSET)) + + val playerUUID = UUID.fromString(json["uuid"]?.asString()) + val worldUUID = UUID.fromString(json["worldCurrentlyPlaying"]?.asString()) + + App.savegamePlayersName[playerUUID]?.let { if (it.isNotBlank()) playerName = it } + App.savegameWorldsName[worldUUID]?.let { if (it.isNotBlank()) worldName = it } + json["lastPlayTime"]?.asString()?.let { + lastPlayTime = Instant.ofEpochSecond(it.toLong()) + .atZone(TimeZone.getDefault().toZoneId()) + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + } + json["totalPlayTime"]?.asString()?.let { + totalPlayTime = parseDuration(it.toLong()) + } + + } + } + + private fun parseDuration(seconds: Long): String { + val s = seconds % 60 + val m = (seconds / 60) % 60 + val h = (seconds / 3600) % 24 + val d = seconds / 86400 + return if (d == 0L) + "${h.toString().padStart(2,'0')}h${m.toString().padStart(2,'0')}m${s.toString().padStart(2,'0')}s" + else + "${d}d${h.toString().padStart(2,'0')}h${m.toString().padStart(2,'0')}m${s.toString().padStart(2,'0')}s" + } + + private var sprite: SpriteAnimation? = null + + internal var hasTexture = false + private set + + private val cellCol = CELL_COL + + override fun render(batch: SpriteBatch, camera: Camera) { + // try to generate a texture + if (skimmer.initialised && !hasTexture) { + skimmer.getFile(-1L)?.bytes?.let { + val animFile = skimmer.getFile(-2L)!! + val p = ReadPlayer(skimmer, ByteArray64Reader(it, Common.CHARSET)) + val sprite = SpriteAnimation(p) + val animDesc = ADProperties(ByteArray64Reader(animFile.bytes, Common.CHARSET)) + p.reassembleSprite(skimmer, sprite, animDesc) + sprite.textureRegion.get(0,0).let { + thumb = it + } + this.sprite = sprite + } + + hasTexture = true + } + + val highlightCol = if (mouseUp) UIItemTextButton.defaultActiveCol else Color.WHITE + val x = posX.toFloat() + val y = posY.toFloat() + + // draw box backgrounds + batch.color = cellCol + Toolkit.fillArea(batch, posX, posY, 106, height) + Toolkit.fillArea(batch, posX + 116, posY + 63, width - 116, 57) + + // draw borders + batch.color = highlightCol + // avatar border + Toolkit.drawBoxBorder(batch, posX - 1, posY - 1, 106 + 2, height + 2) + // infocell border + Toolkit.drawBoxBorder(batch, posX + 115, posY + 62, width - 114, 59) + // infocell divider + Toolkit.fillArea(batch, posX + 118, posY + 90, width - 120, 1) + + // player avatar + batch.color = Color.WHITE + thumb?.let { + batch.draw(it, x + FastMath.ceil((106f - it.regionWidth) / 2f), y + FastMath.ceil((height - it.regionHeight) / 2f)) + } + // texts + App.fontGame.draw(batch, playerName, x + 120f, y + height - 54f) + App.fontGame.draw(batch, worldName, x + 120f, y + height - 24f) + App.fontGame.draw(batch, lastPlayTime, x + width - 4f - App.fontGame.getWidth(lastPlayTime), y + height - 54f) + App.fontGame.draw(batch, totalPlayTime, x + width - 4f - App.fontGame.getWidth(totalPlayTime), y + height - 24f) + } override fun dispose() { + thumb?.texture?.dispose() + thumbPixmap?.dispose() + sprite?.dispose() } @@ -398,6 +537,7 @@ class UIItemWorldCells( private val colourBad = Color(0xFF0011FF.toInt()) + private val cellCol = CELL_COL init { @@ -405,6 +545,7 @@ class UIItemWorldCells( } override var clickOnceListener: ((Int, Int, Int) -> Unit)? = { _: Int, _: Int, _: Int -> + parent.worldDisk = skimmer TODO() } @@ -435,8 +576,10 @@ class UIItemWorldCells( val x = posX.toFloat() val y = posY.toFloat() - - // TODO draw border + // draw background + batch.color = cellCol + Toolkit.fillArea(batch, posX, posY, width, height) + // draw border batch.color = highlightCol Toolkit.drawBoxBorder(batch, posX-1, posY-1, width+2, height+2) diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UITitleCharactersList.kt b/src/net/torvald/terrarum/modulebasegame/ui/UITitleCharactersList.kt deleted file mode 100644 index 429af9853..000000000 --- a/src/net/torvald/terrarum/modulebasegame/ui/UITitleCharactersList.kt +++ /dev/null @@ -1,73 +0,0 @@ -package net.torvald.terrarum.modulebasegame.ui - -import com.badlogic.gdx.graphics.Camera -import com.badlogic.gdx.graphics.Color -import com.badlogic.gdx.graphics.g2d.SpriteBatch -import net.torvald.terrarum.App -import net.torvald.terrarum.Second -import net.torvald.terrarum.blendNormal -import net.torvald.terrarum.ui.UICanvas -import net.torvald.terrarum.ui.UIItemList - -/** - * Created by minjaesong on 2018-09-15. - */ -class UITitleCharactersList : UICanvas() { - - override var openCloseTime: Second = 0f - - private val moduleAreaHMargin = 48 - private val moduleAreaBorder = 8 - - override var width = App.scr.width - UIRemoCon.remoConWidth - moduleAreaHMargin - override var height = App.scr.height - moduleAreaHMargin * 2 - - private val moduleInfoCells = ArrayList() - // build characters list - init { - //SavegameLedger.getSavefileList()?.forEachIndexed { index, file -> - // - //} - } - - private val mouduleArea = UIItemList( - this, - moduleInfoCells, - UIRemoCon.remoConWidth, moduleAreaHMargin, - width, - height, - inactiveCol = Color.WHITE, - border = moduleAreaBorder - ) - - - init { - uiItems.add(mouduleArea) - } - - override fun updateUI(delta: Float) { - mouduleArea.update(delta) - } - - override fun renderUI(batch: SpriteBatch, camera: Camera) { - batch.color = Color.WHITE - blendNormal(batch) - mouduleArea.render(batch, camera) - } - - override fun doOpening(delta: Float) { - } - - override fun doClosing(delta: Float) { - } - - override fun endOpening(delta: Float) { - } - - override fun endClosing(delta: Float) { - } - - override fun dispose() { - } - -} \ No newline at end of file diff --git a/src/net/torvald/terrarum/serialise/WriteActor.kt b/src/net/torvald/terrarum/serialise/WriteActor.kt index 872e18e12..d5f6f5e31 100644 --- a/src/net/torvald/terrarum/serialise/WriteActor.kt +++ b/src/net/torvald/terrarum/serialise/WriteActor.kt @@ -101,6 +101,9 @@ object WritePlayer { /** * Player-specific [ReadActor]. * + * @param disk disk + * @param dataStream Reader containing JSON file + * * Created by minjaesong on 2021-10-07. */ object ReadPlayer { diff --git a/work_files/UI/character_cell.kra b/work_files/UI/character_cell.kra index c61680949..17137ace7 100644 --- a/work_files/UI/character_cell.kra +++ b/work_files/UI/character_cell.kra @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6a175474a5dfd719a7f42d4cfcb94a798f11c8ae57c0108cecad165ea19e8487 -size 221010 +oid sha256:9a6afa64a130e927260b7a6b6b06b19a4345a1b354655492b51fd20396fefdfb +size 124756