mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-12 03:24:06 +09:00
working savegame migrator
This commit is contained in:
@@ -194,4 +194,5 @@ class ItemCodex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun hasItem(itemID: ItemID): Boolean = dynamicItemInventory.containsKey(itemID)
|
fun hasItem(itemID: ItemID): Boolean = dynamicItemInventory.containsKey(itemID)
|
||||||
|
fun isEmpty(): Boolean = itemCodex.isEmpty()
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
package net.torvald.terrarum.modulebasegame
|
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.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.IngamePlayer
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||||
import net.torvald.util.SortedArrayList
|
import net.torvald.util.SortedArrayList
|
||||||
import kotlin.reflect.full.declaredFunctions
|
import kotlin.reflect.full.declaredFunctions
|
||||||
import kotlin.reflect.full.findAnnotation
|
import kotlin.reflect.full.findAnnotation
|
||||||
@@ -54,7 +59,7 @@ internal object SavegameMigrator {
|
|||||||
|
|
||||||
if (from > to) throw IllegalArgumentException("Illegal query '$query'")
|
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('!')) {
|
else if (query.endsWith('+') || query.endsWith('!')) {
|
||||||
val operator = query.last()
|
val operator = query.last()
|
||||||
@@ -79,7 +84,8 @@ internal object SavegameMigrator {
|
|||||||
this::class.declaredFunctions.filter {
|
this::class.declaredFunctions.filter {
|
||||||
annotationMatches(worldVersion, it.findAnnotation())
|
annotationMatches(worldVersion, it.findAnnotation())
|
||||||
}.forEach { func ->
|
}.forEach { func ->
|
||||||
actors0.forEach { actor -> func.call(actor) }
|
printdbg(this, func.toString())
|
||||||
|
actors0.forEach { actor -> func.call(this, actor) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -93,19 +99,59 @@ internal object SavegameMigrator {
|
|||||||
this::class.declaredFunctions.filter {
|
this::class.declaredFunctions.filter {
|
||||||
annotationMatches(worldVersion, it.findAnnotation())
|
annotationMatches(worldVersion, it.findAnnotation())
|
||||||
}.forEach { func ->
|
}.forEach { func ->
|
||||||
nonPlayers.forEach { actor -> func.call(actor) }
|
nonPlayers.forEach { actor -> func.call(this, actor) }
|
||||||
}
|
}
|
||||||
|
|
||||||
this::class.declaredFunctions.filter {
|
this::class.declaredFunctions.filter {
|
||||||
annotationMatches(playerVersion, it.findAnnotation())
|
annotationMatches(playerVersion, it.findAnnotation())
|
||||||
}.forEach { func ->
|
}.forEach { func ->
|
||||||
players.forEach { player -> func.call(player) }
|
players.forEach { player -> func.call(this, player) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************/
|
||||||
|
/* INSERT MIGRATION FUNCTIONS HERE */
|
||||||
|
/***********************************/
|
||||||
|
|
||||||
|
|
||||||
@AppliedVersion("all")
|
@AppliedVersion("all")
|
||||||
fun mergeUnlitBlocks(actor: Actor) {
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -122,10 +122,11 @@ class ActorInventory() : FixtureInventory() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear(): List<InventoryPair> {
|
||||||
super.clear()
|
val r = super.clear()
|
||||||
itemEquipped.fill(null)
|
itemEquipped.fill(null)
|
||||||
quickSlot.fill(null)
|
quickSlot.fill(null)
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,45 @@ open class FixtureInventory() {
|
|||||||
val CAPACITY_MODE_NO_ENCUMBER = 0
|
val CAPACITY_MODE_NO_ENCUMBER = 0
|
||||||
val CAPACITY_MODE_COUNT = 1
|
val CAPACITY_MODE_COUNT = 1
|
||||||
val CAPACITY_MODE_WEIGHT = 2
|
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 isEmpty() = totalCount == 0L
|
||||||
fun isNotEmpty() = totalCount > 0
|
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) {
|
open fun add(itemID: ItemID, count: Long = 1) {
|
||||||
if (ItemCodex[itemID] == null)
|
if (ItemCodex[itemID] == null)
|
||||||
throw NullPointerException("Item not found: $itemID")
|
throw NullPointerException("Item not found: $itemID")
|
||||||
@@ -61,23 +87,7 @@ open class FixtureInventory() {
|
|||||||
}
|
}
|
||||||
open fun add(item0: GameItem, count: Long = 1L) {
|
open fun add(item0: GameItem, count: Long = 1L) {
|
||||||
|
|
||||||
var item = item0
|
val item = filterItem(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++
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// println("[ActorInventory] add-by-elem $item, $count")
|
// println("[ActorInventory] add-by-elem $item, $count")
|
||||||
@@ -167,6 +177,12 @@ open class FixtureInventory() {
|
|||||||
updateEncumbrance()
|
updateEncumbrance()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun clear(): List<InventoryPair> {
|
||||||
|
val r = itemList.cloneToList()
|
||||||
|
itemList.clear()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HashMap<GameItem, Amounts>
|
* HashMap<GameItem, Amounts>
|
||||||
*/
|
*/
|
||||||
@@ -285,10 +301,6 @@ open class FixtureInventory() {
|
|||||||
return -(low + 1) // key not found
|
return -(low + 1) // key not found
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun clear() {
|
|
||||||
itemList.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateEncumbrance() {
|
fun updateEncumbrance() {
|
||||||
totalWeight0 = itemList.sumOf { ItemCodex[it.itm]!!.mass * it.qty }
|
totalWeight0 = itemList.sumOf { ItemCodex[it.itm]!!.mass * it.qty }
|
||||||
totalCount0 = itemList.sumOf { it.qty }
|
totalCount0 = itemList.sumOf { it.qty }
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ import net.torvald.terrarum.gameworld.GameWorld
|
|||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.modulebasegame.ChunkLoadingLoadScreen
|
import net.torvald.terrarum.modulebasegame.ChunkLoadingLoadScreen
|
||||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||||
|
import net.torvald.terrarum.modulebasegame.SavegameMigrator
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||||
import net.torvald.terrarum.realestate.LandUtil
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
import net.torvald.terrarum.savegame.*
|
import net.torvald.terrarum.savegame.*
|
||||||
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
||||||
import net.torvald.terrarum.serialise.Common
|
import net.torvald.terrarum.serialise.Common
|
||||||
|
import net.torvald.terrarum.utils.JsonFetcher
|
||||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
@@ -120,6 +122,8 @@ object LoadSavegame {
|
|||||||
|
|
||||||
operator fun invoke(diskPair: DiskPair) = invoke(diskPair.player, diskPair.world)
|
operator fun invoke(diskPair: DiskPair) = invoke(diskPair.player, diskPair.world)
|
||||||
|
|
||||||
|
private val getGenver = Regex("""(?<="genver":)[0-9]+""")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param playerDisk DiskSkimmer representing the Player.
|
* @param playerDisk DiskSkimmer representing the Player.
|
||||||
* @param worldDisk0 DiskSkimmer representing the World to be loaded.
|
* @param worldDisk0 DiskSkimmer representing the World to be loaded.
|
||||||
@@ -128,14 +132,18 @@ object LoadSavegame {
|
|||||||
operator fun invoke(playerDisk: DiskSkimmer, worldDisk0: DiskSkimmer? = null) {
|
operator fun invoke(playerDisk: DiskSkimmer, worldDisk0: DiskSkimmer? = null) {
|
||||||
val newIngame = TerrarumIngame(App.batch)
|
val newIngame = TerrarumIngame(App.batch)
|
||||||
playerDisk.rebuild()
|
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}")
|
printdbg(this, "Player localhash: ${player.localHashStr}, hasSprite: ${player.sprite != null}")
|
||||||
|
|
||||||
val currentWorldId = player.worldCurrentlyPlaying
|
val currentWorldId = player.worldCurrentlyPlaying
|
||||||
val worldDisk = worldDisk0 ?: App.savegameWorlds[currentWorldId]!!.loadable()
|
val worldDisk = worldDisk0 ?: App.savegameWorlds[currentWorldId]!!.loadable()
|
||||||
worldDisk.rebuild()
|
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.layerTerrain = BlockLayer(world.width, world.height)
|
||||||
world.layerWall = BlockLayer(world.width, world.height)
|
world.layerWall = BlockLayer(world.width, world.height)
|
||||||
@@ -150,13 +158,24 @@ object LoadSavegame {
|
|||||||
// worldDisk.dispose()
|
// worldDisk.dispose()
|
||||||
// playerDisk.dispose()
|
// playerDisk.dispose()
|
||||||
|
|
||||||
|
|
||||||
val loadJob = { it: LoadScreenBase ->
|
val loadJob = { it: LoadScreenBase ->
|
||||||
val loadscreen = it as ChunkLoadingLoadScreen
|
val loadscreen = it as ChunkLoadingLoadScreen
|
||||||
loadscreen.addMessage(Lang["MENU_IO_LOADING"])
|
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 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
|
newIngame.gameLoadInfoPayload = worldParam
|
||||||
|
|||||||
Reference in New Issue
Block a user