diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/tile/RenderTemplate.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/tile/RenderTemplate.kt index 4d3fd396..3497c443 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/tile/RenderTemplate.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/tile/RenderTemplate.kt @@ -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() - - val CACHE = object : TypeAdapter() { - 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) - } - } - } } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/util/ReferenceAdapter.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/util/ReferenceAdapter.kt new file mode 100644 index 00000000..bba16013 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/util/ReferenceAdapter.kt @@ -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(val parent: TypeAdapter) : TypeAdapter() { + private val cache = ConcurrentHashMap() + + 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 TypeAdapter.asReference(): TypeAdapter { + return ReferenceAdapter(this) +}