Update matter entangler recipe, replace ingredient matrix with helpers over shaped recipe pattern
This commit is contained in:
parent
e80947d8d7
commit
7cb6949e27
@ -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<Ingredient>) : Codec<IIngredientMatrix> {
|
||||
private val ingredientList = Codec.list(ingredientCodec)
|
||||
private val doubleIngredientList = Codec.list(ingredientList)
|
||||
|
||||
override fun <T : Any> encode(input: IIngredientMatrix, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
||||
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<String>, val key: Map<Char, Ingredient>)
|
||||
|
||||
private val handwrittenCodec = RecordCodecBuilder.create<Handwritten> {
|
||||
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 <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<IIngredientMatrix, T>> {
|
||||
return ops.getList(input).mapOrElse(
|
||||
{
|
||||
val lines = ArrayList<DataResult<List<Ingredient>>>()
|
||||
|
||||
it.accept {
|
||||
lines.add(ingredientList.decode(ops, it).map { it.first })
|
||||
}
|
||||
|
||||
val errors = ArrayList<Supplier<String>>()
|
||||
val ingredients = ArrayList<List<Ingredient>>()
|
||||
|
||||
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()))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
@ -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 <T : CustomPacketPayload> PayloadRegistrar.playToClient(
|
||||
@ -74,6 +75,7 @@ fun FriendlyByteBuf.readByteList(): ByteArrayList {
|
||||
|
||||
fun <S : ByteBuf, V> StreamCodec<S, V>.wrap(): MatteryStreamCodec<S, V> = MatteryStreamCodec.Wrapper(this)
|
||||
fun <S : ByteBuf, V> MatteryStreamCodec<S, V>.nullable(): MatteryStreamCodec<S, V?> = MatteryStreamCodec.Nullable(this)
|
||||
fun <S : ByteBuf, V : Any> MatteryStreamCodec<S, V>.optional(): MatteryStreamCodec<S, Optional<V>> = MatteryStreamCodec.Optional(this)
|
||||
|
||||
fun <V> StreamCodec<in RegistryFriendlyByteBuf, V>.encode(registry: RegistryAccess, value: V): ByteArrayList {
|
||||
return encodePayload(registry) {
|
||||
|
@ -52,6 +52,31 @@ interface MatteryStreamCodec<S : ByteBuf, V> : StreamCodec<S, V> {
|
||||
}
|
||||
}
|
||||
|
||||
class Optional<S : ByteBuf, V : Any>(val parent: MatteryStreamCodec<S, V>) : MatteryStreamCodec<S, java.util.Optional<V>> {
|
||||
override fun decode(stream: S): java.util.Optional<V> {
|
||||
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<V>) {
|
||||
if (value.isEmpty)
|
||||
stream.writeBoolean(false)
|
||||
else {
|
||||
stream.writeBoolean(true)
|
||||
parent.encode(stream, value.get())
|
||||
}
|
||||
}
|
||||
|
||||
override fun copy(value: java.util.Optional<V>): java.util.Optional<V> {
|
||||
return value.map(parent::copy)
|
||||
}
|
||||
|
||||
override fun compare(a: java.util.Optional<V>, b: java.util.Optional<V>): Boolean {
|
||||
if (a.isEmpty && b.isEmpty) return true
|
||||
if (a.isEmpty || b.isEmpty) return false
|
||||
return parent.compare(a.get(), b.get())
|
||||
}
|
||||
}
|
||||
|
||||
class Collection<S : FriendlyByteBuf, E, C : MutableCollection<E>>(val elementCodec: MatteryStreamCodec<in S, E>, val collectionFactory: (Int) -> C) : MatteryStreamCodec<S, C> {
|
||||
override fun decode(stream: S): C {
|
||||
val size = stream.readVarInt()
|
||||
|
@ -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<ByteBuf, Nothing?> = StreamCodec.of<ByteBuf, Nothing?>({ _, _ -> }, { 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 <S : ByteBuf, T, T0, T1, T2, T3, T4, T5, T6> composite(
|
||||
c0: StreamCodec<in S, T0>, g0: (T) -> T0,
|
||||
c1: StreamCodec<in S, T1>, g1: (T) -> T1,
|
||||
c2: StreamCodec<in S, T2>, g2: (T) -> T2,
|
||||
c3: StreamCodec<in S, T3>, g3: (T) -> T3,
|
||||
c4: StreamCodec<in S, T4>, g4: (T) -> T4,
|
||||
c5: StreamCodec<in S, T5>, g5: (T) -> T5,
|
||||
c6: StreamCodec<in S, T6>, g6: (T) -> T6,
|
||||
factory: (T0, T1, T2, T3, T4, T5, T6) -> T
|
||||
): StreamCodec<S, T> {
|
||||
return object : StreamCodec<S, T> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
78
src/main/kotlin/ru/dbotthepony/mc/otm/recipe/Ext.kt
Normal file
78
src/main/kotlin/ru/dbotthepony/mc/otm/recipe/Ext.kt
Normal file
@ -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
|
||||
}
|
@ -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
|
||||
|
@ -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<CraftingInput>, Iterable<Ingredient> {
|
||||
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<Ingredient> {
|
||||
return (0 until width).iterator().flatMap { x ->
|
||||
(0 until height).iterator().map { y ->
|
||||
get(x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val ingredients: NonNullList<Ingredient> get() {
|
||||
val result = NonNullList.createWithCapacity<Ingredient>(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<Ingredient> {
|
||||
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<Ingredient>): 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
|
||||
}
|
||||
}
|
||||
}
|
@ -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<CraftingInput> {
|
||||
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<CraftingInput> {
|
||||
}
|
||||
|
||||
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<DataComponentType<UUID>> = Optional.empty(),
|
||||
val fixedUuid: Optional<UUID> = 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<Ingredient> {
|
||||
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<MatterEntanglerRecipe> { 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<Energy> {
|
||||
private val energyCodec: MapCodec<Energy> = codec.xmap(::Energy, Energy::parent)
|
||||
private val energyStreamCodec: StreamCodec<RegistryFriendlyByteBuf, Energy> = streamCodec.map(::Energy, Energy::parent)
|
||||
|
||||
override fun codec(): MapCodec<Energy> {
|
||||
return energyCodec
|
||||
}
|
||||
|
||||
val ENERGY_SERIALIZER = SERIALIZER.xmap(::Energy, Energy::parent)
|
||||
val MATTER_SERIALIZER = SERIALIZER.xmap(::Matter, Matter::parent)
|
||||
override fun streamCodec(): StreamCodec<RegistryFriendlyByteBuf, Energy> {
|
||||
return energyStreamCodec
|
||||
}
|
||||
}
|
||||
|
||||
private object MatterSerializer : RecipeSerializer<Matter> {
|
||||
private val matterCodec: MapCodec<Matter> = codec.xmap(::Matter, Matter::parent)
|
||||
private val matterStreamCodec: StreamCodec<RegistryFriendlyByteBuf, Matter> = streamCodec.map(::Matter, Matter::parent)
|
||||
|
||||
override fun codec(): MapCodec<Matter> {
|
||||
return matterCodec
|
||||
}
|
||||
|
||||
override fun streamCodec(): StreamCodec<RegistryFriendlyByteBuf, Matter> {
|
||||
return matterStreamCodec
|
||||
}
|
||||
}
|
||||
|
||||
companion object : RecipeSerializer<MatterEntanglerRecipe> {
|
||||
val codec: MapCodec<MatterEntanglerRecipe> = 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<DataComponentType<UUID>>).optionalFieldOf("uuidKey").forGetter(MatterEntanglerRecipe::uuidKey),
|
||||
UUIDUtil.STRING_CODEC.optionalFieldOf("fixedUuid").forGetter(MatterEntanglerRecipe::fixedUuid)
|
||||
).apply(it, ::MatterEntanglerRecipe)
|
||||
}
|
||||
|
||||
val streamCodec: StreamCodec<RegistryFriendlyByteBuf, MatterEntanglerRecipe> = 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<RegistryFriendlyByteBuf, Optional<DataComponentType<UUID>>>, MatterEntanglerRecipe::uuidKey,
|
||||
UUIDUtil.STREAM_CODEC.wrap().optional(), MatterEntanglerRecipe::fixedUuid,
|
||||
::MatterEntanglerRecipe
|
||||
)
|
||||
|
||||
override fun codec(): MapCodec<MatterEntanglerRecipe> {
|
||||
return codec
|
||||
}
|
||||
|
||||
override fun streamCodec(): StreamCodec<RegistryFriendlyByteBuf, MatterEntanglerRecipe> {
|
||||
return streamCodec
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user