From 908a6ed9533516fd0a4d6149f5c6a3e0f39029cb Mon Sep 17 00:00:00 2001 From: minjaesong Date: Fri, 29 Sep 2023 21:26:24 +0900 Subject: [PATCH] working savegame migrator --- .../terrarum/itemproperties/ItemCodex.kt | 1 + .../modulebasegame/SavegameMigrator.kt | 56 +++++++++++-- .../gameactors/ActorInventory.kt | 5 +- .../gameactors/FixtureInventory.kt | 80 +++++++++++-------- .../modulebasegame/serialise/WriteSavegame.kt | 25 +++++- 5 files changed, 123 insertions(+), 44 deletions(-) diff --git a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt index 2c09fae02..61e5824ae 100644 --- a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt +++ b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt @@ -194,4 +194,5 @@ class ItemCodex { } fun hasItem(itemID: ItemID): Boolean = dynamicItemInventory.containsKey(itemID) + fun isEmpty(): Boolean = itemCodex.isEmpty() } \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/SavegameMigrator.kt b/src/net/torvald/terrarum/modulebasegame/SavegameMigrator.kt index 019a64a32..bb114ce59 100644 --- a/src/net/torvald/terrarum/modulebasegame/SavegameMigrator.kt +++ b/src/net/torvald/terrarum/modulebasegame/SavegameMigrator.kt @@ -1,7 +1,12 @@ package net.torvald.terrarum.modulebasegame +import net.torvald.terrarum.App.printdbg +import net.torvald.terrarum.ItemCodex import net.torvald.terrarum.gameactors.Actor +import net.torvald.terrarum.gameitems.isDynamic +import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer +import net.torvald.terrarum.modulebasegame.gameactors.Pocketed import net.torvald.util.SortedArrayList import kotlin.reflect.full.declaredFunctions import kotlin.reflect.full.findAnnotation @@ -54,7 +59,7 @@ internal object SavegameMigrator { if (from > to) throw IllegalArgumentException("Illegal query '$query'") - matched = matched or (from <= fileVersion && fileVersion <= to) + matched = matched or (fileVersion in from..to) } else if (query.endsWith('+') || query.endsWith('!')) { val operator = query.last() @@ -79,7 +84,8 @@ internal object SavegameMigrator { this::class.declaredFunctions.filter { annotationMatches(worldVersion, it.findAnnotation()) }.forEach { func -> - actors0.forEach { actor -> func.call(actor) } + printdbg(this, func.toString()) + actors0.forEach { actor -> func.call(this, actor) } } } else { @@ -93,19 +99,59 @@ internal object SavegameMigrator { this::class.declaredFunctions.filter { annotationMatches(worldVersion, it.findAnnotation()) }.forEach { func -> - nonPlayers.forEach { actor -> func.call(actor) } + nonPlayers.forEach { actor -> func.call(this, actor) } } this::class.declaredFunctions.filter { annotationMatches(playerVersion, it.findAnnotation()) }.forEach { func -> - players.forEach { player -> func.call(player) } + players.forEach { player -> func.call(this, player) } } } } + + + + /***********************************/ + /* INSERT MIGRATION FUNCTIONS HERE */ + /***********************************/ + + @AppliedVersion("all") fun mergeUnlitBlocks(actor: Actor) { - TODO() + if (ItemCodex.isEmpty()) throw Error("ItemCodex is empty") + + if (actor is Pocketed) { + val oldItemEquipped = actor.inventory.itemEquipped.copyOf() + val oldQuickSlot = actor.inventory.quickSlot.copyOf() + val oldItems = actor.inventory.clear() + + oldItems.forEach { (itm, qty) -> + actor.inventory.add(itm, qty) + } + + oldItemEquipped.forEachIndexed { index, id0 -> + if (id0?.isDynamic() == true) + actor.inventory.itemEquipped[index] = id0 + else { + val id = FixtureInventory.filterItem(ItemCodex[id0]) + actor.inventory.itemEquipped[index] = id?.dynamicID + } + } + + oldQuickSlot.forEachIndexed { index, id0 -> + if (id0?.isDynamic() == true) + actor.inventory.quickSlot[index] = id0 + else { + val id = FixtureInventory.filterItem(ItemCodex[id0]) + actor.inventory.quickSlot[index] = id?.dynamicID + } + } + } } + + + + } \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt index 4684b5bee..8ca695648 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt @@ -122,10 +122,11 @@ class ActorInventory() : FixtureInventory() { } } - override fun clear() { - super.clear() + override fun clear(): List { + val r = super.clear() itemEquipped.fill(null) quickSlot.fill(null) + return r } } diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureInventory.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureInventory.kt index b7ee0969d..df0e4fd7f 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureInventory.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureInventory.kt @@ -29,6 +29,45 @@ open class FixtureInventory() { val CAPACITY_MODE_NO_ENCUMBER = 0 val CAPACITY_MODE_COUNT = 1 val CAPACITY_MODE_WEIGHT = 2 + + + private fun filterItem0(item: GameItem): GameItem { + return if (item.originalID.isBlock()) { + val drop = BlockCodex[item.originalID].drop.ifBlank { item.originalID } + ItemCodex[drop] ?: throw NullPointerException("Item: ${item.originalID}, drop: ${BlockCodex[item.originalID].drop}") + } + else if (item.originalID.isWall()) { + val blockID = item.originalID.substringAfter('@') + val drop = BlockCodex[blockID].drop.ifBlank { blockID } + ItemCodex["wall@$drop"] ?: throw NullPointerException("Item: ${item.originalID}, drop: ${BlockCodex[item.originalID].drop}") + } + else { + item + } + } + + fun filterItem(item0: GameItem?): GameItem? { + if (item0 == null) return null + + var item = item0 + var recursionCount = 0 + var breakNow = false + var item1: GameItem + while (!breakNow) { + if (recursionCount > 16) throw IllegalStateException("Item filter recursion is too deep, check the filtering code") + + item1 = filterItem0(item!!) + + if (item1 == item) { + breakNow = true + } + + item = item1 + + recursionCount++ + } + return item + } } /** @@ -40,19 +79,6 @@ open class FixtureInventory() { fun isEmpty() = totalCount == 0L fun isNotEmpty() = totalCount > 0 - private fun filterItem(item: GameItem): GameItem { - return if (item.originalID.isBlock()) { - ItemCodex[BlockCodex[item.originalID].drop]!! - } - else if (item.originalID.isWall()) { - val blockID = item.originalID.substringAfter('@') - ItemCodex["wall@${BlockCodex[blockID].drop}"]!! - } - else { - item - } - } - open fun add(itemID: ItemID, count: Long = 1) { if (ItemCodex[itemID] == null) throw NullPointerException("Item not found: $itemID") @@ -61,23 +87,7 @@ open class FixtureInventory() { } open fun add(item0: GameItem, count: Long = 1L) { - var item = item0 - var recursionCount = 0 - var breakNow = false - var item1: GameItem - while (!breakNow) { - if (recursionCount > 16) throw IllegalStateException("Item filter recursion is too deep, check the filtering code") - - item1 = filterItem(item) - - if (item1 == item) { - breakNow = true - } - - item = item1 - - recursionCount++ - } + val item = filterItem(item0)!! // println("[ActorInventory] add-by-elem $item, $count") @@ -166,6 +176,12 @@ open class FixtureInventory() { updateEncumbrance() } + + open fun clear(): List { + val r = itemList.cloneToList() + itemList.clear() + return r + } /** * HashMap @@ -285,10 +301,6 @@ open class FixtureInventory() { return -(low + 1) // key not found } - open fun clear() { - itemList.clear() - } - fun updateEncumbrance() { totalWeight0 = itemList.sumOf { ItemCodex[it.itm]!!.mass * it.qty } totalCount0 = itemList.sumOf { it.qty } diff --git a/src/net/torvald/terrarum/modulebasegame/serialise/WriteSavegame.kt b/src/net/torvald/terrarum/modulebasegame/serialise/WriteSavegame.kt index ddcab0f31..72461be69 100644 --- a/src/net/torvald/terrarum/modulebasegame/serialise/WriteSavegame.kt +++ b/src/net/torvald/terrarum/modulebasegame/serialise/WriteSavegame.kt @@ -9,12 +9,14 @@ import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.modulebasegame.ChunkLoadingLoadScreen import net.torvald.terrarum.modulebasegame.IngameRenderer +import net.torvald.terrarum.modulebasegame.SavegameMigrator import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer import net.torvald.terrarum.realestate.LandUtil import net.torvald.terrarum.savegame.* import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO import net.torvald.terrarum.serialise.Common +import net.torvald.terrarum.utils.JsonFetcher import net.torvald.terrarum.worlddrawer.WorldCamera import java.io.File import java.io.Reader @@ -120,6 +122,8 @@ object LoadSavegame { operator fun invoke(diskPair: DiskPair) = invoke(diskPair.player, diskPair.world) + private val getGenver = Regex("""(?<="genver":)[0-9]+""") + /** * @param playerDisk DiskSkimmer representing the Player. * @param worldDisk0 DiskSkimmer representing the World to be loaded. @@ -128,14 +132,18 @@ object LoadSavegame { operator fun invoke(playerDisk: DiskSkimmer, worldDisk0: DiskSkimmer? = null) { val newIngame = TerrarumIngame(App.batch) playerDisk.rebuild() - val player = ReadActor.invoke(playerDisk, ByteArray64Reader(playerDisk.getFile(SAVEGAMEINFO)!!.bytes, Common.CHARSET)) as IngamePlayer + + val playerDiskSavegameInfo = ByteArray64Reader(playerDisk.getFile(SAVEGAMEINFO)!!.bytes, Common.CHARSET) + + val player = ReadActor.invoke(playerDisk, playerDiskSavegameInfo) as IngamePlayer printdbg(this, "Player localhash: ${player.localHashStr}, hasSprite: ${player.sprite != null}") val currentWorldId = player.worldCurrentlyPlaying val worldDisk = worldDisk0 ?: App.savegameWorlds[currentWorldId]!!.loadable() worldDisk.rebuild() - val world = ReadWorld(ByteArray64Reader(worldDisk.getFile(SAVEGAMEINFO)!!.bytes, Common.CHARSET), worldDisk.diskFile) + val worldDiskSavegameInfo = ByteArray64Reader(worldDisk.getFile(SAVEGAMEINFO)!!.bytes, Common.CHARSET) + val world = ReadWorld(worldDiskSavegameInfo, worldDisk.diskFile) world.layerTerrain = BlockLayer(world.width, world.height) world.layerWall = BlockLayer(world.width, world.height) @@ -150,13 +158,24 @@ object LoadSavegame { // worldDisk.dispose() // playerDisk.dispose() + val loadJob = { it: LoadScreenBase -> val loadscreen = it as ChunkLoadingLoadScreen loadscreen.addMessage(Lang["MENU_IO_LOADING"]) + val worldGenver = CharArray(128).let { + worldDiskSavegameInfo.read(it, 0, 128) + getGenver.find(String(it))?.value?.toLong()!! + } + val playerGenver = CharArray(128).let { + playerDiskSavegameInfo.read(it, 0, 128) + getGenver.find(String(it))?.value?.toLong()!! + } + + val actors = world.actors.distinct() - val worldParam = TerrarumIngame.Codices(newIngame.worldDisk, world, actors, player) + val worldParam = TerrarumIngame.Codices(newIngame.worldDisk, world, actors, player, worldGenver, playerGenver) newIngame.gameLoadInfoPayload = worldParam