mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
185 lines
6.4 KiB
Kotlin
185 lines
6.4 KiB
Kotlin
package net.torvald.terrarum.serialise
|
|
|
|
import com.badlogic.gdx.Gdx
|
|
import com.badlogic.gdx.graphics.GL30
|
|
import com.badlogic.gdx.graphics.OrthographicCamera
|
|
import com.badlogic.gdx.graphics.Pixmap
|
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
|
import com.badlogic.gdx.utils.ScreenUtils
|
|
import net.torvald.gdx.graphics.PixmapIO2
|
|
import net.torvald.terrarum.*
|
|
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
|
|
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
|
|
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
|
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64
|
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64GrowableOutputStream
|
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64InputStream
|
|
import org.apache.commons.codec.digest.DigestUtils
|
|
import java.io.ByteArrayOutputStream
|
|
import java.util.zip.Deflater
|
|
import java.util.zip.DeflaterOutputStream
|
|
|
|
object WriteWorldInfo {
|
|
|
|
val META_MAGIC = "TESV".toByteArray(Charsets.UTF_8)
|
|
val NULL = 0.toByte()
|
|
|
|
val VERSION = 1
|
|
val HASHED_FILES_COUNT = 3
|
|
|
|
/**
|
|
* TODO currently it'll dump the temporary file (tmp_worldinfo1) onto the disk and will return the temp file.
|
|
*
|
|
* @return List of ByteArray64, worldinfo0..worldinfo3; `null` on failure
|
|
*/
|
|
internal operator fun invoke(ingame: IngameInstance): List<ByteArray64>? {
|
|
|
|
//val path = "${AppLoader.defaultSaveDir}/tmp_worldinfo"
|
|
|
|
val infileList = arrayOf(
|
|
ModMgr.getGdxFilesFromEveryMod("blocks/blocks.csv"),
|
|
ModMgr.getGdxFilesFromEveryMod("items/items.csv"),
|
|
ModMgr.getGdxFilesFromEveryMod("materials/materials.csv")
|
|
)
|
|
|
|
val outFiles = ArrayList<ByteArray64>() // for worldinfo1-3 only
|
|
val worldInfoHash = ArrayList<ByteArray>() // hash of worldinfo1-3
|
|
// try to write worldinfo1-3
|
|
|
|
for (filenum in 1..HASHED_FILES_COUNT) {
|
|
val outputStream = ByteArray64GrowableOutputStream()
|
|
val infile = infileList[filenum - 1]
|
|
|
|
infile.forEach {
|
|
outputStream.write("## from file: ${it.nameWithoutExtension()} ##############################\n".toByteArray())
|
|
val readBytes = it.readBytes()
|
|
outputStream.write(readBytes)
|
|
outputStream.write("\n".toByteArray())
|
|
}
|
|
|
|
outputStream.flush()
|
|
outputStream.close()
|
|
|
|
|
|
outFiles.add(outputStream.toByteArray64())
|
|
|
|
|
|
worldInfoHash.add(DigestUtils.sha256(ByteArray64InputStream(outputStream.toByteArray64())))
|
|
}
|
|
|
|
|
|
// compose save meta (actual writing part)
|
|
val metaOut = ByteArray64GrowableOutputStream()
|
|
|
|
|
|
metaOut.write(META_MAGIC)
|
|
metaOut.write(VERSION)
|
|
metaOut.write(HASHED_FILES_COUNT)
|
|
|
|
// world name
|
|
val world = ingame.world
|
|
val worldNameBytes = world.worldName.toByteArray(Charsets.UTF_8)
|
|
//metaOut.write(worldNameBytes)
|
|
worldNameBytes.forEach {
|
|
if (it != 0.toByte()) metaOut.write(it.toInt())
|
|
}
|
|
metaOut.write(NULL.toInt())
|
|
|
|
// terrain seed
|
|
metaOut.write(world.generatorSeed.toLittle())
|
|
|
|
// randomiser seed
|
|
metaOut.write(RoguelikeRandomiser.RNG.state0.toLittle())
|
|
metaOut.write(RoguelikeRandomiser.RNG.state1.toLittle())
|
|
|
|
// weather seed
|
|
metaOut.write(WeatherMixer.RNG.state0.toLittle())
|
|
metaOut.write(WeatherMixer.RNG.state1.toLittle())
|
|
|
|
// reference ID of the player
|
|
metaOut.write(Terrarum.PLAYER_REF_ID.toLittle())
|
|
|
|
// ingame time_t
|
|
metaOut.write((world as GameWorldExtension).time.TIME_T.toLittle())
|
|
|
|
// creation time (real world time)
|
|
metaOut.write(world.creationTime.toULittle48())
|
|
|
|
// time at save (real world time)
|
|
val timeNow = System.currentTimeMillis() / 1000L
|
|
metaOut.write(timeNow.toULittle48())
|
|
|
|
// get playtime and save it
|
|
val timeToAdd = (timeNow - world.loadTime).toInt()
|
|
metaOut.write((world.totalPlayTime + timeToAdd).toLittle())
|
|
world.lastPlayTime = timeNow
|
|
world.totalPlayTime += timeToAdd
|
|
|
|
// SHA256SUM of worldinfo1-3
|
|
worldInfoHash.forEach {
|
|
metaOut.write(it)
|
|
}
|
|
|
|
// thumbnail
|
|
val texreg = ingame.actorGamer.sprite?.textureRegion
|
|
if (texreg != null) {
|
|
val batch = SpriteBatch()
|
|
val camera = OrthographicCamera(texreg.tileW.toFloat(), texreg.tileH.toFloat())
|
|
val fbo = FrameBuffer(Pixmap.Format.RGBA8888, texreg.tileW, texreg.tileH, false)
|
|
|
|
fbo.inAction(camera, batch) {
|
|
batch.inUse {
|
|
batch.draw(texreg.get(0, 0), 0f, 0f)
|
|
}
|
|
}
|
|
|
|
// bind and unbind the fbo so that I can get the damned Pixmap using ScreenUtils
|
|
// NullPointerException if not appconfig.useGL30
|
|
Gdx.gl30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, fbo.framebufferHandle)
|
|
Gdx.gl30.glReadBuffer(GL30.GL_COLOR_ATTACHMENT0)
|
|
|
|
val outpixmap = ScreenUtils.getFrameBufferPixmap(0, 0, fbo.width, fbo.height)
|
|
|
|
Gdx.gl30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, 0)
|
|
Gdx.gl30.glReadBuffer(GL30.GL_BACK)
|
|
|
|
|
|
val tgaSize = PixmapIO2.HEADER_FOOTER_SIZE + outpixmap.width * outpixmap.height * 4
|
|
val byteArrayOS = ByteArrayOutputStream(tgaSize)
|
|
PixmapIO2._writeTGA(byteArrayOS, outpixmap, true, true)
|
|
byteArrayOS.flush()
|
|
byteArrayOS.close()
|
|
|
|
|
|
//PixmapIO2.writeTGA(Gdx.files.absolute(AppLoader.defaultDir+"/tmp_writeworldinfo+outpixmap.tga"), outpixmap, true)
|
|
|
|
|
|
outpixmap.dispose()
|
|
batch.dispose()
|
|
fbo.dispose()
|
|
|
|
|
|
|
|
// write uncompressed size
|
|
metaOut.write(tgaSize.toULittleShort())
|
|
// write compressed tga
|
|
val deflater = DeflaterOutputStream(metaOut, Deflater(Deflater.BEST_COMPRESSION, true), false)
|
|
deflater.write(byteArrayOS.toByteArray())
|
|
deflater.flush(); deflater.finish()
|
|
// write footer
|
|
metaOut.write(-1); metaOut.write(-2)
|
|
}
|
|
|
|
// more data goes here //
|
|
|
|
|
|
metaOut.flush()
|
|
metaOut.close()
|
|
|
|
|
|
|
|
return listOf(metaOut.toByteArray64()) + outFiles.toList()
|
|
}
|
|
|
|
} |