Подгрузка прототипов предметов, немного комментариев в коде

This commit is contained in:
DBotThePony 2022-12-29 15:34:35 +07:00
parent cfe892e220
commit 176ca9db65
Signed by: DBot
GPG Key ID: DCC23B5715498507
6 changed files with 122 additions and 11 deletions

View File

@ -4,9 +4,18 @@ import com.google.gson.GsonBuilder
import com.google.gson.TypeAdapter
import java.util.Arrays
import java.util.stream.Stream
import kotlin.reflect.KProperty
inline fun <reified T> GsonBuilder.registerTypeAdapter(adapter: TypeAdapter<T>): GsonBuilder {
return registerTypeAdapter(T::class.java, adapter)
}
fun <T> Array<T>.stream(): Stream<T> = Arrays.stream(this)
operator fun <T> ThreadLocal<T>.getValue(thisRef: Any, property: KProperty<*>): T? {
return get()
}
operator fun <T> ThreadLocal<T>.setValue(thisRef: Any, property: KProperty<*>, value: T?) {
set(value)
}

View File

@ -8,6 +8,8 @@ import ru.dbotthepony.kstarbound.api.NonExistingFile
import ru.dbotthepony.kstarbound.api.PhysicalFile
import ru.dbotthepony.kstarbound.api.explore
import ru.dbotthepony.kstarbound.defs.*
import ru.dbotthepony.kstarbound.defs.item.ItemDefinition
import ru.dbotthepony.kstarbound.defs.item.ItemRarity
import ru.dbotthepony.kstarbound.defs.liquid.LiquidDefinition
import ru.dbotthepony.kstarbound.defs.projectile.*
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
@ -42,14 +44,10 @@ const val PIXELS_IN_STARBOUND_UNITf = 8.0f
object Starbound {
private val LOGGER = LogManager.getLogger()
private val _readingFolder = ThreadLocal<String>()
/**
* Служит переменной для указания из какой папки происходит чтение asset'а в данном потоке
*/
var readingFolder: String?
get() = _readingFolder.get()
private set(value) { _readingFolder.set(value) }
var readingFolder by ThreadLocal<String>()
private val tiles = HashMap<String, TileDefinition>()
private val tilesByMaterialID = Int2ObjectAVLTreeMap<TileDefinition>()
@ -64,6 +62,8 @@ object Starbound {
private val parallax = HashMap<String, ParallaxPrototype>()
private val functions = HashMap<String, JsonFunction>()
private val items = HashMap<String, ItemDefinition>()
val liquidAccess: Map<String, LiquidDefinition> = Collections.unmodifiableMap(liquid)
val liquidByIDAccess: Map<Int, LiquidDefinition> = Collections.unmodifiableMap(liquidByID)
val tileModifiersAccess: Map<String, MaterialModifier> = Collections.unmodifiableMap(tileModifiers)
@ -73,6 +73,7 @@ object Starbound {
val projectilesAccess: Map<String, ConfiguredProjectile> = Collections.unmodifiableMap(projectiles)
val parallaxAccess: Map<String, ParallaxPrototype> = Collections.unmodifiableMap(parallax)
val functionsAccess: Map<String, JsonFunction> = Collections.unmodifiableMap(functions)
val itemAccess: Map<String, ItemDefinition> = Collections.unmodifiableMap(items)
val gson: Gson = GsonBuilder()
.enableComplexMapKeySerialization()
@ -100,6 +101,8 @@ object Starbound {
.also(RenderTemplate::registerGson)
.also(TileDefinition::registerGson)
.also(LiquidDefinition::registerGson)
.also(ItemDefinition::registerGson)
.also(ItemRarity::registerGson)
.registerTypeAdapter(DamageType::class.java, CustomEnumTypeAdapter(DamageType.values()).nullSafe())
@ -239,6 +242,7 @@ object Starbound {
loadStage(callback, this::loadParallax, "parallax definitions")
loadStage(callback, this::loadMaterialModifiers, "material modifier definitions")
loadStage(callback, this::loadLiquidDefinitions, "liquid definitions")
loadStage(callback, this::loadItemDefinitions, "item definitions")
initializing = false
initialized = true
@ -339,7 +343,7 @@ object Starbound {
private fun loadParallax(callback: (String) -> Unit) {
for (fs in fileSystems) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".parallax") }) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".parallax") && it.isFile }) {
try {
callback("Loading $listedFile")
@ -360,7 +364,7 @@ object Starbound {
readingFolder = "/tiles/materials"
for (fs in fileSystems) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".matmod") }) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".matmod") && it.isFile }) {
try {
callback("Loading $listedFile")
@ -387,7 +391,7 @@ object Starbound {
private fun loadLiquidDefinitions(callback: (String) -> Unit) {
for (fs in fileSystems) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".liquid") }) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".liquid") && it.isFile }) {
try {
callback("Loading $listedFile")
@ -409,4 +413,27 @@ object Starbound {
readingFolder = null
}
private fun loadItemDefinitions(callback: (String) -> Unit) {
for (fs in fileSystems) {
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".item") && it.isFile }) {
try {
callback("Loading $listedFile")
readingFolder = listedFile.computeDirectory()
val def = gson.fromJson(listedFile.reader(), ItemDefinition::class.java)
check(items.put(def.itemName, def) == null) { "Already has item with name ${def.itemName} loaded!" }
} catch (err: Throwable) {
LOGGER.error("Loading item definition file $listedFile", err)
}
if (terminateLoading) {
return
}
}
}
readingFolder = null
}
}

View File

@ -0,0 +1,33 @@
package ru.dbotthepony.kstarbound.defs.item
import com.google.gson.GsonBuilder
import ru.dbotthepony.kstarbound.io.KConcreteTypeAdapter
import ru.dbotthepony.kstarbound.registerTypeAdapter
data class ItemDefinition(
val itemName: String,
val price: Long = 0L,
val rarity: ItemRarity = ItemRarity.COMMON,
val category: String? = null,
val inventoryIcon: String? = null,
val description: String = "...",
val shortdescription: String = "...",
val itemTags: List<String> = listOf()
) {
companion object {
val ADAPTER = KConcreteTypeAdapter.Builder(ItemDefinition::class)
.plain(ItemDefinition::itemName)
.plain(ItemDefinition::price)
.plain(ItemDefinition::rarity)
.plain(ItemDefinition::category)
.plain(ItemDefinition::inventoryIcon)
.plain(ItemDefinition::description)
.plain(ItemDefinition::shortdescription)
.list(ItemDefinition::itemTags)
.build()
fun registerGson(gsonBuilder: GsonBuilder) {
gsonBuilder.registerTypeAdapter(ADAPTER)
}
}
}

View File

@ -0,0 +1,32 @@
package ru.dbotthepony.kstarbound.defs.item
import com.google.gson.GsonBuilder
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.io.CustomEnumTypeAdapter
import ru.dbotthepony.kstarbound.io.IStringSerializable
import ru.dbotthepony.kstarbound.registerTypeAdapter
enum class ItemRarity(val canonical: String) : IStringSerializable {
COMMON("Common"),
UNCOMMON("Uncommon"),
RARE("Rare"),
LEGENDARY("Legendary"),
ESSENTIAL("Essential");
override fun match(name: String): Boolean {
return name == this.canonical || name.lowercase() == this.name.lowercase()
}
override fun write(out: JsonWriter) {
out.value(canonical)
}
companion object {
val ADAPTER: TypeAdapter<ItemRarity> = CustomEnumTypeAdapter(values()).nullSafe()
fun registerGson(gsonBuilder: GsonBuilder) {
gsonBuilder.registerTypeAdapter(ADAPTER)
}
}
}

View File

@ -26,6 +26,6 @@ class CustomEnumTypeAdapter<T : Enum<T>>(private val clazz: Array<T>) : TypeAdap
}
}
throw IllegalArgumentException("${clazz[0]::class.java.name} does not have value for $str")
throw IllegalArgumentException("${clazz[0]::class.qualifiedName} does not have value for $str")
}
}

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.kstarbound.io
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import com.google.common.collect.Interners
import com.google.gson.GsonBuilder
import com.google.gson.JsonSyntaxException
import com.google.gson.TypeAdapter
@ -174,7 +175,7 @@ class KConcreteTypeAdapter<T : Any>(
private val returnTypeCache = Object2ObjectArrayMap<KProperty1<T, *>, KType>()
private val mapped = Object2IntArrayMap<String>()
private val internedStrings = Interners.newWeakInterner<String>()
private val loggedMisses = ObjectArraySet<String>()
init {
@ -267,9 +268,11 @@ class KConcreteTypeAdapter<T : Any>(
reader.beginObject()
}
// таблица присутствия значений (если значение true то на i было значение внутри json)
val presentValues = BooleanArray(types.size)
val readValues = arrayOfNulls<Any>(types.size)
// Если нам необходимо читать объект как набор данных массива, то давай
if (asList) {
val iterator = types.iterator()
var fieldId = 0
@ -299,6 +302,7 @@ class KConcreteTypeAdapter<T : Any>(
fieldId++
}
// иначе - читаем как json object
} else {
while (reader.peek() != JsonToken.END_OBJECT) {
val name = reader.nextName()
@ -323,9 +327,10 @@ class KConcreteTypeAdapter<T : Any>(
}
}
// intern'им строки для более быстрой работы сравнения последних
for (i in readValues.indices) {
if (readValues[i] is String) {
readValues[i] = (readValues[i] as String).intern()
readValues[i] = internedStrings.intern(readValues[i] as String)
}
}
@ -335,6 +340,8 @@ class KConcreteTypeAdapter<T : Any>(
reader.endObject()
}
// если у нас есть все значения для конструктора (все значения присутствуют в исходном json объекте)
// или у нас нет Java'вского конструктора, то делаем вызов "обычного" конструктора
if (syntheticFactory == null || presentValues.all { it }) {
for ((i, pair) in types.withIndex()) {
val (field) = pair
@ -407,6 +414,9 @@ class KConcreteTypeAdapter<T : Any>(
}
}
/**
* Позволяет построить класс [KConcreteTypeAdapter] на основе заданных параметров
*/
class Builder<T : Any>(val clazz: KClass<T>) {
private val types = ArrayList<Pair<KProperty1<T, *>, TypeAdapter<*>>>()