я даже не знаю что сказать про динамические прототипы...

This commit is contained in:
DBotThePony 2023-02-07 20:09:52 +07:00
parent df4937f1df
commit ebdf0aa642
Signed by: DBot
GPG Key ID: DCC23B5715498507
34 changed files with 292 additions and 196 deletions

View File

@ -1,9 +1,12 @@
package ru.dbotthepony.kstarbound package ru.dbotthepony.kstarbound
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import org.lwjgl.Version import org.lwjgl.Version
import org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose import org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose
import ru.dbotthepony.kstarbound.client.StarboundClient import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.defs.item.DynamicItemDefinition
import ru.dbotthepony.kstarbound.io.BTreeDB import ru.dbotthepony.kstarbound.io.BTreeDB
import ru.dbotthepony.kstarbound.world.ChunkPos import ru.dbotthepony.kstarbound.world.ChunkPos
import ru.dbotthepony.kstarbound.world.entities.ItemEntity import ru.dbotthepony.kstarbound.world.entities.ItemEntity
@ -86,7 +89,7 @@ fun main() {
val getMat = starbound.tilesByID[materialID] val getMat = starbound.tilesByID[materialID]
if (getMat != null) { if (getMat != null) {
chunk.foreground[x, y].material = getMat chunk.foreground[x, y].material = getMat.value
hitTile = true hitTile = true
} }
@ -102,7 +105,7 @@ fun main() {
chunk.foreground[x, y].setHueShift(colorShift) chunk.foreground[x, y].setHueShift(colorShift)
if (getModifier != null && getMat != null) { if (getModifier != null && getMat != null) {
chunk.foreground[x, y].modifier = getModifier chunk.foreground[x, y].modifier = getModifier.value
} }
val modifierHueShift = reader.readUnsignedByte() val modifierHueShift = reader.readUnsignedByte()
@ -113,7 +116,7 @@ fun main() {
val getMat2 = starbound.tilesByID[materialID2] val getMat2 = starbound.tilesByID[materialID2]
if (getMat2 != null) { if (getMat2 != null) {
chunk.background[x, y].material = getMat2 chunk.background[x, y].material = getMat2.value
hitTile = true hitTile = true
} }
@ -127,7 +130,7 @@ fun main() {
val getModifier2 = starbound.tileModifiersByID[modifier2] val getModifier2 = starbound.tileModifiersByID[modifier2]
if (getModifier2 != null && getMat2 != null) { if (getModifier2 != null && getMat2 != null) {
chunk.background[x, y].modifier = getModifier2 chunk.background[x, y].modifier = getModifier2.value
} }
chunk.background[x, y].color = colorVariant2 chunk.background[x, y].color = colorVariant2
@ -151,7 +154,7 @@ fun main() {
val getLiquid = starbound.liquidByID[liquid] val getLiquid = starbound.liquidByID[liquid]
if (getLiquid != null) { if (getLiquid != null) {
val state = chunk.setLiquid(x, y, getLiquid)!! val state = chunk.setLiquid(x, y, getLiquid.value)!!
state.isInfinite = liquidIsInfinite state.isInfinite = liquidIsInfinite
state.pressure = liquidPressure state.pressure = liquidPressure
@ -178,7 +181,7 @@ fun main() {
val rand = java.util.Random() val rand = java.util.Random()
for (i in 0 .. 10) { for (i in 0 .. 10) {
val item = ItemEntity(client.world!!, item) val item = ItemEntity(client.world!!, item.value)
item.position = Vector2d(600.0 + 16.0 + i, 721.0 + 48.0) item.position = Vector2d(600.0 + 16.0 + i, 721.0 + 48.0)
item.spawn() item.spawn()

View File

@ -1,5 +1,8 @@
package ru.dbotthepony.kstarbound package ru.dbotthepony.kstarbound
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.internal.bind.JsonTreeReader
import it.unimi.dsi.fastutil.ints.Int2ObjectMap import it.unimi.dsi.fastutil.ints.Int2ObjectMap
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import it.unimi.dsi.fastutil.ints.IntCollection import it.unimi.dsi.fastutil.ints.IntCollection
@ -10,35 +13,57 @@ import it.unimi.dsi.fastutil.objects.ObjectCollection
import it.unimi.dsi.fastutil.objects.ObjectIterator import it.unimi.dsi.fastutil.objects.ObjectIterator
import it.unimi.dsi.fastutil.objects.ObjectSet import it.unimi.dsi.fastutil.objects.ObjectSet
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kstarbound.api.IStarboundFile
import ru.dbotthepony.kstarbound.util.PathStack
import java.util.* import java.util.*
import kotlin.reflect.KClass
class ObjectRegistry<T>(val name: String, val key: (T) -> String, val intKey: ((T) -> Int)? = null) { inline fun <reified T : Any> ObjectRegistry(name: String, noinline key: (T) -> String, noinline intKey: ((T) -> Int)? = null): ObjectRegistry<T> {
private val objects = Object2ObjectOpenHashMap<String, T>() return ObjectRegistry(T::class, name, key, intKey)
private val intObjects = Int2ObjectOpenHashMap<T>() }
private val origins = Object2ObjectOpenHashMap<String, Any>() class RegistryObject<T : Any>(val value: T, private val json: JsonObject, val file: IStarboundFile, val gson: Gson, val pathStack: PathStack) {
private val intOrigins = Int2ObjectOpenHashMap<Any>() fun copy(): JsonObject {
return json.deepCopy()
}
val view: Map<String, T> = Collections.unmodifiableMap(objects) override fun equals(other: Any?): Boolean {
val intView = object : Int2ObjectMap<T> { return other is RegistryObject<*> && other.value == value && other.json == json
override fun get(key: Int): T? = intObjects[key] }
override fun hashCode(): Int {
return value.hashCode().rotateRight(13) xor json.hashCode()
}
override fun toString(): String {
return "RegistryObject[$value from $file]"
}
}
class ObjectRegistry<T : Any>(val clazz: KClass<T>, val name: String, val key: (T) -> String, val intKey: ((T) -> Int)? = null) {
private val objects = Object2ObjectOpenHashMap<String, RegistryObject<T>>()
private val intObjects = Int2ObjectOpenHashMap<RegistryObject<T>>()
val view: Map<String, RegistryObject<T>> = Collections.unmodifiableMap(objects)
val intView = object : Int2ObjectMap<RegistryObject<T>> {
override fun get(key: Int): RegistryObject<T>? = intObjects[key]
override fun containsKey(key: Int) = intObjects.containsKey(key) override fun containsKey(key: Int) = intObjects.containsKey(key)
override fun defaultReturnValue(rv: T) = throw UnsupportedOperationException() override fun defaultReturnValue(rv: RegistryObject<T>) = throw UnsupportedOperationException()
override fun defaultReturnValue(): T = throw UnsupportedOperationException() override fun defaultReturnValue(): RegistryObject<T> = throw UnsupportedOperationException()
override fun containsValue(value: T) = intObjects.containsValue(value) override fun containsValue(value: RegistryObject<T>) = intObjects.containsValue(value)
override fun isEmpty() = intObjects.isEmpty() override fun isEmpty() = intObjects.isEmpty()
override fun putAll(from: Map<out Int, T>) = throw UnsupportedOperationException() override fun putAll(from: Map<out Int, RegistryObject<T>>) = throw UnsupportedOperationException()
private val int2ObjectEntrySet: ObjectSet<Int2ObjectMap.Entry<T>> = object : ObjectSet<Int2ObjectMap.Entry<T>> { private val int2ObjectEntrySet: ObjectSet<Int2ObjectMap.Entry<RegistryObject<T>>> = object : ObjectSet<Int2ObjectMap.Entry<RegistryObject<T>>> {
override val size: Int override val size: Int
get() = intObjects.int2ObjectEntrySet().size get() = intObjects.int2ObjectEntrySet().size
override fun add(element: Int2ObjectMap.Entry<T>) = throw UnsupportedOperationException() override fun add(element: Int2ObjectMap.Entry<RegistryObject<T>>) = throw UnsupportedOperationException()
override fun addAll(elements: Collection<Int2ObjectMap.Entry<T>>) = throw UnsupportedOperationException() override fun addAll(elements: Collection<Int2ObjectMap.Entry<RegistryObject<T>>>) = throw UnsupportedOperationException()
override fun clear() = throw UnsupportedOperationException() override fun clear() = throw UnsupportedOperationException()
override fun iterator(): ObjectIterator<Int2ObjectMap.Entry<T>> { override fun iterator(): ObjectIterator<Int2ObjectMap.Entry<RegistryObject<T>>> {
return object : ObjectIterator<Int2ObjectMap.Entry<T>> { return object : ObjectIterator<Int2ObjectMap.Entry<RegistryObject<T>>> {
val iterator = intObjects.int2ObjectEntrySet().iterator() val iterator = intObjects.int2ObjectEntrySet().iterator()
override fun hasNext() = iterator.hasNext() override fun hasNext() = iterator.hasNext()
override fun remove() = throw UnsupportedOperationException() override fun remove() = throw UnsupportedOperationException()
@ -46,15 +71,15 @@ class ObjectRegistry<T>(val name: String, val key: (T) -> String, val intKey: ((
} }
} }
override fun contains(element: Int2ObjectMap.Entry<T>) = intObjects.int2ObjectEntrySet().contains(element) override fun contains(element: Int2ObjectMap.Entry<RegistryObject<T>>) = intObjects.int2ObjectEntrySet().contains(element)
override fun containsAll(elements: Collection<Int2ObjectMap.Entry<T>>) = intObjects.int2ObjectEntrySet().containsAll(elements) override fun containsAll(elements: Collection<Int2ObjectMap.Entry<RegistryObject<T>>>) = intObjects.int2ObjectEntrySet().containsAll(elements)
override fun isEmpty() = intObjects.int2ObjectEntrySet().isEmpty() override fun isEmpty() = intObjects.int2ObjectEntrySet().isEmpty()
override fun remove(element: Int2ObjectMap.Entry<T>) = throw UnsupportedOperationException() override fun remove(element: Int2ObjectMap.Entry<RegistryObject<T>>) = throw UnsupportedOperationException()
override fun removeAll(elements: Collection<Int2ObjectMap.Entry<T>>) = throw UnsupportedOperationException() override fun removeAll(elements: Collection<Int2ObjectMap.Entry<RegistryObject<T>>>) = throw UnsupportedOperationException()
override fun retainAll(elements: Collection<Int2ObjectMap.Entry<T>>) = throw UnsupportedOperationException() override fun retainAll(elements: Collection<Int2ObjectMap.Entry<RegistryObject<T>>>) = throw UnsupportedOperationException()
} }
override fun int2ObjectEntrySet(): ObjectSet<Int2ObjectMap.Entry<T>> { override fun int2ObjectEntrySet(): ObjectSet<Int2ObjectMap.Entry<RegistryObject<T>>> {
return int2ObjectEntrySet return int2ObjectEntrySet
} }
@ -89,82 +114,69 @@ class ObjectRegistry<T>(val name: String, val key: (T) -> String, val intKey: ((
get() = intObjects.keys.size get() = intObjects.keys.size
} }
override val values: ObjectCollection<T> = object : ObjectCollection<T> { override val values: ObjectCollection<RegistryObject<T>> = object : ObjectCollection<RegistryObject<T>> {
override val size: Int override val size: Int
get() = intObjects.values.size get() = intObjects.values.size
override fun add(element: T) = throw UnsupportedOperationException() override fun add(element: RegistryObject<T>) = throw UnsupportedOperationException()
override fun addAll(elements: Collection<T>) = throw UnsupportedOperationException() override fun addAll(elements: Collection<RegistryObject<T>>) = throw UnsupportedOperationException()
override fun clear() = throw UnsupportedOperationException() override fun clear() = throw UnsupportedOperationException()
override fun iterator(): ObjectIterator<T> { override fun iterator(): ObjectIterator<RegistryObject<T>> {
return object : ObjectIterator<T> { return object : ObjectIterator<RegistryObject<T>> {
val iterator = intObjects.values.iterator() val iterator = intObjects.values.iterator()
override fun hasNext() = iterator.hasNext() override fun hasNext() = iterator.hasNext()
override fun next(): T = iterator.next() override fun next(): RegistryObject<T> = iterator.next()
override fun remove() = throw UnsupportedOperationException() override fun remove() = throw UnsupportedOperationException()
} }
} }
override fun contains(element: T) = intObjects.values.contains(element) override fun contains(element: RegistryObject<T>) = intObjects.values.contains(element)
override fun containsAll(elements: Collection<T>) = intObjects.values.containsAll(elements) override fun containsAll(elements: Collection<RegistryObject<T>>) = intObjects.values.containsAll(elements)
override fun isEmpty() = intObjects.values.isEmpty() override fun isEmpty() = intObjects.values.isEmpty()
override fun remove(element: T) = throw UnsupportedOperationException() override fun remove(element: RegistryObject<T>) = throw UnsupportedOperationException()
override fun removeAll(elements: Collection<T>) = throw UnsupportedOperationException() override fun removeAll(elements: Collection<RegistryObject<T>>) = throw UnsupportedOperationException()
override fun retainAll(elements: Collection<T>) = throw UnsupportedOperationException() override fun retainAll(elements: Collection<RegistryObject<T>>) = throw UnsupportedOperationException()
} }
override val size: Int override val size: Int
get() = intObjects.size get() = intObjects.size
} }
fun clearOrigins() {
origins.clear()
intOrigins.clear()
}
fun clear() { fun clear() {
clearOrigins()
objects.clear() objects.clear()
intObjects.clear() intObjects.clear()
} }
fun add(value: T, origin: Any? = null): Boolean { fun add(gson: Gson, file: IStarboundFile, pathStack: PathStack): Boolean {
val key = this.key.invoke(value) return pathStack(file.computeDirectory()) {
val elem = gson.fromJson(file.reader(), JsonObject::class.java)
val value = gson.fromJson<T>(JsonTreeReader(elem), clazz.java)
add(RegistryObject(value, elem, file, gson, pathStack))
}
}
fun add(value: T, json: JsonObject, file: IStarboundFile, gson: Gson, pathStack: PathStack): Boolean {
return add(RegistryObject(value, json, file, gson, pathStack))
}
private fun add(value: RegistryObject<T>): Boolean {
val key = this.key.invoke(value.value)
val existing = objects.put(key, value) val existing = objects.put(key, value)
if (existing != null) { if (existing != null) {
val oldOrigin = origins[key] LOGGER.warn("Registry $name already has object with key $key! Overwriting. (old originated from ${existing.file}, new originate from ${value.file}).")
if (origin == null && oldOrigin == null)
LOGGER.warn("Registry $name already has object with key $key! Overwriting.")
else if (origin == null)
LOGGER.warn("Registry $name already has object with key $key! Overwriting. (old originated from $oldOrigin)")
else
LOGGER.warn("Registry $name already has object with key $key! Overwriting. (old originated from $oldOrigin, new originate from $origin).")
} }
if (origin == null)
origins.remove(key)
else
origins[key] = origin
if (this.intKey == null) if (this.intKey == null)
return existing != null return existing != null
val intKey = this.intKey.invoke(value) val intKey = this.intKey.invoke(value.value)
val intExisting = intObjects.put(intKey, value) val intExisting = intObjects.put(intKey, value)
if (intExisting != null) { if (intExisting != null) {
val oldOrigin = intOrigins[intKey] LOGGER.warn("Registry $name already has object with ID $intKey (new $key, old ${this.key.invoke(intExisting.value)})! Overwriting. (old originated from ${intExisting.file}, new originate from ${value.file}).")
if (origin == null && oldOrigin == null)
LOGGER.warn("Registry $name already has object with ID $intKey (new $key, old ${this.key.invoke(intExisting)})! Overwriting.")
else if (origin == null)
LOGGER.warn("Registry $name already has object with ID $intKey (new $key, old ${this.key.invoke(intExisting)})! Overwriting. (old originated from $oldOrigin)")
else
LOGGER.warn("Registry $name already has object with ID $intKey (new $key, old ${this.key.invoke(intExisting)})! Overwriting. (old originated from $oldOrigin, new originate from $origin).")
} }
return existing != null || intExisting != null return existing != null || intExisting != null

View File

@ -3,6 +3,7 @@ package ru.dbotthepony.kstarbound
import com.google.common.collect.Interner import com.google.common.collect.Interner
import com.google.common.collect.Interners import com.google.common.collect.Interners
import com.google.gson.* import com.google.gson.*
import com.google.gson.internal.bind.JsonTreeReader
import com.google.gson.internal.bind.TypeAdapters import com.google.gson.internal.bind.TypeAdapters
import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
@ -53,7 +54,7 @@ import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementationTypeFactory
import ru.dbotthepony.kstarbound.io.json.factory.ArrayListAdapterFactory import ru.dbotthepony.kstarbound.io.json.factory.ArrayListAdapterFactory
import ru.dbotthepony.kstarbound.io.json.factory.ImmutableCollectionAdapterFactory import ru.dbotthepony.kstarbound.io.json.factory.ImmutableCollectionAdapterFactory
import ru.dbotthepony.kstarbound.math.* import ru.dbotthepony.kstarbound.math.*
import ru.dbotthepony.kstarbound.util.AssetPathStack import ru.dbotthepony.kstarbound.util.PathStack
import ru.dbotthepony.kstarbound.util.SBPattern import ru.dbotthepony.kstarbound.util.SBPattern
import ru.dbotthepony.kstarbound.util.WriteOnce import ru.dbotthepony.kstarbound.util.WriteOnce
import java.io.* import java.io.*
@ -70,7 +71,7 @@ class Starbound : ISBFileLocator {
private val logger = LogManager.getLogger() private val logger = LogManager.getLogger()
val stringInterner: Interner<String> = Interners.newWeakInterner() val stringInterner: Interner<String> = Interners.newWeakInterner()
val pathStack = AssetPathStack(stringInterner) val pathStack = PathStack(stringInterner)
private val _tiles = ObjectRegistry("tiles", TileDefinition::materialName, TileDefinition::materialId) private val _tiles = ObjectRegistry("tiles", TileDefinition::materialName, TileDefinition::materialId)
val tiles = _tiles.view val tiles = _tiles.view
@ -296,9 +297,8 @@ class Starbound : ISBFileLocator {
logger.info("Loaded $name in ${System.currentTimeMillis() - time}ms") logger.info("Loaded $name in ${System.currentTimeMillis() - time}ms")
} }
private fun <T> loadStage( private fun <T : Any> loadStage(
callback: (Boolean, Boolean, String) -> Unit, callback: (Boolean, Boolean, String) -> Unit,
clazz: Class<T>,
registry: ObjectRegistry<T>, registry: ObjectRegistry<T>,
files: List<IStarboundFile>, files: List<IStarboundFile>,
) { ) {
@ -306,8 +306,7 @@ class Starbound : ISBFileLocator {
for (listedFile in files) { for (listedFile in files) {
try { try {
it("Loading $listedFile") it("Loading $listedFile")
val def = pathStack(listedFile.computeDirectory()) { gson.fromJson(listedFile.reader(), clazz) } registry.add(gson, listedFile, pathStack)
registry.add(def, listedFile)
} catch (err: Throwable) { } catch (err: Throwable) {
logger.error("Loading ${registry.name} definition file $listedFile", err) logger.error("Loading ${registry.name} definition file $listedFile", err)
} }
@ -391,12 +390,12 @@ class Starbound : ISBFileLocator {
loadStage(callback, this::loadItemDefinitions, "item definitions") loadStage(callback, this::loadItemDefinitions, "item definitions")
loadStage(callback, TileDefinition::class.java, _tiles, ext2files["material"] ?: listOf()) loadStage(callback, _tiles, ext2files["material"] ?: listOf())
loadStage(callback, MaterialModifier::class.java, _tileModifiers, ext2files["matmod"] ?: listOf()) loadStage(callback, _tileModifiers, ext2files["matmod"] ?: listOf())
loadStage(callback, LiquidDefinition::class.java, _liquid, ext2files["liquid"] ?: listOf()) loadStage(callback, _liquid, ext2files["liquid"] ?: listOf())
loadStage(callback, StatusEffectDefinition::class.java, _statusEffects, ext2files["statuseffect"] ?: listOf()) loadStage(callback, _statusEffects, ext2files["statuseffect"] ?: listOf())
loadStage(callback, Species::class.java, _species, ext2files["species"] ?: listOf()) loadStage(callback, _species, ext2files["species"] ?: listOf())
loadStage(callback, ParticleDefinition::class.java, _particles, ext2files["particle"] ?: listOf()) loadStage(callback, _particles, ext2files["particle"] ?: listOf())
pathStack.block("/") { pathStack.block("/") {
playerDefinition = gson.fromJson(locate("/player.config").reader(), PlayerDefinition::class.java) playerDefinition = gson.fromJson(locate("/player.config").reader(), PlayerDefinition::class.java)
@ -456,8 +455,9 @@ class Starbound : ISBFileLocator {
for (listedFile in fs.explore().filter { it.isFile }.filter { f -> files.keys.any { f.name.endsWith(it) } }) { for (listedFile in fs.explore().filter { it.isFile }.filter { f -> files.keys.any { f.name.endsWith(it) } }) {
try { try {
callback("Loading $listedFile") callback("Loading $listedFile")
val def: ItemPrototype = pathStack(listedFile.computeDirectory()) { gson.fromJson(listedFile.reader(), files.entries.first { listedFile.name.endsWith(it.key) }.value) } val json = gson.fromJson(listedFile.reader(), JsonObject::class.java)
_items.add(def, listedFile) val def: ItemPrototype = pathStack(listedFile.computeDirectory()) { gson.fromJson(JsonTreeReader(json), files.entries.first { listedFile.name.endsWith(it.key) }.value) }
_items.add(def, json, listedFile, gson, pathStack)
} catch (err: Throwable) { } catch (err: Throwable) {
logger.error("Loading item definition file $listedFile", err) logger.error("Loading item definition file $listedFile", err)
} }

View File

@ -72,14 +72,14 @@ class TileRenderers(val client: StarboundClient) {
fun getTileRenderer(defName: String): TileRenderer { fun getTileRenderer(defName: String): TileRenderer {
return tileRenderersCache.computeIfAbsent(defName) { return tileRenderersCache.computeIfAbsent(defName) {
val def = client.starbound.tiles[defName] // TODO: Пустой рендерер val def = client.starbound.tiles[defName] // TODO: Пустой рендерер
return@computeIfAbsent TileRenderer(this, def!!) return@computeIfAbsent TileRenderer(this, def!!.value)
} }
} }
fun getModifierRenderer(defName: String): TileRenderer { fun getModifierRenderer(defName: String): TileRenderer {
return modifierRenderersCache.computeIfAbsent(defName) { return modifierRenderersCache.computeIfAbsent(defName) {
val def = client.starbound.tileModifiers[defName] // TODO: Пустой рендерер val def = client.starbound.tileModifiers[defName] // TODO: Пустой рендерер
return@computeIfAbsent TileRenderer(this, def!!) return@computeIfAbsent TileRenderer(this, def!!.value)
} }
} }

View File

@ -9,8 +9,7 @@ import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import ru.dbotthepony.kstarbound.api.ISBFileLocator import ru.dbotthepony.kstarbound.api.ISBFileLocator
import ru.dbotthepony.kstarbound.util.AssetPathStack import ru.dbotthepony.kstarbound.util.PathStack
import java.io.Reader
import java.lang.reflect.ParameterizedType import java.lang.reflect.ParameterizedType
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@ -20,7 +19,7 @@ import java.util.concurrent.ConcurrentHashMap
* *
* Созданный [TypeAdapter] имеет встроенный кеш. * Созданный [TypeAdapter] имеет встроенный кеш.
*/ */
class AssetReferenceFactory(val remapper: AssetPathStack, val locator: ISBFileLocator) : TypeAdapterFactory { class AssetReferenceFactory(val remapper: PathStack, val locator: ISBFileLocator) : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? { override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.rawType == AssetReference::class.java) { if (type.rawType == AssetReference::class.java) {
val param = type.type as? ParameterizedType ?: return null val param = type.type as? ParameterizedType ?: return null

View File

@ -6,9 +6,9 @@ import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.util.AssetPathStack import ru.dbotthepony.kstarbound.util.PathStack
class DirectAssetReferenceFactory(val remapper: AssetPathStack) : TypeAdapterFactory { class DirectAssetReferenceFactory(val remapper: PathStack) : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? { override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.rawType == DirectAssetReference::class.java) { if (type.rawType == DirectAssetReference::class.java) {
return object : TypeAdapter<DirectAssetReference>() { return object : TypeAdapter<DirectAssetReference>() {

View File

@ -0,0 +1,65 @@
package ru.dbotthepony.kstarbound.defs
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.internal.bind.JsonTreeReader
import com.google.gson.reflect.TypeToken
import ru.dbotthepony.kstarbound.RegistryObject
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
private fun merge(destination: JsonObject, source: JsonObject) {
for ((k, v) in source.entrySet()) {
if (v is JsonObject) {
val original = destination[k]
if (original is JsonObject) {
merge(original, v)
} else {
destination.add(k, v)
}
} else {
destination.add(k, v)
}
}
}
abstract class DynamicDefinition<Def : Any>(val original: RegistryObject<Def>) {
private var isDirty = false
private var dynamicData = JsonObject()
fun markDirty() {
isDirty = true
}
var def: Def = original.value
get() {
if (isDirty) {
synchronized(this) {
if (!isDirty) return field
val copy = original.copy()
merge(copy, dynamicData)
original.pathStack(original.file.computeDirectory()) {
field = original.gson.fromJson(JsonTreeReader(copy), field::class.java)
}
isDirty = false
}
}
return field
}
private set
fun setJson(saveInput: JsonObject) {
if (saveInput == dynamicData) return
sanitize(saveInput)
if (saveInput == dynamicData) return
isDirty = true
dynamicData = saveInput
}
abstract fun sanitize(saveInput: JsonObject)
}

View File

@ -10,6 +10,7 @@ import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap
import ru.dbotthepony.kstarbound.RegistryObject
import java.lang.ref.Reference import java.lang.ref.Reference
import java.lang.ref.ReferenceQueue import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -18,7 +19,7 @@ import java.util.concurrent.ConcurrentHashMap
import java.util.function.Supplier import java.util.function.Supplier
class RegistryReferenceFactory : TypeAdapterFactory { class RegistryReferenceFactory : TypeAdapterFactory {
private val types = Reference2ObjectArrayMap<Class<*>, (String) -> Nothing?>() private val types = Reference2ObjectArrayMap<Class<*>, (String) -> RegistryObject<Nothing>?>()
private var isLenient = false private var isLenient = false
fun lenient(): RegistryReferenceFactory { fun lenient(): RegistryReferenceFactory {
@ -26,12 +27,12 @@ class RegistryReferenceFactory : TypeAdapterFactory {
return this return this
} }
fun <T> add(clazz: Class<T>, resolver: (String) -> T?): RegistryReferenceFactory { fun <T : Any> add(clazz: Class<T>, resolver: (String) -> RegistryObject<T>?): RegistryReferenceFactory {
check(types.put(clazz, resolver as (String) -> Nothing?) == null) { "Already has resolver for class $clazz!" } check(types.put(clazz, resolver as (String) -> RegistryObject<Nothing>?) == null) { "Already has resolver for class $clazz!" }
return this return this
} }
inline fun <reified T> add(noinline resolver: (String) -> T?) = add(T::class.java, resolver) inline fun <reified T: Any> add(noinline resolver: (String) -> RegistryObject<T>?) = add(T::class.java, resolver)
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? { override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.rawType == RegistryReference::class.java) { if (type.rawType == RegistryReference::class.java) {
@ -45,7 +46,7 @@ class RegistryReferenceFactory : TypeAdapterFactory {
} }
} }
class RegistryReferenceTypeAdapter<T>(val resolver: (String) -> T?, val strings: TypeAdapter<String>) : TypeAdapter<RegistryReference<T>>() { class RegistryReferenceTypeAdapter<T : Any>(val resolver: (String) -> RegistryObject<T>?, val strings: TypeAdapter<String>) : TypeAdapter<RegistryReference<T>>() {
override fun write(out: JsonWriter, value: RegistryReference<T>?) { override fun write(out: JsonWriter, value: RegistryReference<T>?) {
if (value == null) if (value == null)
out.nullValue() out.nullValue()
@ -65,21 +66,21 @@ class RegistryReferenceTypeAdapter<T>(val resolver: (String) -> T?, val strings:
} }
} }
data class RegistryReference<T>(val name: String, val resolver: (String) -> T?) : Supplier<T?>, () -> T?, Lazy<T?> { data class RegistryReference<T : Any>(val name: String, val resolver: (String) -> RegistryObject<T>?) : Supplier<RegistryObject<T>?>, () -> RegistryObject<T>?, Lazy<RegistryObject<T>?> {
private val lazy = lazy { resolver.invoke(name) } private val lazy = lazy { resolver.invoke(name) }
override fun get(): T? { override fun get(): RegistryObject<T>? {
return lazy.value return lazy.value
} }
override val value: T? override val value: RegistryObject<T>?
get() = lazy.value get() = lazy.value
override fun isInitialized(): Boolean { override fun isInitialized(): Boolean {
return lazy.isInitialized() return lazy.isInitialized()
} }
override fun invoke(): T? { override fun invoke(): RegistryObject<T>? {
return lazy.value return lazy.value
} }
} }

View File

@ -3,26 +3,16 @@ package ru.dbotthepony.kstarbound.defs.image
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.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonArray import com.google.gson.JsonArray
import com.google.gson.JsonNull import com.google.gson.JsonNull
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonSyntaxException import com.google.gson.JsonSyntaxException
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.internal.bind.TypeAdapters import com.google.gson.internal.bind.TypeAdapters
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.api.ISBFileLocator import ru.dbotthepony.kstarbound.api.ISBFileLocator
import ru.dbotthepony.kstarbound.client.gl.GLTexture2D import ru.dbotthepony.kstarbound.client.gl.GLTexture2D
import ru.dbotthepony.kstarbound.io.json.stream import ru.dbotthepony.kstarbound.io.json.stream
import ru.dbotthepony.kstarbound.io.json.transform import ru.dbotthepony.kstarbound.util.PathStack
import ru.dbotthepony.kstarbound.registerTypeAdapter
import ru.dbotthepony.kstarbound.util.AssetPathStack
import ru.dbotthepony.kstarbound.util.WriteOnce
import ru.dbotthepony.kvector.vector.nint.Vector2i import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.vector.nint.Vector4i import ru.dbotthepony.kvector.vector.nint.Vector4i
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@ -169,7 +159,7 @@ class AtlasConfiguration private constructor(
} }
} }
class Registry(val locator: ISBFileLocator, val remapper: AssetPathStack, val gson: Gson) { class Registry(val locator: ISBFileLocator, val remapper: PathStack, val gson: Gson) {
private val cache = ConcurrentHashMap<String, AtlasConfiguration>() private val cache = ConcurrentHashMap<String, AtlasConfiguration>()
private fun generateFakeNames(dimensions: Vector2i): JsonArray { private fun generateFakeNames(dimensions: Vector2i): JsonArray {

View File

@ -5,8 +5,7 @@ import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.util.PathStack
import ru.dbotthepony.kstarbound.util.AssetPathStack
/** /**
* Хранит данные (пару) вида "/example/animated.png" у которого, вероятнее всего, есть "/example/animated.frames" * Хранит данные (пару) вида "/example/animated.png" у которого, вероятнее всего, есть "/example/animated.frames"
@ -17,7 +16,7 @@ data class ImageReference(
val image: String, val image: String,
val config: AtlasConfiguration, val config: AtlasConfiguration,
) { ) {
class Adapter(private val remapper: AssetPathStack, private val atlasRegistry: () -> AtlasConfiguration.Registry) : TypeAdapter<ImageReference>() { class Adapter(private val remapper: PathStack, private val atlasRegistry: () -> AtlasConfiguration.Registry) : TypeAdapter<ImageReference>() {
override fun write(out: JsonWriter, value: ImageReference?) { override fun write(out: JsonWriter, value: ImageReference?) {
if (value == null) if (value == null)
out.nullValue() out.nullValue()

View File

@ -3,8 +3,7 @@ package ru.dbotthepony.kstarbound.defs.image
import com.google.gson.TypeAdapter import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.util.PathStack
import ru.dbotthepony.kstarbound.util.AssetPathStack
import ru.dbotthepony.kstarbound.util.SBPattern import ru.dbotthepony.kstarbound.util.SBPattern
/** /**
@ -22,7 +21,7 @@ data class SpriteReference(
return atlas[resolved] ?: atlas.any() return atlas[resolved] ?: atlas.any()
} }
class Adapter(private val remapper: AssetPathStack, private val atlasRegistry: () -> AtlasConfiguration.Registry) : TypeAdapter<SpriteReference>() { class Adapter(private val remapper: PathStack, private val atlasRegistry: () -> AtlasConfiguration.Registry) : TypeAdapter<SpriteReference>() {
override fun write(out: JsonWriter, value: SpriteReference?) { override fun write(out: JsonWriter, value: SpriteReference?) {
if (value == null) if (value == null)
out.nullValue() out.nullValue()

View File

@ -32,6 +32,4 @@ data class ArmorItemDefinition(
override val armorType: ArmorPieceType, override val armorType: ArmorPieceType,
val descriptionData: ThingDescription, val descriptionData: ThingDescription,
val json: Map<String, Any>,
) : IArmorItemDefinition, IThingWithDescription by descriptionData ) : IArmorItemDefinition, IThingWithDescription by descriptionData

View File

@ -46,8 +46,6 @@ open class ArmorItemPrototype : ItemPrototype(), IArmorItemDefinition {
radioMessagesOnPickup = radioMessagesOnPickup, radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount, fuelAmount = fuelAmount,
json = enrollMap(json),
colorOptions = colorOptions, colorOptions = colorOptions,
maleFrames = maleFrames, maleFrames = maleFrames,
femaleFrames = femaleFrames, femaleFrames = femaleFrames,

View File

@ -29,6 +29,4 @@ data class CurrencyItemDefinition(
override val value: Long, override val value: Long,
val descriptionData: ThingDescription, val descriptionData: ThingDescription,
val json: Map<String, Any>,
) : ICurrencyItemDefinition, IThingWithDescription by descriptionData ) : ICurrencyItemDefinition, IThingWithDescription by descriptionData

View File

@ -39,8 +39,6 @@ class CurrencyItemPrototype : ItemPrototype(), ICurrencyItemDefinition {
radioMessagesOnPickup = radioMessagesOnPickup, radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount, fuelAmount = fuelAmount,
json = enrollMap(json),
pickupSoundsSmall = pickupSoundsSmall, pickupSoundsSmall = pickupSoundsSmall,
pickupSoundsMedium = pickupSoundsMedium, pickupSoundsMedium = pickupSoundsMedium,
pickupSoundsLarge = pickupSoundsLarge, pickupSoundsLarge = pickupSoundsLarge,

View File

@ -0,0 +1,12 @@
package ru.dbotthepony.kstarbound.defs.item
import com.google.gson.JsonObject
import ru.dbotthepony.kstarbound.RegistryObject
import ru.dbotthepony.kstarbound.defs.DynamicDefinition
class DynamicItemDefinition(def: RegistryObject<IItemDefinition>) : DynamicDefinition<IItemDefinition>(def) {
override fun sanitize(saveInput: JsonObject) {
saveInput.remove("itemName")
saveInput.remove("pickupQuestTemplates")
}
}

View File

@ -30,6 +30,4 @@ data class FlashlightDefinition(
override val handPosition: Vector2d, override val handPosition: Vector2d,
val descriptionData: ThingDescription, val descriptionData: ThingDescription,
val json: Map<String, Any>
) : IFlashlightDefinition, IThingWithDescription by descriptionData ) : IFlashlightDefinition, IThingWithDescription by descriptionData

View File

@ -37,8 +37,6 @@ class FlashlightPrototype : ItemPrototype(), IFlashlightDefinition {
radioMessagesOnPickup = radioMessagesOnPickup, radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount, fuelAmount = fuelAmount,
json = enrollMap(json),
lightPosition = lightPosition, lightPosition = lightPosition,
lightColor = lightColor, lightColor = lightColor,
beamLevel = beamLevel, beamLevel = beamLevel,

View File

@ -33,6 +33,4 @@ data class HarvestingToolDefinition(
override val fireTime: Double, override val fireTime: Double,
val descriptionData: ThingDescription, val descriptionData: ThingDescription,
val json: Map<String, Any>
) : IHarvestingToolDefinition, IThingWithDescription by descriptionData ) : IHarvestingToolDefinition, IThingWithDescription by descriptionData

View File

@ -40,8 +40,6 @@ class HarvestingToolPrototype : ItemPrototype(), IHarvestingToolDefinition {
radioMessagesOnPickup = radioMessagesOnPickup, radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount, fuelAmount = fuelAmount,
json = enrollMap(json),
frames = frames, frames = frames,
animationCycle = animationCycle, animationCycle = animationCycle,
blockRadius = blockRadius, blockRadius = blockRadius,

View File

@ -11,7 +11,7 @@ import ru.dbotthepony.kstarbound.defs.image.AtlasConfiguration
import ru.dbotthepony.kstarbound.defs.image.ImageReference import ru.dbotthepony.kstarbound.defs.image.ImageReference
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
import ru.dbotthepony.kstarbound.util.AssetPathStack import ru.dbotthepony.kstarbound.util.PathStack
interface IArmorItemDefinition : ILeveledItemDefinition, IScriptableItemDefinition { interface IArmorItemDefinition : ILeveledItemDefinition, IScriptableItemDefinition {
/** /**
@ -46,7 +46,7 @@ interface IArmorItemDefinition : ILeveledItemDefinition, IScriptableItemDefiniti
override val backSleeve: ImageReference? = null, override val backSleeve: ImageReference? = null,
override val frontSleeve: ImageReference? = null, override val frontSleeve: ImageReference? = null,
) : IArmorFrames { ) : IArmorFrames {
class Factory(private val remapper: AssetPathStack, private val atlasRegistry: () -> AtlasConfiguration.Registry) : TypeAdapterFactory { class Factory(private val remapper: PathStack, private val atlasRegistry: () -> AtlasConfiguration.Registry) : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? { override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.rawType == ArmorFrames::class.java) { if (type.rawType == ArmorFrames::class.java) {
return object : TypeAdapter<ArmorFrames>() { return object : TypeAdapter<ArmorFrames>() {

View File

@ -7,13 +7,11 @@ import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.defs.IThingWithDescription import ru.dbotthepony.kstarbound.defs.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.image.SpriteReference import ru.dbotthepony.kstarbound.defs.image.SpriteReference
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
import ru.dbotthepony.kstarbound.io.json.ifString import ru.dbotthepony.kstarbound.util.PathStack
import ru.dbotthepony.kstarbound.util.AssetPathStack
interface IItemDefinition : IThingWithDescription { interface IItemDefinition : IThingWithDescription {
/** /**
@ -53,7 +51,7 @@ interface IItemDefinition : IThingWithDescription {
data class InventoryIcon( data class InventoryIcon(
override val image: SpriteReference override val image: SpriteReference
) : IInventoryIcon { ) : IInventoryIcon {
class Factory(val remapper: AssetPathStack, val spriteRegistry: SpriteReference.Adapter) : TypeAdapterFactory { class Factory(val remapper: PathStack, val spriteRegistry: SpriteReference.Adapter) : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? { override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.rawType == InventoryIcon::class.java) { if (type.rawType == InventoryIcon::class.java) {
return object : TypeAdapter<InventoryIcon>() { return object : TypeAdapter<InventoryIcon>() {

View File

@ -24,6 +24,4 @@ data class ItemDefinition(
override val fuelAmount: Long?, override val fuelAmount: Long?,
val descriptionData: ThingDescription, val descriptionData: ThingDescription,
val json: Map<String, Any>
) : IItemDefinition, IThingWithDescription by descriptionData ) : IItemDefinition, IThingWithDescription by descriptionData

View File

@ -11,7 +11,7 @@ import ru.dbotthepony.kstarbound.io.json.builder.JsonIgnoreProperty
import ru.dbotthepony.kstarbound.util.NotNullVar import ru.dbotthepony.kstarbound.util.NotNullVar
@JsonBuilder @JsonBuilder
open class ItemPrototype : IItemDefinition, INativeJsonHolder { open class ItemPrototype : IItemDefinition {
@JsonIgnoreProperty @JsonIgnoreProperty
final override var shortdescription: String = "..." final override var shortdescription: String = "..."
@JsonIgnoreProperty @JsonIgnoreProperty
@ -36,13 +36,6 @@ open class ItemPrototype : IItemDefinition, INativeJsonHolder {
@JsonPropertyConfig(isFlat = true) @JsonPropertyConfig(isFlat = true)
var descriptionData: ThingDescription by NotNullVar() var descriptionData: ThingDescription by NotNullVar()
@JsonIgnoreProperty
var json: Map<String, Any> = mapOf()
final override fun acceptJson(json: MutableMap<String, Any>) {
this.json = json
}
open fun assemble(): IItemDefinition { open fun assemble(): IItemDefinition {
return ItemDefinition( return ItemDefinition(
descriptionData = descriptionData, descriptionData = descriptionData,
@ -61,8 +54,6 @@ open class ItemPrototype : IItemDefinition, INativeJsonHolder {
twoHanded = twoHanded, twoHanded = twoHanded,
radioMessagesOnPickup = radioMessagesOnPickup, radioMessagesOnPickup = radioMessagesOnPickup,
fuelAmount = fuelAmount, fuelAmount = fuelAmount,
json = enrollMap(json),
) )
} }
} }

View File

@ -24,6 +24,4 @@ data class LiquidItemDefinition(
override val liquid: MaterialReference, override val liquid: MaterialReference,
val descriptionData: ThingDescription, val descriptionData: ThingDescription,
val json: Map<String, Any>
) : ILiquidItem, IThingWithDescription by descriptionData ) : ILiquidItem, IThingWithDescription by descriptionData

View File

@ -40,8 +40,6 @@ class LiquidItemPrototype : ItemPrototype() {
fuelAmount = fuelAmount, fuelAmount = fuelAmount,
liquid = checkNotNull(liquid) { "Liquid is null (either 'liquidId' or 'liquidName' should be present, or 'liquid' itself)" }, liquid = checkNotNull(liquid) { "Liquid is null (either 'liquidId' or 'liquidName' should be present, or 'liquid' itself)" },
json = enrollMap(json),
) )
} }
} }

View File

@ -24,6 +24,4 @@ data class MaterialItemDefinition(
override val material: MaterialReference, override val material: MaterialReference,
val descriptionData: ThingDescription, val descriptionData: ThingDescription,
val json: Map<String, Any>
) : IMaterialItem, IThingWithDescription by descriptionData ) : IMaterialItem, IThingWithDescription by descriptionData

View File

@ -40,8 +40,6 @@ class MaterialItemPrototype : ItemPrototype() {
fuelAmount = fuelAmount, fuelAmount = fuelAmount,
material = checkNotNull(material) { "Material is null (either 'materialId' or 'materialName' should be present, or 'material' itself)" }, material = checkNotNull(material) { "Material is null (either 'materialId' or 'materialName' should be present, or 'material' itself)" },
json = enrollMap(json),
) )
} }
} }

View File

@ -62,6 +62,8 @@ annotation class JsonIgnoreProperty
annotation class JsonPropertyConfig( annotation class JsonPropertyConfig(
val isFlat: Boolean = false, val isFlat: Boolean = false,
val write: Boolean = true,
val mustBePresent: Int = 0, val mustBePresent: Int = 0,
) )

View File

@ -19,7 +19,6 @@ import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement
import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter.Builder import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter.Builder
import ru.dbotthepony.kstarbound.util.NotNullVar import ru.dbotthepony.kstarbound.util.NotNullVar
@ -29,40 +28,6 @@ import kotlin.reflect.KMutableProperty1
import kotlin.reflect.full.declaredMembers import kotlin.reflect.full.declaredMembers
import kotlin.reflect.jvm.isAccessible import kotlin.reflect.jvm.isAccessible
/**
* Данный интерфейс имеет один единственный метод: [acceptJson]
*
* Используется в связке с [BuilderAdapter] для классов, которым необходимо хранить оригинальную JSON структуру
*/
interface IJsonHolder {
/**
* Выставляет [JsonObject], который является источником данных для данной структуры
*/
fun acceptJson(json: JsonObject)
}
/**
* Для классов, которые хотят принимать Java'вские [Map] напрямую, как оригинальную JSON структуру
*/
interface INativeJsonHolder : IJsonHolder {
override fun acceptJson(json: JsonObject) {
acceptJson(flattenJsonElement(json))
}
fun acceptJson(json: MutableMap<String, Any>)
}
@Suppress("FunctionName")
fun <T : Any> BuilderAdapter(factory: () -> T, vararg fields: KMutableProperty1<T, *>): TypeAdapterFactory {
val builder = BuilderAdapter.Builder(factory)
for (field in fields) {
builder.auto(field)
}
return builder
}
/** /**
* [TypeAdapter] для классов, которые создаются "без всего", а после наполняются данными (паттерн builder). * [TypeAdapter] для классов, которые создаются "без всего", а после наполняются данными (паттерн builder).
*/ */

View File

@ -0,0 +1,15 @@
package ru.dbotthepony.kstarbound.io.json.builder
import com.google.gson.JsonObject
/**
* Данный интерфейс имеет один единственный метод: [acceptJson]
*
* Используется в связке с [BuilderAdapter] для классов, которым необходимо хранить оригинальную JSON структуру
*/
interface IJsonHolder {
/**
* Выставляет [JsonObject], который является источником данных для данной структуры
*/
fun acceptJson(json: JsonObject)
}

View File

@ -0,0 +1,15 @@
package ru.dbotthepony.kstarbound.io.json.builder
import com.google.gson.JsonObject
import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement
/**
* Для классов, которые хотят принимать Java'вские [Map] напрямую, как оригинальную JSON структуру
*/
interface INativeJsonHolder : IJsonHolder {
override fun acceptJson(json: JsonObject) {
acceptJson(flattenJsonElement(json))
}
fun acceptJson(json: MutableMap<String, Any>)
}

View File

@ -0,0 +1,56 @@
package ru.dbotthepony.kstarbound.lua
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION)
annotation class LuaExposed
interface ILuaIndex {
fun luaIndex(index: Any?): Any?
}
interface ILuaNewIndex {
fun luaIndex(index: Any?, value: Any?)
}
class JVM2LuaWrapper<R : Any>(val value: R) {
private abstract class LuaBinding<in R : Any> {
abstract fun invoke(receiver: R, values: Array<Any?>): Any?
abstract fun read(receiver: R): Any?
abstract fun write(receiver: R, value: Any?)
}
private class LuaFunctionBinding<in R : Any>(private val func: (R, Array<Any?>) -> Any?) : LuaBinding<R>() {
override fun invoke(receiver: R, values: Array<Any?>): Any? {
return func.invoke(receiver, values)
}
override fun read(receiver: R) {
throw UnsupportedOperationException("attempt to index a function value")
}
override fun write(receiver: R, value: Any?) {
throw UnsupportedOperationException("attempt to new index a function value")
}
}
private class LuaPropertyBinding<in R : Any>(private val read: (R) -> Any?, private val write: ((R, Any?) -> Unit)?) : LuaBinding<R>() {
override fun invoke(receiver: R, values: Array<Any?>): Any? {
throw UnsupportedOperationException("attempt to call a value")
}
override fun read(receiver: R): Any? {
return read.invoke(receiver)
}
override fun write(receiver: R, value: Any?) {
if (write == null)
throw UnsupportedOperationException("attempt to new index a read-only value")
write.invoke(receiver, value)
}
}
companion object {
//private val decls =
}
}

View File

@ -3,7 +3,7 @@ package ru.dbotthepony.kstarbound.util
import com.google.common.collect.Interner import com.google.common.collect.Interner
import kotlin.concurrent.getOrSet import kotlin.concurrent.getOrSet
class AssetPathStack(private val interner: Interner<String>? = null) { class PathStack(private val interner: Interner<String>? = null) {
private val _stack = ThreadLocal<ArrayDeque<String>>() private val _stack = ThreadLocal<ArrayDeque<String>>()
private val stack: ArrayDeque<String> get() = _stack.getOrSet { ArrayDeque() } private val stack: ArrayDeque<String> get() = _stack.getOrSet { ArrayDeque() }