From 8e9f5fa1411dd00aea9a2794fd0b4909e9c61049 Mon Sep 17 00:00:00 2001 From: FlorianMichael <60033407+FlorianMichael@users.noreply.github.com> Date: Sun, 1 Oct 2023 20:22:56 +0200 Subject: [PATCH] Implemented packet syncing correctly. --- .../ClientPlayerInteractionManager1_18_2.java | 17 ++++++++ .../definition/ClientsideFixes.java | 40 +++++++++++++++++++ .../definition/TripleChestHandler1_13_2.java | 14 +++++++ .../MixinClientCommonNetworkHandler.java | 14 ++++++- .../MixinInventoryPackets.java | 13 ++++-- .../MixinWorldPackets.java | 17 +++----- 6 files changed, 98 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/florianmichael/viafabricplus/definition/ClientPlayerInteractionManager1_18_2.java b/src/main/java/de/florianmichael/viafabricplus/definition/ClientPlayerInteractionManager1_18_2.java index 39b054a7..8a02e0c4 100644 --- a/src/main/java/de/florianmichael/viafabricplus/definition/ClientPlayerInteractionManager1_18_2.java +++ b/src/main/java/de/florianmichael/viafabricplus/definition/ClientPlayerInteractionManager1_18_2.java @@ -19,9 +19,12 @@ package de.florianmichael.viafabricplus.definition; import de.florianmichael.viafabricplus.ViaFabricPlus; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; +import de.florianmichael.viafabricplus.protocolhack.util.BlockStateTranslator; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; +import net.minecraft.network.PacketByteBuf; import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; import net.minecraft.util.Pair; import net.minecraft.util.math.BlockPos; @@ -29,8 +32,22 @@ import net.minecraft.util.math.Vec2f; import net.raphimc.vialoader.util.VersionEnum; import java.util.Objects; +import java.util.function.Consumer; public class ClientPlayerInteractionManager1_18_2 { + public final static Consumer OLD_PACKET_HANDLER = data -> { + try { + final var pos = data.readBlockPos(); + final var blockState = Block.STATE_IDS.get(BlockStateTranslator.translateBlockState1_18(data.readVarInt())); + final var action = data.readEnumConstant(PlayerActionC2SPacket.Action.class); + final var allGood = data.readBoolean(); + + ClientPlayerInteractionManager1_18_2.handleBlockBreakAck(pos, blockState, action, allGood); + } catch (Exception e) { + ViaFabricPlus.LOGGER.error("Failed to read BlockBreakAck packet data", e); + } + }; + private final static Object2ObjectLinkedOpenHashMap, PositionAndRotation> UN_ACKED_ACTIONS = new Object2ObjectLinkedOpenHashMap<>(); public static void trackBlockAction(final PlayerActionC2SPacket.Action action, final BlockPos blockPos) { diff --git a/src/main/java/de/florianmichael/viafabricplus/definition/ClientsideFixes.java b/src/main/java/de/florianmichael/viafabricplus/definition/ClientsideFixes.java index cc8bf721..735f6e87 100644 --- a/src/main/java/de/florianmichael/viafabricplus/definition/ClientsideFixes.java +++ b/src/main/java/de/florianmichael/viafabricplus/definition/ClientsideFixes.java @@ -31,12 +31,15 @@ import net.minecraft.client.font.FontStorage; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.network.PacketByteBuf; import net.minecraft.registry.Registries; 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; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; /** * This class contains random fields and methods that are used to fix bugs on the client side @@ -58,6 +61,16 @@ public class ClientsideFixes { */ private final static Map LEGACY_ARMOR_POINTS = new HashMap<>(); + /** + * Contains all tasks that are waiting for a packet to be received, this system can be used to sync ViaVersion tasks with the correct thread + */ + private final static Map> PENDING_EXECUTION_TASKS = new ConcurrentHashMap<>(); + + /** + * This identifier is an internal identifier that is used to identify packets that are sent by ViaFabricPlus + */ + public final static String PACKET_SYNC_IDENTIFIER = UUID.randomUUID() + ":" + UUID.randomUUID(); + /** * The current chat limit */ @@ -123,6 +136,33 @@ public class ClientsideFixes { }); } + /** + * Executes a sync task and returns the uuid of the task + * + * @param task The task to execute + * @return The uuid of the task + */ + public static String executeSyncTask(final Consumer task) { + final var uuid = UUID.randomUUID().toString(); + PENDING_EXECUTION_TASKS.put(uuid, task); + return uuid; + } + + public static void handleSyncTask(final PacketByteBuf buf) { + buf.resetReaderIndex(); + + final var uuid = buf.readString(); + + if (PENDING_EXECUTION_TASKS.containsKey(uuid)) { + MinecraftClient.getInstance().execute(() -> { // Execute the task on the main thread + final var task = PENDING_EXECUTION_TASKS.get(uuid); + PENDING_EXECUTION_TASKS.remove(uuid); + + task.accept(buf); + }); + } + } + /** * Returns the armor points of an armor item in legacy versions (<= 1.8.x) * diff --git a/src/main/java/de/florianmichael/viafabricplus/definition/TripleChestHandler1_13_2.java b/src/main/java/de/florianmichael/viafabricplus/definition/TripleChestHandler1_13_2.java index 25850b0e..d49e6bad 100644 --- a/src/main/java/de/florianmichael/viafabricplus/definition/TripleChestHandler1_13_2.java +++ b/src/main/java/de/florianmichael/viafabricplus/definition/TripleChestHandler1_13_2.java @@ -17,9 +17,12 @@ */ package de.florianmichael.viafabricplus.definition; +import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.libs.gson.JsonElement; +import de.florianmichael.viafabricplus.ViaFabricPlus; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ingame.HandledScreens; +import net.minecraft.network.PacketByteBuf; import net.minecraft.resource.featuretoggle.FeatureFlags; import net.minecraft.resource.featuretoggle.FeatureSet; import net.minecraft.screen.GenericContainerScreenHandler; @@ -27,8 +30,19 @@ import net.minecraft.screen.ScreenHandlerType; import net.minecraft.text.Text; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; public class TripleChestHandler1_13_2 { + public final static Consumer TRIPLE_CHEST_HANDLER = data -> { + final var byteBuf = data.asByteBuf(); + + try { + TripleChestHandler1_13_2.handleTripleChestHandler(Type.SHORT.readPrimitive(byteBuf), Type.COMPONENT.read(byteBuf), Type.SHORT.readPrimitive(byteBuf)); + } catch (Exception e) { + ViaFabricPlus.LOGGER.error("Failed to open custom ScreenHandler with dimension 9xN", e); + } + }; + public static void handleTripleChestHandler(final short windowID, final JsonElement title, final short slots) { int n = slots / 9; final int modulo = slots % 9; diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/network/MixinClientCommonNetworkHandler.java b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/network/MixinClientCommonNetworkHandler.java index a9fd7a5d..bd0fe4ff 100644 --- a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/network/MixinClientCommonNetworkHandler.java +++ b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/network/MixinClientCommonNetworkHandler.java @@ -17,12 +17,15 @@ */ package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft.network; +import de.florianmichael.viafabricplus.definition.ClientsideFixes; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; +import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientCommonNetworkHandler; import net.minecraft.network.listener.ServerPacketListener; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.s2c.common.CommonPingS2CPacket; +import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket; import net.minecraft.screen.ScreenHandler; import net.raphimc.vialoader.util.VersionEnum; import org.spongepowered.asm.mixin.Final; @@ -37,10 +40,9 @@ import java.time.Duration; import java.util.function.BooleanSupplier; @SuppressWarnings("UnstableApiUsage") -@Mixin(ClientCommonNetworkHandler.class) +@Mixin(value = ClientCommonNetworkHandler.class, priority = 1 /* Has to be applied before Fabric's Networking API, so it doesn't cancel our custom-payload packets */) public abstract class MixinClientCommonNetworkHandler { - @Shadow @Final protected MinecraftClient client; @Shadow protected abstract void send(Packet packet, BooleanSupplier sendCondition, Duration expiry); @@ -73,4 +75,12 @@ public abstract class MixinClientCommonNetworkHandler { send(packet, sendCondition, expiry); } + + @Inject(method = "onCustomPayload(Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;)V", at = @At("HEAD"), cancellable = true) + public void handleSyncTask(CustomPayloadS2CPacket packet, CallbackInfo ci) { + if (packet.payload().id().toString().equals(ClientsideFixes.PACKET_SYNC_IDENTIFIER) && packet.payload() instanceof PacketByteBufPayload payload) { + ClientsideFixes.handleSyncTask(payload.data()); + ci.cancel(); // Cancel the packet, so it doesn't get processed by the client + } + } } diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/viaversion/protocol1_14to1_13_2/MixinInventoryPackets.java b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/viaversion/protocol1_14to1_13_2/MixinInventoryPackets.java index 0c8a1e03..81ab048c 100644 --- a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/viaversion/protocol1_14to1_13_2/MixinInventoryPackets.java +++ b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/viaversion/protocol1_14to1_13_2/MixinInventoryPackets.java @@ -27,11 +27,11 @@ import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.libs.gson.JsonElement; import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ClientboundPackets1_14; import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.packets.InventoryPackets; +import de.florianmichael.viafabricplus.definition.ClientsideFixes; import de.florianmichael.viafabricplus.definition.TripleChestHandler1_13_2; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; import io.netty.buffer.Unpooled; import net.minecraft.SharedConstants; -import net.minecraft.client.MinecraftClient; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -48,7 +48,9 @@ public class MixinInventoryPackets { @Inject(method = "lambda$registerPackets$0", at = @At(value = "INVOKE", target = "Ljava/util/logging/Logger;warning(Ljava/lang/String;)V"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) private static void supportCustomSlots(PacketWrapper wrapper, CallbackInfo ci, Short windowId, String type, JsonElement title, Short slots, int typeId) { if (typeId == -1) { - wrapper.cancel(); + wrapper.clearPacket(); + wrapper.setPacketType(ClientboundPackets1_14.PLUGIN_MESSAGE); + wrapper.write(Type.STRING, ClientsideFixes.PACKET_SYNC_IDENTIFIER); final List protocolPath = Via.getManager().getProtocolManager().getProtocolPath(SharedConstants.getProtocolVersion(), ProtocolVersion.v1_13_2.getVersion()); final var userConnection = ProtocolHack.createFakerUserConnection(); @@ -63,9 +65,12 @@ public class MixinInventoryPackets { fakeOpenWindow.read(Type.VAR_INT); fakeOpenWindow.read(Type.VAR_INT); - final var remappedTitle = fakeOpenWindow.read(Type.COMPONENT); + final String uuid = ClientsideFixes.executeSyncTask(TripleChestHandler1_13_2.TRIPLE_CHEST_HANDLER); - MinecraftClient.getInstance().executeSync(() -> TripleChestHandler1_13_2.handleTripleChestHandler(windowId, remappedTitle, slots)); + wrapper.write(Type.STRING, uuid); + wrapper.write(Type.SHORT, windowId); + wrapper.write(Type.COMPONENT, fakeOpenWindow.read(Type.COMPONENT)); + wrapper.write(Type.SHORT, slots); } catch (Exception e) { Via.getPlatform().getLogger().log(Level.SEVERE, "Failed to emulate Triple Chest", e); } diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/viaversion/protocol1_19to1_18_2/MixinWorldPackets.java b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/viaversion/protocol1_19to1_18_2/MixinWorldPackets.java index 9b35a700..c37a596d 100644 --- a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/viaversion/protocol1_19to1_18_2/MixinWorldPackets.java +++ b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/viaversion/protocol1_19to1_18_2/MixinWorldPackets.java @@ -25,11 +25,7 @@ import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPacke import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.Protocol1_19To1_18_2; import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.packets.WorldPackets; import de.florianmichael.viafabricplus.definition.ClientPlayerInteractionManager1_18_2; -import de.florianmichael.viafabricplus.protocolhack.util.BlockStateTranslator; -import net.minecraft.block.Block; -import net.minecraft.client.MinecraftClient; -import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; -import net.minecraft.util.math.BlockPos; +import de.florianmichael.viafabricplus.definition.ClientsideFixes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -40,17 +36,16 @@ public class MixinWorldPackets { @Redirect(method = "register", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/protocols/protocol1_19to1_18_2/Protocol1_19To1_18_2;cancelClientbound(Lcom/viaversion/viaversion/api/protocol/packet/ClientboundPacketType;)V")) private static void passAcknowledgePlayerDigging(Protocol1_19To1_18_2 instance, ClientboundPacketType clientboundPacketType) { instance.registerClientbound(ClientboundPackets1_18.ACKNOWLEDGE_PLAYER_DIGGING, ClientboundPackets1_19.PLUGIN_MESSAGE, wrapper -> { - wrapper.cancel(); if (wrapper.user().getProtocolInfo().getPipeline().contains(Protocol1_14_4To1_14_3.class)) { + wrapper.cancel(); return; } - final var pos = wrapper.read(Type.POSITION1_14); - final var blockState = Block.STATE_IDS.get(BlockStateTranslator.translateBlockState1_18(wrapper.read(Type.VAR_INT))); - final var action = PlayerActionC2SPacket.Action.values()[wrapper.read(Type.VAR_INT)]; - final var allGood = wrapper.read(Type.BOOLEAN); + wrapper.resetReader(); + final var uuid = ClientsideFixes.executeSyncTask(ClientPlayerInteractionManager1_18_2.OLD_PACKET_HANDLER); - MinecraftClient.getInstance().executeSync(() -> ClientPlayerInteractionManager1_18_2.handleBlockBreakAck(new BlockPos(pos.x(), pos.y(), pos.z()), blockState, action, allGood)); + wrapper.write(Type.STRING, ClientsideFixes.PACKET_SYNC_IDENTIFIER); + wrapper.write(Type.STRING, uuid); }); } }