Implemented packet syncing correctly.

This commit is contained in:
FlorianMichael 2023-10-01 20:22:56 +02:00
parent b92aa99fd3
commit 8e9f5fa141
No known key found for this signature in database
GPG Key ID: C2FB87E71C425126
6 changed files with 98 additions and 17 deletions

View File

@ -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<PacketByteBuf> 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<Pair<BlockPos, PlayerActionC2SPacket.Action>, PositionAndRotation> UN_ACKED_ACTIONS = new Object2ObjectLinkedOpenHashMap<>();
public static void trackBlockAction(final PlayerActionC2SPacket.Action action, final BlockPos blockPos) {

View File

@ -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<Item, Integer> 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<String, Consumer<PacketByteBuf>> 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<PacketByteBuf> 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)
*

View File

@ -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<PacketByteBuf> 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;

View File

@ -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<? extends ServerPacketListener> 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
}
}
}

View File

@ -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<ProtocolPathEntry> 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);
}

View File

@ -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);
});
}
}