180 lines
6.2 KiB
Kotlin
180 lines
6.2 KiB
Kotlin
package ru.dbotthepony.kstarbound.defs
|
||
|
||
import com.google.common.collect.ImmutableMap
|
||
import com.github.benmanes.caffeine.cache.Interner
|
||
import com.google.gson.Gson
|
||
import com.google.gson.TypeAdapter
|
||
import com.google.gson.TypeAdapterFactory
|
||
import com.google.gson.reflect.TypeToken
|
||
import com.google.gson.stream.JsonReader
|
||
import com.google.gson.stream.JsonToken
|
||
import com.google.gson.stream.JsonWriter
|
||
import ru.dbotthepony.kommons.gson.consumeNull
|
||
import ru.dbotthepony.kstarbound.json.builder.JsonImplementation
|
||
|
||
@JsonImplementation(ThingDescription::class)
|
||
interface IThingWithDescription {
|
||
/**
|
||
* Краткое описание штуки. Несмотря на то, что название свойства подразумевает "описание",
|
||
* на самом деле данное поле отвечает за название штуки.
|
||
*
|
||
* Примеры:
|
||
* * Microwave Oven
|
||
* * Copper Ore
|
||
* * Poptop
|
||
*/
|
||
val shortdescription: String
|
||
|
||
/**
|
||
* Полное описание штуки. Оно отображается игроку, когда последний наводит курсор на штуку.
|
||
*
|
||
* Примеры:
|
||
* * A microwave. For when you're hungry enough to nuke your food.
|
||
* * Copper ore. Can be used for smelting.
|
||
* * The Poptop hums beautifully to confuse its prey.
|
||
*/
|
||
val description: String
|
||
|
||
/**
|
||
* Полное описание штуки для определённых рас
|
||
*
|
||
* Пример для Microwave Oven:
|
||
* Apex: A type of oven.
|
||
* Avian: A bizarre cooking device.
|
||
* Floran: Floran likess raw meat, sssometimes cooked meat is good too.
|
||
* Glitch: Irked. It is encrusted with spattered food, who left it in this state?
|
||
* Human: A microwave. Gotta get me some jacket potatoes.
|
||
* Hylotl: A strange, spinning oven.
|
||
* Novakid: This lil' rotatin' oven cooks food at speed!
|
||
*
|
||
* Как это выглядит в JSON структуре:
|
||
* ```json
|
||
* {
|
||
* ...
|
||
*
|
||
* "apexDescription" : "A type of oven.",
|
||
* "avianDescription" : "A bizarre cooking device.",
|
||
* "floranDescription" : "Floran likess raw meat, sssometimes cooked meat is good too.",
|
||
* "glitchDescription" : "Irked. It is encrusted with spattered food, who left it in this state?",
|
||
* "humanDescription" : "A microwave. Gotta get me some jacket potatoes.",
|
||
* "hylotlDescription" : "A strange, spinning oven.",
|
||
* "novakidDescription" : "This lil' rotatin' oven cooks food at speed!",
|
||
*
|
||
* ...
|
||
* }
|
||
* ```
|
||
*
|
||
* Для получения описания для определённой расы необходимо знать ID расы, как показано выше (`apex`, `avian`, ...)
|
||
*/
|
||
val racialDescription: Map<String, String> get() = mapOf()
|
||
|
||
/**
|
||
* Кратное описание штуки для определённых рас. В оригинальной игре не встречается
|
||
*/
|
||
val racialShortDescription: Map<String, String> get() = mapOf()
|
||
}
|
||
|
||
data class ThingDescription(
|
||
override val shortdescription: String = "...",
|
||
override val description: String = "...",
|
||
override val racialDescription: Map<String, String> = mapOf(),
|
||
override val racialShortDescription: Map<String, String> = mapOf(),
|
||
) : IThingWithDescription {
|
||
companion object {
|
||
val EMPTY = ThingDescription()
|
||
}
|
||
|
||
fun fixDescription(newDescription: String): ThingDescription {
|
||
return copy(
|
||
shortdescription = if (shortdescription == "...") newDescription else shortdescription,
|
||
description = if (description == "...") newDescription else description,
|
||
)
|
||
}
|
||
|
||
class Factory(val interner: Interner<String> = Interner { it }) : TypeAdapterFactory {
|
||
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
||
if (type.rawType == ThingDescription::class.java) {
|
||
return object : TypeAdapter<ThingDescription>() {
|
||
override fun write(out: JsonWriter, value: ThingDescription?) {
|
||
if (value == null)
|
||
out.nullValue()
|
||
else {
|
||
out.beginObject()
|
||
|
||
out.name("shortdescription")
|
||
out.value(value.shortdescription)
|
||
|
||
out.name("description")
|
||
out.value(value.description)
|
||
|
||
for ((k, v) in value.racialDescription) {
|
||
out.name("${k}Description")
|
||
out.value(v)
|
||
}
|
||
|
||
for ((k, v) in value.racialShortDescription) {
|
||
out.name("${k}Shortdescription")
|
||
out.value(v)
|
||
}
|
||
|
||
out.endObject()
|
||
}
|
||
}
|
||
|
||
override fun read(`in`: JsonReader): ThingDescription? {
|
||
if (`in`.consumeNull())
|
||
return null
|
||
|
||
`in`.beginObject()
|
||
|
||
var shortdescription: String? = null
|
||
var description: String? = null
|
||
val racial = ImmutableMap.Builder<String, String>()
|
||
val racialShort = ImmutableMap.Builder<String, String>()
|
||
|
||
while (`in`.peek() !== JsonToken.END_OBJECT) {
|
||
when (val name = `in`.nextName()) {
|
||
"shortdescription" -> shortdescription = `in`.nextString()
|
||
"description" -> description = `in`.nextString()
|
||
else -> {
|
||
try {
|
||
if (name.endsWith("shortdescription") || name.endsWith("shortDescription") || name.endsWith("Shortdescription") || name.endsWith("ShortDescription")) {
|
||
racialShort.put(interner.intern(name.substring(0, name.length - "shortdescription".length)), interner.intern(`in`.nextString()))
|
||
} else if (name.endsWith("description") || name.endsWith("Description")) {
|
||
racial.put(interner.intern(name.substring(0, name.length - "description".length)), interner.intern(`in`.nextString()))
|
||
} else {
|
||
`in`.skipValue()
|
||
}
|
||
} catch (_: IllegalStateException) {
|
||
`in`.skipValue()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
`in`.endObject()
|
||
|
||
if (shortdescription == null && description == null) {
|
||
shortdescription = "..."
|
||
description = "..."
|
||
} else if (shortdescription == null) {
|
||
shortdescription = description
|
||
} else if (description == null) {
|
||
description = shortdescription
|
||
}
|
||
|
||
return ThingDescription(
|
||
shortdescription = shortdescription!!,
|
||
description = description!!,
|
||
racialDescription = racial.build(),
|
||
racialShortDescription = racialShort.build()
|
||
)
|
||
}
|
||
} as TypeAdapter<T>
|
||
}
|
||
|
||
return null
|
||
}
|
||
}
|
||
}
|