diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/BoundMatterFunction.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/BoundMatterFunction.kt new file mode 100644 index 000000000..fd38c23f0 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/BoundMatterFunction.kt @@ -0,0 +1,90 @@ +package ru.dbotthepony.mc.otm.matter + +import com.google.common.collect.ImmutableList +import com.google.gson.JsonArray +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import com.google.gson.JsonParseException +import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.set +import ru.dbotthepony.mc.otm.data.stream + +class BoundMatterFunction(val function: MatterFunction, val value: T) { + fun apply(self: T): T { + return function.updateValue(self, value) + } + + fun toJson(): JsonObject { + return JsonObject().also { + it["type"] = function.name + + if (value is Int || value is Double) + it["value"] = value + else + it["value"] = value.toString() + } + } + + companion object { + inline fun getValue(value: JsonElement): T { + return when (T::class) { + ImpreciseFraction::class -> ImpreciseFraction(value.asString) as T + Double::class -> value.asDouble as T + Int::class -> value.asInt as T + else -> throw RuntimeException("Unknown number type: ${T::class.qualifiedName}") + } + } + + inline fun deserializeFunctionTree(input: JsonElement?, name: String): List> { + if (input == null) { + return listOf() + } + + if (input !is JsonArray) { + throw JsonParseException("Expected $name to be JsonArray, ${input::class.qualifiedName} given") + } + + return input.stream().map { + if (it !is JsonObject) { + throw JsonParseException("All elements in function tree must be JsonObjects, ${it::class.qualifiedName} given") + } + + val type = it["type"]?.asString ?: throw JsonParseException("Invalid `type` value in function object") + val value = it["value"] ?: throw JsonParseException("Missing `value` value in function object") + + val parsedValue: T = getValue(value) + val fn: MatterFunction + + try { + fn = MatterFunction.valueOf(type.uppercase()) + } catch (err: NoSuchElementException) { + throw JsonParseException("No such function: $type", err) + } + + return@map BoundMatterFunction(fn, parsedValue) + }.collect(ImmutableList.toImmutableList()) + } + + fun apply(value: T, funcs: Collection>): T { + if (funcs.isEmpty()) { + return value + } + + var newValue = value + + for (func in funcs) { + newValue = func.apply(newValue) + } + + return newValue + } + + fun apply(funcs: Collection>, value: T): T { + return apply(value, funcs) + } + } +} + +fun Collection>.apply(value: T): T { + return BoundMatterFunction.apply(this, value) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterDataProvider.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterDataProvider.kt index 7df5ac405..9b34c3a98 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterDataProvider.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterDataProvider.kt @@ -112,24 +112,24 @@ open class MatterDataProvider(protected val dataGenerator: DataGenerator, val na } class UpdateConfiguration(name: ResourceLocation) : Configuration(name) { - val matterFunctions = ArrayList>() - val complexityFunctions = ArrayList>() - val priorityFunctions = ArrayList>() + val matterFunctions = ArrayList>() + val complexityFunctions = ArrayList>() + val priorityFunctions = ArrayList>() - fun addMatterFunction(function: UpdateAction.Function, value: ImpreciseFraction): UpdateConfiguration { - matterFunctions.add(UpdateAction.BoundFunction(function, value)) + fun addMatterFunction(function: MatterFunction, value: ImpreciseFraction): UpdateConfiguration { + matterFunctions.add(BoundMatterFunction(function, value)) matter = null return this } - fun addComplexityFunction(function: UpdateAction.Function, value: Double): UpdateConfiguration { - complexityFunctions.add(UpdateAction.BoundFunction(function, value)) + fun addComplexityFunction(function: MatterFunction, value: Double): UpdateConfiguration { + complexityFunctions.add(BoundMatterFunction(function, value)) matter = null return this } - fun addPriorityFunction(function: UpdateAction.Function, value: Int): UpdateConfiguration { - priorityFunctions.add(UpdateAction.BoundFunction(function, value)) + fun addPriorityFunction(function: MatterFunction, value: Int): UpdateConfiguration { + priorityFunctions.add(BoundMatterFunction(function, value)) matter = null return this } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterFunction.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterFunction.kt new file mode 100644 index 000000000..a889c0311 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterFunction.kt @@ -0,0 +1,76 @@ +package ru.dbotthepony.mc.otm.matter + +import com.google.gson.JsonParseException +import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.integerDivisionDown +import ru.dbotthepony.mc.otm.core.integerDivisionUp + +enum class MatterFunction { + ADD { + override fun updateValue(self: Int, other: Int): Int = self + other + override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self + other + override fun updateValue(self: Double, other: Double): Double = self + other + }, + SUBTRACT { + override fun updateValue(self: Int, other: Int): Int = self - other + override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self - other + override fun updateValue(self: Double, other: Double): Double = self - other + }, + MULTIPLY { + override fun updateValue(self: Int, other: Int): Int = self * other + override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self * other + override fun updateValue(self: Double, other: Double): Double = self * other + }, + DIVIDE { + override fun updateValue(self: Int, other: Int): Int = self / other + override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self / other + override fun updateValue(self: Double, other: Double): Double = self / other + }, + DIVIDE_UP { + override fun updateValue(self: Int, other: Int): Int = integerDivisionUp(self, other) + override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = throw JsonParseException( + "Integer division up is available only for integers" + ) + override fun updateValue(self: Double, other: Double): Double = throw JsonParseException( + "Integer division up is available only for integers" + ) + }, + DIVIDE_DOWN { + override fun updateValue(self: Int, other: Int): Int = integerDivisionDown(self, other) + override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = throw JsonParseException( + "Integer division down is available only for integers" + ) + override fun updateValue(self: Double, other: Double): Double = throw JsonParseException( + "Integer division down is available only for integers" + ) + }, + MODULO { + override fun updateValue(self: Int, other: Int): Int = self % other + override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self % other + override fun updateValue(self: Double, other: Double): Double = self % other + }, + AT_LEAST { + override fun updateValue(self: Int, other: Int): Int = self.coerceAtLeast(other) + override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self.coerceAtLeast(other) + override fun updateValue(self: Double, other: Double): Double = self.coerceAtLeast(other) + }, + AT_MOST { + override fun updateValue(self: Int, other: Int): Int = self.coerceAtMost(other) + override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self.coerceAtMost(other) + override fun updateValue(self: Double, other: Double): Double = self.coerceAtMost(other) + }, + ; + + protected abstract fun updateValue(self: Int, other: Int): Int + protected abstract fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction + protected abstract fun updateValue(self: Double, other: Double): Double + + fun updateValue(self: T, other: T): T { + return when (self) { + is ImpreciseFraction -> updateValue(self, other) + is Double -> updateValue(self, other) + is Int -> updateValue(self, other) + else -> throw RuntimeException("Unknown number type: ${self::class.qualifiedName}") + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterManager.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterManager.kt index 8141521cd..12a93e90a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterManager.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterManager.kt @@ -113,6 +113,18 @@ object MatterManager : SimpleJsonResourceReloadListener(GsonBuilder().setPrettyP private val computedEntries = Reference2ObjectOpenHashMap() val computedEntriesView: Map = Collections.unmodifiableMap(computedEntries) + fun searchKeyEntry(index: ResourceLocation): KeyEntry? { + return keyEntries[index] + } + + fun searchTagEntry(index: ResourceLocation): TagEntry? { + return tagEntries.firstOrNull { it.tag.location == index } + } + + fun searchTagEntry(index: TagKey): TagEntry? { + return tagEntries.firstOrNull { it.tag == index } + } + private fun doGetDirectInner(value: Item): Entry? { val key = value.registryName ?: throw NullPointerException("$value has no registry name!") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/UpdateAction.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/UpdateAction.kt index c46bd76bb..4dc292bde 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/UpdateAction.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/UpdateAction.kt @@ -9,157 +9,14 @@ import net.minecraft.resources.ResourceLocation import net.minecraft.tags.TagKey import net.minecraft.world.item.Item import ru.dbotthepony.mc.otm.core.ImpreciseFraction -import ru.dbotthepony.mc.otm.core.integerDivisionDown -import ru.dbotthepony.mc.otm.core.integerDivisionUp import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.data.stream +import ru.dbotthepony.mc.otm.matter.BoundMatterFunction.Companion.deserializeFunctionTree class UpdateAction : AbstractRegistryAction { - enum class Function { - ADD { - override fun updateValue(self: Int, other: Int): Int = self + other - override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self + other - override fun updateValue(self: Double, other: Double): Double = self + other - }, - SUBTRACT { - override fun updateValue(self: Int, other: Int): Int = self - other - override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self - other - override fun updateValue(self: Double, other: Double): Double = self - other - }, - MULTIPLY { - override fun updateValue(self: Int, other: Int): Int = self * other - override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self * other - override fun updateValue(self: Double, other: Double): Double = self * other - }, - DIVIDE { - override fun updateValue(self: Int, other: Int): Int = self / other - override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self / other - override fun updateValue(self: Double, other: Double): Double = self / other - }, - DIVIDE_UP { - override fun updateValue(self: Int, other: Int): Int = integerDivisionUp(self, other) - override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = throw JsonParseException( - "Integer division up is available only for integers" - ) - override fun updateValue(self: Double, other: Double): Double = throw JsonParseException( - "Integer division up is available only for integers" - ) - }, - DIVIDE_DOWN { - override fun updateValue(self: Int, other: Int): Int = integerDivisionDown(self, other) - override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = throw JsonParseException( - "Integer division down is available only for integers" - ) - override fun updateValue(self: Double, other: Double): Double = throw JsonParseException( - "Integer division down is available only for integers" - ) - }, - MODULO { - override fun updateValue(self: Int, other: Int): Int = self % other - override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self % other - override fun updateValue(self: Double, other: Double): Double = self % other - }, - AT_LEAST { - override fun updateValue(self: Int, other: Int): Int = self.coerceAtLeast(other) - override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self.coerceAtLeast(other) - override fun updateValue(self: Double, other: Double): Double = self.coerceAtLeast(other) - }, - AT_MOST { - override fun updateValue(self: Int, other: Int): Int = self.coerceAtMost(other) - override fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction = self.coerceAtMost(other) - override fun updateValue(self: Double, other: Double): Double = self.coerceAtMost(other) - }, - ; - - protected abstract fun updateValue(self: Int, other: Int): Int - protected abstract fun updateValue(self: ImpreciseFraction, other: ImpreciseFraction): ImpreciseFraction - protected abstract fun updateValue(self: Double, other: Double): Double - - fun updateValue(self: T, other: T): T { - return when (self) { - is ImpreciseFraction -> updateValue(self, other) - is Double -> updateValue(self, other) - is Int -> updateValue(self, other) - else -> throw RuntimeException("Unknown number type: ${self::class.qualifiedName}") - } - } - } - - class BoundFunction(val function: Function, val value: T) { - fun apply(self: T): T { - return function.updateValue(self, value) - } - - fun toJson(): JsonObject { - return JsonObject().also { - it["type"] = function.name - - if (value is Int || value is Double) - it["value"] = value - else - it["value"] = value.toString() - } - } - } - - companion object { - inline fun getValue(value: JsonElement): T { - return when (T::class) { - ImpreciseFraction::class -> ImpreciseFraction(value.asString) as T - Double::class -> value.asDouble as T - Int::class -> value.asInt as T - else -> throw RuntimeException("Unknown number type: ${T::class.qualifiedName}") - } - } - - inline fun deserializeFunctionTree(input: JsonElement?, name: String): List> { - if (input == null) { - return listOf() - } - - if (input !is JsonArray) { - throw JsonParseException("Expected $name to be JsonArray, ${input::class.qualifiedName} given") - } - - return input.stream().map { - if (it !is JsonObject) { - throw JsonParseException("All elements in function tree must be JsonObjects, ${it::class.qualifiedName} given") - } - - val type = it["type"]?.asString ?: throw JsonParseException("Invalid `type` value in function object") - val value = it["value"] ?: throw JsonParseException("Missing `value` value in function object") - - val parsedValue: T = getValue(value) - val fn: Function - - try { - fn = Function.valueOf(type.uppercase()) - } catch (err: NoSuchElementException) { - throw JsonParseException("No such function: $type", err) - } - - return@map BoundFunction(fn, parsedValue) - }.collect(ImmutableList.toImmutableList()) - } - - fun apply(value: T, funcs: Collection>): T { - if (funcs.isEmpty()) { - return value - } - - var newValue = value - - for (func in funcs) { - newValue = func.apply(newValue) - } - - return newValue - } - } - - val matterFunctions: List> - val complexityFunctions: List> - val priorityFunctions: List> + val matterFunctions: List> + val complexityFunctions: List> + val priorityFunctions: List> constructor(json: JsonObject) : super(json) { matterFunctions = deserializeFunctionTree(json["matter_functions"], "matter_functions") @@ -173,9 +30,9 @@ class UpdateAction : AbstractRegistryAction { complexity: Double? = null, priority: Int? = null, errorOnFailure: Boolean = false, - matterFunctions: List> = ImmutableList.of(), - complexityFunctions: List> = ImmutableList.of(), - priorityFunctions: List> = ImmutableList.of(), + matterFunctions: List> = ImmutableList.of(), + complexityFunctions: List> = ImmutableList.of(), + priorityFunctions: List> = ImmutableList.of(), ) : super(tag = tag, matter = matter, complexity = complexity, priority = priority, errorOnFailure = errorOnFailure) { check(matter != null || complexity != null || priority != null || matterFunctions.isNotEmpty() || complexityFunctions.isNotEmpty() || priorityFunctions.isNotEmpty()) { "Can't update existing entries without anything specified" @@ -192,9 +49,9 @@ class UpdateAction : AbstractRegistryAction { complexity: Double? = null, priority: Int? = null, errorOnFailure: Boolean = false, - matterFunctions: List> = ImmutableList.of(), - complexityFunctions: List> = ImmutableList.of(), - priorityFunctions: List> = ImmutableList.of(), + matterFunctions: List> = ImmutableList.of(), + complexityFunctions: List> = ImmutableList.of(), + priorityFunctions: List> = ImmutableList.of(), ) : super(key = key, matter = matter, complexity = complexity, priority = priority, errorOnFailure = errorOnFailure) { check(matter != null || complexity != null || priority != null || matterFunctions.isNotEmpty() || complexityFunctions.isNotEmpty() || priorityFunctions.isNotEmpty()) { "Can't update existing entries without anything specified" @@ -237,17 +94,17 @@ class UpdateAction : AbstractRegistryAction { fun apply(value: MatterManager.MutableEntry, modifier: ResourceLocation) { if (matterFunctions.isNotEmpty()) - value.matter = apply(value.matter, matterFunctions) + value.matter = matterFunctions.apply(value.matter) else if (matter != null) value.matter = matter if (complexityFunctions.isNotEmpty()) - value.complexity = apply(value.complexity, complexityFunctions) + value.complexity = complexityFunctions.apply(value.complexity) else if (complexity != null) value.complexity = complexity if (priorityFunctions.isNotEmpty()) - value.priority = apply(value.priority, priorityFunctions) + value.priority = priorityFunctions.apply(value.priority) else if (priority != null) value.priority = priority