я даже не знаю что сказать про динамические прототипы...
This commit is contained in:
parent
df4937f1df
commit
ebdf0aa642
@ -1,9 +1,12 @@
|
||||
package ru.dbotthepony.kstarbound
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.lwjgl.Version
|
||||
import org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.defs.item.DynamicItemDefinition
|
||||
import ru.dbotthepony.kstarbound.io.BTreeDB
|
||||
import ru.dbotthepony.kstarbound.world.ChunkPos
|
||||
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
||||
@ -86,7 +89,7 @@ fun main() {
|
||||
val getMat = starbound.tilesByID[materialID]
|
||||
|
||||
if (getMat != null) {
|
||||
chunk.foreground[x, y].material = getMat
|
||||
chunk.foreground[x, y].material = getMat.value
|
||||
hitTile = true
|
||||
}
|
||||
|
||||
@ -102,7 +105,7 @@ fun main() {
|
||||
chunk.foreground[x, y].setHueShift(colorShift)
|
||||
|
||||
if (getModifier != null && getMat != null) {
|
||||
chunk.foreground[x, y].modifier = getModifier
|
||||
chunk.foreground[x, y].modifier = getModifier.value
|
||||
}
|
||||
|
||||
val modifierHueShift = reader.readUnsignedByte()
|
||||
@ -113,7 +116,7 @@ fun main() {
|
||||
val getMat2 = starbound.tilesByID[materialID2]
|
||||
|
||||
if (getMat2 != null) {
|
||||
chunk.background[x, y].material = getMat2
|
||||
chunk.background[x, y].material = getMat2.value
|
||||
hitTile = true
|
||||
}
|
||||
|
||||
@ -127,7 +130,7 @@ fun main() {
|
||||
val getModifier2 = starbound.tileModifiersByID[modifier2]
|
||||
|
||||
if (getModifier2 != null && getMat2 != null) {
|
||||
chunk.background[x, y].modifier = getModifier2
|
||||
chunk.background[x, y].modifier = getModifier2.value
|
||||
}
|
||||
|
||||
chunk.background[x, y].color = colorVariant2
|
||||
@ -151,7 +154,7 @@ fun main() {
|
||||
val getLiquid = starbound.liquidByID[liquid]
|
||||
|
||||
if (getLiquid != null) {
|
||||
val state = chunk.setLiquid(x, y, getLiquid)!!
|
||||
val state = chunk.setLiquid(x, y, getLiquid.value)!!
|
||||
|
||||
state.isInfinite = liquidIsInfinite
|
||||
state.pressure = liquidPressure
|
||||
@ -178,7 +181,7 @@ fun main() {
|
||||
val rand = java.util.Random()
|
||||
|
||||
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.spawn()
|
||||
|
@ -1,5 +1,8 @@
|
||||
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.Int2ObjectOpenHashMap
|
||||
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.ObjectSet
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
||||
import ru.dbotthepony.kstarbound.util.PathStack
|
||||
import java.util.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class ObjectRegistry<T>(val name: String, val key: (T) -> String, val intKey: ((T) -> Int)? = null) {
|
||||
private val objects = Object2ObjectOpenHashMap<String, T>()
|
||||
private val intObjects = Int2ObjectOpenHashMap<T>()
|
||||
inline fun <reified T : Any> ObjectRegistry(name: String, noinline key: (T) -> String, noinline intKey: ((T) -> Int)? = null): ObjectRegistry<T> {
|
||||
return ObjectRegistry(T::class, name, key, intKey)
|
||||
}
|
||||
|
||||
private val origins = Object2ObjectOpenHashMap<String, Any>()
|
||||
private val intOrigins = Int2ObjectOpenHashMap<Any>()
|
||||
class RegistryObject<T : Any>(val value: T, private val json: JsonObject, val file: IStarboundFile, val gson: Gson, val pathStack: PathStack) {
|
||||
fun copy(): JsonObject {
|
||||
return json.deepCopy()
|
||||
}
|
||||
|
||||
val view: Map<String, T> = Collections.unmodifiableMap(objects)
|
||||
val intView = object : Int2ObjectMap<T> {
|
||||
override fun get(key: Int): T? = intObjects[key]
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other is RegistryObject<*> && other.value == value && other.json == json
|
||||
}
|
||||
|
||||
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 defaultReturnValue(rv: T) = throw UnsupportedOperationException()
|
||||
override fun defaultReturnValue(): T = throw UnsupportedOperationException()
|
||||
override fun containsValue(value: T) = intObjects.containsValue(value)
|
||||
override fun defaultReturnValue(rv: RegistryObject<T>) = throw UnsupportedOperationException()
|
||||
override fun defaultReturnValue(): RegistryObject<T> = throw UnsupportedOperationException()
|
||||
override fun containsValue(value: RegistryObject<T>) = intObjects.containsValue(value)
|
||||
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
|
||||
get() = intObjects.int2ObjectEntrySet().size
|
||||
|
||||
override fun add(element: Int2ObjectMap.Entry<T>) = throw UnsupportedOperationException()
|
||||
override fun addAll(elements: Collection<Int2ObjectMap.Entry<T>>) = throw UnsupportedOperationException()
|
||||
override fun add(element: Int2ObjectMap.Entry<RegistryObject<T>>) = throw UnsupportedOperationException()
|
||||
override fun addAll(elements: Collection<Int2ObjectMap.Entry<RegistryObject<T>>>) = throw UnsupportedOperationException()
|
||||
override fun clear() = throw UnsupportedOperationException()
|
||||
|
||||
override fun iterator(): ObjectIterator<Int2ObjectMap.Entry<T>> {
|
||||
return object : ObjectIterator<Int2ObjectMap.Entry<T>> {
|
||||
override fun iterator(): ObjectIterator<Int2ObjectMap.Entry<RegistryObject<T>>> {
|
||||
return object : ObjectIterator<Int2ObjectMap.Entry<RegistryObject<T>>> {
|
||||
val iterator = intObjects.int2ObjectEntrySet().iterator()
|
||||
override fun hasNext() = iterator.hasNext()
|
||||
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 containsAll(elements: Collection<Int2ObjectMap.Entry<T>>) = intObjects.int2ObjectEntrySet().containsAll(elements)
|
||||
override fun contains(element: Int2ObjectMap.Entry<RegistryObject<T>>) = intObjects.int2ObjectEntrySet().contains(element)
|
||||
override fun containsAll(elements: Collection<Int2ObjectMap.Entry<RegistryObject<T>>>) = intObjects.int2ObjectEntrySet().containsAll(elements)
|
||||
override fun isEmpty() = intObjects.int2ObjectEntrySet().isEmpty()
|
||||
override fun remove(element: Int2ObjectMap.Entry<T>) = throw UnsupportedOperationException()
|
||||
override fun removeAll(elements: Collection<Int2ObjectMap.Entry<T>>) = throw UnsupportedOperationException()
|
||||
override fun retainAll(elements: Collection<Int2ObjectMap.Entry<T>>) = throw UnsupportedOperationException()
|
||||
override fun remove(element: Int2ObjectMap.Entry<RegistryObject<T>>) = throw UnsupportedOperationException()
|
||||
override fun removeAll(elements: Collection<Int2ObjectMap.Entry<RegistryObject<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
|
||||
}
|
||||
|
||||
@ -89,82 +114,69 @@ class ObjectRegistry<T>(val name: String, val key: (T) -> String, val intKey: ((
|
||||
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
|
||||
get() = intObjects.values.size
|
||||
|
||||
override fun add(element: T) = throw UnsupportedOperationException()
|
||||
override fun addAll(elements: Collection<T>) = throw UnsupportedOperationException()
|
||||
override fun add(element: RegistryObject<T>) = throw UnsupportedOperationException()
|
||||
override fun addAll(elements: Collection<RegistryObject<T>>) = throw UnsupportedOperationException()
|
||||
override fun clear() = throw UnsupportedOperationException()
|
||||
|
||||
override fun iterator(): ObjectIterator<T> {
|
||||
return object : ObjectIterator<T> {
|
||||
override fun iterator(): ObjectIterator<RegistryObject<T>> {
|
||||
return object : ObjectIterator<RegistryObject<T>> {
|
||||
val iterator = intObjects.values.iterator()
|
||||
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 contains(element: T) = intObjects.values.contains(element)
|
||||
override fun containsAll(elements: Collection<T>) = intObjects.values.containsAll(elements)
|
||||
override fun contains(element: RegistryObject<T>) = intObjects.values.contains(element)
|
||||
override fun containsAll(elements: Collection<RegistryObject<T>>) = intObjects.values.containsAll(elements)
|
||||
override fun isEmpty() = intObjects.values.isEmpty()
|
||||
override fun remove(element: T) = throw UnsupportedOperationException()
|
||||
override fun removeAll(elements: Collection<T>) = throw UnsupportedOperationException()
|
||||
override fun retainAll(elements: Collection<T>) = throw UnsupportedOperationException()
|
||||
override fun remove(element: RegistryObject<T>) = throw UnsupportedOperationException()
|
||||
override fun removeAll(elements: Collection<RegistryObject<T>>) = throw UnsupportedOperationException()
|
||||
override fun retainAll(elements: Collection<RegistryObject<T>>) = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override val size: Int
|
||||
get() = intObjects.size
|
||||
}
|
||||
|
||||
fun clearOrigins() {
|
||||
origins.clear()
|
||||
intOrigins.clear()
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
clearOrigins()
|
||||
objects.clear()
|
||||
intObjects.clear()
|
||||
}
|
||||
|
||||
fun add(value: T, origin: Any? = null): Boolean {
|
||||
val key = this.key.invoke(value)
|
||||
fun add(gson: Gson, file: IStarboundFile, pathStack: PathStack): Boolean {
|
||||
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)
|
||||
|
||||
if (existing != null) {
|
||||
val oldOrigin = origins[key]
|
||||
|
||||
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).")
|
||||
LOGGER.warn("Registry $name already has object with key $key! Overwriting. (old originated from ${existing.file}, new originate from ${value.file}).")
|
||||
}
|
||||
|
||||
if (origin == null)
|
||||
origins.remove(key)
|
||||
else
|
||||
origins[key] = origin
|
||||
|
||||
if (this.intKey == null)
|
||||
return existing != null
|
||||
|
||||
val intKey = this.intKey.invoke(value)
|
||||
val intKey = this.intKey.invoke(value.value)
|
||||
val intExisting = intObjects.put(intKey, value)
|
||||
|
||||
if (intExisting != null) {
|
||||
val oldOrigin = intOrigins[intKey]
|
||||
|
||||
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).")
|
||||
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}).")
|
||||
}
|
||||
|
||||
return existing != null || intExisting != null
|
||||
|
@ -3,6 +3,7 @@ package ru.dbotthepony.kstarbound
|
||||
import com.google.common.collect.Interner
|
||||
import com.google.common.collect.Interners
|
||||
import com.google.gson.*
|
||||
import com.google.gson.internal.bind.JsonTreeReader
|
||||
import com.google.gson.internal.bind.TypeAdapters
|
||||
import com.google.gson.stream.JsonReader
|
||||
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.ImmutableCollectionAdapterFactory
|
||||
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.WriteOnce
|
||||
import java.io.*
|
||||
@ -70,7 +71,7 @@ class Starbound : ISBFileLocator {
|
||||
private val logger = LogManager.getLogger()
|
||||
|
||||
val stringInterner: Interner<String> = Interners.newWeakInterner()
|
||||
val pathStack = AssetPathStack(stringInterner)
|
||||
val pathStack = PathStack(stringInterner)
|
||||
|
||||
private val _tiles = ObjectRegistry("tiles", TileDefinition::materialName, TileDefinition::materialId)
|
||||
val tiles = _tiles.view
|
||||
@ -296,9 +297,8 @@ class Starbound : ISBFileLocator {
|
||||
logger.info("Loaded $name in ${System.currentTimeMillis() - time}ms")
|
||||
}
|
||||
|
||||
private fun <T> loadStage(
|
||||
private fun <T : Any> loadStage(
|
||||
callback: (Boolean, Boolean, String) -> Unit,
|
||||
clazz: Class<T>,
|
||||
registry: ObjectRegistry<T>,
|
||||
files: List<IStarboundFile>,
|
||||
) {
|
||||
@ -306,8 +306,7 @@ class Starbound : ISBFileLocator {
|
||||
for (listedFile in files) {
|
||||
try {
|
||||
it("Loading $listedFile")
|
||||
val def = pathStack(listedFile.computeDirectory()) { gson.fromJson(listedFile.reader(), clazz) }
|
||||
registry.add(def, listedFile)
|
||||
registry.add(gson, listedFile, pathStack)
|
||||
} catch (err: Throwable) {
|
||||
logger.error("Loading ${registry.name} definition file $listedFile", err)
|
||||
}
|
||||
@ -391,12 +390,12 @@ class Starbound : ISBFileLocator {
|
||||
|
||||
loadStage(callback, this::loadItemDefinitions, "item definitions")
|
||||
|
||||
loadStage(callback, TileDefinition::class.java, _tiles, ext2files["material"] ?: listOf())
|
||||
loadStage(callback, MaterialModifier::class.java, _tileModifiers, ext2files["matmod"] ?: listOf())
|
||||
loadStage(callback, LiquidDefinition::class.java, _liquid, ext2files["liquid"] ?: listOf())
|
||||
loadStage(callback, StatusEffectDefinition::class.java, _statusEffects, ext2files["statuseffect"] ?: listOf())
|
||||
loadStage(callback, Species::class.java, _species, ext2files["species"] ?: listOf())
|
||||
loadStage(callback, ParticleDefinition::class.java, _particles, ext2files["particle"] ?: listOf())
|
||||
loadStage(callback, _tiles, ext2files["material"] ?: listOf())
|
||||
loadStage(callback, _tileModifiers, ext2files["matmod"] ?: listOf())
|
||||
loadStage(callback, _liquid, ext2files["liquid"] ?: listOf())
|
||||
loadStage(callback, _statusEffects, ext2files["statuseffect"] ?: listOf())
|
||||
loadStage(callback, _species, ext2files["species"] ?: listOf())
|
||||
loadStage(callback, _particles, ext2files["particle"] ?: listOf())
|
||||
|
||||
pathStack.block("/") {
|
||||
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) } }) {
|
||||
try {
|
||||
callback("Loading $listedFile")
|
||||
val def: ItemPrototype = pathStack(listedFile.computeDirectory()) { gson.fromJson(listedFile.reader(), files.entries.first { listedFile.name.endsWith(it.key) }.value) }
|
||||
_items.add(def, listedFile)
|
||||
val json = gson.fromJson(listedFile.reader(), JsonObject::class.java)
|
||||
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) {
|
||||
logger.error("Loading item definition file $listedFile", err)
|
||||
}
|
||||
|
@ -72,14 +72,14 @@ class TileRenderers(val client: StarboundClient) {
|
||||
fun getTileRenderer(defName: String): TileRenderer {
|
||||
return tileRenderersCache.computeIfAbsent(defName) {
|
||||
val def = client.starbound.tiles[defName] // TODO: Пустой рендерер
|
||||
return@computeIfAbsent TileRenderer(this, def!!)
|
||||
return@computeIfAbsent TileRenderer(this, def!!.value)
|
||||
}
|
||||
}
|
||||
|
||||
fun getModifierRenderer(defName: String): TileRenderer {
|
||||
return modifierRenderersCache.computeIfAbsent(defName) {
|
||||
val def = client.starbound.tileModifiers[defName] // TODO: Пустой рендерер
|
||||
return@computeIfAbsent TileRenderer(this, def!!)
|
||||
return@computeIfAbsent TileRenderer(this, def!!.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,7 @@ import com.google.gson.stream.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||
import ru.dbotthepony.kstarbound.api.ISBFileLocator
|
||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||
import java.io.Reader
|
||||
import ru.dbotthepony.kstarbound.util.PathStack
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@ -20,7 +19,7 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
*
|
||||
* Созданный [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>? {
|
||||
if (type.rawType == AssetReference::class.java) {
|
||||
val param = type.type as? ParameterizedType ?: return null
|
||||
|
@ -6,9 +6,9 @@ import com.google.gson.TypeAdapterFactory
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.google.gson.stream.JsonReader
|
||||
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>? {
|
||||
if (type.rawType == DirectAssetReference::class.java) {
|
||||
return object : TypeAdapter<DirectAssetReference>() {
|
||||
|
@ -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)
|
||||
}
|
@ -10,6 +10,7 @@ import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap
|
||||
import ru.dbotthepony.kstarbound.RegistryObject
|
||||
import java.lang.ref.Reference
|
||||
import java.lang.ref.ReferenceQueue
|
||||
import java.lang.ref.WeakReference
|
||||
@ -18,7 +19,7 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.function.Supplier
|
||||
|
||||
class RegistryReferenceFactory : TypeAdapterFactory {
|
||||
private val types = Reference2ObjectArrayMap<Class<*>, (String) -> Nothing?>()
|
||||
private val types = Reference2ObjectArrayMap<Class<*>, (String) -> RegistryObject<Nothing>?>()
|
||||
private var isLenient = false
|
||||
|
||||
fun lenient(): RegistryReferenceFactory {
|
||||
@ -26,12 +27,12 @@ class RegistryReferenceFactory : TypeAdapterFactory {
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T> add(clazz: Class<T>, resolver: (String) -> T?): RegistryReferenceFactory {
|
||||
check(types.put(clazz, resolver as (String) -> Nothing?) == null) { "Already has resolver for class $clazz!" }
|
||||
fun <T : Any> add(clazz: Class<T>, resolver: (String) -> RegistryObject<T>?): RegistryReferenceFactory {
|
||||
check(types.put(clazz, resolver as (String) -> RegistryObject<Nothing>?) == null) { "Already has resolver for class $clazz!" }
|
||||
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>? {
|
||||
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>?) {
|
||||
if (value == null)
|
||||
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) }
|
||||
|
||||
override fun get(): T? {
|
||||
override fun get(): RegistryObject<T>? {
|
||||
return lazy.value
|
||||
}
|
||||
|
||||
override val value: T?
|
||||
override val value: RegistryObject<T>?
|
||||
get() = lazy.value
|
||||
|
||||
override fun isInitialized(): Boolean {
|
||||
return lazy.isInitialized()
|
||||
}
|
||||
|
||||
override fun invoke(): T? {
|
||||
override fun invoke(): RegistryObject<T>? {
|
||||
return lazy.value
|
||||
}
|
||||
}
|
||||
|
@ -3,26 +3,16 @@ package ru.dbotthepony.kstarbound.defs.image
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonNull
|
||||
import com.google.gson.JsonObject
|
||||
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.reflect.TypeToken
|
||||
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.client.gl.GLTexture2D
|
||||
import ru.dbotthepony.kstarbound.io.json.stream
|
||||
import ru.dbotthepony.kstarbound.io.json.transform
|
||||
import ru.dbotthepony.kstarbound.registerTypeAdapter
|
||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||
import ru.dbotthepony.kstarbound.util.WriteOnce
|
||||
import ru.dbotthepony.kstarbound.util.PathStack
|
||||
import ru.dbotthepony.kvector.vector.nint.Vector2i
|
||||
import ru.dbotthepony.kvector.vector.nint.Vector4i
|
||||
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 fun generateFakeNames(dimensions: Vector2i): JsonArray {
|
||||
|
@ -5,8 +5,7 @@ import com.google.gson.TypeAdapter
|
||||
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.util.AssetPathStack
|
||||
import ru.dbotthepony.kstarbound.util.PathStack
|
||||
|
||||
/**
|
||||
* Хранит данные (пару) вида "/example/animated.png" у которого, вероятнее всего, есть "/example/animated.frames"
|
||||
@ -17,7 +16,7 @@ data class ImageReference(
|
||||
val image: String,
|
||||
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?) {
|
||||
if (value == null)
|
||||
out.nullValue()
|
||||
|
@ -3,8 +3,7 @@ package ru.dbotthepony.kstarbound.defs.image
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||
import ru.dbotthepony.kstarbound.util.PathStack
|
||||
import ru.dbotthepony.kstarbound.util.SBPattern
|
||||
|
||||
/**
|
||||
@ -22,7 +21,7 @@ data class SpriteReference(
|
||||
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?) {
|
||||
if (value == null)
|
||||
out.nullValue()
|
||||
|
@ -32,6 +32,4 @@ data class ArmorItemDefinition(
|
||||
override val armorType: ArmorPieceType,
|
||||
|
||||
val descriptionData: ThingDescription,
|
||||
|
||||
val json: Map<String, Any>,
|
||||
) : IArmorItemDefinition, IThingWithDescription by descriptionData
|
||||
|
@ -46,8 +46,6 @@ open class ArmorItemPrototype : ItemPrototype(), IArmorItemDefinition {
|
||||
radioMessagesOnPickup = radioMessagesOnPickup,
|
||||
fuelAmount = fuelAmount,
|
||||
|
||||
json = enrollMap(json),
|
||||
|
||||
colorOptions = colorOptions,
|
||||
maleFrames = maleFrames,
|
||||
femaleFrames = femaleFrames,
|
||||
|
@ -29,6 +29,4 @@ data class CurrencyItemDefinition(
|
||||
override val value: Long,
|
||||
|
||||
val descriptionData: ThingDescription,
|
||||
|
||||
val json: Map<String, Any>,
|
||||
) : ICurrencyItemDefinition, IThingWithDescription by descriptionData
|
||||
|
@ -39,8 +39,6 @@ class CurrencyItemPrototype : ItemPrototype(), ICurrencyItemDefinition {
|
||||
radioMessagesOnPickup = radioMessagesOnPickup,
|
||||
fuelAmount = fuelAmount,
|
||||
|
||||
json = enrollMap(json),
|
||||
|
||||
pickupSoundsSmall = pickupSoundsSmall,
|
||||
pickupSoundsMedium = pickupSoundsMedium,
|
||||
pickupSoundsLarge = pickupSoundsLarge,
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
@ -30,6 +30,4 @@ data class FlashlightDefinition(
|
||||
override val handPosition: Vector2d,
|
||||
|
||||
val descriptionData: ThingDescription,
|
||||
|
||||
val json: Map<String, Any>
|
||||
) : IFlashlightDefinition, IThingWithDescription by descriptionData
|
||||
|
@ -37,8 +37,6 @@ class FlashlightPrototype : ItemPrototype(), IFlashlightDefinition {
|
||||
radioMessagesOnPickup = radioMessagesOnPickup,
|
||||
fuelAmount = fuelAmount,
|
||||
|
||||
json = enrollMap(json),
|
||||
|
||||
lightPosition = lightPosition,
|
||||
lightColor = lightColor,
|
||||
beamLevel = beamLevel,
|
||||
|
@ -33,6 +33,4 @@ data class HarvestingToolDefinition(
|
||||
override val fireTime: Double,
|
||||
|
||||
val descriptionData: ThingDescription,
|
||||
|
||||
val json: Map<String, Any>
|
||||
) : IHarvestingToolDefinition, IThingWithDescription by descriptionData
|
||||
|
@ -40,8 +40,6 @@ class HarvestingToolPrototype : ItemPrototype(), IHarvestingToolDefinition {
|
||||
radioMessagesOnPickup = radioMessagesOnPickup,
|
||||
fuelAmount = fuelAmount,
|
||||
|
||||
json = enrollMap(json),
|
||||
|
||||
frames = frames,
|
||||
animationCycle = animationCycle,
|
||||
blockRadius = blockRadius,
|
||||
|
@ -11,7 +11,7 @@ import ru.dbotthepony.kstarbound.defs.image.AtlasConfiguration
|
||||
import ru.dbotthepony.kstarbound.defs.image.ImageReference
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
|
||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||
import ru.dbotthepony.kstarbound.util.PathStack
|
||||
|
||||
interface IArmorItemDefinition : ILeveledItemDefinition, IScriptableItemDefinition {
|
||||
/**
|
||||
@ -46,7 +46,7 @@ interface IArmorItemDefinition : ILeveledItemDefinition, IScriptableItemDefiniti
|
||||
override val backSleeve: ImageReference? = null,
|
||||
override val frontSleeve: ImageReference? = null,
|
||||
) : 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>? {
|
||||
if (type.rawType == ArmorFrames::class.java) {
|
||||
return object : TypeAdapter<ArmorFrames>() {
|
||||
|
@ -7,13 +7,11 @@ import com.google.gson.reflect.TypeToken
|
||||
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.defs.IThingWithDescription
|
||||
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
|
||||
import ru.dbotthepony.kstarbound.io.json.ifString
|
||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||
import ru.dbotthepony.kstarbound.util.PathStack
|
||||
|
||||
interface IItemDefinition : IThingWithDescription {
|
||||
/**
|
||||
@ -53,7 +51,7 @@ interface IItemDefinition : IThingWithDescription {
|
||||
data class InventoryIcon(
|
||||
override val image: SpriteReference
|
||||
) : 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>? {
|
||||
if (type.rawType == InventoryIcon::class.java) {
|
||||
return object : TypeAdapter<InventoryIcon>() {
|
||||
|
@ -24,6 +24,4 @@ data class ItemDefinition(
|
||||
override val fuelAmount: Long?,
|
||||
|
||||
val descriptionData: ThingDescription,
|
||||
|
||||
val json: Map<String, Any>
|
||||
) : IItemDefinition, IThingWithDescription by descriptionData
|
||||
|
@ -11,7 +11,7 @@ import ru.dbotthepony.kstarbound.io.json.builder.JsonIgnoreProperty
|
||||
import ru.dbotthepony.kstarbound.util.NotNullVar
|
||||
|
||||
@JsonBuilder
|
||||
open class ItemPrototype : IItemDefinition, INativeJsonHolder {
|
||||
open class ItemPrototype : IItemDefinition {
|
||||
@JsonIgnoreProperty
|
||||
final override var shortdescription: String = "..."
|
||||
@JsonIgnoreProperty
|
||||
@ -36,13 +36,6 @@ open class ItemPrototype : IItemDefinition, INativeJsonHolder {
|
||||
@JsonPropertyConfig(isFlat = true)
|
||||
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 {
|
||||
return ItemDefinition(
|
||||
descriptionData = descriptionData,
|
||||
@ -61,8 +54,6 @@ open class ItemPrototype : IItemDefinition, INativeJsonHolder {
|
||||
twoHanded = twoHanded,
|
||||
radioMessagesOnPickup = radioMessagesOnPickup,
|
||||
fuelAmount = fuelAmount,
|
||||
|
||||
json = enrollMap(json),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,4 @@ data class LiquidItemDefinition(
|
||||
override val liquid: MaterialReference,
|
||||
|
||||
val descriptionData: ThingDescription,
|
||||
|
||||
val json: Map<String, Any>
|
||||
) : ILiquidItem, IThingWithDescription by descriptionData
|
||||
|
@ -40,8 +40,6 @@ class LiquidItemPrototype : ItemPrototype() {
|
||||
fuelAmount = fuelAmount,
|
||||
|
||||
liquid = checkNotNull(liquid) { "Liquid is null (either 'liquidId' or 'liquidName' should be present, or 'liquid' itself)" },
|
||||
|
||||
json = enrollMap(json),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,4 @@ data class MaterialItemDefinition(
|
||||
override val material: MaterialReference,
|
||||
|
||||
val descriptionData: ThingDescription,
|
||||
|
||||
val json: Map<String, Any>
|
||||
) : IMaterialItem, IThingWithDescription by descriptionData
|
||||
|
@ -40,8 +40,6 @@ class MaterialItemPrototype : ItemPrototype() {
|
||||
fuelAmount = fuelAmount,
|
||||
|
||||
material = checkNotNull(material) { "Material is null (either 'materialId' or 'materialName' should be present, or 'material' itself)" },
|
||||
|
||||
json = enrollMap(json),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,8 @@ annotation class JsonIgnoreProperty
|
||||
annotation class JsonPropertyConfig(
|
||||
val isFlat: Boolean = false,
|
||||
|
||||
val write: Boolean = true,
|
||||
|
||||
val mustBePresent: Int = 0,
|
||||
)
|
||||
|
||||
|
@ -19,7 +19,6 @@ import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.defs.util.flattenJsonElement
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.BuilderAdapter.Builder
|
||||
import ru.dbotthepony.kstarbound.util.NotNullVar
|
||||
@ -29,40 +28,6 @@ import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.full.declaredMembers
|
||||
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).
|
||||
*/
|
||||
|
@ -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)
|
||||
}
|
@ -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>)
|
||||
}
|
@ -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 =
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ package ru.dbotthepony.kstarbound.util
|
||||
import com.google.common.collect.Interner
|
||||
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: ArrayDeque<String> get() = _stack.getOrSet { ArrayDeque() }
|
||||
|
Loading…
Reference in New Issue
Block a user