KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/defs/IThingWithDescription.kt
2024-03-17 11:10:18 +07:00

180 lines
6.2 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}
}