From ebdf0aa6420b6005d3ce321da31dd7c7fe234b99 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 7 Feb 2023 20:09:52 +0700 Subject: [PATCH] =?UTF-8?q?=D1=8F=20=D0=B4=D0=B0=D0=B6=D0=B5=20=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=B7=D0=BD=D0=B0=D1=8E=20=D1=87=D1=82=D0=BE=20=D1=81?= =?UTF-8?q?=D0=BA=D0=B0=D0=B7=D0=B0=D1=82=D1=8C=20=D0=BF=D1=80=D0=BE=20?= =?UTF-8?q?=D0=B4=D0=B8=D0=BD=D0=B0=D0=BC=D0=B8=D1=87=D0=B5=D1=81=D0=BA?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BF=D1=80=D0=BE=D1=82=D0=BE=D1=82=D0=B8=D0=BF?= =?UTF-8?q?=D1=8B...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/ru/dbotthepony/kstarbound/Main.kt | 15 +- .../dbotthepony/kstarbound/ObjectRegistry.kt | 140 ++++++++++-------- .../ru/dbotthepony/kstarbound/Starbound.kt | 28 ++-- .../kstarbound/client/render/TileRenderer.kt | 4 +- .../kstarbound/defs/AssetReference.kt | 5 +- .../kstarbound/defs/DirectAssetReference.kt | 4 +- .../kstarbound/defs/DynamicDefinition.kt | 65 ++++++++ .../kstarbound/defs/RegistryReference.kt | 19 +-- .../defs/image/AtlasConfiguration.kt | 14 +- .../kstarbound/defs/image/ImageReference.kt | 5 +- .../kstarbound/defs/image/SpriteReference.kt | 5 +- .../defs/item/ArmorItemDefinition.kt | 2 - .../defs/item/ArmorItemPrototype.kt | 2 - .../defs/item/CurrencyItemDefinition.kt | 2 - .../defs/item/CurrencyItemPrototype.kt | 2 - .../defs/item/DynamicItemDefinition.kt | 12 ++ .../defs/item/FlashlightDefinition.kt | 2 - .../defs/item/FlashlightPrototype.kt | 2 - .../defs/item/HarvestingToolDefinition.kt | 2 - .../defs/item/HarvestingToolPrototype.kt | 2 - .../defs/item/IArmorItemDefinition.kt | 4 +- .../kstarbound/defs/item/IItemDefinition.kt | 6 +- .../kstarbound/defs/item/ItemDefinition.kt | 2 - .../kstarbound/defs/item/ItemPrototype.kt | 11 +- .../defs/item/LiquidItemDefinition.kt | 2 - .../defs/item/LiquidItemPrototype.kt | 2 - .../defs/item/MaterialItemDefinition.kt | 2 - .../defs/item/MaterialItemPrototype.kt | 2 - .../kstarbound/io/json/builder/Annotations.kt | 2 + .../io/json/builder/BuilderAdapter.kt | 35 ----- .../kstarbound/io/json/builder/IJsonHolder.kt | 15 ++ .../io/json/builder/INativeJsonHolder.kt | 15 ++ .../kstarbound/lua/JVM2LuaWrapper.kt | 56 +++++++ .../util/{AssetPathStack.kt => PathStack.kt} | 2 +- 34 files changed, 292 insertions(+), 196 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/defs/DynamicDefinition.kt create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/DynamicItemDefinition.kt create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/IJsonHolder.kt create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/INativeJsonHolder.kt create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/lua/JVM2LuaWrapper.kt rename src/main/kotlin/ru/dbotthepony/kstarbound/util/{AssetPathStack.kt => PathStack.kt} (93%) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt index 248fd8bb..85646f1c 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt @@ -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() diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/ObjectRegistry.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/ObjectRegistry.kt index 3edb13fa..224afc68 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/ObjectRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/ObjectRegistry.kt @@ -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(val name: String, val key: (T) -> String, val intKey: ((T) -> Int)? = null) { - private val objects = Object2ObjectOpenHashMap() - private val intObjects = Int2ObjectOpenHashMap() +inline fun ObjectRegistry(name: String, noinline key: (T) -> String, noinline intKey: ((T) -> Int)? = null): ObjectRegistry { + return ObjectRegistry(T::class, name, key, intKey) +} - private val origins = Object2ObjectOpenHashMap() - private val intOrigins = Int2ObjectOpenHashMap() +class RegistryObject(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 = Collections.unmodifiableMap(objects) - val intView = object : Int2ObjectMap { - 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(val clazz: KClass, val name: String, val key: (T) -> String, val intKey: ((T) -> Int)? = null) { + private val objects = Object2ObjectOpenHashMap>() + private val intObjects = Int2ObjectOpenHashMap>() + + val view: Map> = Collections.unmodifiableMap(objects) + val intView = object : Int2ObjectMap> { + override fun get(key: Int): RegistryObject? = 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) = throw UnsupportedOperationException() + override fun defaultReturnValue(): RegistryObject = throw UnsupportedOperationException() + override fun containsValue(value: RegistryObject) = intObjects.containsValue(value) override fun isEmpty() = intObjects.isEmpty() - override fun putAll(from: Map) = throw UnsupportedOperationException() + override fun putAll(from: Map>) = throw UnsupportedOperationException() - private val int2ObjectEntrySet: ObjectSet> = object : ObjectSet> { + private val int2ObjectEntrySet: ObjectSet>> = object : ObjectSet>> { override val size: Int get() = intObjects.int2ObjectEntrySet().size - override fun add(element: Int2ObjectMap.Entry) = throw UnsupportedOperationException() - override fun addAll(elements: Collection>) = throw UnsupportedOperationException() + override fun add(element: Int2ObjectMap.Entry>) = throw UnsupportedOperationException() + override fun addAll(elements: Collection>>) = throw UnsupportedOperationException() override fun clear() = throw UnsupportedOperationException() - override fun iterator(): ObjectIterator> { - return object : ObjectIterator> { + override fun iterator(): ObjectIterator>> { + return object : ObjectIterator>> { val iterator = intObjects.int2ObjectEntrySet().iterator() override fun hasNext() = iterator.hasNext() override fun remove() = throw UnsupportedOperationException() @@ -46,15 +71,15 @@ class ObjectRegistry(val name: String, val key: (T) -> String, val intKey: (( } } - override fun contains(element: Int2ObjectMap.Entry) = intObjects.int2ObjectEntrySet().contains(element) - override fun containsAll(elements: Collection>) = intObjects.int2ObjectEntrySet().containsAll(elements) + override fun contains(element: Int2ObjectMap.Entry>) = intObjects.int2ObjectEntrySet().contains(element) + override fun containsAll(elements: Collection>>) = intObjects.int2ObjectEntrySet().containsAll(elements) override fun isEmpty() = intObjects.int2ObjectEntrySet().isEmpty() - override fun remove(element: Int2ObjectMap.Entry) = throw UnsupportedOperationException() - override fun removeAll(elements: Collection>) = throw UnsupportedOperationException() - override fun retainAll(elements: Collection>) = throw UnsupportedOperationException() + override fun remove(element: Int2ObjectMap.Entry>) = throw UnsupportedOperationException() + override fun removeAll(elements: Collection>>) = throw UnsupportedOperationException() + override fun retainAll(elements: Collection>>) = throw UnsupportedOperationException() } - override fun int2ObjectEntrySet(): ObjectSet> { + override fun int2ObjectEntrySet(): ObjectSet>> { return int2ObjectEntrySet } @@ -89,82 +114,69 @@ class ObjectRegistry(val name: String, val key: (T) -> String, val intKey: (( get() = intObjects.keys.size } - override val values: ObjectCollection = object : ObjectCollection { + override val values: ObjectCollection> = object : ObjectCollection> { override val size: Int get() = intObjects.values.size - override fun add(element: T) = throw UnsupportedOperationException() - override fun addAll(elements: Collection) = throw UnsupportedOperationException() + override fun add(element: RegistryObject) = throw UnsupportedOperationException() + override fun addAll(elements: Collection>) = throw UnsupportedOperationException() override fun clear() = throw UnsupportedOperationException() - override fun iterator(): ObjectIterator { - return object : ObjectIterator { + override fun iterator(): ObjectIterator> { + return object : ObjectIterator> { val iterator = intObjects.values.iterator() override fun hasNext() = iterator.hasNext() - override fun next(): T = iterator.next() + override fun next(): RegistryObject = iterator.next() override fun remove() = throw UnsupportedOperationException() } } - override fun contains(element: T) = intObjects.values.contains(element) - override fun containsAll(elements: Collection) = intObjects.values.containsAll(elements) + override fun contains(element: RegistryObject) = intObjects.values.contains(element) + override fun containsAll(elements: Collection>) = intObjects.values.containsAll(elements) override fun isEmpty() = intObjects.values.isEmpty() - override fun remove(element: T) = throw UnsupportedOperationException() - override fun removeAll(elements: Collection) = throw UnsupportedOperationException() - override fun retainAll(elements: Collection) = throw UnsupportedOperationException() + override fun remove(element: RegistryObject) = throw UnsupportedOperationException() + override fun removeAll(elements: Collection>) = throw UnsupportedOperationException() + override fun retainAll(elements: Collection>) = 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(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): 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 diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt index ca0b6067..80cc11fd 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt @@ -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 = 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 loadStage( + private fun loadStage( callback: (Boolean, Boolean, String) -> Unit, - clazz: Class, registry: ObjectRegistry, files: List, ) { @@ -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) } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/TileRenderer.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/TileRenderer.kt index e995b9de..d5ae910b 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/TileRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/TileRenderer.kt @@ -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) } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/AssetReference.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/AssetReference.kt index af5c2a8a..e20835de 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/AssetReference.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/AssetReference.kt @@ -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 create(gson: Gson, type: TypeToken): TypeAdapter? { if (type.rawType == AssetReference::class.java) { val param = type.type as? ParameterizedType ?: return null diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/DirectAssetReference.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/DirectAssetReference.kt index 581d1428..5897a5ed 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/DirectAssetReference.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/DirectAssetReference.kt @@ -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 create(gson: Gson, type: TypeToken): TypeAdapter? { if (type.rawType == DirectAssetReference::class.java) { return object : TypeAdapter() { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/DynamicDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/DynamicDefinition.kt new file mode 100644 index 00000000..35aa126e --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/DynamicDefinition.kt @@ -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(val original: RegistryObject) { + 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) +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/RegistryReference.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/RegistryReference.kt index 37009a7d..e85c4a14 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/RegistryReference.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/RegistryReference.kt @@ -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, (String) -> Nothing?>() + private val types = Reference2ObjectArrayMap, (String) -> RegistryObject?>() private var isLenient = false fun lenient(): RegistryReferenceFactory { @@ -26,12 +27,12 @@ class RegistryReferenceFactory : TypeAdapterFactory { return this } - fun add(clazz: Class, resolver: (String) -> T?): RegistryReferenceFactory { - check(types.put(clazz, resolver as (String) -> Nothing?) == null) { "Already has resolver for class $clazz!" } + fun add(clazz: Class, resolver: (String) -> RegistryObject?): RegistryReferenceFactory { + check(types.put(clazz, resolver as (String) -> RegistryObject?) == null) { "Already has resolver for class $clazz!" } return this } - inline fun add(noinline resolver: (String) -> T?) = add(T::class.java, resolver) + inline fun add(noinline resolver: (String) -> RegistryObject?) = add(T::class.java, resolver) override fun create(gson: Gson, type: TypeToken): TypeAdapter? { if (type.rawType == RegistryReference::class.java) { @@ -45,7 +46,7 @@ class RegistryReferenceFactory : TypeAdapterFactory { } } -class RegistryReferenceTypeAdapter(val resolver: (String) -> T?, val strings: TypeAdapter) : TypeAdapter>() { +class RegistryReferenceTypeAdapter(val resolver: (String) -> RegistryObject?, val strings: TypeAdapter) : TypeAdapter>() { override fun write(out: JsonWriter, value: RegistryReference?) { if (value == null) out.nullValue() @@ -65,21 +66,21 @@ class RegistryReferenceTypeAdapter(val resolver: (String) -> T?, val strings: } } -data class RegistryReference(val name: String, val resolver: (String) -> T?) : Supplier, () -> T?, Lazy { +data class RegistryReference(val name: String, val resolver: (String) -> RegistryObject?) : Supplier?>, () -> RegistryObject?, Lazy?> { private val lazy = lazy { resolver.invoke(name) } - override fun get(): T? { + override fun get(): RegistryObject? { return lazy.value } - override val value: T? + override val value: RegistryObject? get() = lazy.value override fun isInitialized(): Boolean { return lazy.isInitialized() } - override fun invoke(): T? { + override fun invoke(): RegistryObject? { return lazy.value } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/AtlasConfiguration.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/AtlasConfiguration.kt index ef3a3470..e3f7617d 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/AtlasConfiguration.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/AtlasConfiguration.kt @@ -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() private fun generateFakeNames(dimensions: Vector2i): JsonArray { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/ImageReference.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/ImageReference.kt index fb20b0b4..12fe3f96 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/ImageReference.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/ImageReference.kt @@ -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() { + class Adapter(private val remapper: PathStack, private val atlasRegistry: () -> AtlasConfiguration.Registry) : TypeAdapter() { override fun write(out: JsonWriter, value: ImageReference?) { if (value == null) out.nullValue() diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/SpriteReference.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/SpriteReference.kt index 8a800526..3590847e 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/SpriteReference.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/SpriteReference.kt @@ -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() { + class Adapter(private val remapper: PathStack, private val atlasRegistry: () -> AtlasConfiguration.Registry) : TypeAdapter() { override fun write(out: JsonWriter, value: SpriteReference?) { if (value == null) out.nullValue() diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ArmorItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ArmorItemDefinition.kt index 638852f9..210dee3c 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ArmorItemDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ArmorItemDefinition.kt @@ -32,6 +32,4 @@ data class ArmorItemDefinition( override val armorType: ArmorPieceType, val descriptionData: ThingDescription, - - val json: Map, ) : IArmorItemDefinition, IThingWithDescription by descriptionData diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ArmorItemPrototype.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ArmorItemPrototype.kt index cbc5a7df..436f5332 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ArmorItemPrototype.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ArmorItemPrototype.kt @@ -46,8 +46,6 @@ open class ArmorItemPrototype : ItemPrototype(), IArmorItemDefinition { radioMessagesOnPickup = radioMessagesOnPickup, fuelAmount = fuelAmount, - json = enrollMap(json), - colorOptions = colorOptions, maleFrames = maleFrames, femaleFrames = femaleFrames, diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/CurrencyItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/CurrencyItemDefinition.kt index 94edeb65..f87f0836 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/CurrencyItemDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/CurrencyItemDefinition.kt @@ -29,6 +29,4 @@ data class CurrencyItemDefinition( override val value: Long, val descriptionData: ThingDescription, - - val json: Map, ) : ICurrencyItemDefinition, IThingWithDescription by descriptionData diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/CurrencyItemPrototype.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/CurrencyItemPrototype.kt index 6c574ac1..d8c40d70 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/CurrencyItemPrototype.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/CurrencyItemPrototype.kt @@ -39,8 +39,6 @@ class CurrencyItemPrototype : ItemPrototype(), ICurrencyItemDefinition { radioMessagesOnPickup = radioMessagesOnPickup, fuelAmount = fuelAmount, - json = enrollMap(json), - pickupSoundsSmall = pickupSoundsSmall, pickupSoundsMedium = pickupSoundsMedium, pickupSoundsLarge = pickupSoundsLarge, diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/DynamicItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/DynamicItemDefinition.kt new file mode 100644 index 00000000..39fe10a3 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/DynamicItemDefinition.kt @@ -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) : DynamicDefinition(def) { + override fun sanitize(saveInput: JsonObject) { + saveInput.remove("itemName") + saveInput.remove("pickupQuestTemplates") + } +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/FlashlightDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/FlashlightDefinition.kt index 387ed9ba..8bc83675 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/FlashlightDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/FlashlightDefinition.kt @@ -30,6 +30,4 @@ data class FlashlightDefinition( override val handPosition: Vector2d, val descriptionData: ThingDescription, - - val json: Map ) : IFlashlightDefinition, IThingWithDescription by descriptionData diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/FlashlightPrototype.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/FlashlightPrototype.kt index af001dbf..b223d648 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/FlashlightPrototype.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/FlashlightPrototype.kt @@ -37,8 +37,6 @@ class FlashlightPrototype : ItemPrototype(), IFlashlightDefinition { radioMessagesOnPickup = radioMessagesOnPickup, fuelAmount = fuelAmount, - json = enrollMap(json), - lightPosition = lightPosition, lightColor = lightColor, beamLevel = beamLevel, diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/HarvestingToolDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/HarvestingToolDefinition.kt index 2bbae579..7397f2ef 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/HarvestingToolDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/HarvestingToolDefinition.kt @@ -33,6 +33,4 @@ data class HarvestingToolDefinition( override val fireTime: Double, val descriptionData: ThingDescription, - - val json: Map ) : IHarvestingToolDefinition, IThingWithDescription by descriptionData diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/HarvestingToolPrototype.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/HarvestingToolPrototype.kt index bbf477a2..f79f8c62 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/HarvestingToolPrototype.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/HarvestingToolPrototype.kt @@ -40,8 +40,6 @@ class HarvestingToolPrototype : ItemPrototype(), IHarvestingToolDefinition { radioMessagesOnPickup = radioMessagesOnPickup, fuelAmount = fuelAmount, - json = enrollMap(json), - frames = frames, animationCycle = animationCycle, blockRadius = blockRadius, diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/IArmorItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/IArmorItemDefinition.kt index a4f2cd70..a0214132 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/IArmorItemDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/IArmorItemDefinition.kt @@ -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 create(gson: Gson, type: TypeToken): TypeAdapter? { if (type.rawType == ArmorFrames::class.java) { return object : TypeAdapter() { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/IItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/IItemDefinition.kt index 6a6ed981..142aae79 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/IItemDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/IItemDefinition.kt @@ -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 create(gson: Gson, type: TypeToken): TypeAdapter? { if (type.rawType == InventoryIcon::class.java) { return object : TypeAdapter() { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt index aadaccb7..14097042 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt @@ -24,6 +24,4 @@ data class ItemDefinition( override val fuelAmount: Long?, val descriptionData: ThingDescription, - - val json: Map ) : IItemDefinition, IThingWithDescription by descriptionData diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemPrototype.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemPrototype.kt index dc6bd434..496714df 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemPrototype.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemPrototype.kt @@ -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 = mapOf() - - final override fun acceptJson(json: MutableMap) { - 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), ) } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/LiquidItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/LiquidItemDefinition.kt index d0f4a62e..4843a888 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/LiquidItemDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/LiquidItemDefinition.kt @@ -24,6 +24,4 @@ data class LiquidItemDefinition( override val liquid: MaterialReference, val descriptionData: ThingDescription, - - val json: Map ) : ILiquidItem, IThingWithDescription by descriptionData diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/LiquidItemPrototype.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/LiquidItemPrototype.kt index e0073255..d703762f 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/LiquidItemPrototype.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/LiquidItemPrototype.kt @@ -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), ) } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/MaterialItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/MaterialItemDefinition.kt index 7b974071..a9263752 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/MaterialItemDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/MaterialItemDefinition.kt @@ -24,6 +24,4 @@ data class MaterialItemDefinition( override val material: MaterialReference, val descriptionData: ThingDescription, - - val json: Map ) : IMaterialItem, IThingWithDescription by descriptionData diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/MaterialItemPrototype.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/MaterialItemPrototype.kt index 3ec4f453..778da48a 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/MaterialItemPrototype.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/MaterialItemPrototype.kt @@ -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), ) } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/Annotations.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/Annotations.kt index 42beb0db..622421b9 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/Annotations.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/Annotations.kt @@ -62,6 +62,8 @@ annotation class JsonIgnoreProperty annotation class JsonPropertyConfig( val isFlat: Boolean = false, + val write: Boolean = true, + val mustBePresent: Int = 0, ) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/BuilderAdapter.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/BuilderAdapter.kt index 1cbfa83d..5a07adf4 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/BuilderAdapter.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/BuilderAdapter.kt @@ -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) -} - -@Suppress("FunctionName") -fun BuilderAdapter(factory: () -> T, vararg fields: KMutableProperty1): TypeAdapterFactory { - val builder = BuilderAdapter.Builder(factory) - - for (field in fields) { - builder.auto(field) - } - - return builder -} - /** * [TypeAdapter] для классов, которые создаются "без всего", а после наполняются данными (паттерн builder). */ diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/IJsonHolder.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/IJsonHolder.kt new file mode 100644 index 00000000..7927f257 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/IJsonHolder.kt @@ -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) +} \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/INativeJsonHolder.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/INativeJsonHolder.kt new file mode 100644 index 00000000..0898ef90 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/INativeJsonHolder.kt @@ -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) +} \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/JVM2LuaWrapper.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/JVM2LuaWrapper.kt new file mode 100644 index 00000000..72d626e8 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/JVM2LuaWrapper.kt @@ -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(val value: R) { + private abstract class LuaBinding { + abstract fun invoke(receiver: R, values: Array): Any? + abstract fun read(receiver: R): Any? + abstract fun write(receiver: R, value: Any?) + } + + private class LuaFunctionBinding(private val func: (R, Array) -> Any?) : LuaBinding() { + override fun invoke(receiver: R, values: Array): 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(private val read: (R) -> Any?, private val write: ((R, Any?) -> Unit)?) : LuaBinding() { + override fun invoke(receiver: R, values: Array): 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 = + } +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/util/AssetPathStack.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/util/PathStack.kt similarity index 93% rename from src/main/kotlin/ru/dbotthepony/kstarbound/util/AssetPathStack.kt rename to src/main/kotlin/ru/dbotthepony/kstarbound/util/PathStack.kt index 63ece0bc..7ab13fc2 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/util/AssetPathStack.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/util/PathStack.kt @@ -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? = null) { +class PathStack(private val interner: Interner? = null) { private val _stack = ThreadLocal>() private val stack: ArrayDeque get() = _stack.getOrSet { ArrayDeque() }