From 7cb6949e2738101a7010dcffefd4624abb0df22d Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 22 Aug 2024 18:13:16 +0700 Subject: [PATCH] Update matter entangler recipe, replace ingredient matrix with helpers over shaped recipe pattern --- .../mc/otm/data/IngredientMatrixCodec.kt | 113 ------------ .../ru/dbotthepony/mc/otm/network/Ext.kt | 2 + .../mc/otm/network/MatteryStreamCodec.kt | 25 +++ .../mc/otm/network/StreamCodecs.kt | 37 +++- .../ru/dbotthepony/mc/otm/recipe/Ext.kt | 78 +++++++++ .../mc/otm/recipe/IMatteryRecipe.kt | 4 + .../mc/otm/recipe/IngredientMatrix.kt | 162 ------------------ .../mc/otm/recipe/MatterEntanglerRecipe.kt | 119 ++++++++----- 8 files changed, 220 insertions(+), 320 deletions(-) delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/IngredientMatrixCodec.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/recipe/Ext.kt delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/recipe/IngredientMatrix.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/IngredientMatrixCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/IngredientMatrixCodec.kt deleted file mode 100644 index cafb075bb..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/data/IngredientMatrixCodec.kt +++ /dev/null @@ -1,113 +0,0 @@ -package ru.dbotthepony.mc.otm.data - -import com.mojang.datafixers.util.Pair -import com.mojang.serialization.Codec -import com.mojang.serialization.DataResult -import com.mojang.serialization.DynamicOps -import com.mojang.serialization.JsonOps -import com.mojang.serialization.codecs.RecordCodecBuilder -import net.minecraft.world.item.crafting.Ingredient -import ru.dbotthepony.mc.otm.core.collect.allEqual -import ru.dbotthepony.mc.otm.core.collect.map -import ru.dbotthepony.mc.otm.core.collect.toList -import ru.dbotthepony.mc.otm.core.collect.toStream -import ru.dbotthepony.mc.otm.core.stream -import ru.dbotthepony.mc.otm.recipe.IIngredientMatrix -import ru.dbotthepony.mc.otm.recipe.IngredientMatrix -import java.util.function.Supplier - -class IngredientMatrixCodec(ingredientCodec: Codec) : Codec { - private val ingredientList = Codec.list(ingredientCodec) - private val doubleIngredientList = Codec.list(ingredientList) - - override fun encode(input: IIngredientMatrix, ops: DynamicOps, prefix: T): DataResult { - return doubleIngredientList.encode( - (0 until input.height).iterator().map { row -> - (0 until input.width).iterator().map { column -> - input[column, row] - }.toList() - }.toList(), - ops, - prefix - ) - } - - private data class Handwritten(val pattern: List, val key: Map) - - private val handwrittenCodec = RecordCodecBuilder.create { - it.group( - Codec.list(Codec.STRING) - .flatXmap( - { DataResult.success(it) }, - { if (it.iterator().map { it.length }.allEqual()) DataResult.success(it) else DataResult.error { "One or more of patten strings differ in length" } } - ) - .fieldOf("pattern").forGetter(Handwritten::pattern), - Codec.unboundedMap( - Codec.STRING - .flatXmap( - { if (it.length == 1) DataResult.success(it[0]) else DataResult.error { "Ingredient key must be exactly 1 symbol in length, '$it' is invalid" } }, - { DataResult.success(it.toString()) } - ), ingredientCodec).fieldOf("key").forGetter(Handwritten::key) - ).apply(it, ::Handwritten) - } - - override fun decode(ops: DynamicOps, input: T): DataResult> { - return ops.getList(input).mapOrElse( - { - val lines = ArrayList>>() - - it.accept { - lines.add(ingredientList.decode(ops, it).map { it.first }) - } - - val errors = ArrayList>() - val ingredients = ArrayList>() - - lines.withIndex().forEach { - val (line, result) = it - result.mapOrElse({ ingredients.add(it) }, { errors.add { "Line $line: ${it.message()}" } }) - } - - if (errors.isNotEmpty()) { - DataResult.error { "Failed to decode ingredient matrix: ${errors.joinToString { it.get() }}" } - } else if (ingredients.isEmpty()) { - DataResult.error { "Ingredient list is empty" } - } else if (!ingredients.iterator().map { it.size }.allEqual()) { - DataResult.error { "Ingredient list is not a matrix (one or multiple of rows are mismatched size)" } - } else { - val result = IngredientMatrix(ingredients.first().size, ingredients.size) - - for ((row, columns) in ingredients.withIndex()) { - for ((column, ingredient) in columns.withIndex()) { - result[column, row] = ingredient - } - } - - DataResult.success(Pair(result, ops.empty())) - } - }, - { err1 -> - handwrittenCodec.decode(ops, input).mapOrElse( - { - DataResult.success(it) - }, - { - DataResult.error { "Failed to decode ingredients as list: ${err1.message()} and as pattern/dictionary: ${it.message()}" } - } - ).flatMap { - val handwritten = it.first - val result = IngredientMatrix(handwritten.pattern.first().length, handwritten.pattern.size) - - for ((row, pattern) in handwritten.pattern.withIndex()) { - for ((column, symbol) in pattern.withIndex()) { - val ingredient = if (symbol == ' ') handwritten.key[symbol] ?: Ingredient.EMPTY else handwritten.key[symbol] ?: return@flatMap DataResult.error { "Unknown ingredient with index '$symbol'" } - result[column, row] = ingredient - } - } - - DataResult.success(Pair(result, ops.empty())) - } - } - ) - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt index 2aaacf5d5..4f4bdcd5c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt @@ -13,6 +13,7 @@ import net.minecraft.network.protocol.common.custom.CustomPacketPayload import net.neoforged.neoforge.network.connection.ConnectionType import net.neoforged.neoforge.network.handling.IPayloadContext import net.neoforged.neoforge.network.registration.PayloadRegistrar +import java.util.Optional import kotlin.reflect.KFunction1 fun PayloadRegistrar.playToClient( @@ -74,6 +75,7 @@ fun FriendlyByteBuf.readByteList(): ByteArrayList { fun StreamCodec.wrap(): MatteryStreamCodec = MatteryStreamCodec.Wrapper(this) fun MatteryStreamCodec.nullable(): MatteryStreamCodec = MatteryStreamCodec.Nullable(this) +fun MatteryStreamCodec.optional(): MatteryStreamCodec> = MatteryStreamCodec.Optional(this) fun StreamCodec.encode(registry: RegistryAccess, value: V): ByteArrayList { return encodePayload(registry) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt index 2fd8afa6e..11e59ee7d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt @@ -52,6 +52,31 @@ interface MatteryStreamCodec : StreamCodec { } } + class Optional(val parent: MatteryStreamCodec) : MatteryStreamCodec> { + override fun decode(stream: S): java.util.Optional { + return if (!stream.readBoolean()) java.util.Optional.empty() else java.util.Optional.of(parent.decode(stream)) + } + + override fun encode(stream: S, value: java.util.Optional) { + if (value.isEmpty) + stream.writeBoolean(false) + else { + stream.writeBoolean(true) + parent.encode(stream, value.get()) + } + } + + override fun copy(value: java.util.Optional): java.util.Optional { + return value.map(parent::copy) + } + + override fun compare(a: java.util.Optional, b: java.util.Optional): Boolean { + if (a.isEmpty && b.isEmpty) return true + if (a.isEmpty || b.isEmpty) return false + return parent.compare(a.get(), b.get()) + } + } + class Collection>(val elementCodec: MatteryStreamCodec, val collectionFactory: (Int) -> C) : MatteryStreamCodec { override fun decode(stream: S): C { val size = stream.readVarInt() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt index 64b954b5f..cb5085cd2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt @@ -3,17 +3,14 @@ package ru.dbotthepony.mc.otm.network import io.netty.buffer.ByteBuf import net.minecraft.core.UUIDUtil import net.minecraft.network.FriendlyByteBuf -import net.minecraft.network.RegistryFriendlyByteBuf import net.minecraft.network.codec.ByteBufCodecs import net.minecraft.network.codec.StreamCodec import net.minecraft.resources.ResourceLocation -import net.minecraft.util.valueproviders.FloatProvider import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.readDecimal import ru.dbotthepony.mc.otm.core.math.writeDecimal import ru.dbotthepony.mc.otm.core.readItemType import ru.dbotthepony.mc.otm.core.writeItemType -import kotlin.reflect.KMutableProperty1 object StreamCodecs { val NOTHING: MatteryStreamCodec = StreamCodec.of({ _, _ -> }, { null }).wrap() @@ -38,4 +35,38 @@ object StreamCodecs { val ITEM_TYPE = StreamCodec.of(FriendlyByteBuf::writeItemType, FriendlyByteBuf::readItemType).wrap() val ITEM_TYPE_NULLABLE = ITEM_TYPE.nullable() val DECIMAL = StreamCodec.of(FriendlyByteBuf::writeDecimal, FriendlyByteBuf::readDecimal).wrap() + + fun composite( + c0: StreamCodec, g0: (T) -> T0, + c1: StreamCodec, g1: (T) -> T1, + c2: StreamCodec, g2: (T) -> T2, + c3: StreamCodec, g3: (T) -> T3, + c4: StreamCodec, g4: (T) -> T4, + c5: StreamCodec, g5: (T) -> T5, + c6: StreamCodec, g6: (T) -> T6, + factory: (T0, T1, T2, T3, T4, T5, T6) -> T + ): StreamCodec { + return object : StreamCodec { + override fun decode(stream: S): T { + val v0 = c0.decode(stream) + val v1 = c1.decode(stream) + val v2 = c2.decode(stream) + val v3 = c3.decode(stream) + val v4 = c4.decode(stream) + val v5 = c5.decode(stream) + val v6 = c6.decode(stream) + return factory(v0, v1, v2, v3, v4, v5, v6) + } + + override fun encode(stream: S, value: T) { + c0.encode(stream, g0(value)) + c1.encode(stream, g1(value)) + c2.encode(stream, g2(value)) + c3.encode(stream, g3(value)) + c4.encode(stream, g4(value)) + c5.encode(stream, g5(value)) + c6.encode(stream, g6(value)) + } + } + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/Ext.kt new file mode 100644 index 000000000..86ac3cdfa --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/Ext.kt @@ -0,0 +1,78 @@ +package ru.dbotthepony.mc.otm.recipe + +import net.minecraft.world.item.crafting.CraftingInput +import net.minecraft.world.item.crafting.Ingredient +import net.minecraft.world.item.crafting.ShapedRecipePattern +import ru.dbotthepony.mc.otm.core.get +import ru.dbotthepony.mc.otm.core.isNotEmpty + +val ShapedRecipePattern.isIncomplete: Boolean + get() = ingredients().any { it.items.size == 1 && it.hasNoItems() } + +val ShapedRecipePattern.width: Int get() = width() +val ShapedRecipePattern.height: Int get() = height() + +operator fun ShapedRecipePattern.get(column: Int, row: Int): Ingredient { + return ingredients()[column + row * width] +} + +operator fun ShapedRecipePattern.get(column: Int, row: Int, flop: Boolean): Ingredient { + return if (flop) + get(width - column - 1, row) + else + get(column, row) +} + +fun ShapedRecipePattern.preemptiveTest(t: CraftingInput, fromColumn: Int, fromRow: Int, flop: Boolean): Boolean { + if (t.width() - fromColumn < width || t.height() - fromRow < height) + return false + + for (column in 0 until width) { + for (row in 0 until height) { + val item = t[fromColumn + column, fromRow + row, flop] + val ingredient = this[column, row, flop] + + if (!ingredient.test(item) && item.isNotEmpty) { + return false + } + } + } + + return true +} + +fun ShapedRecipePattern.preemptiveTest(t: CraftingInput): Boolean { + if (t.width() < width || t.height() < height) + return false + + for (column in 0 .. t.width() - width) + for (row in 0 .. t.height() - height) + if (preemptiveTest(t, column, row, false) || preemptiveTest(t, column, row, true)) + return true + + return false +} + +fun ShapedRecipePattern.test(t: CraftingInput, fromColumn: Int, fromRow: Int, flop: Boolean): Boolean { + if (t.width() - fromColumn < width || t.height() - fromRow < height) + return false + + for (column in 0 until width) + for (row in 0 until height) + if (!this[column, row, flop].test(t[fromColumn + column, fromRow + row, flop])) + return false + + return true +} + +fun ShapedRecipePattern.test(t: CraftingInput): Boolean { + if (t.width() < width || t.height() < height) + return false + + for (column in 0 .. t.width() - width) + for (row in 0 .. t.height() - height) + if (test(t, column, row, false) || test(t, column, row, true)) + return true + + return false +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/IMatteryRecipe.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/IMatteryRecipe.kt index 83ff38568..60ff297bd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/IMatteryRecipe.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/IMatteryRecipe.kt @@ -1,10 +1,14 @@ package ru.dbotthepony.mc.otm.recipe +import net.minecraft.core.HolderLookup import net.minecraft.core.NonNullList import net.minecraft.world.item.ItemStack import net.minecraft.world.item.crafting.Ingredient import net.minecraft.world.item.crafting.Recipe import net.minecraft.world.item.crafting.RecipeInput +import net.minecraft.world.item.crafting.RecipeSerializer +import net.minecraft.world.item.crafting.RecipeType +import net.minecraft.world.level.Level // passthrough all default methods to fix Kotlin bug related to implementation delegation not properly working on Java interfaces // https://youtrack.jetbrains.com/issue/KT-55080/Change-the-behavior-of-inheritance-delegation-to-delegates-implementing-Java-interfaces-with-default-methods diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/IngredientMatrix.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/IngredientMatrix.kt deleted file mode 100644 index 407806a1c..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/IngredientMatrix.kt +++ /dev/null @@ -1,162 +0,0 @@ -package ru.dbotthepony.mc.otm.recipe - -import net.minecraft.core.NonNullList -import net.minecraft.world.item.crafting.CraftingInput -import net.minecraft.world.item.crafting.Ingredient -import ru.dbotthepony.mc.otm.core.collect.allEqual -import ru.dbotthepony.mc.otm.core.collect.any -import ru.dbotthepony.mc.otm.core.collect.flatMap -import ru.dbotthepony.mc.otm.core.collect.map -import ru.dbotthepony.mc.otm.core.get -import ru.dbotthepony.mc.otm.core.isNotEmpty -import ru.dbotthepony.mc.otm.core.util.InvalidableLazy -import java.util.function.Predicate - -interface IIngredientMatrix : Predicate, Iterable { - val width: Int - val height: Int - val isEmpty: Boolean - get() = width == 0 || height == 0 - - val isIncomplete: Boolean - get() = iterator().any { it.hasNoItems() } - - operator fun get(column: Int, row: Int): Ingredient - - operator fun get(column: Int, row: Int, flop: Boolean): Ingredient { - return if (flop) - get(width - column - 1, row) - else - get(column, row) - } - - override fun iterator(): Iterator { - return (0 until width).iterator().flatMap { x -> - (0 until height).iterator().map { y -> - get(x, y) - } - } - } - - val ingredients: NonNullList get() { - val result = NonNullList.createWithCapacity(width * height) - - for (x in 0 until width) { - for (y in 0 until height) { - result.add(get(x, y)) - } - } - - return result - } - - fun test(t: CraftingInput, fromColumn: Int, fromRow: Int, flop: Boolean): Boolean { - if (t.width() - fromColumn < width || t.height() - fromRow < height) - return false - - for (column in 0 until width) - for (row in 0 until height) - if (!this[column, row, flop].test(t[fromColumn + column, fromRow + row, flop])) - return false - - return true - } - - fun preemptiveTest(t: CraftingInput, fromColumn: Int, fromRow: Int, flop: Boolean): Boolean { - if (t.width() - fromColumn < width || t.height() - fromRow < height) - return false - - for (column in 0 until width) { - for (row in 0 until height) { - val item = t[fromColumn + column, fromRow + row, flop] - val ingredient = this[column, row, flop] - - if (!ingredient.test(item) && item.isNotEmpty) { - return false - } - } - } - - return true - } - - override fun test(t: CraftingInput): Boolean { - if (t.width() < width || t.height() < height) - return false - - for (column in 0 .. t.width() - width) - for (row in 0 .. t.height() - height) - if (test(t, column, row, false) || test(t, column, row, true)) - return true - - return false - } - - fun preemptiveTest(t: CraftingInput): Boolean { - if (t.width() < width || t.height() < height) - return false - - for (column in 0 .. t.width() - width) - for (row in 0 .. t.height() - height) - if (preemptiveTest(t, column, row, false) || preemptiveTest(t, column, row, true)) - return true - - return false - } - - companion object : IIngredientMatrix { - override val width: Int - get() = 0 - override val height: Int - get() = 0 - - override fun get(column: Int, row: Int): Ingredient { - return Ingredient.EMPTY - } - } -} - -class IngredientMatrix(override val width: Int, override val height: Int) : IIngredientMatrix { - private val data = Array(width * height) { Ingredient.EMPTY } - - private val lazy = InvalidableLazy.Impl { - super.isIncomplete - } - - override val isIncomplete by lazy - - override fun iterator(): Iterator { - return data.iterator() - } - - override fun get(column: Int, row: Int): Ingredient { - require(column in 0 until width) { "Column out of bounds: $column (matrix width: $width)" } - require(row in 0 until height) { "Row out of bounds: $row > (matrix height: $height)" } - return data[column + row * width] - } - - operator fun set(column: Int, row: Int, value: Ingredient) { - require(column in 0 until width) { "Column out of bounds: $column (matrix width: $width)" } - require(row in 0 until height) { "Row out of bounds: $row > (matrix height: $height)" } - data[column + row * width] = value - lazy.invalidate() - } - - companion object { - fun of(vararg values: Collection): IngredientMatrix { - if (!values.iterator().map { it.size }.allEqual()) { - throw IllegalArgumentException("One or more rows have different number of columns than the rest") - } - - val result = IngredientMatrix(values.first().size, values.size) - - for ((y, l) in values.withIndex()) { - for ((x, i) in l.withIndex()) { - result[x, y] = i - } - } - - return result - } - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt index 689182a1b..598bb6ea1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt @@ -1,26 +1,31 @@ package ru.dbotthepony.mc.otm.recipe import com.mojang.serialization.Codec +import com.mojang.serialization.MapCodec import com.mojang.serialization.codecs.RecordCodecBuilder import net.minecraft.core.HolderLookup import net.minecraft.core.NonNullList -import net.minecraft.core.RegistryAccess import net.minecraft.core.UUIDUtil -import net.minecraft.resources.ResourceLocation +import net.minecraft.core.component.DataComponentType +import net.minecraft.network.RegistryFriendlyByteBuf +import net.minecraft.network.codec.StreamCodec import net.minecraft.world.item.ItemStack import net.minecraft.world.item.crafting.CraftingInput import net.minecraft.world.item.crafting.Ingredient import net.minecraft.world.item.crafting.RecipeSerializer import net.minecraft.world.item.crafting.RecipeType +import net.minecraft.world.item.crafting.ShapedRecipePattern import net.minecraft.world.level.Level +import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.matteryEnergy import ru.dbotthepony.mc.otm.core.collect.filterNotNull import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.data.DecimalCodec -import ru.dbotthepony.mc.otm.data.IngredientMatrixCodec import ru.dbotthepony.mc.otm.data.minRange +import ru.dbotthepony.mc.otm.network.StreamCodecs +import ru.dbotthepony.mc.otm.network.optional +import ru.dbotthepony.mc.otm.network.wrap import ru.dbotthepony.mc.otm.registry.MItems import ru.dbotthepony.mc.otm.registry.MRecipes import java.util.Optional @@ -30,7 +35,7 @@ import kotlin.jvm.optionals.getOrElse interface IMatterEntanglerRecipe : IMatteryRecipe { val matter: Decimal val ticks: Double - val ingredients: IIngredientMatrix + val ingredients: ShapedRecipePattern val result: ItemStack val experience: Float @@ -38,12 +43,12 @@ interface IMatterEntanglerRecipe : IMatteryRecipe { } open class MatterEntanglerRecipe( - override val ingredients: IIngredientMatrix, + override val ingredients: ShapedRecipePattern, override val matter: Decimal, override val ticks: Double, override val result: ItemStack, override val experience: Float = 0f, - val uuidKey: String = "uuid", + val uuidKey: Optional> = Optional.empty(), val fixedUuid: Optional = Optional.empty() ) : IMatterEntanglerRecipe { override fun matches(container: CraftingInput, level: Level): Boolean { @@ -58,7 +63,9 @@ open class MatterEntanglerRecipe( override fun assemble(container: CraftingInput, registry: HolderLookup.Provider): ItemStack { return result.copy().also { - it.tagNotNull[uuidKey] = fixedUuid.getOrElse { UUID.randomUUID() } + uuidKey.ifPresent { id -> + it[id] = fixedUuid.getOrElse { UUID.randomUUID() } + } } } @@ -66,12 +73,12 @@ open class MatterEntanglerRecipe( return width >= ingredients.width && height >= ingredients.height } - override fun getResultItem(registry: RegistryAccess): ItemStack { + override fun getResultItem(registry: HolderLookup.Provider): ItemStack { return result } override fun getSerializer(): RecipeSerializer<*> { - return SERIALIZER + return Companion } override fun getType(): RecipeType<*> { @@ -79,7 +86,7 @@ open class MatterEntanglerRecipe( } override fun getIngredients(): NonNullList { - return ingredients.ingredients + return ingredients.ingredients() } override fun isIncomplete(): Boolean { @@ -94,10 +101,6 @@ open class MatterEntanglerRecipe( return ItemStack(MItems.MATTER_ENTANGLER) } - fun toFinished(id: ResourceLocation): FinishedRecipe { - return SERIALIZER.toFinished(this, id) - } - fun energetic() = Energy(this) fun matter() = Matter(this) @@ -110,49 +113,81 @@ open class MatterEntanglerRecipe( } } - fun toFinished(id: ResourceLocation): FinishedRecipe { - return ENERGY_SERIALIZER.toFinished(this, id) - } - override fun getSerializer(): RecipeSerializer<*> { - return ENERGY_SERIALIZER + return EnergySerializer } } open class Matter(val parent: MatterEntanglerRecipe) : IMatterEntanglerRecipe by parent { override fun assemble(container: CraftingInput, registry: HolderLookup.Provider): ItemStack { return parent.assemble(container, registry).also { result -> - container.items().iterator().map { it.matter }.filterNotNull().forEach { - result.matter!!.storedMatter += it.storedMatter + container.items().iterator().map { it.getCapability(MatteryCapability.MATTER_ITEM) }.filterNotNull().forEach { + result.getCapability(MatteryCapability.MATTER_ITEM)!!.storedMatter += it.storedMatter } } } - fun toFinished(id: ResourceLocation): FinishedRecipe { - return MATTER_SERIALIZER.toFinished(this, id) - } - override fun getSerializer(): RecipeSerializer<*> { - return MATTER_SERIALIZER + return MatterSerializer } } - companion object { - val SERIALIZER = Codec2RecipeSerializer { context -> - RecordCodecBuilder.create { - it.group( - IngredientMatrixCodec(context.ingredients).fieldOf("ingredients").forGetter(MatterEntanglerRecipe::ingredients), - DecimalCodec.minRange(Decimal.ZERO).fieldOf("matter").forGetter(MatterEntanglerRecipe::matter), - Codec.DOUBLE.minRange(0.0).fieldOf("ticks").forGetter(MatterEntanglerRecipe::ticks), - ItemStack.CODEC.fieldOf("result").forGetter(MatterEntanglerRecipe::result), - Codec.FLOAT.minRange(0f).optionalFieldOf("experience", 0f).forGetter(MatterEntanglerRecipe::experience), - Codec.STRING.optionalFieldOf("uuidKey", "uuid").forGetter(MatterEntanglerRecipe::uuidKey), - UUIDUtil.STRING_CODEC.optionalFieldOf("fixedUuid").forGetter(MatterEntanglerRecipe::fixedUuid) - ).apply(it, ::MatterEntanglerRecipe) - } + private object EnergySerializer : RecipeSerializer { + private val energyCodec: MapCodec = codec.xmap(::Energy, Energy::parent) + private val energyStreamCodec: StreamCodec = streamCodec.map(::Energy, Energy::parent) + + override fun codec(): MapCodec { + return energyCodec } - val ENERGY_SERIALIZER = SERIALIZER.xmap(::Energy, Energy::parent) - val MATTER_SERIALIZER = SERIALIZER.xmap(::Matter, Matter::parent) + override fun streamCodec(): StreamCodec { + return energyStreamCodec + } + } + + private object MatterSerializer : RecipeSerializer { + private val matterCodec: MapCodec = codec.xmap(::Matter, Matter::parent) + private val matterStreamCodec: StreamCodec = streamCodec.map(::Matter, Matter::parent) + + override fun codec(): MapCodec { + return matterCodec + } + + override fun streamCodec(): StreamCodec { + return matterStreamCodec + } + } + + companion object : RecipeSerializer { + val codec: MapCodec = RecordCodecBuilder.mapCodec { + it.group( + ShapedRecipePattern.MAP_CODEC.fieldOf("ingredients").forGetter(MatterEntanglerRecipe::ingredients), + DecimalCodec.minRange(Decimal.ZERO).fieldOf("matter").forGetter(MatterEntanglerRecipe::matter), + Codec.DOUBLE.minRange(0.0).fieldOf("ticks").forGetter(MatterEntanglerRecipe::ticks), + ItemStack.CODEC.fieldOf("result").forGetter(MatterEntanglerRecipe::result), + Codec.FLOAT.minRange(0f).optionalFieldOf("experience", 0f).forGetter(MatterEntanglerRecipe::experience), + (DataComponentType.CODEC as Codec>).optionalFieldOf("uuidKey").forGetter(MatterEntanglerRecipe::uuidKey), + UUIDUtil.STRING_CODEC.optionalFieldOf("fixedUuid").forGetter(MatterEntanglerRecipe::fixedUuid) + ).apply(it, ::MatterEntanglerRecipe) + } + + val streamCodec: StreamCodec = StreamCodecs.composite( + ShapedRecipePattern.STREAM_CODEC, MatterEntanglerRecipe::ingredients, + StreamCodecs.DECIMAL, { it.matter }, + StreamCodecs.DOUBLE, MatterEntanglerRecipe::ticks, + ItemStack.STREAM_CODEC, MatterEntanglerRecipe::result, + StreamCodecs.FLOAT, MatterEntanglerRecipe::experience, + DataComponentType.STREAM_CODEC.wrap().optional() as StreamCodec>>, MatterEntanglerRecipe::uuidKey, + UUIDUtil.STREAM_CODEC.wrap().optional(), MatterEntanglerRecipe::fixedUuid, + ::MatterEntanglerRecipe + ) + + override fun codec(): MapCodec { + return codec + } + + override fun streamCodec(): StreamCodec { + return streamCodec + } } }