From 3c5ea937a5d768d5e6cb0f996027fa12dd9f32fd Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 31 Dec 2023 18:23:07 +0700 Subject: [PATCH] More backporting --- .../otm/capability/MatteryPlayerCapability.kt | 2 +- .../mc/otm/client/screen/MatteryScreen.kt | 4 +- .../client/screen/decorative/PainterScreen.kt | 1 + .../otm/client/screen/panels/EditablePanel.kt | 2 +- .../mc/otm/data/Codec2RecipeSerializer.kt | 102 +++++++----------- .../mc/otm/data/IngredientCodec.kt | 23 ++++ .../mc/otm/network/MatteryNetworkChannel.kt | 33 +++--- .../recipe/ExplosiveHammerPrimingRecipe.kt | 15 ++- 8 files changed, 87 insertions(+), 95 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/IngredientCodec.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt index a279abffd..c477a6a75 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt @@ -531,7 +531,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial super.onJobTick(status) if (isExopackVisible && ply.level().random.nextFloat() <= 0.05f) { - MatteryPlayerNetworkChannel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(ply as ServerPlayer), ExopackSmokePacket(ply.uuid)) + MatteryPlayerNetworkChannel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with { ply as ServerPlayer }, ExopackSmokePacket(ply.uuid)) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt index 67f24f1b2..0385b5fc0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt @@ -564,7 +564,7 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit return super.mouseReleased(p_97812_, p_97813_, p_97814_) } - override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean { + override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollY: Double): Boolean { for (panel in panels) { if (panel.mouseScrolledChecked(mouseX, mouseY, scrollY)) { return true @@ -647,7 +647,7 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit val mouseYf = mouseY.toFloat() // dark background - this.renderBackground(graphics, mouseX, mouseY, partialTick) + this.renderBackground(graphics) super.hoveredSlot = null var hovered = false diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/PainterScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/PainterScreen.kt index fd52916fd..59d5c98d5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/PainterScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/PainterScreen.kt @@ -32,6 +32,7 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.map import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.util.CreativeMenuItemComparator +import ru.dbotthepony.mc.otm.core.value import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt index 981705c2f..ed660ee97 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt @@ -108,7 +108,7 @@ open class EditablePanel @JvmOverloads constructor( return this@EditablePanel.mouseDragged(p_94740_, p_94741_, p_94742_, p_94743_, p_94744_) } - override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean { + override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollY: Double): Boolean { return this@EditablePanel.mouseScrolled(mouseX, mouseY, scrollY) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/Codec2RecipeSerializer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/Codec2RecipeSerializer.kt index b32702611..3ddf52bd2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/data/Codec2RecipeSerializer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/Codec2RecipeSerializer.kt @@ -8,9 +8,6 @@ import com.mojang.serialization.Codec import com.mojang.serialization.DataResult import com.mojang.serialization.DynamicOps import com.mojang.serialization.JsonOps -import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import net.minecraft.advancements.AdvancementHolder import net.minecraft.data.recipes.FinishedRecipe import net.minecraft.network.FriendlyByteBuf import net.minecraft.resources.ResourceLocation @@ -24,15 +21,7 @@ import ru.dbotthepony.mc.otm.core.util.readBinaryJsonWithCodecIndirect import ru.dbotthepony.mc.otm.core.util.writeBinaryJsonWithCodec import kotlin.collections.ArrayDeque import kotlin.concurrent.getOrSet -import kotlin.reflect.KProperty -/** - * 1.20.2: Mojang FINALLY moved json IO of recipes to codecs - * - * ...but they forgot to do the same for Networking them, Ingredient does not have codec for network. - * - * Mojang.... Mojang never changes. - */ class Codec2RecipeSerializer>( val empty: S?, codec: (Codec2RecipeSerializer.Context) -> Codec, @@ -40,45 +29,15 @@ class Codec2RecipeSerializer>( constructor(supplier: (Codec2RecipeSerializer.Context) -> Codec) : this(null, supplier) private class CurrentContext { + val idStack = ArrayDeque() var isNetwork = 0 } inner class Context { + val id: ResourceLocation + get() = checkNotNull(context.idStack.lastOrNull()) { "Not currently deserializing recipe" } + val ingredients: Codec get() = ActualIngredientCodec - - fun

> wrap(serializer: RecipeSerializer

): Codec

{ - return object : Codec

{ - override fun encode(input: P, ops: DynamicOps, prefix: T): DataResult { - if (context.isNetwork > 0) { - val parent = Unpooled.buffer() - val buff = FriendlyByteBuf(parent) - serializer.toNetwork(buff, input) - return DataResult.success(ops.createByteList(parent.nioBuffer())) - } else { - return serializer.codec().encode(input, ops, prefix) - } - } - - override fun decode(ops: DynamicOps, input: T): DataResult> { - if (context.isNetwork > 0) { - return ops.getByteBuffer(input).flatMap { - val parent = Unpooled.buffer() - val buff = FriendlyByteBuf(parent) - parent.writeBytes(it) - parent.setIndex(0, 0) - val read = serializer.fromNetwork(buff) - - if (read == null) - DataResult.error { "Unable to read parent recipe from network" } - else - DataResult.success(Pair(read, ops.empty())) - } - } else { - return serializer.codec().decode(ops, input) - } - } - } - } } private val codec = codec.invoke(Context()) @@ -97,30 +56,45 @@ class Codec2RecipeSerializer>( } } - override fun codec(): Codec { - return this + override fun fromJson(id: ResourceLocation, data: JsonObject): S { + try { + context.idStack.addLast(id) + + return decode(JsonOps.INSTANCE, data).get().map( + { it.first }, + { empty ?: throw JsonSyntaxException("Failed to deserialize recipe from JSON: ${it.message()}") } + ) + } finally { + context.idStack.removeLast() + } } - override fun fromNetwork(data: FriendlyByteBuf): S? { + override fun fromNetwork(id: ResourceLocation, data: FriendlyByteBuf): S? { try { + context.idStack.addLast(id) context.isNetwork++ + return data.readBinaryJsonWithCodecIndirect(this) - .resultOrPartial { LOGGER.error("Failed to read recipe from network: $it") }.orElse(null) + .resultOrPartial { LOGGER.error("Failed to read recipe $id from network: $it") }.orElse(null) } finally { context.isNetwork-- + context.idStack.removeLast() } } override fun toNetwork(data: FriendlyByteBuf, recipe: S) { try { + context.idStack.addLast(recipe.id) context.isNetwork++ + data.writeBinaryJsonWithCodec(this, recipe) } finally { context.isNetwork-- + context.idStack.removeLast() } } - fun toFinished(recipe: S, id: ResourceLocation): FinishedRecipe { + fun toFinished(recipe: S): FinishedRecipe { return object : FinishedRecipe { override fun serializeRecipeData(p_125967_: JsonObject) { encode(recipe, JsonOps.INSTANCE, p_125967_).get().map( @@ -137,15 +111,19 @@ class Codec2RecipeSerializer>( ) } - override fun id(): ResourceLocation { - return id + override fun getId(): ResourceLocation { + return recipe.id } - override fun type(): RecipeSerializer<*> { + override fun getType(): RecipeSerializer<*> { return this@Codec2RecipeSerializer } - override fun advancement(): AdvancementHolder? { + override fun serializeAdvancement(): JsonObject? { + return null + } + + override fun getAdvancementId(): ResourceLocation? { return null } } @@ -156,7 +134,7 @@ class Codec2RecipeSerializer>( return if (context.isNetwork > 0) { networkIngredientCodec.encode(input, ops, prefix) } else { - Ingredient.CODEC.encode(input, ops, prefix) + IngredientCodec.encode(input, ops, prefix) } } @@ -164,7 +142,7 @@ class Codec2RecipeSerializer>( return if (context.isNetwork > 0) { networkIngredientCodec.decode(ops, input) } else { - Ingredient.CODEC.decode(ops, input) + IngredientCodec.decode(ops, input) } } } @@ -178,14 +156,8 @@ class Codec2RecipeSerializer>( * since RecipeSerializers are expected to be stateless. [Codec2RecipeSerializer], however, is stateful (threading PoV). * To make it stateless, [ThreadLocal] is used. */ - private val context by object : ThreadLocal() { - override fun initialValue(): CurrentContext { - return CurrentContext() - } - } + private val contextHolder = ThreadLocal() + private val context: CurrentContext + get() = contextHolder.getOrSet { CurrentContext() } } } - -private operator fun ThreadLocal.getValue(companion: Codec2RecipeSerializer.Companion, property: KProperty<*>): T { - return get() -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/IngredientCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/IngredientCodec.kt new file mode 100644 index 000000000..27c18ade8 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/IngredientCodec.kt @@ -0,0 +1,23 @@ +package ru.dbotthepony.mc.otm.data + +import com.google.gson.JsonSyntaxException +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 net.minecraft.world.item.crafting.Ingredient + +object IngredientCodec : Codec { + override fun encode(input: Ingredient, ops: DynamicOps, prefix: T): DataResult { + return DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.toJson())) + } + + override fun decode(ops: DynamicOps, input: T): DataResult> { + try { + return DataResult.success(Pair(Ingredient.fromJson(ops.convertTo(JsonOps.INSTANCE, input)), ops.empty())) + } catch (err: JsonSyntaxException) { + return DataResult.error { "Error decoding Ingredient: ${err.message}" } + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt index 7b69da821..72d34340a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt @@ -5,12 +5,11 @@ import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer import net.minecraft.world.entity.Entity import net.minecraft.world.entity.player.Player -import net.minecraftforge.event.network.CustomPayloadEvent -import net.minecraftforge.network.Channel -import net.minecraftforge.network.ChannelBuilder import net.minecraftforge.network.NetworkDirection +import net.minecraftforge.network.NetworkEvent +import net.minecraftforge.network.NetworkRegistry import net.minecraftforge.network.PacketDistributor -import net.minecraftforge.network.SimpleChannel +import net.minecraftforge.network.simple.SimpleChannel import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER import ru.dbotthepony.mc.otm.OverdriveThatMatters @@ -20,6 +19,7 @@ import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.locks.LockSupport import java.util.function.BiConsumer import java.util.function.Function +import java.util.function.Supplier import kotlin.reflect.KClass class MNetworkContext(val sender: ServerPlayer?, packetHandled: GetterSetter, private val enqueuer: (Runnable) -> CompletableFuture<*>) { @@ -36,23 +36,20 @@ interface MatteryPacket { } abstract class MatteryNetworkChannel(val version: Int, val name: String) { - val channel: SimpleChannel = ChannelBuilder - .named(ResourceLocation(OverdriveThatMatters.MOD_ID, name)) - .acceptedVersions(Channel.VersionTest.exact(version)) - .networkProtocolVersion(version) - .simpleChannel() + val channel: SimpleChannel = NetworkRegistry + .newSimpleChannel(ResourceLocation(OverdriveThatMatters.MOD_ID, name), version::toString, String::equals, String::equals) - fun sendToServer(packet: Any) = channel.send(packet, PacketDistributor.SERVER.noArg()) + fun sendToServer(packet: Any) = channel.send(PacketDistributor.SERVER.noArg(), packet) fun send(ply: Player, packet: Any) { if (ply is ServerPlayer) { - queue.add(Task(channel, PacketDistributor.PLAYER.with(ply), packet)) + queue.add(Task(channel, PacketDistributor.PLAYER.with { ply }, packet)) } } fun sendNow(ply: Player, packet: Any) { if (ply is ServerPlayer) { - channel.send(packet, PacketDistributor.PLAYER.with(ply)) + channel.send(PacketDistributor.PLAYER.with { ply }, packet) } } @@ -61,7 +58,7 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) { return } - queue.add(Task(channel, PacketDistributor.TRACKING_ENTITY.with(entity), packet)) + queue.add(Task(channel, PacketDistributor.TRACKING_ENTITY.with { entity }, packet)) } fun sendTrackingAndSelf(entity: Entity, packet: Any) { @@ -69,7 +66,7 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) { return } - queue.add(Task(channel, PacketDistributor.TRACKING_ENTITY_AND_SELF.with(entity), packet)) + queue.add(Task(channel, PacketDistributor.TRACKING_ENTITY_AND_SELF.with { entity }, packet)) } fun send(distributor: PacketDistributor.PacketTarget, packet: Any) { @@ -77,7 +74,7 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) { } fun sendNow(distributor: PacketDistributor.PacketTarget, packet: Any) { - channel.send(packet, distributor) + channel.send(distributor, packet) } private var nextNetworkPacketID = 0 @@ -94,8 +91,8 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) { throw IndexOutOfBoundsException("Network message ID overflow!") } - val builder = channel.messageBuilder(packetClass, direction) - val bridgeHandler = BiConsumer { a, b -> handler(a, MNetworkContext(b.sender, GetterSetter.of({ b.packetHandled }, { b.packetHandled = it }), b::enqueueWork)) } + val builder = channel.messageBuilder(packetClass, nextNetworkPacketID++) + val bridgeHandler = BiConsumer> { a, b -> handler(a, MNetworkContext(b.get().sender, GetterSetter.of({ b.get().packetHandled }, { b.get().packetHandled = it }), b.get()::enqueueWork)) } if (handleOnMainThread) { builder.consumerMainThread(bridgeHandler) @@ -154,7 +151,7 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) { LockSupport.park() } else { try { - task.channel.send(task.packet, task.target) + task.channel.send(task.target, task.packet) } catch(err: Throwable) { logger.error("Error executing network dispatcher task", err) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/ExplosiveHammerPrimingRecipe.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/ExplosiveHammerPrimingRecipe.kt index 884138e00..5349dc5f7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/ExplosiveHammerPrimingRecipe.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/ExplosiveHammerPrimingRecipe.kt @@ -1,12 +1,8 @@ package ru.dbotthepony.mc.otm.recipe -import com.google.gson.JsonObject -import com.google.gson.JsonSyntaxException import com.mojang.serialization.codecs.RecordCodecBuilder import net.minecraft.core.NonNullList import net.minecraft.core.RegistryAccess -import net.minecraft.data.recipes.FinishedRecipe -import net.minecraft.network.FriendlyByteBuf import net.minecraft.resources.ResourceLocation import net.minecraft.world.inventory.CraftingContainer import net.minecraft.world.item.ItemStack @@ -19,12 +15,15 @@ import net.minecraftforge.common.Tags import ru.dbotthepony.mc.otm.container.util.stream import ru.dbotthepony.mc.otm.core.isActuallyEmpty import ru.dbotthepony.mc.otm.core.isNotEmpty -import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.data.Codec2RecipeSerializer import ru.dbotthepony.mc.otm.item.tool.ExplosiveHammerItem import ru.dbotthepony.mc.otm.registry.MItems -class ExplosiveHammerPrimingRecipe(val payload: Ingredient) : CraftingRecipe { +class ExplosiveHammerPrimingRecipe(val payload: Ingredient, val id: ResourceLocation) : CraftingRecipe { + override fun getId(): ResourceLocation { + return id + } + override fun isIncomplete(): Boolean { return payload.isActuallyEmpty } @@ -70,14 +69,14 @@ class ExplosiveHammerPrimingRecipe(val payload: Ingredient) : CraftingRecipe { return NonNullList.of(Ingredient.of(), Ingredient.of(MItems.EXPLOSIVE_HAMMER), Ingredient.of(Tags.Items.GUNPOWDER), payload) } - fun toFinished(id: ResourceLocation) = CODEC.toFinished(this, id) + fun toFinished() = CODEC.toFinished(this) companion object { val CODEC = Codec2RecipeSerializer { p -> RecordCodecBuilder.create { it.group( p.ingredients.fieldOf("payload").forGetter(ExplosiveHammerPrimingRecipe::payload) - ).apply(it, ::ExplosiveHammerPrimingRecipe) + ).apply(it) { a -> ExplosiveHammerPrimingRecipe(a, p.id) } } } }