mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-14 20:44:05 +09:00
savegame migrator wip
This commit is contained in:
111
src/net/torvald/terrarum/modulebasegame/SavegameMigrator.kt
Normal file
111
src/net/torvald/terrarum/modulebasegame/SavegameMigrator.kt
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package net.torvald.terrarum.modulebasegame
|
||||||
|
|
||||||
|
import net.torvald.terrarum.gameactors.Actor
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||||
|
import net.torvald.util.SortedArrayList
|
||||||
|
import kotlin.reflect.full.declaredFunctions
|
||||||
|
import kotlin.reflect.full.findAnnotation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param versionAnnotation If the version of the savegame meets the condition, the filter will be run
|
||||||
|
* - `all`: applies to all versions
|
||||||
|
* - `0.3.1`: applies to any past versions up to 0.3.1
|
||||||
|
* - `0.3.1+`: applies to any future versions including 0.3.1
|
||||||
|
* - `0.3.1!`: applies to verson 0.3.1 only
|
||||||
|
* - `0.3.1-0.3.4`: applies to version 0.3.1 to 0.3.4
|
||||||
|
* - `0.3.1-0.3.4;0.4.3-0.4.5`: applies to (0.3.1 to 0.3.4) and (0.4.3-0.4.5)
|
||||||
|
* - `0.3.1-0.3.4;0.5.0+`: applies to (0.3.1 to 0.3.4) and (0.5.0 and onward)
|
||||||
|
*
|
||||||
|
* Following syntaxes are considered as undefined behaviours:
|
||||||
|
* - `0.3.1-0.3.4;0.5.0`
|
||||||
|
*/
|
||||||
|
annotation class AppliedVersion(val versionAnnotation: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-09-29.
|
||||||
|
*/
|
||||||
|
internal object SavegameMigrator {
|
||||||
|
|
||||||
|
private fun Char.isNotAsciiDigit() = this.code !in 0x30..0x39
|
||||||
|
|
||||||
|
private fun toVersionIndex(a_dot_b_dot_c: String): Long {
|
||||||
|
val abc = a_dot_b_dot_c.split('.').map { it.toLong() }
|
||||||
|
if (abc.size != 3) throw IllegalArgumentException("Parse error: $a_dot_b_dot_c")
|
||||||
|
|
||||||
|
return abc[0].shl(48) or abc[1].shl(24) or abc[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun annotationMatches(fileVersion: Long, annotation: AppliedVersion?): Boolean {
|
||||||
|
if (annotation == null) return false
|
||||||
|
if (annotation.versionAnnotation.equals("all")) return true
|
||||||
|
|
||||||
|
var matched = false
|
||||||
|
|
||||||
|
annotation.versionAnnotation.split(";").forEach { query ->
|
||||||
|
// is range?
|
||||||
|
if (query.contains('-')) {
|
||||||
|
val from0 = query.substringBefore('-')
|
||||||
|
val to0 = query.substringAfter('-')
|
||||||
|
if (from0.last().isNotAsciiDigit() || to0.last().isNotAsciiDigit())
|
||||||
|
throw IllegalArgumentException("Illegal query '$query'")
|
||||||
|
|
||||||
|
val from = toVersionIndex(from0)
|
||||||
|
val to = toVersionIndex(to0)
|
||||||
|
|
||||||
|
if (from > to) throw IllegalArgumentException("Illegal query '$query'")
|
||||||
|
|
||||||
|
matched = matched or (from <= fileVersion && fileVersion <= to)
|
||||||
|
}
|
||||||
|
else if (query.endsWith('+') || query.endsWith('!')) {
|
||||||
|
val operator = query.last()
|
||||||
|
val specVersion = toVersionIndex(query.substringBefore(operator))
|
||||||
|
|
||||||
|
matched = matched or when (operator) {
|
||||||
|
'+' -> (fileVersion >= specVersion)
|
||||||
|
'!' -> (fileVersion == specVersion)
|
||||||
|
else -> throw IllegalArgumentException("Unknown operator '$operator' for query '$query'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
matched = matched or (fileVersion <= toVersionIndex(query))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun invoke(worldVersion: Long, playerVersion: Long, actors0: SortedArrayList<Actor>) {
|
||||||
|
if (worldVersion == playerVersion) {
|
||||||
|
this::class.declaredFunctions.filter {
|
||||||
|
annotationMatches(worldVersion, it.findAnnotation())
|
||||||
|
}.forEach { func ->
|
||||||
|
actors0.forEach { actor -> func.call(actor) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val nonPlayers = ArrayList<Actor>()
|
||||||
|
val players = ArrayList<IngamePlayer>()
|
||||||
|
for (actor in actors0) {
|
||||||
|
if (actor is IngamePlayer) players.add(actor)
|
||||||
|
else nonPlayers.add(actor)
|
||||||
|
}
|
||||||
|
|
||||||
|
this::class.declaredFunctions.filter {
|
||||||
|
annotationMatches(worldVersion, it.findAnnotation())
|
||||||
|
}.forEach { func ->
|
||||||
|
nonPlayers.forEach { actor -> func.call(actor) }
|
||||||
|
}
|
||||||
|
|
||||||
|
this::class.declaredFunctions.filter {
|
||||||
|
annotationMatches(playerVersion, it.findAnnotation())
|
||||||
|
}.forEach { func ->
|
||||||
|
players.forEach { player -> func.call(player) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AppliedVersion("all")
|
||||||
|
fun mergeUnlitBlocks(actor: Actor) {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -306,17 +306,19 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class Codices(
|
data class Codices(
|
||||||
val disk: VirtualDisk, // WORLD disk
|
val disk: VirtualDisk, // WORLD disk
|
||||||
val world: GameWorld,
|
val world: GameWorld,
|
||||||
// val meta: WriteMeta.WorldMeta,
|
// val meta: WriteMeta.WorldMeta,
|
||||||
// val block: BlockCodex,
|
// val block: BlockCodex,
|
||||||
// val item: ItemCodex,
|
// val item: ItemCodex,
|
||||||
// val wire: WireCodex,
|
// val wire: WireCodex,
|
||||||
// val material: MaterialCodex,
|
// val material: MaterialCodex,
|
||||||
// val faction: FactionCodex,
|
// val faction: FactionCodex,
|
||||||
// val apocryphas: Map<String, Any>,
|
// val apocryphas: Map<String, Any>,
|
||||||
val actors: List<ActorID>,
|
val actors: List<ActorID>,
|
||||||
val player: IngamePlayer
|
val player: IngamePlayer,
|
||||||
|
val worldGenver: Long,
|
||||||
|
val playerGenver: Long
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -403,6 +405,8 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
actorNowPlaying = codices.player
|
actorNowPlaying = codices.player
|
||||||
actorGamer = codices.player
|
actorGamer = codices.player
|
||||||
|
|
||||||
|
SavegameMigrator.invoke(codices.worldGenver, codices.playerGenver, actorContainerActive)
|
||||||
|
|
||||||
printdbg(this, "postInitForLoadFromSave exit")
|
printdbg(this, "postInitForLoadFromSave exit")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user