mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
still working on the new savegame scheme
main game works fine, saving/loading will not be possible
This commit is contained in:
@@ -7,12 +7,14 @@ The main game directory is composed of following directories:
|
||||
```
|
||||
.Terrarum
|
||||
+ Players
|
||||
- <Player Name Here>, TVDA { (-1) player JSON, (-2) optional spritedef, (-3) optional spritedef-glow, (-1025) sprite-bodypart-name-to-entry-number-map.properties, (1+) optional textures and sprite defs }
|
||||
- <Player Name Here>, TVDA { (-1) player JSON, (-2) spritedef, (-3) optional spritedef-glow, (-1025) sprite-bodypart-name-to-entry-number-map.properties, (1+) optional bodyparts tga.gz }
|
||||
if file -1025 is not there, read bodyparts from assets directory
|
||||
optionally encrypt the files other than -1
|
||||
+ Shared
|
||||
- <e.g. Disk GUID>, TEVD { * }
|
||||
- <this directory can have anything>
|
||||
+ Worlds
|
||||
- <World Name Here>, TVDA { WriteWorld, actors (mainly fixtures) JSON, chunk data, screenshot.tga.gz taken by the last player }
|
||||
- <World Name Here>, TVDA { (-1) WriteWorld, (actorID) actors (mainly fixtures) JSON, (0x1_0000_0000 + (layerNumber << 24) + chunkNumber) chunk data, (-2) screenshot.tga.gz taken by the last player }
|
||||
```
|
||||
|
||||
(TEVD stands for Terrarum Virtual Disk spec version 3, TVDA stands for spec version 254; both have MAGIC header of `TEVd`)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -37,25 +37,41 @@ interface HasAssembledSprite {
|
||||
_rebuild(animGlow, spriteGlow)
|
||||
}
|
||||
|
||||
/*fun rebuild(animDescPath: String, spriteAnimation: SpriteAnimation) {
|
||||
_rebuild(ADProperties(StringReader(animDescPath)), spriteAnimation)
|
||||
fun reassembleSprite(disk: SimpleFileSystem, sprite: SpriteAnimation?, anim: ADProperties?, spriteGlow: SpriteAnimation? = null, animGlow: ADProperties? = null) {
|
||||
if (anim != null && sprite != null)
|
||||
_rebuild(disk, anim, sprite)
|
||||
if (animGlow != null && spriteGlow != null)
|
||||
_rebuild(disk, animGlow, spriteGlow)
|
||||
}
|
||||
|
||||
fun rebuild(animDesc: FileHandle, spriteAnimation: SpriteAnimation) {
|
||||
_rebuild(ADProperties(animDesc.read()), spriteAnimation)
|
||||
}
|
||||
|
||||
fun rebuild(javaProp: Properties, spriteAnimation: SpriteAnimation) {
|
||||
_rebuild(ADProperties(javaProp), spriteAnimation)
|
||||
}*/
|
||||
|
||||
|
||||
private fun _rebuild(ad: ADProperties, sprite: SpriteAnimation) {
|
||||
// TODO injecting held item/armour pictures? Would it be AssembleSheetPixmap's job?
|
||||
|
||||
// TODO resolve bodyparts (must read ID-to-bodypartmap.properties first)
|
||||
val pixmap = AssembleSheetPixmap.fromAssetsDir(ad)
|
||||
val texture = Texture(pixmap)
|
||||
texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
|
||||
pixmap.dispose()
|
||||
val regionPack = TextureRegionPack(texture, ad.frameWidth, ad.frameHeight)
|
||||
|
||||
val pixmap = AssembleSheetPixmap(ad)
|
||||
val newAnimDelays = FloatArray(ad.animations.size)
|
||||
val newAnimFrames = IntArray(ad.animations.size)
|
||||
|
||||
ad.animations.forEach { t, u ->
|
||||
val index = u.row - 1
|
||||
newAnimDelays[index] = u.delay
|
||||
newAnimFrames[index] = u.frames
|
||||
}
|
||||
|
||||
sprite.setSpriteImage(regionPack)
|
||||
sprite.delays = newAnimDelays
|
||||
sprite.nFrames = newAnimFrames
|
||||
sprite.nRows = newAnimDelays.size
|
||||
}
|
||||
|
||||
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 texture = Texture(pixmap)
|
||||
texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
|
||||
pixmap.dispose()
|
||||
|
||||
@@ -4,7 +4,14 @@ import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import net.torvald.terrarum.linearSearch
|
||||
import net.torvald.terrarum.serialise.Common
|
||||
import net.torvald.terrarum.tvda.ByteArray64InputStream
|
||||
import net.torvald.terrarum.tvda.ByteArray64Reader
|
||||
import net.torvald.terrarum.tvda.SimpleFileSystem
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
/**
|
||||
* Assembles the single frame of the animation, outputs GDX Pixmap.
|
||||
@@ -15,14 +22,10 @@ import java.io.InputStream
|
||||
*/
|
||||
object AssembleSheetPixmap {
|
||||
|
||||
operator fun invoke(properties: ADProperties): Pixmap {
|
||||
private fun drawAndGetCanvas(properties: ADProperties, fileGetter: (String) -> InputStream): Pixmap {
|
||||
val canvas = Pixmap(properties.cols * properties.frameWidth, properties.rows * properties.frameHeight, Pixmap.Format.RGBA8888)
|
||||
canvas.blending = Pixmap.Blending.SourceOver
|
||||
|
||||
val fileGetter = { path: String ->
|
||||
Gdx.files.internal(path).read()
|
||||
}
|
||||
|
||||
// actually draw
|
||||
properties.transforms.forEach { t, _ ->
|
||||
drawThisFrame(t, canvas, properties, fileGetter)
|
||||
@@ -31,6 +34,21 @@ object AssembleSheetPixmap {
|
||||
return canvas
|
||||
}
|
||||
|
||||
fun fromAssetsDir(properties: ADProperties) = drawAndGetCanvas(properties) { partName: String ->
|
||||
Gdx.files.internal("assets/${properties.toFilename(partName)}").read()
|
||||
}
|
||||
|
||||
fun fromVirtualDisk(disk: SimpleFileSystem, properties: ADProperties): Pixmap {
|
||||
val bodypartMapping = Properties()
|
||||
bodypartMapping.load(ByteArray64Reader(disk.getFile(-1025L)!!.bytes, Common.CHARSET))
|
||||
|
||||
val fileGetter = { partName: String ->
|
||||
ByteArray64InputStream(disk.getFile(bodypartMapping[partName] as Long)!!.bytes)
|
||||
}
|
||||
|
||||
return drawAndGetCanvas(properties, fileGetter)
|
||||
}
|
||||
|
||||
private fun drawThisFrame(frameName: String,
|
||||
canvas: Pixmap,
|
||||
properties: ADProperties,
|
||||
@@ -42,7 +60,7 @@ object AssembleSheetPixmap {
|
||||
val bodypartOrigins = properties.bodyparts
|
||||
val bodypartImages = properties.bodyparts.keys.map {
|
||||
try {
|
||||
val bytes = fileGetter("assets/${properties.toFilename(it)}").readAllBytes()
|
||||
val bytes = fileGetter(it).readAllBytes()
|
||||
it to Pixmap(bytes, 0, bytes.size)
|
||||
}
|
||||
catch (e: GdxRuntimeException) {
|
||||
|
||||
@@ -298,7 +298,7 @@ class SpriteAssemblerPreview: Game() {
|
||||
}
|
||||
|
||||
private fun assembleImage(prop: ADProperties) {
|
||||
image = AssembleSheetPixmap(prop)
|
||||
image = AssembleSheetPixmap.fromAssetsDir(prop)
|
||||
}
|
||||
|
||||
// TODO rename to requestAssembly
|
||||
|
||||
@@ -92,7 +92,7 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
|
||||
oldWorld.dispose()
|
||||
}
|
||||
/** how many different planets/stages/etc. are thenre. Whole stages must be manually managed by YOU. */
|
||||
var gameworldIndices = ArrayList<Int>()
|
||||
//var gameworldIndices = ArrayList<Int>()
|
||||
|
||||
/** The actor the game is currently allowing you to control.
|
||||
*
|
||||
|
||||
@@ -702,7 +702,7 @@ fun AppUpdateListOfSavegames() {
|
||||
fun checkForSavegameDamage(skimmer: DiskSkimmer): Boolean {
|
||||
try {
|
||||
// # check for meta
|
||||
val metaFile = skimmer.requestFile(-1) ?: return true
|
||||
/*val metaFile = skimmer.requestFile(-1) ?: return true
|
||||
// # check if The Player is there
|
||||
val player = skimmer.requestFile(PLAYER_REF_ID.toLong().and(0xFFFFFFFFL))?.contents ?: return true
|
||||
// # check if:
|
||||
@@ -723,7 +723,7 @@ fun checkForSavegameDamage(skimmer: DiskSkimmer): Boolean {
|
||||
System.err.println("Nonexisting actor $it for savegame ${skimmer.diskFile.absolutePath}")
|
||||
hasMissingActor = true
|
||||
}
|
||||
}; if (hasMissingActor) return true
|
||||
}; if (hasMissingActor) return true*/
|
||||
|
||||
|
||||
return false
|
||||
|
||||
@@ -140,7 +140,7 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
printdbg(this, "Demo world loaded")
|
||||
}
|
||||
catch (e: IOException) {
|
||||
demoWorld = GameWorld(1, LandUtil.CHUNK_W, LandUtil.CHUNK_H, 0L, 0L)
|
||||
demoWorld = GameWorld(LandUtil.CHUNK_W, LandUtil.CHUNK_H, 0L, 0L)
|
||||
printdbg(this, "Demo world not found, using empty world")
|
||||
}
|
||||
|
||||
@@ -230,9 +230,8 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
// load list of savegames
|
||||
println("[TitleScreen] update list of savegames")
|
||||
App.updateListOfSavegames()
|
||||
|
||||
// App.savegames.forEach { println(it.diskFile.absolutePath) }
|
||||
// TODO to show "Continue" and "Load" on the titlescreen, uncomment this line
|
||||
// App.updateListOfSavegames()
|
||||
|
||||
|
||||
loadThingsWhileIntroIsVisible()
|
||||
|
||||
@@ -14,6 +14,10 @@ import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.utils.*
|
||||
import net.torvald.util.SortedArrayList
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import java.util.*
|
||||
import kotlin.NoSuchElementException
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
typealias BlockAddress = Long
|
||||
@@ -29,17 +33,8 @@ class GameWorldTitleScreen : GameWorld() {
|
||||
open class GameWorld() : Disposable {
|
||||
|
||||
var worldName: String = "New World"
|
||||
/** Index start at 1 */
|
||||
var worldIndex: Int = 1234567890
|
||||
set(value) {
|
||||
if (value <= 0)
|
||||
throw Error("World index start at 1; you've entered $value")
|
||||
|
||||
printdbg(this, "Creation of new world with index $value, called by:")
|
||||
printStackTrace(this)
|
||||
|
||||
field = value
|
||||
}
|
||||
var worldIndex: UUID = UUID.randomUUID() // should not be immutable as JSON loader will want to overwrite it
|
||||
var worldCreator: UUID = UUID(0L,0L) // TODO record a value to this
|
||||
var width: Int = 999; private set
|
||||
var height: Int = 999; private set
|
||||
|
||||
@@ -120,10 +115,9 @@ open class GameWorld() : Disposable {
|
||||
/**
|
||||
* Create new world
|
||||
*/
|
||||
constructor(worldIndex: Int, width: Int, height: Int, creationTIME_T: Long, lastPlayTIME_T: Long): this() {
|
||||
constructor(width: Int, height: Int, creationTIME_T: Long, lastPlayTIME_T: Long): this() {
|
||||
if (width <= 0 || height <= 0) throw IllegalArgumentException("Non-positive width/height: ($width, $height)")
|
||||
|
||||
this.worldIndex = worldIndex
|
||||
this.width = width
|
||||
this.height = height
|
||||
|
||||
@@ -675,7 +669,7 @@ open class GameWorld() : Disposable {
|
||||
|
||||
fun makeNullWorld(): GameWorld {
|
||||
if (nullWorldInstance == null)
|
||||
nullWorldInstance = GameWorld(1, 1, 1, 0, 0)
|
||||
nullWorldInstance = GameWorld(1, 1, 0, 0)
|
||||
|
||||
return nullWorldInstance!!
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
private val timeNow = System.currentTimeMillis() / 1000
|
||||
|
||||
val gameWorld = GameWorld(1, 1024, 256, timeNow, timeNow)
|
||||
val gameWorld = GameWorld(90*12, 90*4, timeNow, timeNow)
|
||||
|
||||
init {
|
||||
// ghetto world for building
|
||||
|
||||
@@ -348,9 +348,9 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
// init map as chosen size
|
||||
val timeNow = App.getTIME_T()
|
||||
world = GameWorld(1, worldParams.width, worldParams.height, timeNow, timeNow) // new game, so the creation time is right now
|
||||
world = GameWorld(worldParams.width, worldParams.height, timeNow, timeNow) // new game, so the creation time is right now
|
||||
world.generatorSeed = worldParams.worldGenSeed
|
||||
gameworldIndices.add(world.worldIndex)
|
||||
//gameworldIndices.add(world.worldIndex)
|
||||
world.extraFields["basegame.economy"] = GameEconomy()
|
||||
|
||||
// generate terrain for the map
|
||||
|
||||
@@ -5,6 +5,7 @@ import net.torvald.spriteanimation.HasAssembledSprite
|
||||
import net.torvald.spriteassembler.ADProperties
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
@@ -15,9 +16,10 @@ import net.torvald.terrarum.gameactors.AVKey
|
||||
|
||||
class IngamePlayer : ActorHumanoid, HasAssembledSprite {
|
||||
|
||||
var UUID = UUID(0L,0L); private set
|
||||
internal var worldCurrentlyPlaying: UUID = UUID(0L,0L) // only filled up on save and load; DO NOT USE THIS
|
||||
override var animDesc: ADProperties? = null
|
||||
override var animDescGlow: ADProperties? = null
|
||||
internal var worldCurrentlyPlaying = 0 // only filled up on save and load; DO NOT USE THIS
|
||||
|
||||
private constructor()
|
||||
|
||||
@@ -33,10 +35,10 @@ class IngamePlayer : ActorHumanoid, HasAssembledSprite {
|
||||
* **Use PlayerFactory to build player!**
|
||||
*/
|
||||
init {
|
||||
referenceID = Terrarum.PLAYER_REF_ID // forcibly set ID
|
||||
referenceID = Terrarum.PLAYER_REF_ID // TODO assign random ID
|
||||
density = BASE_DENSITY
|
||||
collisionType = COLLISION_KINEMATIC
|
||||
worldCurrentlyPlaying = Terrarum.ingame?.world?.worldIndex ?: 0
|
||||
worldCurrentlyPlaying = Terrarum.ingame?.world?.worldIndex ?: UUID(0L,0L)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import java.io.InputStream
|
||||
import java.io.Reader
|
||||
import java.io.StringReader
|
||||
import java.math.BigInteger
|
||||
import java.util.*
|
||||
import java.util.zip.GZIPInputStream
|
||||
import java.util.zip.GZIPOutputStream
|
||||
|
||||
@@ -172,6 +173,16 @@ object Common {
|
||||
return hashMap
|
||||
}
|
||||
})
|
||||
// UUID
|
||||
jsoner.setSerializer(UUID::class.java, object : Json.Serializer<UUID> {
|
||||
override fun write(json: Json, obj: UUID, knownType: Class<*>?) {
|
||||
json.writeValue(obj.toString())
|
||||
}
|
||||
|
||||
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): UUID {
|
||||
return UUID.fromString(jsonData.asString())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private data class LayerInfo(val h: String, val b: String, val x: Int, val y: Int)
|
||||
|
||||
@@ -29,6 +29,11 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
|
||||
private val actorProgressMultiplier = 1f
|
||||
|
||||
override fun run() {
|
||||
callback()
|
||||
return
|
||||
|
||||
// TODO //
|
||||
|
||||
disk.saveMode = 2 * isAuto.toInt() // no quick
|
||||
|
||||
if (hasThumbnail) {
|
||||
@@ -81,9 +86,9 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
|
||||
// Commented out; nothing to write
|
||||
|
||||
// Write ItemCodex//
|
||||
val itemCodexContent = EntryFile(Common.zip(ByteArray64.fromByteArray(Common.jsoner.toJson(ItemCodex).toByteArray(Common.CHARSET))))
|
||||
val items = DiskEntry(-17, 0, creation_t, time_t, itemCodexContent)
|
||||
addFile(disk, items)
|
||||
// val itemCodexContent = EntryFile(Common.zip(ByteArray64.fromByteArray(Common.jsoner.toJson(ItemCodex).toByteArray(Common.CHARSET))))
|
||||
// val items = DiskEntry(-17, 0, creation_t, time_t, itemCodexContent)
|
||||
// addFile(disk, items)
|
||||
// Gotta save dynamicIDs
|
||||
|
||||
// Write WireCodex//
|
||||
@@ -104,15 +109,15 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
|
||||
// addFile(disk, factions)
|
||||
|
||||
// Write Apocryphas//
|
||||
val apocryphasContent = EntryFile(Common.zip(ByteArray64.fromByteArray(Common.jsoner.toJson(Apocryphas).toByteArray(Common.CHARSET))))
|
||||
val apocryphas = DiskEntry(-1024, 0, creation_t, time_t, apocryphasContent)
|
||||
addFile(disk, apocryphas)
|
||||
// val apocryphasContent = EntryFile(Common.zip(ByteArray64.fromByteArray(Common.jsoner.toJson(Apocryphas).toByteArray(Common.CHARSET))))
|
||||
// val apocryphas = DiskEntry(-1024, 0, creation_t, time_t, apocryphasContent)
|
||||
// addFile(disk, apocryphas)
|
||||
|
||||
// Write World //
|
||||
val worldNum = ingame.world.worldIndex
|
||||
val worldMeta = EntryFile(WriteWorld.encodeToByteArray64(ingame, time_t))
|
||||
val world = DiskEntry(worldNum.toLong(), 0, creation_t, time_t, worldMeta)
|
||||
addFile(disk, world)
|
||||
// val worldNum = ingame.world.worldIndex
|
||||
// val worldMeta = EntryFile(WriteWorld.encodeToByteArray64(ingame, time_t))
|
||||
// val world = DiskEntry(worldNum.toLong(), 0, creation_t, time_t, worldMeta)
|
||||
// addFile(disk, world)
|
||||
|
||||
WriteSavegame.saveProgress += 1f
|
||||
|
||||
@@ -125,7 +130,7 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
|
||||
Echo("Writing chunks... ${(cw*ch*layer) + chunkNumber + 1}/${cw*ch*layers.size}")
|
||||
|
||||
val chunkBytes = WriteWorld.encodeChunk(layers[layer]!!, cx, cy)
|
||||
val entryID = worldNum.toLong().shl(32) or layer.toLong().shl(24) or chunkNumber
|
||||
val entryID = 0x1_0000_0000L or layer.toLong().shl(24) or chunkNumber
|
||||
|
||||
val entryContent = EntryFile(chunkBytes)
|
||||
val entry = DiskEntry(entryID, 0, creation_t, time_t, entryContent)
|
||||
|
||||
@@ -34,6 +34,11 @@ class QuickSaveThread(val disk: VirtualDisk, val file: File, val ingame: Terraru
|
||||
|
||||
|
||||
override fun run() {
|
||||
callback()
|
||||
return
|
||||
|
||||
// TODO //
|
||||
|
||||
val skimmer = DiskSkimmer(file, Common.CHARSET)
|
||||
|
||||
if (hasThumbnail) {
|
||||
@@ -82,7 +87,7 @@ class QuickSaveThread(val disk: VirtualDisk, val file: File, val ingame: Terraru
|
||||
// Write World //
|
||||
val worldNum = ingame.world.worldIndex
|
||||
val worldMeta = EntryFile(WriteWorld.encodeToByteArray64(ingame, time_t))
|
||||
val world = DiskEntry(worldNum.toLong(), 0, creation_t, time_t, worldMeta)
|
||||
val world = DiskEntry(-1-1-1-1-1-1-1, 0, creation_t, time_t, worldMeta)
|
||||
addFile(disk, world); skimmer.appendEntryOnly(world)
|
||||
|
||||
WriteSavegame.saveProgress += 1f
|
||||
@@ -101,7 +106,7 @@ class QuickSaveThread(val disk: VirtualDisk, val file: File, val ingame: Terraru
|
||||
// println("Chunk xy from number $chunkNumber -> (${chunkXY.x}, ${chunkXY.y})")
|
||||
|
||||
val chunkBytes = WriteWorld.encodeChunk(layer, chunkXY.x, chunkXY.y)
|
||||
val entryID = worldNum.toLong().shl(32) or layerNum.toLong().shl(24) or chunkNumber.toLong()
|
||||
val entryID = 0x1_0000_0000L or layerNum.toLong().shl(24) or chunkNumber.toLong()
|
||||
|
||||
val entryContent = EntryFile(chunkBytes)
|
||||
val entry = DiskEntry(entryID, 0, creation_t, time_t, entryContent)
|
||||
|
||||
@@ -3,6 +3,8 @@ package net.torvald.terrarum.serialise
|
||||
import net.torvald.spriteanimation.HasAssembledSprite
|
||||
import net.torvald.spriteanimation.SpriteAnimation
|
||||
import net.torvald.spriteassembler.ADProperties
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.NoSuchActorWithIDException
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
@@ -49,17 +51,53 @@ object WriteActor {
|
||||
* Created by minjaesong on 2021-10-07.
|
||||
*/
|
||||
object WritePlayer {
|
||||
operator fun invoke(player: IngamePlayer, disk: VirtualDisk) {
|
||||
|
||||
/**
|
||||
* Will happily overwrite existing entry
|
||||
*/
|
||||
private fun addFile(disk: VirtualDisk, file: DiskEntry) {
|
||||
disk.entries[file.entryID] = file
|
||||
file.parentEntryID = 0
|
||||
val dir = VDUtil.getAsDirectory(disk, 0)
|
||||
if (!dir.contains(file.entryID)) dir.add(file.entryID)
|
||||
}
|
||||
|
||||
operator fun invoke(player: IngamePlayer, playerDisk: VirtualDisk) {
|
||||
val time_t = App.getTIME_T()
|
||||
val actorJson = WriteActor.encodeToByteArray64(player)
|
||||
val adl = player.animDesc?.getRawADL() // NULLABLE!
|
||||
val adl = player.animDesc!!.getRawADL()
|
||||
val adlGlow = player.animDescGlow?.getRawADL() // NULLABLE!
|
||||
}
|
||||
|
||||
operator fun invoke(player: IngamePlayer, skimmer: DiskSkimmer) {
|
||||
val jsonContents = EntryFile(actorJson)
|
||||
val jsonCreationDate = playerDisk.getEntry(-1)?.creationDate ?: time_t
|
||||
addFile(playerDisk, DiskEntry(-1L, 0L, jsonCreationDate, time_t, jsonContents))
|
||||
|
||||
val adlContents = EntryFile(ByteArray64.fromByteArray(adl.toByteArray(Common.CHARSET)))
|
||||
val adlCreationDate = playerDisk.getEntry(-2)?.creationDate ?: time_t
|
||||
addFile(playerDisk, DiskEntry(-1L, 0L, adlCreationDate, time_t, adlContents))
|
||||
|
||||
if (adlGlow != null) {
|
||||
val adlGlowContents = EntryFile(ByteArray64.fromByteArray(adlGlow.toByteArray(Common.CHARSET)))
|
||||
val adlGlowCreationDate = playerDisk.getEntry(-3)?.creationDate ?: time_t
|
||||
addFile(playerDisk, DiskEntry(-1L, 0L, adlGlowCreationDate, time_t, adlGlowContents))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Player-specific [ReadActor].
|
||||
*
|
||||
* Created by minjaesong on 2021-10-07.
|
||||
*/
|
||||
object ReadPlayer {
|
||||
|
||||
operator fun invoke(disk: SimpleFileSystem, dataStream: Reader): IngamePlayer =
|
||||
ReadActor(disk, dataStream) as IngamePlayer
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Actor's JSON representation is expected to have "class" property on the root object, such as:
|
||||
@@ -71,8 +109,8 @@ object WritePlayer {
|
||||
*/
|
||||
object ReadActor {
|
||||
|
||||
operator fun invoke(disk: SimpleFileSystem, worldDataStream: Reader): Actor =
|
||||
fillInDetails(disk, Common.jsoner.fromJson(null, worldDataStream))
|
||||
operator fun invoke(disk: SimpleFileSystem, dataStream: Reader): Actor =
|
||||
fillInDetails(disk, Common.jsoner.fromJson(null, dataStream))
|
||||
|
||||
fun readActorBare(worldDataStream: Reader): Actor =
|
||||
Common.jsoner.fromJson(null, worldDataStream)
|
||||
@@ -89,19 +127,30 @@ object ReadActor {
|
||||
|
||||
actor.sprite = SpriteAnimation(actor)
|
||||
if (animFileGlow != null) actor.spriteGlow = SpriteAnimation(actor)
|
||||
actor.reassembleSprite(
|
||||
actor.sprite!!,
|
||||
ADProperties(ByteArray64Reader(animFile!!.bytes, Common.CHARSET)),
|
||||
actor.spriteGlow,
|
||||
if (animFileGlow == null) null else ADProperties(ByteArray64Reader(animFileGlow.bytes, Common.CHARSET))
|
||||
)
|
||||
val bodypartsFile = disk.getFile(-1025)
|
||||
|
||||
if (bodypartsFile != null)
|
||||
actor.reassembleSprite(
|
||||
disk,
|
||||
actor.sprite!!,
|
||||
ADProperties(ByteArray64Reader(animFile!!.bytes, Common.CHARSET)),
|
||||
actor.spriteGlow,
|
||||
if (animFileGlow == null) null else ADProperties(ByteArray64Reader(animFileGlow.bytes, Common.CHARSET))
|
||||
)
|
||||
else
|
||||
actor.reassembleSprite(
|
||||
actor.sprite!!,
|
||||
ADProperties(ByteArray64Reader(animFile!!.bytes, Common.CHARSET)),
|
||||
actor.spriteGlow,
|
||||
if (animFileGlow == null) null else ADProperties(ByteArray64Reader(animFileGlow.bytes, Common.CHARSET))
|
||||
)
|
||||
}
|
||||
|
||||
return actor
|
||||
}
|
||||
|
||||
fun readActorAndAddToWorld(ingame: TerrarumIngame, disk: SimpleFileSystem, worldDataStream: Reader): Actor {
|
||||
val actor = invoke(disk, worldDataStream)
|
||||
fun readActorAndAddToWorld(ingame: TerrarumIngame, disk: SimpleFileSystem, dataStream: Reader): Actor {
|
||||
val actor = invoke(disk, dataStream)
|
||||
|
||||
// replace existing player
|
||||
val oldPlayerID = ingame.actorNowPlaying?.referenceID
|
||||
|
||||
@@ -24,12 +24,11 @@ object WriteMeta {
|
||||
randseed1 = RoguelikeRandomiser.RNG.state1,
|
||||
weatseed0 = WeatherMixer.RNG.state0,
|
||||
weatseed1 = WeatherMixer.RNG.state1,
|
||||
playerid = ingame.actorGamer.referenceID,
|
||||
creation_t = ingame.creationTime,
|
||||
lastplay_t = time_t,
|
||||
playtime_t = ingame.totalPlayTime + currentPlayTime_t,
|
||||
loadorder = ModMgr.loadOrder.toTypedArray(),
|
||||
worlds = ingame.gameworldIndices.toTypedArray()
|
||||
//worlds = ingame.gameworldIndices.toTypedArray()
|
||||
)
|
||||
|
||||
return Common.jsoner.toJson(meta)
|
||||
@@ -52,8 +51,8 @@ object WriteMeta {
|
||||
val creation_t: Long = 0,
|
||||
val lastplay_t: Long = 0,
|
||||
val playtime_t: Long = 0,
|
||||
val loadorder: Array<String> = arrayOf(), // do not use list; Could not instantiate instance of class: java.util.Collections$SingletonList
|
||||
val worlds: Array<Int> = arrayOf() // do not use list; Could not instantiate instance of class: java.util.Collections$SingletonList
|
||||
val loadorder: Array<String> = arrayOf() // do not use list; Could not instantiate instance of class: java.util.Collections$SingletonList
|
||||
//val worlds: Array<Int> = arrayOf() // do not use list; Could not instantiate instance of class: java.util.Collections$SingletonList
|
||||
) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
||||
@@ -56,6 +56,10 @@ object WriteSavegame {
|
||||
|
||||
|
||||
fun immediate(disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, callback: () -> Unit = {}) {
|
||||
return
|
||||
|
||||
// TODO //
|
||||
|
||||
savingStatus = 0
|
||||
|
||||
Echo("Immediate save fired")
|
||||
@@ -68,6 +72,10 @@ object WriteSavegame {
|
||||
}
|
||||
|
||||
fun quick(disk: VirtualDisk, file: File, ingame: TerrarumIngame, isAuto: Boolean, callback: () -> Unit = {}) {
|
||||
return
|
||||
|
||||
// TODO //
|
||||
|
||||
savingStatus = 0
|
||||
|
||||
Echo("Quicksave queued")
|
||||
@@ -111,6 +119,8 @@ object LoadSavegame {
|
||||
fun getFileReader(disk: VirtualDisk, id: Long): Reader = ByteArray64Reader(getFileBytes(disk, id), Common.CHARSET)
|
||||
|
||||
operator fun invoke(disk: VirtualDisk) {
|
||||
TODO()
|
||||
|
||||
val newIngame = TerrarumIngame(App.batch)
|
||||
|
||||
val meta = ReadMeta(disk)
|
||||
@@ -118,7 +128,7 @@ object LoadSavegame {
|
||||
// NOTE: do NOT set ingame.actorNowPlaying as one read directly from the disk;
|
||||
// you'll inevitably read the player actor twice, and they're separate instances of the player!
|
||||
val currentWorld = (ReadActor.readActorBare(getFileReader(disk, Terrarum.PLAYER_REF_ID.toLong())) as IngamePlayer).worldCurrentlyPlaying
|
||||
val world = ReadWorld(getFileReader(disk, currentWorld.toLong()))
|
||||
val world = ReadWorld(getFileReader(disk, -1-1-1-1-1-1))
|
||||
|
||||
// set lateinit vars on the gameworld FIRST
|
||||
world.layerTerrain = BlockLayer(world.width, world.height)
|
||||
@@ -153,7 +163,6 @@ object LoadSavegame {
|
||||
|
||||
|
||||
// load all the world blocklayer chunks
|
||||
val worldnum = world.worldIndex.toLong()
|
||||
val cw = LandUtil.CHUNK_W
|
||||
val ch = LandUtil.CHUNK_H
|
||||
val chunkCount = world.width * world.height / (cw * ch)
|
||||
@@ -162,7 +171,7 @@ object LoadSavegame {
|
||||
for (layer in worldLayer.indices) {
|
||||
loadscreen.addMessage("${Lang["MENU_IO_LOADING"]} ${chunk*worldLayer.size+layer+1}/${chunkCount*2}")
|
||||
|
||||
val chunkFile = VDUtil.getAsNormalFile(disk, worldnum.shl(32) or layer.toLong().shl(24) or chunk)
|
||||
val chunkFile = VDUtil.getAsNormalFile(disk, 0x1_0000_0000L or layer.toLong().shl(24) or chunk)
|
||||
val chunkXY = LandUtil.chunkNumToChunkXY(world, chunk.toInt())
|
||||
|
||||
ReadWorld.decodeChunkToLayer(chunkFile.getContent(), worldLayer[layer]!!, chunkXY.x, chunkXY.y)
|
||||
|
||||
@@ -11,7 +11,7 @@ class SpriteAssemblerTest {
|
||||
|
||||
operator fun invoke() {
|
||||
val properties = ADProperties(StringReader(ADLParsingTest().TEST_STR))
|
||||
AssembleSheetPixmap.invoke(properties)
|
||||
AssembleSheetPixmap.fromAssetsDir(properties)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -250,6 +250,7 @@ removefile:
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEntry(id: EntryID) = requestFile(id)
|
||||
override fun getFile(id: EntryID) = requestFile(id)?.contents as? EntryFile
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,5 +4,6 @@ package net.torvald.terrarum.tvda
|
||||
* Created by minjaesong on 2021-10-07.
|
||||
*/
|
||||
interface SimpleFileSystem {
|
||||
fun getEntry(id: EntryID): DiskEntry?
|
||||
fun getFile(id: EntryID): EntryFile?
|
||||
}
|
||||
@@ -143,6 +143,7 @@ class VirtualDisk(
|
||||
extraInfoBytes = footer.toByteArray()
|
||||
}
|
||||
|
||||
override fun getEntry(id: EntryID) = entries[id]
|
||||
override fun getFile(id: EntryID) = try { VDUtil.getAsNormalFile(this, id) } catch (e: NullPointerException) { null }
|
||||
|
||||
private fun serializeEntriesOnly(): ByteArray64 {
|
||||
|
||||
@@ -18,6 +18,8 @@ import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||
import net.torvald.terrarum.modulebasegame.ui.abs
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@@ -154,7 +156,7 @@ object LightmapRenderer {
|
||||
return // something's wrong but we'll ignore it like a trustful AK
|
||||
}
|
||||
|
||||
if (world.worldIndex == -1) return
|
||||
if (world.worldIndex == UUID(0L,0L)) return
|
||||
|
||||
|
||||
for_x_start = WorldCamera.zoomedX / TILE_SIZE // fix for premature lightmap rendering
|
||||
|
||||
Reference in New Issue
Block a user