From 00a5c3ea271b90828d030f5e457355f9fe28400c Mon Sep 17 00:00:00 2001 From: Liyan Zhao Date: Wed, 16 Oct 2024 19:40:24 +0800 Subject: [PATCH 1/2] fix: use item on players This fix check the latency of the player you are using on. If it equals to 0, it is possibly a fake player so block using item on client side. Assumes the server has enabled `openFakePlayerInventory` on clients. --- .../gugle/carpet/mixin/ItemFrameMixin.java | 2 +- .../dubhe/gugle/carpet/mixin/PlayerMixin.java | 41 +++++++++---------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/main/java/dev/dubhe/gugle/carpet/mixin/ItemFrameMixin.java b/src/main/java/dev/dubhe/gugle/carpet/mixin/ItemFrameMixin.java index 01bd0b5..8b9cb57 100644 --- a/src/main/java/dev/dubhe/gugle/carpet/mixin/ItemFrameMixin.java +++ b/src/main/java/dev/dubhe/gugle/carpet/mixin/ItemFrameMixin.java @@ -25,7 +25,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin({ItemFrame.class}) +@Mixin(ItemFrame.class) abstract class ItemFrameMixin extends Entity { public ItemFrameMixin(EntityType entityType, Level level) { super(entityType, level); diff --git a/src/main/java/dev/dubhe/gugle/carpet/mixin/PlayerMixin.java b/src/main/java/dev/dubhe/gugle/carpet/mixin/PlayerMixin.java index e712820..738b044 100644 --- a/src/main/java/dev/dubhe/gugle/carpet/mixin/PlayerMixin.java +++ b/src/main/java/dev/dubhe/gugle/carpet/mixin/PlayerMixin.java @@ -9,6 +9,8 @@ import dev.dubhe.gugle.carpet.tools.FakePlayerEnderChestContainer; import dev.dubhe.gugle.carpet.tools.FakePlayerInventoryContainer; import dev.dubhe.gugle.carpet.tools.FakePlayerInventoryMenu; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.PlayerInfo; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.SimpleMenuProvider; @@ -40,30 +42,25 @@ private void tick(CallbackInfo ci) { @WrapOperation(method = "interactOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;interact(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/InteractionResult;")) private InteractionResult interactOn(Entity entity, Player player, InteractionHand hand, Operation original) { - // 此处不能直接使用entity instanceof EntityPlayerMPFake - // 第一次entity instanceof Player是为了排除掉非玩家实体,避免影响非玩家实体的交互逻辑,第二次instanceof在interact方法中,用来判断交互玩家是否为假玩家 - // 在服务端,entity instanceof Player可能是多余的 - // 但是在客户端中,如果直接entity instanceof EntityPlayerMPFake,那么在右键假玩家时,客户端并不知道当前交互的玩家是不是假玩家 - // 因此右键交互时可能会应用玩家手中的物品功能,例如使用熔岩桶右键玩家时可能在假玩家位置放置岩浆,使用风弹右键玩家时可能发射风弹 - // 所以客户端在交互前要先判断一下当前交互的实体是不是玩家,这用来防止意外的使用物品功能 - // 尽管这带来了一些新的问题,例如玩家飞行时不能对着玩家使用烟花,不能对着玩家吃食物,但是这相比意外使用物品是小问题 - if (entity instanceof Player interactPlayer && (GcaSetting.openFakePlayerInventory || GcaSetting.openFakePlayerEnderChest)) { - return interact(interactPlayer, player, hand, original); - } - return original.call(entity, player, hand); - } - - @Unique - private InteractionResult interact(Player entity, Player player, InteractionHand hand, Operation original) { - InteractionResult result; - if (entity instanceof EntityPlayerMPFake fakePlayer) { - // 打开物品栏 - result = this.openInventory(player, fakePlayer); + if (player.level().isClientSide()) { + // 客户端在交互前要先判断一下当前交互的实体是不是玩家,这用来防止意外的使用物品功能 + if (entity instanceof Player && Minecraft.getInstance().getConnection() != null) { + PlayerInfo info = Minecraft.getInstance().getConnection().getPlayerInfo(player.getUUID()); + if (info != null && info.getLatency() == 0) { + return InteractionResult.CONSUME; + } + } } else { - // 怎么判断一个客户端玩家是不是假玩家? - return InteractionResult.SUCCESS; + if ((GcaSetting.openFakePlayerInventory || GcaSetting.openFakePlayerEnderChest) && entity instanceof EntityPlayerMPFake fakePlayer) { + // 打开物品栏 + InteractionResult result = this.openInventory(player, fakePlayer); + if (result != InteractionResult.PASS) { + player.stopUsingItem(); + return result; + } + } } - return result == InteractionResult.PASS ? original.call(entity, player, hand) : result; + return original.call(entity, player, hand); } @Unique From 12d61db69b913611f89b6eabb04e82ec03fffb1f Mon Sep 17 00:00:00 2001 From: Liyan Zhao Date: Thu, 17 Oct 2024 08:16:17 +0800 Subject: [PATCH 2/2] fix: crash on servers --- .../dubhe/gugle/carpet/mixin/PlayerMixin.java | 10 +++---- .../dubhe/gugle/carpet/tools/ClientUtils.java | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 src/main/java/dev/dubhe/gugle/carpet/tools/ClientUtils.java diff --git a/src/main/java/dev/dubhe/gugle/carpet/mixin/PlayerMixin.java b/src/main/java/dev/dubhe/gugle/carpet/mixin/PlayerMixin.java index 738b044..eb07e59 100644 --- a/src/main/java/dev/dubhe/gugle/carpet/mixin/PlayerMixin.java +++ b/src/main/java/dev/dubhe/gugle/carpet/mixin/PlayerMixin.java @@ -6,11 +6,10 @@ import dev.dubhe.gugle.carpet.GcaExtension; import dev.dubhe.gugle.carpet.GcaSetting; import dev.dubhe.gugle.carpet.api.tools.text.ComponentTranslate; +import dev.dubhe.gugle.carpet.tools.ClientUtils; import dev.dubhe.gugle.carpet.tools.FakePlayerEnderChestContainer; import dev.dubhe.gugle.carpet.tools.FakePlayerInventoryContainer; import dev.dubhe.gugle.carpet.tools.FakePlayerInventoryMenu; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.PlayerInfo; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.SimpleMenuProvider; @@ -44,11 +43,8 @@ private void tick(CallbackInfo ci) { private InteractionResult interactOn(Entity entity, Player player, InteractionHand hand, Operation original) { if (player.level().isClientSide()) { // 客户端在交互前要先判断一下当前交互的实体是不是玩家,这用来防止意外的使用物品功能 - if (entity instanceof Player && Minecraft.getInstance().getConnection() != null) { - PlayerInfo info = Minecraft.getInstance().getConnection().getPlayerInfo(player.getUUID()); - if (info != null && info.getLatency() == 0) { - return InteractionResult.CONSUME; - } + if (entity instanceof Player && ClientUtils.isFakePlayer(player)) { + return InteractionResult.CONSUME; } } else { if ((GcaSetting.openFakePlayerInventory || GcaSetting.openFakePlayerEnderChest) && entity instanceof EntityPlayerMPFake fakePlayer) { diff --git a/src/main/java/dev/dubhe/gugle/carpet/tools/ClientUtils.java b/src/main/java/dev/dubhe/gugle/carpet/tools/ClientUtils.java new file mode 100644 index 0000000..7f72208 --- /dev/null +++ b/src/main/java/dev/dubhe/gugle/carpet/tools/ClientUtils.java @@ -0,0 +1,26 @@ +package dev.dubhe.gugle.carpet.tools; + +import carpet.patches.EntityPlayerMPFake; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.PlayerInfo; +import net.minecraft.world.entity.player.Player; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public class ClientUtils { + private static @Nullable PlayerInfo getPlayerInfo(UUID uuid) { + if (Minecraft.getInstance().getConnection() != null) { + return Minecraft.getInstance().getConnection().getPlayerInfo(uuid); + } + return null; + } + + public static boolean isFakePlayer(Player player) { + if (player.level().isClientSide()) { + PlayerInfo info = getPlayerInfo(player.getUUID()); + return info != null && info.getLatency() == 0; + } + return player instanceof EntityPlayerMPFake; + } +}