mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
integration of blob and actorvalue
This commit is contained in:
@@ -27,6 +27,7 @@ open class KVHashMap {
|
||||
|
||||
var hashMap: HashMap<String, Any>
|
||||
|
||||
|
||||
/**
|
||||
* Add key-value pair to the configuration table.
|
||||
* If key does not exist on the table, new key will be generated.
|
||||
@@ -37,18 +38,7 @@ open class KVHashMap {
|
||||
* @param value
|
||||
*/
|
||||
open operator fun set(key: String, value: Any) {
|
||||
hashMap.put(key.toLowerCase(), value)
|
||||
}
|
||||
|
||||
fun setBlob(key: String, value: ByteArray) {
|
||||
val filename0 = hashMap.getOrPut(key.toLowerCase()) { "blob://${UUID.randomUUID()}" } as String
|
||||
if (filename0.startsWith("blob://")) {
|
||||
Terrarum.getSharedSaveFiledesc(filename0.removePrefix("blob://")).let {
|
||||
if (!it.exists()) it.createNewFile()
|
||||
it.writeBytes(value) // will overwrite whatever's there
|
||||
}
|
||||
}
|
||||
else throw TypeCastException("ActorValue is not blob")
|
||||
hashMap[key.toLowerCase()] = value
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,19 +79,6 @@ open class KVHashMap {
|
||||
return value as Boolean
|
||||
}
|
||||
|
||||
fun getAsBlob(key: String): ByteArray? {
|
||||
val uri = getAsString(key) ?: return null
|
||||
if (uri.startsWith("blob://")) {
|
||||
val filename = uri.removePrefix("blob://")
|
||||
val file = Terrarum.getSharedSaveFiledesc(filename)
|
||||
if (file.exists())
|
||||
return file.readBytes()
|
||||
else
|
||||
throw IOException("Blob not found")
|
||||
}
|
||||
else throw TypeCastException("ActorValue is not blob")
|
||||
}
|
||||
|
||||
fun hasKey(key: String) = hashMap.containsKey(key)
|
||||
|
||||
val keySet: Set<Any>
|
||||
@@ -111,13 +88,6 @@ open class KVHashMap {
|
||||
if (hashMap[key] != null) {
|
||||
val value = hashMap[key]!!
|
||||
hashMap.remove(key, value)
|
||||
|
||||
(value as? String)?.let {
|
||||
if (it.startsWith("blob://")) {
|
||||
val filename = it.removePrefix("blob://")
|
||||
Terrarum.getSharedSaveFiledesc(filename).delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.KVHashMap
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.savegame.*
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
/**
|
||||
* For the dictionary of recognised ActorValues, see the source code of [net.torvald.terrarum.gameactors.AVKey]
|
||||
@@ -12,6 +20,8 @@ class ActorValue : KVHashMap {
|
||||
@Transient lateinit var actor: Actor
|
||||
internal set
|
||||
|
||||
@Transient private val BLOB = "blob://" // typical filename will be like "blob://-2147483648"
|
||||
|
||||
constructor()
|
||||
|
||||
constructor(actor: Actor) : this() {
|
||||
@@ -24,18 +34,122 @@ class ActorValue : KVHashMap {
|
||||
}
|
||||
|
||||
override fun set(key: String, value: Any) {
|
||||
super.set(key, value)
|
||||
// check if the key exists and is a blob
|
||||
if (getAsString(key.toLowerCase())?.startsWith(BLOB) == true) {
|
||||
throw IllegalStateException("Cannot write plain values to the blob object")
|
||||
}
|
||||
else
|
||||
super.set(key, value)
|
||||
|
||||
actor.onActorValueChange(key, value) // fire the event handler
|
||||
}
|
||||
|
||||
fun setBlob(key: String, ref: Long, value: ByteArray64) {
|
||||
checkActorBlobRef(ref)
|
||||
|
||||
// if setBlob is invoked on non-existing key, adds random empty blob to the key
|
||||
// filename0 will be whatever value stored on the actorvalue, cast to String
|
||||
val preexisted = hashMap.containsKey(key.toLowerCase())
|
||||
|
||||
val filename0 = hashMap.getOrPut(key.toLowerCase()) { "$BLOB$ref" } as String
|
||||
if (filename0.startsWith(BLOB)) {
|
||||
writeBlobBin(ref, value)
|
||||
}
|
||||
else {
|
||||
// rollback key addition, if applicable
|
||||
if (preexisted) hashMap.remove(key.toLowerCase())
|
||||
throw TypeCastException("ActorValue is not blob")
|
||||
}
|
||||
}
|
||||
|
||||
fun getAsBlob(key: String): ByteArray64? {
|
||||
val uri = getAsString(key) ?: return null
|
||||
if (uri.startsWith(BLOB)) {
|
||||
return readBlobBin(uri.removePrefix(BLOB).toLong())
|
||||
}
|
||||
else throw TypeCastException("ActorValue is not blob")
|
||||
}
|
||||
|
||||
override fun remove(key: String) {
|
||||
if (hashMap[key] != null) {
|
||||
hashMap.remove(key, hashMap[key]!!)
|
||||
val value = hashMap[key]!!
|
||||
hashMap.remove(key, value)
|
||||
|
||||
// remove blob
|
||||
(value as? String)?.let {
|
||||
if (it.startsWith(BLOB)) {
|
||||
deleteBlobBin(it.removePrefix(BLOB).toLong())
|
||||
}
|
||||
}
|
||||
|
||||
actor.onActorValueChange(key, null)
|
||||
}
|
||||
}
|
||||
|
||||
fun clone(newActor: Actor): ActorValue {
|
||||
return ActorValue(newActor, hashMap)
|
||||
// TODO clone blobs
|
||||
}
|
||||
|
||||
private fun readBlobBin(ref: Long): ByteArray64? {
|
||||
checkActorBlobRef(ref)
|
||||
|
||||
if (INGAME.actorNowPlaying == actor) {
|
||||
val disk = INGAME.playerDisk
|
||||
return disk.getFile(ref)?.bytes
|
||||
}
|
||||
else if (actor is IngamePlayer) {
|
||||
val diskSkimmer = DiskSkimmer(Terrarum.getPlayerSaveFiledesc((actor as IngamePlayer).uuid.toString()))
|
||||
return diskSkimmer.getFile(ref)?.bytes
|
||||
}
|
||||
else throw IllegalStateException("Actor is not a player")
|
||||
}
|
||||
|
||||
private fun writeBlobBin(ref: Long, contents: ByteArray64) {
|
||||
checkActorBlobRef(ref)
|
||||
|
||||
val time = App.getTIME_T()
|
||||
val file = EntryFile(contents)
|
||||
|
||||
if (INGAME.actorNowPlaying == actor) {
|
||||
val disk = INGAME.playerDisk
|
||||
|
||||
disk.getFile(ref).let {
|
||||
// create new file if one not exists, then pass it
|
||||
if (it == null) {
|
||||
VDUtil.addFile(disk, DiskEntry(ref, 0, time, time, file))
|
||||
file
|
||||
}
|
||||
else it
|
||||
}.bytes = contents
|
||||
|
||||
disk.getEntry(ref)!!.modificationDate = time
|
||||
}
|
||||
else if (actor is IngamePlayer) {
|
||||
val diskSkimmer = DiskSkimmer(Terrarum.getPlayerSaveFiledesc((actor as IngamePlayer).uuid.toString()))
|
||||
val oldCreationDate = diskSkimmer.getEntry(ref)?.creationDate
|
||||
|
||||
diskSkimmer.appendEntry(DiskEntry(ref, 0, oldCreationDate ?: time, time, file))
|
||||
}
|
||||
else throw IllegalStateException("Actor is not a player")
|
||||
}
|
||||
|
||||
private fun deleteBlobBin(ref: Long) {
|
||||
checkActorBlobRef(ref)
|
||||
|
||||
if (INGAME.actorNowPlaying == actor) {
|
||||
val disk = INGAME.playerDisk
|
||||
VDUtil.deleteFile(disk, ref)
|
||||
}
|
||||
else if (actor is IngamePlayer) {
|
||||
val diskSkimmer = DiskSkimmer(Terrarum.getPlayerSaveFiledesc((actor as IngamePlayer).uuid.toString()))
|
||||
diskSkimmer.deleteEntry(ref)
|
||||
}
|
||||
else throw IllegalStateException("Actor is not a player")
|
||||
}
|
||||
|
||||
private fun checkActorBlobRef(ref: Long) {
|
||||
if (ref > -2147483648L) throw IllegalArgumentException("File Ref $ref is not a valid ActorValue blob")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user