Больше свойств у прототипа предмета

This commit is contained in:
DBotThePony 2022-12-29 16:32:24 +07:00
parent 5f3c33d9cb
commit 5e29072fcf
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 141 additions and 33 deletions

View File

@ -3,6 +3,8 @@ package ru.dbotthepony.kstarbound.defs.item
import com.google.gson.GsonBuilder
import ru.dbotthepony.kstarbound.io.KConcreteTypeAdapter
import ru.dbotthepony.kstarbound.registerTypeAdapter
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.nint.Vector2i
data class ItemDefinition(
val itemName: String,
@ -12,8 +14,71 @@ data class ItemDefinition(
val inventoryIcon: String? = null,
val description: String = "...",
val shortdescription: String = "...",
val itemTags: List<String> = listOf()
val itemTags: List<String> = listOf(),
val learnBlueprintsOnPickup: List<String> = listOf(),
val maxStack: Long = 9999L,
val eventCategory: String? = null,
val consumeOnPickup: Boolean = false,
val pickupQuestTemplates: List<String> = listOf(),
/**
* Используется в костях-ископаемых
*/
val race: String? = null,
val displayImage: String? = null,
val displayoffset: Vector2d? = null,
/**
* Используется в костях-ископаемых
*/
val fossilSetName: String? = null,
/**
* Используется в костях-ископаемых
*/
val setIndex: Int? = null,
/**
* Используется в костях-ископаемых
*/
val setCount: Int? = null,
/**
* Используется в костях-ископаемых
*/
val setCollectables: Map<String, String>? = null,
/**
* Используется в костях-ископаемых
*/
val completeFossilIcon: String? = null,
/**
* Используется в костях-ископаемых
*/
val completeFossilObject: String? = null,
/**
* Используется в костях-ископаемых
*/
val completeSetDescriptions: FossilSetDescription? = null,
/**
* Заставляет SAIL болтать
*/
val radioMessagesOnPickup: List<String> = listOf(),
/**
* Топливо корабля
*/
val fuelAmount: Long? = null,
) {
data class FossilSetDescription(
val price: Long = 0L,
val shortdescription: String = "...",
val description: String = "..."
)
companion object {
val ADAPTER = KConcreteTypeAdapter.Builder(ItemDefinition::class)
.plain(ItemDefinition::itemName)
@ -23,11 +88,40 @@ data class ItemDefinition(
.plain(ItemDefinition::inventoryIcon)
.plain(ItemDefinition::description)
.plain(ItemDefinition::shortdescription)
.list(ItemDefinition::itemTags)
.list(ItemDefinition::learnBlueprintsOnPickup)
.plain(ItemDefinition::maxStack)
.plain(ItemDefinition::eventCategory)
.plain(ItemDefinition::consumeOnPickup)
.list(ItemDefinition::pickupQuestTemplates)
.plain(ItemDefinition::race)
.plain(ItemDefinition::displayImage)
.plain(ItemDefinition::displayoffset)
.plain(ItemDefinition::fossilSetName)
.plain(ItemDefinition::setIndex)
.plain(ItemDefinition::setCount)
.map(ItemDefinition::setCollectables, String::class)
.plain(ItemDefinition::completeFossilIcon)
.plain(ItemDefinition::completeFossilObject)
.plain(ItemDefinition::completeSetDescriptions)
.list(ItemDefinition::radioMessagesOnPickup)
.plain(ItemDefinition::fuelAmount)
.build()
val FOSSIL_ADAPTER = KConcreteTypeAdapter.Builder(FossilSetDescription::class)
.plain(FossilSetDescription::price)
.plain(FossilSetDescription::shortdescription)
.plain(FossilSetDescription::description)
.build()
fun registerGson(gsonBuilder: GsonBuilder) {
gsonBuilder.registerTypeAdapter(ADAPTER)
gsonBuilder.registerTypeAdapter(FOSSIL_ADAPTER)
}
}
}

View File

@ -2,8 +2,8 @@ package ru.dbotthepony.kstarbound.io
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import com.google.common.collect.Interner
import com.google.common.collect.Interners
import com.google.gson.GsonBuilder
import com.google.gson.JsonSyntaxException
import com.google.gson.TypeAdapter
import com.google.gson.internal.bind.TypeAdapters
@ -18,19 +18,19 @@ import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.getValue
import ru.dbotthepony.kstarbound.setValue
import java.lang.reflect.Constructor
import java.util.BitSet
import kotlin.jvm.internal.DefaultConstructorMarker
import kotlin.properties.Delegates
import kotlin.reflect.*
import kotlin.reflect.full.isSuperclassOf
import kotlin.reflect.full.isSupertypeOf
import kotlin.reflect.full.memberProperties
@Suppress("unchecked_cast")
private fun <T> resolveBound(bound: Class<T>): TypeAdapter<T> {
private fun <T> resolveBound(bound: Class<T>, stringAdapter: TypeAdapter<String>): TypeAdapter<T> {
return when (bound) {
Float::class.java -> TypeAdapters.FLOAT as TypeAdapter<T>
Double::class.java -> TypeAdapters.DOUBLE as TypeAdapter<T>
String::class.java -> TypeAdapters.STRING as TypeAdapter<T>
String::class.java -> stringAdapter as TypeAdapter<T>
Int::class.java -> TypeAdapters.INTEGER as TypeAdapter<T>
Long::class.java -> TypeAdapters.LONG as TypeAdapter<T>
Boolean::class.java -> TypeAdapters.BOOLEAN as TypeAdapter<T>
@ -38,10 +38,8 @@ private fun <T> resolveBound(bound: Class<T>): TypeAdapter<T> {
}
}
class ListAdapter<T>(private val bound: Class<T>) : TypeAdapter<List<T>>() {
private val resolvedBound by lazy {
resolveBound(bound)
}
private class ListAdapter<T>(private val bound: Class<T>, private val stringAdapter: TypeAdapter<String>) : TypeAdapter<List<T>>() {
private val resolvedBound by lazy { resolveBound(bound, stringAdapter) }
override fun write(out: JsonWriter, value: List<T>) {
out.beginArray()
@ -72,14 +70,9 @@ class ListAdapter<T>(private val bound: Class<T>) : TypeAdapter<List<T>>() {
}
}
class MapAdapter<K, V>(private val boundKey: Class<K>, private val boundValue: Class<V>) : TypeAdapter<Map<K, V>>() {
private val resolvedKey by lazy {
resolveBound(boundKey)
}
private val resolvedValue by lazy {
resolveBound(boundValue)
}
private class MapAdapter<K, V>(private val boundKey: Class<K>, private val boundValue: Class<V>, private val stringAdapter: TypeAdapter<String>) : TypeAdapter<Map<K, V>>() {
private val resolvedKey by lazy { resolveBound(boundKey, stringAdapter) }
private val resolvedValue by lazy { resolveBound(boundValue, stringAdapter) }
override fun write(out: JsonWriter, value: Map<K, V>) {
out.beginArray()
@ -117,10 +110,8 @@ class MapAdapter<K, V>(private val boundKey: Class<K>, private val boundValue: C
}
}
class StringMapAdapter<V>(private val bound: Class<V>) : TypeAdapter<Map<String, V>>() {
private val resolvedBound by lazy {
resolveBound(bound)
}
private class StringMapAdapter<V>(private val bound: Class<V>, private val stringAdapter: TypeAdapter<String>, private val interner: () -> Interner<String>) : TypeAdapter<Map<String, V>>() {
private val resolvedBound by lazy { resolveBound(bound, stringAdapter) }
override fun write(out: JsonWriter, value: Map<String, V>) {
val resolvedBound = resolvedBound
@ -143,7 +134,7 @@ class StringMapAdapter<V>(private val bound: Class<V>) : TypeAdapter<Map<String,
val resolvedBound = resolvedBound
while (reader.peek() != JsonToken.END_OBJECT) {
builder.put(reader.nextName(), resolvedBound.read(reader))
builder.put(interner.invoke().intern(reader.nextName()), resolvedBound.read(reader))
}
reader.endObject()
@ -153,7 +144,7 @@ class StringMapAdapter<V>(private val bound: Class<V>) : TypeAdapter<Map<String,
}
private class LazyTypeProvider<T : Any?>(private val bound: Class<T>) : TypeAdapter<T>() {
private val resolved by lazy { resolveBound(bound) }
private val resolved by lazy { resolveBound(bound, TypeAdapters.STRING) }
override fun write(out: JsonWriter, value: T) {
resolved.write(out, value)
@ -441,6 +432,17 @@ class KConcreteTypeAdapter<T : Any>(
*/
class Builder<T : Any>(val clazz: KClass<T>) {
private val types = ArrayList<Pair<KProperty1<T, *>, TypeAdapter<*>>>()
private var interner by Delegates.notNull<Interner<String>>()
private val internedStringAdapter: TypeAdapter<String> = object : TypeAdapter<String>() {
override fun write(out: JsonWriter, value: String) {
return TypeAdapters.STRING.write(out, value)
}
override fun read(`in`: JsonReader): String {
return interner.intern(TypeAdapters.STRING.read(`in`))
}
}
/**
* Добавляет поле с определённым адаптером
@ -467,7 +469,7 @@ class KConcreteTypeAdapter<T : Any>(
} else if (classifier.isSuperclassOf(Long::class)) {
types.add(field to TypeAdapters.LONG)
} else if (classifier.isSuperclassOf(String::class)) {
types.add(field to TypeAdapters.STRING)
types.add(field to internedStringAdapter)
} else if (classifier.isSuperclassOf(Boolean::class)) {
types.add(field to TypeAdapters.BOOLEAN)
} else {
@ -498,7 +500,7 @@ class KConcreteTypeAdapter<T : Any>(
* Список неизменяем (создаётся объект [ImmutableList])
*/
fun <V : Any> list(field: KProperty1<T, List<V>?>, type: Class<V>): Builder<T> {
types.add(field to ListAdapter(type))
types.add(field to ListAdapter(type, internedStringAdapter))
return this
}
@ -517,7 +519,7 @@ class KConcreteTypeAdapter<T : Any>(
* Таблица неизменяема (создаётся объект [ImmutableMap])
*/
fun <K, V> map(field: KProperty1<T, Map<K, V>>, keyType: Class<K>, valueType: Class<V>): Builder<T> {
types.add(field to MapAdapter(keyType, valueType))
types.add(field to MapAdapter(keyType, valueType, internedStringAdapter))
return this
}
@ -526,8 +528,8 @@ class KConcreteTypeAdapter<T : Any>(
*
* Таблица неизменяема (создаётся объект [ImmutableMap])
*/
fun <K : Any, V : Any> map(field: KProperty1<T, Map<K, V>>, keyType: KClass<K>, valueType: KClass<V>): Builder<T> {
types.add(field to MapAdapter(keyType.java, valueType.java))
fun <K : Any, V : Any> map(field: KProperty1<T, Map<K, V>?>, keyType: KClass<K>, valueType: KClass<V>): Builder<T> {
types.add(field to MapAdapter(keyType.java, valueType.java, internedStringAdapter))
return this
}
@ -536,8 +538,8 @@ class KConcreteTypeAdapter<T : Any>(
*
* Таблица неизменяема (создаётся объект [ImmutableMap])
*/
fun <V> map(field: KProperty1<T, Map<String, V>>, valueType: Class<V>): Builder<T> {
types.add(field to StringMapAdapter(valueType))
fun <V> map(field: KProperty1<T, Map<String, V>?>, valueType: Class<V>): Builder<T> {
types.add(field to StringMapAdapter(valueType, internedStringAdapter, ::interner))
return this
}
@ -546,17 +548,29 @@ class KConcreteTypeAdapter<T : Any>(
*
* Таблица неизменяема (создаётся объект [ImmutableMap])
*/
fun <V : Any> map(field: KProperty1<T, Map<String, V>>, valueType: KClass<V>): Builder<T> {
types.add(field to StringMapAdapter(valueType.java))
fun <V : Any> map(field: KProperty1<T, Map<String, V>?>, valueType: KClass<V>): Builder<T> {
types.add(field to StringMapAdapter(valueType.java, internedStringAdapter, ::interner))
return this
}
fun build(asList: Boolean = false): KConcreteTypeAdapter<T> {
return KConcreteTypeAdapter(clazz, ImmutableList.copyOf(types), asList = asList)
return KConcreteTypeAdapter(clazz, ImmutableList.copyOf(types), asList = asList).also {
interner = it.internedStrings
}
}
}
companion object {
private val LOGGER = LogManager.getLogger()
/*fun <T : Any> simple(clazz: KClass<T>, asList: Boolean = false): KConcreteTypeAdapter<T> {
val builder = Builder(clazz)
for (argument in clazz.primaryConstructor!!.parameters) {
builder.plain(argument.)
}
return builder.build(asList = asList)
}*/
}
}