mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-10 18:44:05 +09:00
detects corrupted and damaged and deleted and whatever savefiles; uiitem will call show() and hide() upon opening and closing
This commit is contained in:
@@ -10,13 +10,15 @@ uniform sampler2D u_texture;
|
|||||||
|
|
||||||
|
|
||||||
// "steps" of R, G and B. Must be integer && equal or greater than 2
|
// "steps" of R, G and B. Must be integer && equal or greater than 2
|
||||||
uniform float rcount = 32.0;
|
uniform float rcount = 8.0;
|
||||||
uniform float gcount = 64.0;
|
uniform float gcount = 8.0;
|
||||||
uniform float bcount = 32.0;
|
uniform float bcount = 8.0;
|
||||||
uniform float acount = 1.0;
|
uniform float acount = 1.0;
|
||||||
|
|
||||||
int bayer[14 * 14] = int[](131,187,8,78,50,18,134,89,155,102,29,95,184,73,22,86,113,171,142,105,34,166,9,60,151,128,40,110,168,137,45,28,64,188,82,54,124,189,80,13,156,56,7,61,186,121,154,6,108,177,24,100,38,176,93,123,83,148,96,17,88,133,44,145,69,161,139,72,30,181,115,27,163,47,178,65,164,14,120,48,5,127,153,52,190,58,126,81,116,21,106,77,173,92,191,63,99,12,76,144,4,185,37,149,192,39,135,23,117,31,170,132,35,172,103,66,129,79,3,97,57,159,70,141,53,94,114,20,49,158,19,146,169,122,183,11,104,180,2,165,152,87,182,118,91,42,67,25,84,147,43,85,125,68,16,136,71,10,193,112,160,138,51,111,162,26,194,46,174,107,41,143,33,74,1,101,195,15,75,140,109,90,32,62,157,98,167,119,179,59,36,130,175,55,0,150);
|
//int bayer[14 * 14] = int[](131,187,8,78,50,18,134,89,155,102,29,95,184,73,22,86,113,171,142,105,34,166,9,60,151,128,40,110,168,137,45,28,64,188,82,54,124,189,80,13,156,56,7,61,186,121,154,6,108,177,24,100,38,176,93,123,83,148,96,17,88,133,44,145,69,161,139,72,30,181,115,27,163,47,178,65,164,14,120,48,5,127,153,52,190,58,126,81,116,21,106,77,173,92,191,63,99,12,76,144,4,185,37,149,192,39,135,23,117,31,170,132,35,172,103,66,129,79,3,97,57,159,70,141,53,94,114,20,49,158,19,146,169,122,183,11,104,180,2,165,152,87,182,118,91,42,67,25,84,147,43,85,125,68,16,136,71,10,193,112,160,138,51,111,162,26,194,46,174,107,41,143,33,74,1,101,195,15,75,140,109,90,32,62,157,98,167,119,179,59,36,130,175,55,0,150);
|
||||||
float bayerSize = 14.0;
|
//float bayerSize = 14.0;
|
||||||
|
int bayer[4 * 4] = int[](0,8,2,10,12,4,14,6,3,11,1,9,15,7,13,5);
|
||||||
|
float bayerSize = 4.0;
|
||||||
|
|
||||||
|
|
||||||
float bayerDivider = bayerSize * bayerSize;
|
float bayerDivider = bayerSize * bayerSize;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame;
|
|||||||
import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory;
|
import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory;
|
||||||
import net.torvald.terrarum.serialise.WriteConfig;
|
import net.torvald.terrarum.serialise.WriteConfig;
|
||||||
import net.torvald.terrarum.serialise.WriteMeta;
|
import net.torvald.terrarum.serialise.WriteMeta;
|
||||||
|
import net.torvald.terrarum.tvda.DiskSkimmer;
|
||||||
import net.torvald.terrarum.tvda.VirtualDisk;
|
import net.torvald.terrarum.tvda.VirtualDisk;
|
||||||
import net.torvald.terrarum.utils.JsonFetcher;
|
import net.torvald.terrarum.utils.JsonFetcher;
|
||||||
import net.torvald.terrarum.worlddrawer.CreateTileAtlas;
|
import net.torvald.terrarum.worlddrawer.CreateTileAtlas;
|
||||||
@@ -196,7 +197,7 @@ public class App implements ApplicationListener {
|
|||||||
/**
|
/**
|
||||||
* Sorted by the lastplaytime, in reverse order (index 0 is the most recent game played)
|
* Sorted by the lastplaytime, in reverse order (index 0 is the most recent game played)
|
||||||
*/
|
*/
|
||||||
public static ArrayList<Pair<File, WriteMeta.WorldMeta>> savegames = new ArrayList<>();
|
public static ArrayList<DiskSkimmer> savegames = new ArrayList<>();
|
||||||
|
|
||||||
public static void updateListOfSavegames() {
|
public static void updateListOfSavegames() {
|
||||||
AppUpdateListOfSavegames();
|
AppUpdateListOfSavegames();
|
||||||
@@ -301,7 +302,6 @@ public class App implements ApplicationListener {
|
|||||||
createDirs();
|
createDirs();
|
||||||
initialiseConfig();
|
initialiseConfig();
|
||||||
readConfigJson();
|
readConfigJson();
|
||||||
updateListOfSavegames();
|
|
||||||
|
|
||||||
setGamepadButtonLabels();
|
setGamepadButtonLabels();
|
||||||
|
|
||||||
|
|||||||
@@ -22,15 +22,13 @@ import net.torvald.terrarum.blockproperties.WireCodex
|
|||||||
import net.torvald.terrarum.gameactors.Actor
|
import net.torvald.terrarum.gameactors.Actor
|
||||||
import net.torvald.terrarum.gameactors.ActorID
|
import net.torvald.terrarum.gameactors.ActorID
|
||||||
import net.torvald.terrarum.gameactors.faction.FactionCodex
|
import net.torvald.terrarum.gameactors.faction.FactionCodex
|
||||||
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
import net.torvald.terrarum.gameworld.fmod
|
import net.torvald.terrarum.gameworld.fmod
|
||||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||||
import net.torvald.terrarum.itemproperties.MaterialCodex
|
import net.torvald.terrarum.itemproperties.MaterialCodex
|
||||||
import net.torvald.terrarum.serialise.Common
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||||
import net.torvald.terrarum.serialise.ReadMeta
|
import net.torvald.terrarum.serialise.*
|
||||||
import net.torvald.terrarum.tvda.DiskSkimmer
|
import net.torvald.terrarum.tvda.*
|
||||||
import net.torvald.terrarum.tvda.EntryFile
|
|
||||||
import net.torvald.terrarum.tvda.VDUtil
|
|
||||||
import net.torvald.terrarum.tvda.VirtualDisk
|
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||||
import net.torvald.terrarumsansbitmap.gdx.GameFontBase
|
import net.torvald.terrarumsansbitmap.gdx.GameFontBase
|
||||||
@@ -520,7 +518,7 @@ val ccK = GameFontBase.toColorCode(0xF888)
|
|||||||
val ccE = GameFontBase.toColorCode(0xFBBB)
|
val ccE = GameFontBase.toColorCode(0xFBBB)
|
||||||
|
|
||||||
// Zelda-esque text colour emphasis
|
// Zelda-esque text colour emphasis
|
||||||
val emphStrong = GameFontBase.toColorCode(0xFF88)
|
val emphRed = GameFontBase.toColorCode(0xFF88)
|
||||||
val emphObj = GameFontBase.toColorCode(0xF0FF)
|
val emphObj = GameFontBase.toColorCode(0xF0FF)
|
||||||
val emphVerb = GameFontBase.toColorCode(0xFFF6)
|
val emphVerb = GameFontBase.toColorCode(0xFFF6)
|
||||||
|
|
||||||
@@ -687,39 +685,52 @@ fun AppUpdateListOfSavegames() {
|
|||||||
App.savegames.clear()
|
App.savegames.clear()
|
||||||
File(App.defaultSaveDir).listFiles().filter { !it.isDirectory && !it.name.contains('.') }.map { file ->
|
File(App.defaultSaveDir).listFiles().filter { !it.isDirectory && !it.name.contains('.') }.map { file ->
|
||||||
try {
|
try {
|
||||||
DiskSkimmer(file, Common.CHARSET) { it.containsKey(-1) }.requestFile(-1)?.let {
|
DiskSkimmer(file, Common.CHARSET, true)
|
||||||
file to ReadMeta.fromDiskEntry(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (e: Throwable) {
|
catch (e: Throwable) {
|
||||||
System.err.println("Unable to load a savefile ${file.absolutePath}")
|
System.err.println("Unable to load a savefile ${file.absolutePath}")
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}.filter { it != null }.sortedByDescending { it!!.second.lastplay_t }.forEach {
|
}.filter { it != null }.sortedByDescending { it!!.diskFile.lastModified() }.forEach {
|
||||||
App.savegames.add(it!!)
|
App.savegames.add(it!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param skimmer loaded with the savefile
|
* @param skimmer loaded with the savefile, rebuilt/updated beforehand
|
||||||
*/
|
*/
|
||||||
fun checkForSavegameDamage(skimmer: DiskSkimmer): Boolean {
|
fun checkForSavegameDamage(skimmer: DiskSkimmer): Boolean {
|
||||||
// # check if The Player is there
|
try {
|
||||||
val player = skimmer.requestFile(PLAYER_REF_ID.toLong().and(0xFFFFFFFFL))?.contents ?: return true
|
// # check for meta
|
||||||
// # check if:
|
val metaFile = skimmer.requestFile(-1) ?: return true
|
||||||
// the world The Player is at actually exists
|
// # check if The Player is there
|
||||||
// all the actors for the world actually exists
|
val player = skimmer.requestFile(PLAYER_REF_ID.toLong().and(0xFFFFFFFFL))?.contents ?: return true
|
||||||
val currentWorld = (player as EntryFile).bytes.let {
|
// # check if:
|
||||||
val maxsize = 1 shl 30
|
// the world The Player is at actually exists
|
||||||
val worldIndexRegex = Regex("""worldIndex: ?([0-9]+)""")
|
// all the actors for the world actually exists
|
||||||
val rawJson = it.sliceArray(0 until minOf(maxsize, if (it.size >= maxsize) maxsize else it.size.toInt())).toString(Common.CHARSET)
|
// TODO might want SAX parser for JSON
|
||||||
|
val currentWorld = (player as EntryFile).bytes.let {
|
||||||
|
(ReadActor.readActorBare(ByteArray64Reader(it, Common.CHARSET)) as? IngamePlayer
|
||||||
|
?: return true).worldCurrentlyPlaying
|
||||||
|
}
|
||||||
|
if (currentWorld == 0) return true
|
||||||
|
val worldData = (skimmer.requestFile(currentWorld.toLong())?.contents as? EntryFile)?.bytes ?: return true
|
||||||
|
val world = Common.jsoner.fromJson(GameWorld::class.java, ByteArray64Reader(worldData, Common.CHARSET))
|
||||||
|
|
||||||
// todo
|
var hasMissingActor = false
|
||||||
|
world.actors.forEach {
|
||||||
|
if (!skimmer.hasEntry(it.toLong().and(0xFFFFFFFFL))) {
|
||||||
|
System.err.println("Nonexisting actor $it for savegame ${skimmer.diskFile.absolutePath}")
|
||||||
|
hasMissingActor = true
|
||||||
|
}
|
||||||
|
}; if (hasMissingActor) return true
|
||||||
|
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
catch (e: Throwable) {
|
||||||
|
e.printStackTrace()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// skimmer.requestFile(367228416) ?: return true
|
|
||||||
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
@@ -218,11 +218,14 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
|||||||
|
|
||||||
worldFBO = FrameBuffer(Pixmap.Format.RGBA8888, App.scr.width, App.scr.height, false)
|
worldFBO = FrameBuffer(Pixmap.Format.RGBA8888, App.scr.width, App.scr.height, false)
|
||||||
|
|
||||||
loadThingsWhileIntroIsVisible()
|
|
||||||
|
|
||||||
// load list of savegames
|
// load list of savegames
|
||||||
|
println("[TitleScreen] update list of savegames")
|
||||||
App.updateListOfSavegames()
|
App.updateListOfSavegames()
|
||||||
|
|
||||||
|
// App.savegames.forEach { println(it.diskFile.absolutePath) }
|
||||||
|
|
||||||
|
|
||||||
|
loadThingsWhileIntroIsVisible()
|
||||||
printdbg(this, "show() exit")
|
printdbg(this, "show() exit")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class UIFakeGradOverlay : UICanvas() {
|
|||||||
override fun updateUI(delta: Float) {}
|
override fun updateUI(delta: Float) {}
|
||||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
blendMul(batch)
|
blendMul(batch)
|
||||||
batch.draw(tex, 0f, 0f, App.scr.halfwf * 1.5f, App.scr.hf)
|
batch.draw(tex, 0f, 0f, App.scr.wf, App.scr.hf)
|
||||||
|
|
||||||
blendNormal(batch)
|
blendNormal(batch)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer
|
|||||||
import net.torvald.getKeycapConsole
|
import net.torvald.getKeycapConsole
|
||||||
import net.torvald.getKeycapPC
|
import net.torvald.getKeycapPC
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
|
import net.torvald.terrarum.App.printdbg
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.serialise.Common
|
import net.torvald.terrarum.serialise.Common
|
||||||
import net.torvald.terrarum.serialise.LoadSavegame
|
import net.torvald.terrarum.serialise.LoadSavegame
|
||||||
@@ -73,14 +74,6 @@ class UILoadDemoSavefiles : UICanvas() {
|
|||||||
else
|
else
|
||||||
"${getKeycapConsole('R')} ${Lang["MENU_CONTROLS_SCROLL"]}"
|
"${getKeycapConsole('R')} ${Lang["MENU_CONTROLS_SCROLL"]}"
|
||||||
|
|
||||||
// read savegames
|
|
||||||
init {
|
|
||||||
App.savegames.forEachIndexed { index, fileMetaPair ->
|
|
||||||
val x = uiX
|
|
||||||
val y = titleTopGradEnd + cellInterval * index
|
|
||||||
addUIitem(UIItemDemoSaveCells(this, x, y, fileMetaPair.first, fileMetaPair.second))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var scrollAreaHeight = height - 2 * App.scr.tvSafeGraphicsHeight - 64
|
private var scrollAreaHeight = height - 2 * App.scr.tvSafeGraphicsHeight - 64
|
||||||
private var listScroll = 0 // only update when animation is finished
|
private var listScroll = 0 // only update when animation is finished
|
||||||
@@ -94,6 +87,31 @@ class UILoadDemoSavefiles : UICanvas() {
|
|||||||
|
|
||||||
private var sliderFBO = FrameBuffer(Pixmap.Format.RGBA8888, uiWidth + 10, height, true)
|
private var sliderFBO = FrameBuffer(Pixmap.Format.RGBA8888, uiWidth + 10, height, true)
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
printdbg(this, "savefiles show()")
|
||||||
|
|
||||||
|
// read savegames
|
||||||
|
var savegamesCount = 0
|
||||||
|
App.savegames.forEach { skimmer ->
|
||||||
|
val x = uiX
|
||||||
|
val y = titleTopGradEnd + cellInterval * savegamesCount
|
||||||
|
try {
|
||||||
|
addUIitem(UIItemDemoSaveCells(this, x, y, skimmer))
|
||||||
|
savegamesCount += 1
|
||||||
|
}
|
||||||
|
catch (e: Throwable) {
|
||||||
|
System.err.println("[UILoadDemoSavefiles] Savefile '${skimmer.diskFile.absolutePath}' cannot be loaded")
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hide() {
|
||||||
|
uiItems.forEach { it.dispose() }
|
||||||
|
uiItems.clear()
|
||||||
|
}
|
||||||
|
|
||||||
override fun updateUI(delta: Float) {
|
override fun updateUI(delta: Float) {
|
||||||
|
|
||||||
if (scrollTarget != listScroll) {
|
if (scrollTarget != listScroll) {
|
||||||
@@ -276,24 +294,28 @@ class UIItemDemoSaveCells(
|
|||||||
parent: UILoadDemoSavefiles,
|
parent: UILoadDemoSavefiles,
|
||||||
initialX: Int,
|
initialX: Int,
|
||||||
initialY: Int,
|
initialY: Int,
|
||||||
val diskfile: File, val meta: WriteMeta.WorldMeta) : UIItem(parent, initialX, initialY) {
|
val skimmer: DiskSkimmer) : UIItem(parent, initialX, initialY) {
|
||||||
|
|
||||||
private val skimmer = DiskSkimmer(diskfile, Common.CHARSET)
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val WIDTH = 480
|
const val WIDTH = 480
|
||||||
const val HEIGHT = 120
|
const val HEIGHT = 120
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
printdbg(this, "Rebuilding skimmer for savefile ${skimmer.diskFile.absolutePath}")
|
||||||
|
skimmer.rebuild()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var saveDamaged = checkForSavegameDamage(skimmer)
|
||||||
|
|
||||||
override val width: Int = WIDTH
|
override val width: Int = WIDTH
|
||||||
override val height: Int = HEIGHT
|
override val height: Int = HEIGHT
|
||||||
|
|
||||||
private lateinit var thumbPixmap: Pixmap
|
private var thumbPixmap: Pixmap? = null
|
||||||
private var thumb: TextureRegion? = null
|
private var thumb: TextureRegion? = null
|
||||||
private val grad = CommonResourcePool.getAsTexture("title_halfgrad")
|
private val grad = CommonResourcePool.getAsTexture("title_halfgrad")
|
||||||
|
|
||||||
private var saveDamaged = checkForSavegameDamage(skimmer)
|
|
||||||
|
|
||||||
private fun parseDuration(seconds: Long): String {
|
private fun parseDuration(seconds: Long): String {
|
||||||
val s = seconds % 60
|
val s = seconds % 60
|
||||||
val m = (seconds / 60) % 60
|
val m = (seconds / 60) % 60
|
||||||
@@ -305,18 +327,25 @@ class UIItemDemoSaveCells(
|
|||||||
"${d}d${h.toString().padStart(2,'0')}h${m.toString().padStart(2,'0')}m${s.toString().padStart(2,'0')}s"
|
"${d}d${h.toString().padStart(2,'0')}h${m.toString().padStart(2,'0')}m${s.toString().padStart(2,'0')}s"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val metaFile = skimmer.requestFile(-1)
|
||||||
|
|
||||||
private val saveName = skimmer.getDiskName(Common.CHARSET)
|
private val saveName = skimmer.getDiskName(Common.CHARSET)
|
||||||
private val saveMode = skimmer.getSaveMode()
|
private val saveMode = skimmer.getSaveMode()
|
||||||
|
private val meta = if (metaFile != null) ReadMeta.fromDiskEntry(metaFile) else null
|
||||||
|
|
||||||
private val lastPlayedTimestamp = Instant.ofEpochSecond(meta.lastplay_t)
|
private val colourBad = Color(0xFF8888FF.toInt())
|
||||||
|
|
||||||
|
private val lastPlayedTimestamp = if (meta != null)
|
||||||
|
Instant.ofEpochSecond(meta.lastplay_t)
|
||||||
.atZone(TimeZone.getDefault().toZoneId())
|
.atZone(TimeZone.getDefault().toZoneId())
|
||||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) +
|
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) +
|
||||||
"/${parseDuration(meta.playtime_t)}"
|
"/${parseDuration(meta.playtime_t)}"
|
||||||
|
else "--:--:--/--h--m--s"
|
||||||
|
|
||||||
init {
|
init {
|
||||||
try {
|
// load thumbnail or use stock if the file is not there
|
||||||
// load a thumbnail
|
skimmer.requestFile(-2)?.let {
|
||||||
val zippedTga = (skimmer.requestFile(-2)!!.contents as EntryFile).bytes
|
val zippedTga = (it.contents as EntryFile).bytes
|
||||||
val gzin = GZIPInputStream(ByteArray64InputStream(zippedTga))
|
val gzin = GZIPInputStream(ByteArray64InputStream(zippedTga))
|
||||||
val tgaFileContents = gzin.readAllBytes(); gzin.close()
|
val tgaFileContents = gzin.readAllBytes(); gzin.close()
|
||||||
|
|
||||||
@@ -326,15 +355,11 @@ class UIItemDemoSaveCells(
|
|||||||
thumb = TextureRegion(thumbTex)
|
thumb = TextureRegion(thumbTex)
|
||||||
thumb!!.setRegion(0, (thumbTex.height - 2 * height) / 2, width * 2, height * 2)
|
thumb!!.setRegion(0, (thumbTex.height - 2 * height) / 2, width * 2, height * 2)
|
||||||
}
|
}
|
||||||
catch (e: NullPointerException) {
|
|
||||||
// use stock texture
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override var clickOnceListener: ((Int, Int, Int) -> Unit)? = { _: Int, _: Int, _: Int ->
|
override var clickOnceListener: ((Int, Int, Int) -> Unit)? = { _: Int, _: Int, _: Int ->
|
||||||
LoadSavegame(VDUtil.readDiskArchive(diskfile, Level.INFO))
|
LoadSavegame(VDUtil.readDiskArchive(skimmer.diskFile, Level.INFO))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||||
@@ -363,9 +388,9 @@ class UIItemDemoSaveCells(
|
|||||||
val tlen = App.fontSmallNumbers.getWidth(lastPlayedTimestamp)
|
val tlen = App.fontSmallNumbers.getWidth(lastPlayedTimestamp)
|
||||||
App.fontSmallNumbers.draw(batch, lastPlayedTimestamp, x + (width - tlen) - 3f, y + height - 16f)
|
App.fontSmallNumbers.draw(batch, lastPlayedTimestamp, x + (width - tlen) - 3f, y + height - 16f)
|
||||||
// file size
|
// file size
|
||||||
App.fontSmallNumbers.draw(batch, "${diskfile.length().ushr(10)} KiB", x + 3f, y + height - 16f)
|
App.fontSmallNumbers.draw(batch, "${skimmer.diskFile.length().ushr(10)} KiB", x + 3f, y + height - 16f)
|
||||||
// savegame name
|
// savegame name
|
||||||
if (saveDamaged) batch.color = Color.RED
|
if (saveDamaged) batch.color = colourBad
|
||||||
App.fontGame.draw(batch, saveName + "${if (saveMode % 2 == 1) "*" else ""}", x + 3f, y + 1f)
|
App.fontGame.draw(batch, saveName + "${if (saveMode % 2 == 1) "*" else ""}", x + 3f, y + 1f)
|
||||||
|
|
||||||
super.render(batch, camera)
|
super.render(batch, camera)
|
||||||
@@ -374,7 +399,7 @@ class UIItemDemoSaveCells(
|
|||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
thumb?.texture?.dispose()
|
thumb?.texture?.dispose()
|
||||||
thumbPixmap.dispose()
|
thumbPixmap?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -32,8 +32,8 @@ class UIProxyLoadLatestSave : UICanvas() {
|
|||||||
|
|
||||||
override fun endOpening(delta: Float) {
|
override fun endOpening(delta: Float) {
|
||||||
if (App.savegames.size > 0) {
|
if (App.savegames.size > 0) {
|
||||||
LoadSavegame(VDUtil.readDiskArchive(App.savegames[0].first, Level.INFO) {
|
LoadSavegame(VDUtil.readDiskArchive(App.savegames[0].diskFile, Level.INFO) {
|
||||||
System.err.println("Possibly damaged savefile ${App.savegames[0].first.absolutePath}:\n$it")
|
System.err.println("Possibly damaged savefile ${App.savegames[0].diskFile.absolutePath}:\n$it")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package net.torvald.terrarum.tvda
|
package net.torvald.terrarum.tvda
|
||||||
|
|
||||||
|
import net.torvald.terrarum.serialise.Common
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
|
import java.nio.file.NoSuchFileException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
import kotlin.experimental.and
|
import kotlin.experimental.and
|
||||||
@@ -18,9 +20,9 @@ import kotlin.experimental.and
|
|||||||
* Created by minjaesong on 2017-11-17.
|
* Created by minjaesong on 2017-11-17.
|
||||||
*/
|
*/
|
||||||
class DiskSkimmer(
|
class DiskSkimmer(
|
||||||
private val diskFile: File,
|
val diskFile: File,
|
||||||
val charset: Charset = Charset.defaultCharset(),
|
val charset: Charset = Charset.defaultCharset(),
|
||||||
private val skimmingStopFunction: (HashMap<EntryID, Long>) -> Boolean = { false }
|
noInit: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -45,6 +47,23 @@ removefile:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
fun checkFileSanity() {
|
||||||
|
if (!diskFile.exists()) throw NoSuchFileException(diskFile.absoluteFile)
|
||||||
|
if (diskFile.length() < 310L) throw RuntimeException("Invalid Virtual Disk file!")
|
||||||
|
|
||||||
|
// check magic
|
||||||
|
val fis = FileInputStream(diskFile)
|
||||||
|
|
||||||
|
val magic = ByteArray(4).let { fis.read(it); it }
|
||||||
|
if (!magic.contentEquals(VirtualDisk.MAGIC)) throw RuntimeException("Invalid Virtual Disk file!")
|
||||||
|
|
||||||
|
fis.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
checkFileSanity()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EntryID to Offset.
|
* EntryID to Offset.
|
||||||
*
|
*
|
||||||
@@ -52,32 +71,30 @@ removefile:
|
|||||||
*/
|
*/
|
||||||
private var entryToOffsetTable = HashMap<EntryID, Long>()
|
private var entryToOffsetTable = HashMap<EntryID, Long>()
|
||||||
|
|
||||||
|
lateinit var fa: RandomAccessFile//RandomAccessFile(diskFile, "rw")
|
||||||
/** temporary storage to store tree edges */
|
|
||||||
// private var directoryStruct = ArrayList<DirectoryEdge>()
|
|
||||||
|
|
||||||
/** root node of the directory tree */
|
|
||||||
// private var directory = DirectoryNode(0, null, DiskEntry.DIRECTORY, "")
|
|
||||||
|
|
||||||
// private data class DirectoryEdge(val nodeParent: EntryID, val node: EntryID, val type: Byte, val name: String)
|
|
||||||
// private data class DirectoryNode(var nodeThis: EntryID, val nodeParent: EntryID?, var type: Byte, var name: String)
|
|
||||||
|
|
||||||
private val dirDelim = Regex("""[\\/]""")
|
|
||||||
private val DIR = "/"
|
|
||||||
|
|
||||||
val fa = RandomAccessFile(diskFile, "rw")
|
|
||||||
|
|
||||||
private fun debugPrintln(s: Any) {
|
private fun debugPrintln(s: Any) {
|
||||||
if (false) println(s.toString())
|
if (false) println(s.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var initialised = false
|
||||||
|
private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
if (!noInit) {
|
||||||
|
rebuild()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rebuild() {
|
||||||
|
checkFileSanity() // state of the file may have been changed (e.g. file deleted) so we check again
|
||||||
|
|
||||||
|
fa = RandomAccessFile(diskFile, "rw")
|
||||||
|
|
||||||
val fis = FileInputStream(diskFile)
|
val fis = FileInputStream(diskFile)
|
||||||
|
|
||||||
println("[DiskSkimmer] loading the diskfile ${diskFile.canonicalPath}")
|
|
||||||
|
|
||||||
var currentPosition = fis.skip(VirtualDisk.HEADER_SIZE) // skip disk header
|
var currentPosition = fis.skip(VirtualDisk.HEADER_SIZE) // skip disk header
|
||||||
|
|
||||||
|
println("[DiskSkimmer] loading the diskfile ${diskFile.canonicalPath}")
|
||||||
|
|
||||||
fun skipRead(bytes: Long) {
|
fun skipRead(bytes: Long) {
|
||||||
currentPosition += fis.skip(bytes)
|
currentPosition += fis.skip(bytes)
|
||||||
@@ -126,6 +143,7 @@ removefile:
|
|||||||
return buffer.toLongBig()
|
return buffer.toLongBig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val currentLength = diskFile.length()
|
val currentLength = diskFile.length()
|
||||||
while (currentPosition < currentLength) {
|
while (currentPosition < currentLength) {
|
||||||
|
|
||||||
@@ -154,13 +172,15 @@ removefile:
|
|||||||
else {
|
else {
|
||||||
debugPrintln("[DiskSkimmer] ... discarding entry $entryID at offset $offset (name: ${diskIDtoReadableFilename(entryID)})")
|
debugPrintln("[DiskSkimmer] ... discarding entry $entryID at offset $offset (name: ${diskIDtoReadableFilename(entryID)})")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skimmingStopFunction(entryToOffsetTable)) break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fis.close()
|
||||||
|
initialised = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun hasEntry(entryID: EntryID) = entryToOffsetTable.containsKey(entryID)
|
||||||
|
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
// THESE ARE METHODS TO SUPPORT ON-LINE READING //
|
// THESE ARE METHODS TO SUPPORT ON-LINE READING //
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -233,18 +233,36 @@ abstract class UICanvas(
|
|||||||
|
|
||||||
fun setAsAlwaysVisible() {
|
fun setAsAlwaysVisible() {
|
||||||
handler.setAsAlwaysVisible()
|
handler.setAsAlwaysVisible()
|
||||||
|
show()
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun setAsOpen() {
|
open fun setAsOpen() {
|
||||||
handler.setAsOpen()
|
handler.setAsOpen()
|
||||||
|
show()
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun setAsClose() {
|
open fun setAsClose() {
|
||||||
handler.setAsClose()
|
handler.setAsClose()
|
||||||
|
hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun toggleOpening() {
|
open fun toggleOpening() {
|
||||||
handler.toggleOpening()
|
// handler.toggleOpening()
|
||||||
|
if (handler.alwaysVisible && !handler.doNotWarnConstant) {
|
||||||
|
throw RuntimeException("[UIHandler] Tried to 'toggle opening of' constant UI")
|
||||||
|
}
|
||||||
|
if (isVisible) {
|
||||||
|
if (!isClosing) {
|
||||||
|
setAsClose()
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!isOpening) {
|
||||||
|
setAsOpen()
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline val isOpened: Boolean
|
inline val isOpened: Boolean
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ void main() {
|
|||||||
var initialX = posX
|
var initialX = posX
|
||||||
var initialY = posY
|
var initialY = posY
|
||||||
|
|
||||||
private var alwaysVisible = false
|
var alwaysVisible = false; private set
|
||||||
|
|
||||||
var isOpening = false
|
var isOpening = false
|
||||||
var isClosing = false
|
var isClosing = false
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ class UIItemTextButtonList(
|
|||||||
private var clickLatched = false
|
private var clickLatched = false
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
printdbg(this, "${this.javaClass.simpleName} show()")
|
// printdbg(this, "${this.javaClass.simpleName} show()")
|
||||||
clickLatched = true
|
clickLatched = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
Each file on the Savegame has following convention:
|
Each file on the Savegame has following convention:
|
||||||
|
|
||||||
|Type|Filename|ID|
|
|Type|Filename|ID|
|
||||||
|--|--|--|
|
|---|---|---|
|
||||||
|Metadata|savegame|-1|
|
|Metadata|savegame|-1|
|
||||||
|Blocks Properties|blocks|-16|
|
|Blocks Properties|blocks|-16|
|
||||||
|Items Properties|items|-17|
|
|Items Properties|items|-17|
|
||||||
|
|||||||
Reference in New Issue
Block a user