More backporting

This commit is contained in:
DBotThePony 2023-12-31 18:23:07 +07:00
parent f16483d7c0
commit 3c5ea937a5
Signed by: DBot
GPG Key ID: DCC23B5715498507
8 changed files with 87 additions and 95 deletions

View File

@ -531,7 +531,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
super.onJobTick(status) super.onJobTick(status)
if (isExopackVisible && ply.level().random.nextFloat() <= 0.05f) { 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))
} }
} }

View File

@ -564,7 +564,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
return super.mouseReleased(p_97812_, p_97813_, p_97814_) 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) { for (panel in panels) {
if (panel.mouseScrolledChecked(mouseX, mouseY, scrollY)) { if (panel.mouseScrolledChecked(mouseX, mouseY, scrollY)) {
return true return true
@ -647,7 +647,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
val mouseYf = mouseY.toFloat() val mouseYf = mouseY.toFloat()
// dark background // dark background
this.renderBackground(graphics, mouseX, mouseY, partialTick) this.renderBackground(graphics)
super.hoveredSlot = null super.hoveredSlot = null
var hovered = false var hovered = false

View File

@ -32,6 +32,7 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.map import ru.dbotthepony.mc.otm.core.map
import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.core.util.CreativeMenuItemComparator import ru.dbotthepony.mc.otm.core.util.CreativeMenuItemComparator
import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu
class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) : MatteryScreen<PainterMenu>(menu, inventory, title) { class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) : MatteryScreen<PainterMenu>(menu, inventory, title) {

View File

@ -108,7 +108,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
return this@EditablePanel.mouseDragged(p_94740_, p_94741_, p_94742_, p_94743_, p_94744_) 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) return this@EditablePanel.mouseScrolled(mouseX, mouseY, scrollY)
} }

View File

@ -8,9 +8,6 @@ import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult import com.mojang.serialization.DataResult
import com.mojang.serialization.DynamicOps import com.mojang.serialization.DynamicOps
import com.mojang.serialization.JsonOps 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.data.recipes.FinishedRecipe
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation 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 ru.dbotthepony.mc.otm.core.util.writeBinaryJsonWithCodec
import kotlin.collections.ArrayDeque import kotlin.collections.ArrayDeque
import kotlin.concurrent.getOrSet 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<S : Recipe<*>>( class Codec2RecipeSerializer<S : Recipe<*>>(
val empty: S?, val empty: S?,
codec: (Codec2RecipeSerializer<S>.Context) -> Codec<S>, codec: (Codec2RecipeSerializer<S>.Context) -> Codec<S>,
@ -40,45 +29,15 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
constructor(supplier: (Codec2RecipeSerializer<S>.Context) -> Codec<S>) : this(null, supplier) constructor(supplier: (Codec2RecipeSerializer<S>.Context) -> Codec<S>) : this(null, supplier)
private class CurrentContext { private class CurrentContext {
val idStack = ArrayDeque<ResourceLocation>()
var isNetwork = 0 var isNetwork = 0
} }
inner class Context { inner class Context {
val id: ResourceLocation
get() = checkNotNull(context.idStack.lastOrNull()) { "Not currently deserializing recipe" }
val ingredients: Codec<Ingredient> get() = ActualIngredientCodec val ingredients: Codec<Ingredient> get() = ActualIngredientCodec
fun <P : Recipe<*>> wrap(serializer: RecipeSerializer<P>): Codec<P> {
return object : Codec<P> {
override fun <T : Any?> encode(input: P, ops: DynamicOps<T>, prefix: T): DataResult<T> {
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 <T : Any?> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<P, T>> {
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()) private val codec = codec.invoke(Context())
@ -97,30 +56,45 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
} }
} }
override fun codec(): Codec<S> { override fun fromJson(id: ResourceLocation, data: JsonObject): S {
return this 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 { try {
context.idStack.addLast(id)
context.isNetwork++ context.isNetwork++
return data.readBinaryJsonWithCodecIndirect(this) 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 { } finally {
context.isNetwork-- context.isNetwork--
context.idStack.removeLast()
} }
} }
override fun toNetwork(data: FriendlyByteBuf, recipe: S) { override fun toNetwork(data: FriendlyByteBuf, recipe: S) {
try { try {
context.idStack.addLast(recipe.id)
context.isNetwork++ context.isNetwork++
data.writeBinaryJsonWithCodec(this, recipe) data.writeBinaryJsonWithCodec(this, recipe)
} finally { } finally {
context.isNetwork-- context.isNetwork--
context.idStack.removeLast()
} }
} }
fun toFinished(recipe: S, id: ResourceLocation): FinishedRecipe { fun toFinished(recipe: S): FinishedRecipe {
return object : FinishedRecipe { return object : FinishedRecipe {
override fun serializeRecipeData(p_125967_: JsonObject) { override fun serializeRecipeData(p_125967_: JsonObject) {
encode(recipe, JsonOps.INSTANCE, p_125967_).get().map( encode(recipe, JsonOps.INSTANCE, p_125967_).get().map(
@ -137,15 +111,19 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
) )
} }
override fun id(): ResourceLocation { override fun getId(): ResourceLocation {
return id return recipe.id
} }
override fun type(): RecipeSerializer<*> { override fun getType(): RecipeSerializer<*> {
return this@Codec2RecipeSerializer return this@Codec2RecipeSerializer
} }
override fun advancement(): AdvancementHolder? { override fun serializeAdvancement(): JsonObject? {
return null
}
override fun getAdvancementId(): ResourceLocation? {
return null return null
} }
} }
@ -156,7 +134,7 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
return if (context.isNetwork > 0) { return if (context.isNetwork > 0) {
networkIngredientCodec.encode(input, ops, prefix) networkIngredientCodec.encode(input, ops, prefix)
} else { } else {
Ingredient.CODEC.encode(input, ops, prefix) IngredientCodec.encode(input, ops, prefix)
} }
} }
@ -164,7 +142,7 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
return if (context.isNetwork > 0) { return if (context.isNetwork > 0) {
networkIngredientCodec.decode(ops, input) networkIngredientCodec.decode(ops, input)
} else { } else {
Ingredient.CODEC.decode(ops, input) IngredientCodec.decode(ops, input)
} }
} }
} }
@ -178,14 +156,8 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
* since RecipeSerializers are expected to be stateless. [Codec2RecipeSerializer], however, is stateful (threading PoV). * since RecipeSerializers are expected to be stateless. [Codec2RecipeSerializer], however, is stateful (threading PoV).
* To make it stateless, [ThreadLocal] is used. * To make it stateless, [ThreadLocal] is used.
*/ */
private val context by object : ThreadLocal<CurrentContext>() { private val contextHolder = ThreadLocal<CurrentContext>()
override fun initialValue(): CurrentContext { private val context: CurrentContext
return CurrentContext() get() = contextHolder.getOrSet { CurrentContext() }
}
}
} }
} }
private operator fun <T> ThreadLocal<T>.getValue(companion: Codec2RecipeSerializer.Companion, property: KProperty<*>): T {
return get()
}

View File

@ -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<Ingredient> {
override fun <T : Any> encode(input: Ingredient, ops: DynamicOps<T>, prefix: T): DataResult<T> {
return DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.toJson()))
}
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<Ingredient, T>> {
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}" }
}
}
}

View File

@ -5,12 +5,11 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player 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.NetworkDirection
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.NetworkRegistry
import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor
import net.minecraftforge.network.SimpleChannel import net.minecraftforge.network.simple.SimpleChannel
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
@ -20,6 +19,7 @@ import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.locks.LockSupport import java.util.concurrent.locks.LockSupport
import java.util.function.BiConsumer import java.util.function.BiConsumer
import java.util.function.Function import java.util.function.Function
import java.util.function.Supplier
import kotlin.reflect.KClass import kotlin.reflect.KClass
class MNetworkContext(val sender: ServerPlayer?, packetHandled: GetterSetter<Boolean>, private val enqueuer: (Runnable) -> CompletableFuture<*>) { class MNetworkContext(val sender: ServerPlayer?, packetHandled: GetterSetter<Boolean>, private val enqueuer: (Runnable) -> CompletableFuture<*>) {
@ -36,23 +36,20 @@ interface MatteryPacket {
} }
abstract class MatteryNetworkChannel(val version: Int, val name: String) { abstract class MatteryNetworkChannel(val version: Int, val name: String) {
val channel: SimpleChannel = ChannelBuilder val channel: SimpleChannel = NetworkRegistry
.named(ResourceLocation(OverdriveThatMatters.MOD_ID, name)) .newSimpleChannel(ResourceLocation(OverdriveThatMatters.MOD_ID, name), version::toString, String::equals, String::equals)
.acceptedVersions(Channel.VersionTest.exact(version))
.networkProtocolVersion(version)
.simpleChannel()
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) { fun send(ply: Player, packet: Any) {
if (ply is ServerPlayer) { 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) { fun sendNow(ply: Player, packet: Any) {
if (ply is ServerPlayer) { 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 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) { fun sendTrackingAndSelf(entity: Entity, packet: Any) {
@ -69,7 +66,7 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) {
return 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) { 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) { fun sendNow(distributor: PacketDistributor.PacketTarget, packet: Any) {
channel.send(packet, distributor) channel.send(distributor, packet)
} }
private var nextNetworkPacketID = 0 private var nextNetworkPacketID = 0
@ -94,8 +91,8 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) {
throw IndexOutOfBoundsException("Network message ID overflow!") throw IndexOutOfBoundsException("Network message ID overflow!")
} }
val builder = channel.messageBuilder(packetClass, direction) val builder = channel.messageBuilder(packetClass, nextNetworkPacketID++)
val bridgeHandler = BiConsumer<T, CustomPayloadEvent.Context> { a, b -> handler(a, MNetworkContext(b.sender, GetterSetter.of({ b.packetHandled }, { b.packetHandled = it }), b::enqueueWork)) } val bridgeHandler = BiConsumer<T, Supplier<NetworkEvent.Context>> { a, b -> handler(a, MNetworkContext(b.get().sender, GetterSetter.of({ b.get().packetHandled }, { b.get().packetHandled = it }), b.get()::enqueueWork)) }
if (handleOnMainThread) { if (handleOnMainThread) {
builder.consumerMainThread(bridgeHandler) builder.consumerMainThread(bridgeHandler)
@ -154,7 +151,7 @@ abstract class MatteryNetworkChannel(val version: Int, val name: String) {
LockSupport.park() LockSupport.park()
} else { } else {
try { try {
task.channel.send(task.packet, task.target) task.channel.send(task.target, task.packet)
} catch(err: Throwable) { } catch(err: Throwable) {
logger.error("Error executing network dispatcher task", err) logger.error("Error executing network dispatcher task", err)
} }

View File

@ -1,12 +1,8 @@
package ru.dbotthepony.mc.otm.recipe package ru.dbotthepony.mc.otm.recipe
import com.google.gson.JsonObject
import com.google.gson.JsonSyntaxException
import com.mojang.serialization.codecs.RecordCodecBuilder import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.NonNullList import net.minecraft.core.NonNullList
import net.minecraft.core.RegistryAccess import net.minecraft.core.RegistryAccess
import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.world.inventory.CraftingContainer import net.minecraft.world.inventory.CraftingContainer
import net.minecraft.world.item.ItemStack 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.container.util.stream
import ru.dbotthepony.mc.otm.core.isActuallyEmpty import ru.dbotthepony.mc.otm.core.isActuallyEmpty
import ru.dbotthepony.mc.otm.core.isNotEmpty 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.data.Codec2RecipeSerializer
import ru.dbotthepony.mc.otm.item.tool.ExplosiveHammerItem import ru.dbotthepony.mc.otm.item.tool.ExplosiveHammerItem
import ru.dbotthepony.mc.otm.registry.MItems 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 { override fun isIncomplete(): Boolean {
return payload.isActuallyEmpty 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) 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 { companion object {
val CODEC = Codec2RecipeSerializer<ExplosiveHammerPrimingRecipe> { p -> val CODEC = Codec2RecipeSerializer<ExplosiveHammerPrimingRecipe> { p ->
RecordCodecBuilder.create { RecordCodecBuilder.create {
it.group( it.group(
p.ingredients.fieldOf("payload").forGetter(ExplosiveHammerPrimingRecipe::payload) p.ingredients.fieldOf("payload").forGetter(ExplosiveHammerPrimingRecipe::payload)
).apply(it, ::ExplosiveHammerPrimingRecipe) ).apply(it) { a -> ExplosiveHammerPrimingRecipe(a, p.id) }
} }
} }
} }