mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-12 22:56:06 +09:00
170 lines
6.0 KiB
Kotlin
170 lines
6.0 KiB
Kotlin
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
|
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
|
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
|
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
|
import net.torvald.terrarum.tvda.*
|
|
import java.io.Reader
|
|
|
|
/**
|
|
* Created by minjaesong on 2021-08-24.
|
|
*/
|
|
object WriteActor {
|
|
|
|
operator fun invoke(actor: Actor): String {
|
|
val s = Common.jsoner.toJson(actor, actor.javaClass)
|
|
return """{"class":"${actor.javaClass.canonicalName}",${s.substring(1)}"""
|
|
}
|
|
|
|
fun encodeToByteArray64(actor: Actor): ByteArray64 {
|
|
val baw = ByteArray64Writer(Common.CHARSET)
|
|
|
|
val classDef = """{"class":"${actor.javaClass.canonicalName}""""
|
|
baw.write(classDef)
|
|
Common.jsoner.toJson(actor, actor.javaClass, baw)
|
|
baw.flush(); baw.close()
|
|
// by this moment, contents of the baw will be:
|
|
// {"class":"some.class.Name"{"actorValue":{},......}
|
|
// (note that first bracket is not closed, and another open bracket after "class" property)
|
|
// and we want to turn it into this:
|
|
// {"class":"some.class.Name","actorValue":{},......}
|
|
val ba = baw.toByteArray64()
|
|
ba[classDef.toByteArray(Common.CHARSET).size.toLong()] = ','.code.toByte()
|
|
|
|
return ba
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Player-specific [WriteActor]. Will write JSON and Animation Description Languages
|
|
*
|
|
* Created by minjaesong on 2021-10-07.
|
|
*/
|
|
object WritePlayer {
|
|
|
|
/**
|
|
* 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()
|
|
val adlGlow = player.animDescGlow?.getRawADL() // NULLABLE!
|
|
|
|
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(-2L, 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(-3L, 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:
|
|
* ```
|
|
* "class":"net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer"
|
|
* ```
|
|
*
|
|
* Created by minjaesong on 2021-08-27.
|
|
*/
|
|
object ReadActor {
|
|
|
|
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)
|
|
|
|
private fun fillInDetails(disk: SimpleFileSystem, actor: Actor): Actor {
|
|
actor.actorValue.actor = actor
|
|
|
|
if (actor is Pocketed)
|
|
actor.inventory.actor = actor
|
|
|
|
if (actor is ActorWithBody && actor is HasAssembledSprite) {
|
|
val animFile = disk.getFile(-2L)
|
|
val animFileGlow = disk.getFile(-3L)
|
|
|
|
actor.sprite = SpriteAnimation(actor)
|
|
if (animFileGlow != null) actor.spriteGlow = SpriteAnimation(actor)
|
|
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, dataStream: Reader): Actor {
|
|
val actor = invoke(disk, dataStream)
|
|
|
|
// replace existing player
|
|
val oldPlayerID = ingame.actorNowPlaying?.referenceID
|
|
try {
|
|
ingame.forceRemoveActor(ingame.getActorByID(actor.referenceID))
|
|
}
|
|
catch (e: NoSuchActorWithIDException) { /* no actor to delete, you may proceed */ }
|
|
ingame.addNewActor(actor)
|
|
|
|
if (actor.referenceID == oldPlayerID)
|
|
ingame.actorNowPlaying = actor as ActorHumanoid
|
|
|
|
|
|
return actor
|
|
}
|
|
|
|
} |