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)
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_)
}
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<T : MatteryMenu>(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

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.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<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_)
}
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)
}

View File

@ -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<S : Recipe<*>>(
val empty: 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)
private class CurrentContext {
val idStack = ArrayDeque<ResourceLocation>()
var isNetwork = 0
}
inner class Context {
val id: ResourceLocation
get() = checkNotNull(context.idStack.lastOrNull()) { "Not currently deserializing recipe" }
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())
@ -97,30 +56,45 @@ class Codec2RecipeSerializer<S : Recipe<*>>(
}
}
override fun codec(): Codec<S> {
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<S : Recipe<*>>(
)
}
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<S : Recipe<*>>(
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<S : Recipe<*>>(
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<S : Recipe<*>>(
* 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<CurrentContext>() {
override fun initialValue(): CurrentContext {
return CurrentContext()
}
}
private val contextHolder = ThreadLocal<CurrentContext>()
private val context: 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.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<Boolean>, 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<T, CustomPayloadEvent.Context> { 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<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) {
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)
}

View File

@ -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<ExplosiveHammerPrimingRecipe> { p ->
RecordCodecBuilder.create {
it.group(
p.ingredients.fieldOf("payload").forGetter(ExplosiveHammerPrimingRecipe::payload)
).apply(it, ::ExplosiveHammerPrimingRecipe)
).apply(it) { a -> ExplosiveHammerPrimingRecipe(a, p.id) }
}
}
}