From f445ecdd9e298e8b44bc17a244d63ef7d01260a6 Mon Sep 17 00:00:00 2001
From: FlorianMichael <60033407+FlorianMichael@users.noreply.github.com>
Date: Sun, 5 Nov 2023 16:30:38 +0100
Subject: [PATCH] Emulate crafting recipe results in <= 1.11.2
Fixed https://github.com/ViaVersion/ViaFabricPlus/issues/60
---
.../definition/ClientsideFixes.java | 29 +++++++++++
.../MixinCraftingScreenHandler.java | 50 +++++++++++++++++++
.../MixinPlayerScreenHandler.java | 26 +++++++---
src/main/resources/viafabricplus.mixins.json | 5 +-
4 files changed, 101 insertions(+), 9 deletions(-)
create mode 100644 src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/screen/screenhandler/MixinCraftingScreenHandler.java
diff --git a/src/main/java/de/florianmichael/viafabricplus/definition/ClientsideFixes.java b/src/main/java/de/florianmichael/viafabricplus/definition/ClientsideFixes.java
index 4a13c9065..c2c735390 100644
--- a/src/main/java/de/florianmichael/viafabricplus/definition/ClientsideFixes.java
+++ b/src/main/java/de/florianmichael/viafabricplus/definition/ClientsideFixes.java
@@ -28,11 +28,16 @@
import net.minecraft.block.Blocks;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.FontStorage;
+import net.minecraft.client.network.ClientPlayNetworkHandler;
+import net.minecraft.inventory.RecipeInputInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.network.PacketByteBuf;
+import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket;
+import net.minecraft.recipe.RecipeType;
import net.minecraft.registry.Registries;
+import net.minecraft.screen.ScreenHandler;
import net.raphimc.vialegacy.protocols.classic.protocolc0_28_30toc0_28_30cpe.data.ClassicProtocolExtension;
import net.raphimc.vialoader.util.VersionEnum;
import net.raphimc.vialoader.util.VersionRange;
@@ -175,6 +180,30 @@ public static int getLegacyArmorPoints(final ItemStack itemStack) {
return LEGACY_ARMOR_POINTS.get(itemStack.getItem());
}
+ /**
+ * Sets the result slot of a crafting screen handler to the correct item stack. In MC <= 1.11.2 the result slot
+ * is not updated when the input slots change, so we need to update it manually, Spigot and Paper re-syncs the slot,
+ * so we don't notice this bug on servers that use Spigot or Paper
+ *
+ * @param syncId The sync id of the screen handler
+ * @param screenHandler The screen handler
+ * @param inventory The inventory of the screen handler
+ */
+ public static void setCraftingResultSlot(final int syncId, final ScreenHandler screenHandler, final RecipeInputInventory inventory) {
+ final var network = MinecraftClient.getInstance().getNetworkHandler();
+ if (network == null) return;
+
+ final var world = MinecraftClient.getInstance().world;
+
+ final var result = network.getRecipeManager().
+ getFirstMatch(RecipeType.CRAFTING, inventory, world). // Get the first matching recipe
+ map(recipe -> recipe.value().craft(inventory, world.getRegistryManager())). // Craft the recipe to get the result
+ orElse(ItemStack.EMPTY); // If there is no recipe, set the result to air
+
+ // Update the result slot
+ network.onScreenHandlerSlotUpdate(new ScreenHandlerSlotUpdateS2CPacket(syncId, screenHandler.getRevision(), 0, result));
+ }
+
public static int getCurrentChatLimit() {
return currentChatLimit;
}
diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/screen/screenhandler/MixinCraftingScreenHandler.java b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/screen/screenhandler/MixinCraftingScreenHandler.java
new file mode 100644
index 000000000..883f9c3e6
--- /dev/null
+++ b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/screen/screenhandler/MixinCraftingScreenHandler.java
@@ -0,0 +1,50 @@
+/*
+ * This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
+ * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.screenhandler;
+
+import de.florianmichael.viafabricplus.definition.ClientsideFixes;
+import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
+import net.minecraft.inventory.Inventory;
+import net.minecraft.inventory.RecipeInputInventory;
+import net.minecraft.screen.AbstractRecipeScreenHandler;
+import net.minecraft.screen.CraftingScreenHandler;
+import net.minecraft.screen.ScreenHandlerType;
+import net.raphimc.vialoader.util.VersionEnum;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(CraftingScreenHandler.class)
+public abstract class MixinCraftingScreenHandler extends AbstractRecipeScreenHandler {
+
+ @Shadow @Final private RecipeInputInventory input;
+
+ public MixinCraftingScreenHandler(ScreenHandlerType> screenHandlerType, int i) {
+ super(screenHandlerType, i);
+ }
+
+ @Inject(method = "onContentChanged", at = @At("HEAD"))
+ public void updateResultSlot(Inventory inventory, CallbackInfo ci) {
+ if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_11_1to1_11_2)) {
+ ClientsideFixes.setCraftingResultSlot(syncId, this, input);
+ }
+ }
+}
diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/screen/screenhandler/MixinPlayerScreenHandler.java b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/screen/screenhandler/MixinPlayerScreenHandler.java
index cafbb5d48..b0aca9c63 100644
--- a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/screen/screenhandler/MixinPlayerScreenHandler.java
+++ b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/screen/screenhandler/MixinPlayerScreenHandler.java
@@ -17,8 +17,10 @@
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.screen.screenhandler;
+import de.florianmichael.viafabricplus.definition.ClientsideFixes;
+import net.minecraft.inventory.Inventory;
+import net.minecraft.inventory.RecipeInputInventory;
import net.raphimc.vialoader.util.VersionEnum;
-import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.inventory.CraftingInventory;
@@ -26,15 +28,17 @@
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.screen.slot.Slot;
+import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.ModifyVariable;
-import org.spongepowered.asm.mixin.injection.Redirect;
-import org.spongepowered.asm.mixin.injection.Slice;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.*;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerScreenHandler.class)
public abstract class MixinPlayerScreenHandler extends AbstractRecipeScreenHandler {
+ @Shadow @Final private RecipeInputInventory craftingInput;
+
public MixinPlayerScreenHandler(ScreenHandlerType> screenHandlerType, int i) {
super(screenHandlerType, i);
}
@@ -51,9 +55,17 @@ private Slot redirectAddOffhandSlot(PlayerScreenHandler screenHandler, Slot slot
@SuppressWarnings("InvalidInjectorMethodSignature")
@ModifyVariable(method = "quickMove", ordinal = 0, at = @At(value = "STORE", ordinal = 0))
private EquipmentSlot injectTransferSlot(EquipmentSlot slot) {
- if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8) && slot == EquipmentSlot.OFFHAND)
+ if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_8) && slot == EquipmentSlot.OFFHAND) {
return EquipmentSlot.MAINHAND;
- else
+ } else {
return slot;
+ }
+ }
+
+ @Inject(method = "onContentChanged", at = @At("HEAD"))
+ public void updateResultSlot(Inventory inventory, CallbackInfo ci) {
+ if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_11_1to1_11_2)) {
+ ClientsideFixes.setCraftingResultSlot(syncId, this, craftingInput);
+ }
}
}
diff --git a/src/main/resources/viafabricplus.mixins.json b/src/main/resources/viafabricplus.mixins.json
index 471d0d7a9..e596dde9d 100644
--- a/src/main/resources/viafabricplus.mixins.json
+++ b/src/main/resources/viafabricplus.mixins.json
@@ -25,6 +25,7 @@
"compat.ipnext.MixinAutoRefillHandler_ItemSlotMonitor",
"compat.sodium.MixinChunkTracker",
"fixes.authlib.MixinKeyPairResponse",
+ "fixes.authlib.MixinYggdrasilUserApiService",
"fixes.minecraft.MixinBipedEntityModel",
"fixes.minecraft.MixinCamera",
"fixes.minecraft.MixinClientPlayerInteractionManager",
@@ -167,9 +168,9 @@
"fixes.viaversion.protocol1_9to1_8.MixinEntityPackets_6_1",
"fixes.viaversion.protocol1_9to1_8.MixinEntityTracker1_9",
"fixes.viaversion.protocol1_9to1_8.MixinMetadataRewriter1_9To1_8",
- "fixes.authlib.MixinYggdrasilUserApiService",
"jsonwebtoken.MixinClasses",
- "jsonwebtoken.MixinDefaultJwtParserBuilder"
+ "jsonwebtoken.MixinDefaultJwtParserBuilder",
+ "fixes.minecraft.screen.screenhandler.MixinCraftingScreenHandler"
],
"injectors": {
"defaultRequire": 1