From 3f623eff1b5b935d9567a07350f5ba7dc35c6e91 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 26 Nov 2025 17:27:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=E8=AF=AD=E8=A8=80=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 22 +++++++++++++ .../minecraft/NetworkReflections.java | 31 +++++++++++++------ .../plugin/user/BukkitServerPlayer.java | 20 ++++++++++-- .../core/entity/player/Player.java | 2 ++ 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 4d7761189..ba62c7b36 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -358,6 +358,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(new FinishConfigurationListener(), NetworkReflections.clazz$ClientboundFinishConfigurationPacket); registerNMSPacketConsumer(new LoginFinishedListener(), NetworkReflections.clazz$ClientboundLoginFinishedPacket); registerNMSPacketConsumer(new UpdateTagsListener(), NetworkReflections.clazz$ClientboundUpdateTagsPacket); + registerNMSPacketConsumer(new ClientInformationListener(), VersionHelper.isOrAbove1_20_2() ? NetworkReflections.clazz$ServerboundClientInformationPacket1 : NetworkReflections.clazz$ServerboundClientInformationPacket0); registerNMSPacketConsumer(new ContainerClickListener1_21_5(), VersionHelper.isOrAbove1_21_5() ? NetworkReflections.clazz$ServerboundContainerClickPacket : null); registerS2CGamePacketListener(new ForgetLevelChunkListener(), this.packetIds.clientboundForgetLevelChunkPacket(), "ClientboundForgetLevelChunkPacket"); registerS2CGamePacketListener(new SetScoreListener1_20_3(), VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1, "ClientboundSetScorePacket"); @@ -1288,6 +1289,27 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } + public static class ClientInformationListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + try { + if (VersionHelper.isOrAbove1_20_2()) { + Object clientInfo = NetworkReflections.field$ServerboundClientInformationPacket$information.get(packet); + if (clientInfo == null) return; + String locale = (String) CoreReflections.field$ClientInformation$language.get(clientInfo); + if (locale == null) return; + ((BukkitServerPlayer) user).setClientLocale(TranslationManager.parseLocale(locale)); + } else { + String locale = (String) NetworkReflections.field$ServerboundClientInformationPacket$language.get(packet); + if (locale == null) return; + ((BukkitServerPlayer) user).setClientLocale(TranslationManager.parseLocale(locale)); + } + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundClientInformationPacket", e); + } + } + } public static class SetCreativeSlotListener implements NMSPacketListener { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index a8f62e3ac..9b1e00511 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1087,20 +1087,31 @@ public final class NetworkReflections { ReflectionUtils.getDeclaredConstructor(clazz$ClientboundMoveEntityPacket$Pos, int.class, short.class, short.class, short.class, boolean.class) ); - // 1.20.2+ - public static final Class clazz$ServerboundClientInformationPacket = - ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerboundClientInformationPacket")); + // 1.20.1 + public static final Class clazz$ServerboundClientInformationPacket0 = + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayInSettings", + "network.protocol.game.ServerboundClientInformationPacket" + ); + + // 1.20.1 + public static final Field field$ServerboundClientInformationPacket$language = MiscUtils.requireNonNullIf(Optional.ofNullable(clazz$ServerboundClientInformationPacket0) + .map(it -> ReflectionUtils.getDeclaredField(it, String.class, 0)) + .orElse(null), !VersionHelper.isOrAbove1_20_2()); // 1.20.2+ - public static final Constructor constructor$ServerboundClientInformationPacket = Optional.ofNullable(clazz$ServerboundClientInformationPacket) - .map(it -> ReflectionUtils.getConstructor(it, 1)) - .orElse(null); + public static final Class clazz$ServerboundClientInformationPacket1 = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerboundClientInformationPacket")), + VersionHelper.isOrAbove1_20_2() + ); // 1.20.2+ - public static final Field field$ServerboundClientInformationPacket$information = Optional.ofNullable(clazz$ServerboundClientInformationPacket) - .map(it -> ReflectionUtils.getDeclaredField(it, 0)) - .orElse(null); - + public static final Field field$ServerboundClientInformationPacket$information = MiscUtils.requireNonNullIf( + Optional.ofNullable(clazz$ServerboundClientInformationPacket1) + .map(it -> ReflectionUtils.getDeclaredField(it, CoreReflections.clazz$ClientInformation, 0)) + .orElse(null), + VersionHelper.isOrAbove1_20_2() + ); public static final Class clazz$ClientboundSetTitleTextPacket = requireNonNull( ReflectionUtils.getClazz( diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index ca013aee3..60ed0d9e8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -127,9 +127,11 @@ public class BukkitServerPlayer extends Player { private ConcurrentLong2ReferenceChainedHashTable trackedChunks; // entity view private Map entityTypeView; - // selected client locale + // 通过指令或api设定的语言 @Nullable private Locale selectedLocale; + // 客户端选择的语言 + private Locale clientLocale; // 存储客户端在发送停止破坏包前正在破坏的最后一个方块 private BlockPos lastStopMiningPos; // 修复连续挖掘的标志位 @@ -1233,7 +1235,21 @@ public class BukkitServerPlayer extends Player { @Override public Locale locale() { - return this.platformPlayer().locale(); + if (this.clientLocale != null) { + return this.clientLocale; + } else { + org.bukkit.entity.Player player = this.platformPlayer(); + if (player != null) { + return player.locale(); + } else { + return Locale.US; + } + } + } + + @Override + public void setClientLocale(Locale clientLocale) { + this.clientLocale = clientLocale; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index c211bdd9f..034502a96 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -180,6 +180,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract Locale locale(); + public abstract void setClientLocale(Locale clientLocale); + public abstract Locale selectedLocale(); public abstract void setSelectedLocale(@Nullable Locale locale);