From c3756b259a4504a061f2dd1e77e32f71562d2dbb Mon Sep 17 00:00:00 2001
From: DBotThePony <dbotthepony@yandex.ru>
Date: Wed, 8 Feb 2023 10:47:56 +0700
Subject: [PATCH] =?UTF-8?q?=D0=B1=D0=BE=D0=BB=D0=B5=D0=B5=20=D0=B1=D1=8B?=
 =?UTF-8?q?=D1=81=D1=82=D1=80=D1=8B=D0=B9=20isMarkedNullable?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../defs/item/DynamicItemDefinition.kt        |  2 ++
 .../io/json/builder/BuilderAdapter.kt         | 26 +++++++++++++------
 .../io/json/builder/FactoryAdapter.kt         |  4 +--
 .../kstarbound/io/json/builder/Properties.kt  |  4 +++
 4 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/DynamicItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/DynamicItemDefinition.kt
index 39fe10a3..d23fd401 100644
--- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/DynamicItemDefinition.kt
+++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/DynamicItemDefinition.kt
@@ -8,5 +8,7 @@ class DynamicItemDefinition(def: RegistryObject<IItemDefinition>) : DynamicDefin
 	override fun sanitize(saveInput: JsonObject) {
 		saveInput.remove("itemName")
 		saveInput.remove("pickupQuestTemplates")
+		saveInput.remove("scripts")
+		saveInput.remove("scriptDelta")
 	}
 }
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 5a07adf4..dedce642 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
@@ -60,6 +60,7 @@ class BuilderAdapter<T : Any> private constructor(
 	val stringInterner: Interner<String> = Interner { it },
 ) : TypeAdapter<T>() {
 	private val loggedMisses = ObjectOpenHashSet<String>()
+	private val flatProperties = properties.values.filter { it.isFlat }
 
 	override fun write(writer: JsonWriter, value: T) {
 		TODO("Not yet implemented")
@@ -69,13 +70,16 @@ class BuilderAdapter<T : Any> private constructor(
 		@Suppress("name_shadowing")
 		var reader = reader
 
+		// загружаем указатели на стек
+		val properties = properties
+
 		val missing = ObjectOpenHashSet<IResolvedMutableProperty<T, *>>()
 		missing.addAll(properties.values)
 
 		val instance = factory.invoke()
 		var json: JsonObject by Delegates.notNull()
 
-		if (instance is IJsonHolder || properties.values.any { it.isFlat }) {
+		if (instance is IJsonHolder || flatProperties.isNotEmpty()) {
 			json = TypeAdapters.JSON_ELEMENT.read(reader) as JsonObject
 			reader = JsonTreeReader(json)
 
@@ -86,6 +90,12 @@ class BuilderAdapter<T : Any> private constructor(
 			}
 		}
 
+		// загружаем указатели на стек
+		val logMisses = logMisses
+		val extraPropertiesAreFatal = extraPropertiesAreFatal
+		val loggedMisses = loggedMisses
+		val ignoreKeys = ignoreKeys
+
 		reader.beginObject()
 
 		while (reader.hasNext()) {
@@ -102,15 +112,15 @@ class BuilderAdapter<T : Any> private constructor(
 				try {
 					val peek = reader.peek()
 
-					if (!property.type.isMarkedNullable && peek == JsonToken.NULL) {
+					if (!property.isMarkedNullable && peek === JsonToken.NULL) {
 						throw NullPointerException("Property ${property.name} of ${instance::class.qualifiedName} does not accept nulls (JSON contains null)")
-					} else if (peek == JsonToken.NULL) {
+					} else if (peek === JsonToken.NULL) {
 						property.set(instance, null)
 						reader.nextNull()
 					} else {
 						val readValue = property.adapter.read(reader)
 
-						if (!property.type.isMarkedNullable && readValue == null)
+						if (!property.isMarkedNullable && readValue == null)
 							throw JsonSyntaxException("Property ${property.name} of ${instance::class.qualifiedName} does not accept nulls (Type provider returned null)")
 
 						property.set(instance, readValue)
@@ -134,14 +144,14 @@ class BuilderAdapter<T : Any> private constructor(
 
 		reader.endObject()
 
-		for (property in properties.values) {
-			if (!property.isFlat || !missing.remove(property))
+		for (property in flatProperties) {
+			if (!missing.remove(property))
 				continue
 
 			try {
 				val read = property.adapter.read(JsonTreeReader(json))
 
-				if (!property.type.isMarkedNullable && read == null) {
+				if (!property.isMarkedNullable && read == null) {
 					throw NullPointerException("Property ${property.name} of ${instance::class.qualifiedName} does not accept nulls (flat property adapter returned NULL)")
 				} else if (read == null) {
 					property.set(instance, null)
@@ -157,7 +167,7 @@ class BuilderAdapter<T : Any> private constructor(
 			if (property.mustBePresent == true) {
 				throw JsonSyntaxException("${instance::class.qualifiedName} demands for ${property.name} to be present, however, it is missing from JSON structure")
 			} else if (property.mustBePresent == null) {
-				if (property.type.isMarkedNullable) {
+				if (property.isMarkedNullable) {
 					continue
 				}
 
diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/FactoryAdapter.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/FactoryAdapter.kt
index eb1bcaee..3a54183a 100644
--- a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/FactoryAdapter.kt
+++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/FactoryAdapter.kt
@@ -296,7 +296,7 @@ class FactoryAdapter<T : Any> private constructor(
 				val (field) = tuple
 
 				if (readValues[i] == null) {
-					if (!tuple.type.isMarkedNullable) {
+					if (!tuple.isMarkedNullable) {
 						throw JsonSyntaxException("Field ${field.name} of ${bound.qualifiedName} does not accept nulls")
 					}
 
@@ -350,7 +350,7 @@ class FactoryAdapter<T : Any> private constructor(
 					throw JsonSyntaxException("Field ${field.name} of ${bound.qualifiedName} is missing")
 				}
 
-				if (tuple.type.isMarkedNullable) {
+				if (tuple.isMarkedNullable) {
 					continue
 				}
 
diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/Properties.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/Properties.kt
index 187d6d74..286c3d25 100644
--- a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/Properties.kt
+++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/builder/Properties.kt
@@ -28,6 +28,7 @@ interface IResolvableProperty<T : Any, V> : IReferencedProperty<T, V> {
 interface IResolvedProperty<T : Any, V> : IReferencedProperty<T, V> {
 	val type: KType
 	val adapter: TypeAdapter<V>
+	val isMarkedNullable: Boolean
 
 	operator fun component1() = property
 	operator fun component2() = adapter
@@ -39,6 +40,7 @@ class ResolvedProperty<T : Any, V>(
 	override val isFlat: Boolean
 ) : IResolvableProperty<T, V>, IResolvedProperty<T, V> {
 	override val type: KType = property.returnType
+	override val isMarkedNullable: Boolean = type.isMarkedNullable
 
 	override fun resolve(gson: Gson?): IResolvedProperty<T, V> {
 		return this
@@ -74,6 +76,7 @@ interface IResolvableMutableProperty<T : Any, V> : IReferencedMutableProperty<T,
 interface IResolvedMutableProperty<T : Any, V> : IResolvableMutableProperty<T, V> {
 	val type: KType
 	val adapter: TypeAdapter<V>
+	val isMarkedNullable: Boolean
 
 	operator fun component1() = property
 	operator fun component2() = adapter
@@ -91,6 +94,7 @@ class ResolvedMutableProperty<T : Any, V>(
 	override val mustBePresent: Boolean?
 ) : IResolvableMutableProperty<T, V>, IResolvedMutableProperty<T, V> {
 	override val type: KType = property.returnType
+	override val isMarkedNullable: Boolean = type.isMarkedNullable
 
 	override fun resolve(gson: Gson?): IResolvedMutableProperty<T, V> {
 		return this