diff --git a/src/main/java/de/florianmichael/viafabricplus/definition/v1_18_2/ClientPlayerInteractionManager1_18_2.java b/src/main/java/de/florianmichael/viafabricplus/definition/v1_18_2/ClientPlayerInteractionManager1_18_2.java new file mode 100644 index 00000000..c8b41a98 --- /dev/null +++ b/src/main/java/de/florianmichael/viafabricplus/definition/v1_18_2/ClientPlayerInteractionManager1_18_2.java @@ -0,0 +1,74 @@ +/* + * 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.definition.v1_18_2; + +import de.florianmichael.viafabricplus.ViaFabricPlus; +import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; +import net.minecraft.util.Pair; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec2f; +import net.raphimc.vialoader.util.VersionEnum; + +public class ClientPlayerInteractionManager1_18_2 { + private final static Object2ObjectLinkedOpenHashMap, PositionAndRotation> unAckedActions = new Object2ObjectLinkedOpenHashMap<>(); + + public final static String ACK_TRANSFORMER_IDENTIFIER = "viafabricplus:acknowledge_player_digging"; + + public static void trackBlockAction(final PlayerActionC2SPacket.Action action, final BlockPos blockPos) { + final var player = MinecraftClient.getInstance().player; + if (player == null) return; + + var rotation = new Vec2f(player.getYaw(), player.getPitch()); + if (ProtocolHack.getTargetVersion().isNewerThan(VersionEnum.r1_16_2)) { + rotation = null; + } + unAckedActions.put(new Pair<>(blockPos, action), new PositionAndRotation(player.getPos().x, player.getPos().y, player.getPos().z, rotation)); + } + + public static void handleBlockBreakAck(final ClientWorld world, final BlockPos blockPos, final BlockState blockState, final PlayerActionC2SPacket.Action action, final boolean allGood) { + final var player = MinecraftClient.getInstance().player; + if (player == null) return; + + final var next = unAckedActions.remove(new Pair<>(blockPos, action)); + final var blockStateFromPos = world.getBlockState(blockPos); + + if ((next == null || !allGood || action != PlayerActionC2SPacket.Action.START_DESTROY_BLOCK && blockStateFromPos != blockState) && blockStateFromPos != blockState) { + world.setBlockState(blockPos, blockState); + if (next != null && world == player.getWorld() && player.collidesWithStateAtPos(blockPos, blockState)) { + if (next.rotation != null) { + player.updatePositionAndAngles(next.x, next.y, next.z, next.rotation.x, next.rotation.y); + } else { + player.updatePosition(next.x, next.y, next.z); + } + } + } + + while (unAckedActions.size() >= 50) { + ViaFabricPlus.LOGGER.error("Too many unacked block actions, dropping {}", unAckedActions.firstKey()); + unAckedActions.removeFirst(); + } + } + + public record PositionAndRotation(double x, double y, double z, Vec2f rotation) { + } +} diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinClientPlayNetworkHandler.java b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinClientPlayNetworkHandler.java index 9c0b8537..464a4eb1 100644 --- a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinClientPlayNetworkHandler.java +++ b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinClientPlayNetworkHandler.java @@ -19,8 +19,12 @@ package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft; import com.llamalad7.mixinextras.injector.WrapWithCondition; import com.mojang.authlib.GameProfile; +import de.florianmichael.viafabricplus.definition.v1_18_2.ClientPlayerInteractionManager1_18_2; +import de.florianmichael.viafabricplus.protocolhack.usage.BlockStateTranslator; +import net.minecraft.block.Block; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; import net.raphimc.vialoader.util.VersionEnum; -import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import de.florianmichael.viafabricplus.ViaFabricPlus; import de.florianmichael.viafabricplus.base.settings.groups.VisualSettings; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; @@ -39,10 +43,7 @@ import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.s2c.play.*; import net.minecraft.screen.ScreenHandler; import org.slf4j.Logger; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -73,6 +74,8 @@ public abstract class MixinClientPlayNetworkHandler { @Shadow @Final private ClientConnection connection; + @Shadow private ClientWorld world; + @Inject(method = "", at = @At("RETURN")) public void fixPlayerListOrdering(MinecraftClient client, Screen screen, ClientConnection connection, ServerInfo serverInfo, GameProfile profile, WorldSession worldSession, CallbackInfo ci) { if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_19_1tor1_19_2)) { @@ -160,4 +163,21 @@ public abstract class MixinClientPlayNetworkHandler { ci.cancel(); } } + + @Inject(method = "onCustomPayload", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/util/thread/ThreadExecutor;)V", shift = At.Shift.AFTER), cancellable = true) + public void handlePseudoPackets(CustomPayloadS2CPacket packet, CallbackInfo ci) { + final var channel = packet.getChannel().toString(); + final var data = packet.getData(); + + if (channel.equals(ClientPlayerInteractionManager1_18_2.ACK_TRANSFORMER_IDENTIFIER)) { + 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(world, pos, blockState, action, allGood); + + ci.cancel(); + } + } } diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinClientPlayerInteractionManager.java b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinClientPlayerInteractionManager.java index 1551786f..f34604f9 100644 --- a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinClientPlayerInteractionManager.java +++ b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinClientPlayerInteractionManager.java @@ -21,6 +21,10 @@ import com.llamalad7.mixinextras.injector.WrapWithCondition; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import de.florianmichael.viafabricplus.definition.v1_18_2.ClientPlayerInteractionManager1_18_2; +import net.minecraft.client.network.SequencedPacketCreator; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; import net.raphimc.vialoader.util.VersionEnum; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ServerboundPackets1_16_2; @@ -131,7 +135,7 @@ public abstract class MixinClientPlayerInteractionManager { final byte button = (byte) clickSlot.getButton(); final short lastActionId = ((IScreenHandler) client.player.currentScreenHandler).viafabricplus_getAndIncrementLastActionId(); final int actionType = clickSlot.getActionType().ordinal(); - final Item item = ItemTranslator.minecraftToViaVersion(viaConnection, slotItemBeforeModification, VersionEnum.r1_16.getVersion()); + final Item item = ItemTranslator.minecraftToViaVersion(slotItemBeforeModification, VersionEnum.r1_16.getVersion()); viaConnection.getChannel().eventLoop().submit(() -> { final PacketWrapper clickSlotPacket = PacketWrapper.create(ServerboundPackets1_16_2.CLICK_WINDOW, viaConnection); @@ -194,4 +198,11 @@ public abstract class MixinClientPlayerInteractionManager { } return interactBlockInternal(player, hand, hitResult); } + + @Inject(method = "sendSequencedPacket", at = @At("HEAD")) + public void handleBlockAcknowledgements(ClientWorld world, SequencedPacketCreator packetCreator, CallbackInfo ci) { + if (ProtocolHack.getTargetVersion().isBetweenInclusive(VersionEnum.r1_18_2, VersionEnum.r1_14_4) && packetCreator instanceof PlayerActionC2SPacket playerActionC2SPacket) { + ClientPlayerInteractionManager1_18_2.trackBlockAction(playerActionC2SPacket.getAction(), playerActionC2SPacket.getPos()); + } + } } 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 new file mode 100644 index 00000000..86b60330 --- /dev/null +++ b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/viaversion/protocol1_19to1_18_2/MixinWorldPackets.java @@ -0,0 +1,47 @@ +/* + * 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.viaversion.protocol1_19to1_18_2; + +import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.protocols.protocol1_14_4to1_14_3.Protocol1_14_4To1_14_3; +import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.ClientboundPackets1_18; +import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPackets1_19; +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.v1_18_2.ClientPlayerInteractionManager1_18_2; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = WorldPackets.class, remap = false) +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 -> { + if (wrapper.user().getProtocolInfo().getPipeline().contains(Protocol1_14_4To1_14_3.class)) { + wrapper.cancel(); + return; + } + + wrapper.resetReader(); + wrapper.write(Type.STRING, ClientPlayerInteractionManager1_18_2.ACK_TRANSFORMER_IDENTIFIER); + }); + } +} diff --git a/src/main/java/de/florianmichael/viafabricplus/protocolhack/provider/viaversion/ViaFabricPlusHandItemProvider.java b/src/main/java/de/florianmichael/viafabricplus/protocolhack/provider/viaversion/ViaFabricPlusHandItemProvider.java index 773ebc58..83ce6a51 100644 --- a/src/main/java/de/florianmichael/viafabricplus/protocolhack/provider/viaversion/ViaFabricPlusHandItemProvider.java +++ b/src/main/java/de/florianmichael/viafabricplus/protocolhack/provider/viaversion/ViaFabricPlusHandItemProvider.java @@ -20,7 +20,6 @@ package de.florianmichael.viafabricplus.protocolhack.provider.viaversion; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.minecraft.item.Item; import net.raphimc.vialoader.util.VersionEnum; -import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.HandItemProvider; import de.florianmichael.viafabricplus.protocolhack.usage.ItemTranslator; import net.minecraft.item.ItemStack; @@ -33,6 +32,6 @@ public class ViaFabricPlusHandItemProvider extends HandItemProvider { if (lastUsedItem == null) { return null; } - return ItemTranslator.minecraftToViaVersion(info, lastUsedItem, VersionEnum.r1_8.getVersion()); + return ItemTranslator.minecraftToViaVersion(lastUsedItem, VersionEnum.r1_8.getVersion()); } } diff --git a/src/main/java/de/florianmichael/viafabricplus/protocolhack/usage/BlockStateTranslator.java b/src/main/java/de/florianmichael/viafabricplus/protocolhack/usage/BlockStateTranslator.java new file mode 100644 index 00000000..e4ae3a18 --- /dev/null +++ b/src/main/java/de/florianmichael/viafabricplus/protocolhack/usage/BlockStateTranslator.java @@ -0,0 +1,59 @@ +/* + * 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.protocolhack.usage; + +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; +import com.viaversion.viaversion.api.protocol.packet.Direction; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.packet.State; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.connection.UserConnectionImpl; +import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.ClientboundPackets1_18; +import io.netty.buffer.Unpooled; +import net.minecraft.SharedConstants; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.math.BlockPos; + +import java.util.List; +import java.util.stream.Collectors; + +public class BlockStateTranslator { + + public static int translateBlockState1_18(int oldId) { + final List protocolPath = Via.getManager().getProtocolManager().getProtocolPath(SharedConstants.getProtocolVersion(), ProtocolVersion.v1_18_2.getVersion()); + if (protocolPath == null) return oldId; + + final PacketByteBuf inputData = new PacketByteBuf(Unpooled.buffer()); + inputData.writeBlockPos(new BlockPos(0, 0, 0)); + inputData.writeVarInt(oldId); + + try { + var wrapper = PacketWrapper.create(ClientboundPackets1_18.BLOCK_CHANGE, inputData.asByteBuf(), new UserConnectionImpl(null, true)); + wrapper.apply(Direction.CLIENTBOUND, State.PLAY, 0, protocolPath.stream().map(ProtocolPathEntry::protocol).collect(Collectors.toList()), true); + + wrapper.read(Type.POSITION1_14); + return wrapper.read(Type.VAR_INT); + } catch (Exception e) { + e.printStackTrace(); + } + + return oldId; + } +} diff --git a/src/main/java/de/florianmichael/viafabricplus/protocolhack/usage/ItemTranslator.java b/src/main/java/de/florianmichael/viafabricplus/protocolhack/usage/ItemTranslator.java index d21db634..51696214 100644 --- a/src/main/java/de/florianmichael/viafabricplus/protocolhack/usage/ItemTranslator.java +++ b/src/main/java/de/florianmichael/viafabricplus/protocolhack/usage/ItemTranslator.java @@ -25,6 +25,7 @@ import com.viaversion.viaversion.api.protocol.packet.Direction; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.State; import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.connection.UserConnectionImpl; import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl; import io.netty.buffer.Unpooled; import net.minecraft.SharedConstants; @@ -39,7 +40,7 @@ import java.util.stream.Collectors; public class ItemTranslator { - public static Item minecraftToViaVersion(final UserConnection user, final ItemStack stack, final int targetVersion) { + public static Item minecraftToViaVersion(final ItemStack stack, final int targetVersion) { final List protocolPath = Via.getManager().getProtocolManager().getProtocolPath(SharedConstants.getProtocolVersion(), targetVersion); if (protocolPath == null) return null; @@ -47,17 +48,17 @@ public class ItemTranslator { final PacketByteBuf emptyBuf = new PacketByteBuf(Unpooled.buffer()); dummyPacket.write(emptyBuf); - final Integer id = NetworkState.PLAY.getPacketId(NetworkSide.SERVERBOUND, dummyPacket); - if (id == null) return null; + final int id = NetworkState.PLAY.getPacketId(NetworkSide.SERVERBOUND, dummyPacket); - final PacketWrapper wrapper = new PacketWrapperImpl(id, emptyBuf, user); try { + final PacketWrapper wrapper = new PacketWrapperImpl(id, emptyBuf, new UserConnectionImpl(null, true)); wrapper.apply(Direction.SERVERBOUND, State.PLAY, 0, protocolPath.stream().map(ProtocolPathEntry::protocol).collect(Collectors.toList())); wrapper.read(Type.SHORT); return wrapper.read(Type.ITEM); } catch (Exception e) { - throw new RuntimeException(e); + e.printStackTrace(); } + return null; } } diff --git a/src/main/resources/viafabricplus.mixins.json b/src/main/resources/viafabricplus.mixins.json index 4df47707..23d77d52 100644 --- a/src/main/resources/viafabricplus.mixins.json +++ b/src/main/resources/viafabricplus.mixins.json @@ -162,15 +162,14 @@ "fixes.viaversion.protocol1_9to1_8.MixinViaIdleThread", "jsonwebtoken.MixinClasses", "jsonwebtoken.MixinDefaultCompressionCodecResolver", - "jsonwebtoken.MixinDefaultJwtParserBuilder" - ], - "injectors": { - "defaultRequire": 1 - }, - "mixins": [ + "jsonwebtoken.MixinDefaultJwtParserBuilder", "fixes.minecraft.block.MixinAbstractSignBlock", "fixes.minecraft.entity.MixinBoatEntity", "fixes.minecraft.entity.MixinCamelEntity", - "fixes.minecraft.item.MixinBrushItem" - ] + "fixes.minecraft.item.MixinBrushItem", + "fixes.viaversion.protocol1_19to1_18_2.MixinWorldPackets" + ], + "injectors": { + "defaultRequire": 1 + } }