Подгрузка прототипов предметов, немного комментариев в коде
This commit is contained in:
parent
cfe892e220
commit
176ca9db65
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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<*>>>()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user