ReferenceAdapter

This commit is contained in:
DBotThePony 2023-01-22 19:08:26 +07:00
parent 6fafcd6185
commit 6f8de045e1
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 63 additions and 27 deletions

View File

@ -11,6 +11,7 @@ import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.io.json.builder.EnumAdapter
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
import ru.dbotthepony.kstarbound.io.json.util.asReference
import ru.dbotthepony.kstarbound.registerTypeAdapter
import ru.dbotthepony.kstarbound.util.WriteOnce
import ru.dbotthepony.kstarbound.world.ITileGetter
@ -268,6 +269,8 @@ data class RenderTemplate(
.mapAsObject(RenderTemplate::rules, RenderRuleList::class.java)
.build()
val CACHE = ADAPTER.asReference()
fun registerGson(gsonBuilder: GsonBuilder) {
gsonBuilder.registerTypeAdapter(RenderPiece.ADAPTER)
gsonBuilder.registerTypeAdapter(RenderRuleList.ADAPTER)
@ -282,32 +285,5 @@ data class RenderTemplate(
gsonBuilder.registerTypeAdapter(EnumAdapter(RenderRuleList.Combination::class.java))
}
private val cache = ConcurrentHashMap<String, RenderTemplate>()
val CACHE = object : TypeAdapter<RenderTemplate>() {
override fun write(out: JsonWriter, value: RenderTemplate) {
ADAPTER.write(out, value)
}
override fun read(reader: JsonReader): RenderTemplate {
if (reader.peek() != JsonToken.STRING) {
throw JsonSyntaxException("Expected string as input for render template cache retriever")
}
var path = reader.nextString()
if (path[0] != '/') {
// относительный путь
val readingFolder = Starbound.assetFolder ?: throw NullPointerException("Currently read folder is not specified")
path = "$readingFolder/$path"
}
return cache.computeIfAbsent(path) {
return@computeIfAbsent Starbound.GSON.fromJson(Starbound.locate(it).reader(), RenderTemplate::class.java)
}
}
}
}
}

View File

@ -0,0 +1,60 @@
package ru.dbotthepony.kstarbound.io.json.util
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.Starbound
import java.util.concurrent.ConcurrentHashMap
/**
* Данный [TypeAdapter] реализует возможности чтения данных по "ссылке" на файл.
*
* К примеру, если в оригинальной структуре может (или обычно) встречаться такое:
*
* ```json
* {
* "thing": { ... },
* }
* ```
*
* и такое:
*
* ```json
* {
* "thing": "/path/to/thing.config"
* }
* ```
*
* То второй вариант будет прочитан из указанного пути и закеширован внутри [ReferenceAdapter]
*/
class ReferenceAdapter<T>(val parent: TypeAdapter<T>) : TypeAdapter<T>() {
private val cache = ConcurrentHashMap<String, T>()
override fun write(out: JsonWriter, value: T) {
parent.write(out, value)
}
override fun read(reader: JsonReader): T {
if (reader.peek() != JsonToken.STRING) {
return parent.read(reader)
}
var path = reader.nextString()
if (path[0] != '/') {
// относительный путь
val readingFolder = Starbound.assetFolder ?: throw NullPointerException("Currently read folder is not specified")
path = "$readingFolder/$path"
}
return cache.computeIfAbsent(path) {
return@computeIfAbsent parent.read(JsonReader(Starbound.locate(it).reader()).also { it.isLenient = true })
}
}
}
fun <T> TypeAdapter<T>.asReference(): TypeAdapter<T> {
return ReferenceAdapter(this)
}