Подгрузка прототипов предметов, немного комментариев в коде
This commit is contained in:
parent
cfe892e220
commit
176ca9db65
@ -4,9 +4,18 @@ import com.google.gson.GsonBuilder
|
|||||||
import com.google.gson.TypeAdapter
|
import com.google.gson.TypeAdapter
|
||||||
import java.util.Arrays
|
import java.util.Arrays
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
inline fun <reified T> GsonBuilder.registerTypeAdapter(adapter: TypeAdapter<T>): GsonBuilder {
|
inline fun <reified T> GsonBuilder.registerTypeAdapter(adapter: TypeAdapter<T>): GsonBuilder {
|
||||||
return registerTypeAdapter(T::class.java, adapter)
|
return registerTypeAdapter(T::class.java, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Array<T>.stream(): Stream<T> = Arrays.stream(this)
|
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.PhysicalFile
|
||||||
import ru.dbotthepony.kstarbound.api.explore
|
import ru.dbotthepony.kstarbound.api.explore
|
||||||
import ru.dbotthepony.kstarbound.defs.*
|
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.liquid.LiquidDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.projectile.*
|
import ru.dbotthepony.kstarbound.defs.projectile.*
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||||
@ -42,14 +44,10 @@ const val PIXELS_IN_STARBOUND_UNITf = 8.0f
|
|||||||
object Starbound {
|
object Starbound {
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
private val _readingFolder = ThreadLocal<String>()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Служит переменной для указания из какой папки происходит чтение asset'а в данном потоке
|
* Служит переменной для указания из какой папки происходит чтение asset'а в данном потоке
|
||||||
*/
|
*/
|
||||||
var readingFolder: String?
|
var readingFolder by ThreadLocal<String>()
|
||||||
get() = _readingFolder.get()
|
|
||||||
private set(value) { _readingFolder.set(value) }
|
|
||||||
|
|
||||||
private val tiles = HashMap<String, TileDefinition>()
|
private val tiles = HashMap<String, TileDefinition>()
|
||||||
private val tilesByMaterialID = Int2ObjectAVLTreeMap<TileDefinition>()
|
private val tilesByMaterialID = Int2ObjectAVLTreeMap<TileDefinition>()
|
||||||
@ -64,6 +62,8 @@ object Starbound {
|
|||||||
private val parallax = HashMap<String, ParallaxPrototype>()
|
private val parallax = HashMap<String, ParallaxPrototype>()
|
||||||
private val functions = HashMap<String, JsonFunction>()
|
private val functions = HashMap<String, JsonFunction>()
|
||||||
|
|
||||||
|
private val items = HashMap<String, ItemDefinition>()
|
||||||
|
|
||||||
val liquidAccess: Map<String, LiquidDefinition> = Collections.unmodifiableMap(liquid)
|
val liquidAccess: Map<String, LiquidDefinition> = Collections.unmodifiableMap(liquid)
|
||||||
val liquidByIDAccess: Map<Int, LiquidDefinition> = Collections.unmodifiableMap(liquidByID)
|
val liquidByIDAccess: Map<Int, LiquidDefinition> = Collections.unmodifiableMap(liquidByID)
|
||||||
val tileModifiersAccess: Map<String, MaterialModifier> = Collections.unmodifiableMap(tileModifiers)
|
val tileModifiersAccess: Map<String, MaterialModifier> = Collections.unmodifiableMap(tileModifiers)
|
||||||
@ -73,6 +73,7 @@ object Starbound {
|
|||||||
val projectilesAccess: Map<String, ConfiguredProjectile> = Collections.unmodifiableMap(projectiles)
|
val projectilesAccess: Map<String, ConfiguredProjectile> = Collections.unmodifiableMap(projectiles)
|
||||||
val parallaxAccess: Map<String, ParallaxPrototype> = Collections.unmodifiableMap(parallax)
|
val parallaxAccess: Map<String, ParallaxPrototype> = Collections.unmodifiableMap(parallax)
|
||||||
val functionsAccess: Map<String, JsonFunction> = Collections.unmodifiableMap(functions)
|
val functionsAccess: Map<String, JsonFunction> = Collections.unmodifiableMap(functions)
|
||||||
|
val itemAccess: Map<String, ItemDefinition> = Collections.unmodifiableMap(items)
|
||||||
|
|
||||||
val gson: Gson = GsonBuilder()
|
val gson: Gson = GsonBuilder()
|
||||||
.enableComplexMapKeySerialization()
|
.enableComplexMapKeySerialization()
|
||||||
@ -100,6 +101,8 @@ object Starbound {
|
|||||||
.also(RenderTemplate::registerGson)
|
.also(RenderTemplate::registerGson)
|
||||||
.also(TileDefinition::registerGson)
|
.also(TileDefinition::registerGson)
|
||||||
.also(LiquidDefinition::registerGson)
|
.also(LiquidDefinition::registerGson)
|
||||||
|
.also(ItemDefinition::registerGson)
|
||||||
|
.also(ItemRarity::registerGson)
|
||||||
|
|
||||||
.registerTypeAdapter(DamageType::class.java, CustomEnumTypeAdapter(DamageType.values()).nullSafe())
|
.registerTypeAdapter(DamageType::class.java, CustomEnumTypeAdapter(DamageType.values()).nullSafe())
|
||||||
|
|
||||||
@ -239,6 +242,7 @@ object Starbound {
|
|||||||
loadStage(callback, this::loadParallax, "parallax definitions")
|
loadStage(callback, this::loadParallax, "parallax definitions")
|
||||||
loadStage(callback, this::loadMaterialModifiers, "material modifier definitions")
|
loadStage(callback, this::loadMaterialModifiers, "material modifier definitions")
|
||||||
loadStage(callback, this::loadLiquidDefinitions, "liquid definitions")
|
loadStage(callback, this::loadLiquidDefinitions, "liquid definitions")
|
||||||
|
loadStage(callback, this::loadItemDefinitions, "item definitions")
|
||||||
|
|
||||||
initializing = false
|
initializing = false
|
||||||
initialized = true
|
initialized = true
|
||||||
@ -339,7 +343,7 @@ object Starbound {
|
|||||||
|
|
||||||
private fun loadParallax(callback: (String) -> Unit) {
|
private fun loadParallax(callback: (String) -> Unit) {
|
||||||
for (fs in fileSystems) {
|
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 {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
|
||||||
@ -360,7 +364,7 @@ object Starbound {
|
|||||||
readingFolder = "/tiles/materials"
|
readingFolder = "/tiles/materials"
|
||||||
|
|
||||||
for (fs in fileSystems) {
|
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 {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
|
||||||
@ -387,7 +391,7 @@ object Starbound {
|
|||||||
|
|
||||||
private fun loadLiquidDefinitions(callback: (String) -> Unit) {
|
private fun loadLiquidDefinitions(callback: (String) -> Unit) {
|
||||||
for (fs in fileSystems) {
|
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 {
|
try {
|
||||||
callback("Loading $listedFile")
|
callback("Loading $listedFile")
|
||||||
|
|
||||||
@ -409,4 +413,27 @@ object Starbound {
|
|||||||
|
|
||||||
readingFolder = null
|
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.ImmutableList
|
||||||
import com.google.common.collect.ImmutableMap
|
import com.google.common.collect.ImmutableMap
|
||||||
|
import com.google.common.collect.Interners
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import com.google.gson.JsonSyntaxException
|
import com.google.gson.JsonSyntaxException
|
||||||
import com.google.gson.TypeAdapter
|
import com.google.gson.TypeAdapter
|
||||||
@ -174,7 +175,7 @@ class KConcreteTypeAdapter<T : Any>(
|
|||||||
|
|
||||||
private val returnTypeCache = Object2ObjectArrayMap<KProperty1<T, *>, KType>()
|
private val returnTypeCache = Object2ObjectArrayMap<KProperty1<T, *>, KType>()
|
||||||
private val mapped = Object2IntArrayMap<String>()
|
private val mapped = Object2IntArrayMap<String>()
|
||||||
|
private val internedStrings = Interners.newWeakInterner<String>()
|
||||||
private val loggedMisses = ObjectArraySet<String>()
|
private val loggedMisses = ObjectArraySet<String>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -267,9 +268,11 @@ class KConcreteTypeAdapter<T : Any>(
|
|||||||
reader.beginObject()
|
reader.beginObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// таблица присутствия значений (если значение true то на i было значение внутри json)
|
||||||
val presentValues = BooleanArray(types.size)
|
val presentValues = BooleanArray(types.size)
|
||||||
val readValues = arrayOfNulls<Any>(types.size)
|
val readValues = arrayOfNulls<Any>(types.size)
|
||||||
|
|
||||||
|
// Если нам необходимо читать объект как набор данных массива, то давай
|
||||||
if (asList) {
|
if (asList) {
|
||||||
val iterator = types.iterator()
|
val iterator = types.iterator()
|
||||||
var fieldId = 0
|
var fieldId = 0
|
||||||
@ -299,6 +302,7 @@ class KConcreteTypeAdapter<T : Any>(
|
|||||||
|
|
||||||
fieldId++
|
fieldId++
|
||||||
}
|
}
|
||||||
|
// иначе - читаем как json object
|
||||||
} else {
|
} else {
|
||||||
while (reader.peek() != JsonToken.END_OBJECT) {
|
while (reader.peek() != JsonToken.END_OBJECT) {
|
||||||
val name = reader.nextName()
|
val name = reader.nextName()
|
||||||
@ -323,9 +327,10 @@ class KConcreteTypeAdapter<T : Any>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// intern'им строки для более быстрой работы сравнения последних
|
||||||
for (i in readValues.indices) {
|
for (i in readValues.indices) {
|
||||||
if (readValues[i] is String) {
|
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()
|
reader.endObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// если у нас есть все значения для конструктора (все значения присутствуют в исходном json объекте)
|
||||||
|
// или у нас нет Java'вского конструктора, то делаем вызов "обычного" конструктора
|
||||||
if (syntheticFactory == null || presentValues.all { it }) {
|
if (syntheticFactory == null || presentValues.all { it }) {
|
||||||
for ((i, pair) in types.withIndex()) {
|
for ((i, pair) in types.withIndex()) {
|
||||||
val (field) = pair
|
val (field) = pair
|
||||||
@ -407,6 +414,9 @@ class KConcreteTypeAdapter<T : Any>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Позволяет построить класс [KConcreteTypeAdapter] на основе заданных параметров
|
||||||
|
*/
|
||||||
class Builder<T : Any>(val clazz: KClass<T>) {
|
class Builder<T : Any>(val clazz: KClass<T>) {
|
||||||
private val types = ArrayList<Pair<KProperty1<T, *>, TypeAdapter<*>>>()
|
private val types = ArrayList<Pair<KProperty1<T, *>, TypeAdapter<*>>>()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user