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