From 3f6b10ed1f0c3a9435b72e44336c65e952159985 Mon Sep 17 00:00:00 2001 From: Lukas Hertkorn Date: Wed, 16 Apr 2025 19:34:54 +0200 Subject: [PATCH 1/4] added Player#setEffectiveLocale and Player#getEffectiveLocale --- .../main/java/org/bukkit/entity/Player.java | 16 ++++++++ .../server/level/ServerPlayer.java.patch | 3 +- ...ConfigurationPacketListenerImpl.java.patch | 2 +- .../ServerGamePacketListenerImpl.java.patch | 2 +- .../craftbukkit/entity/CraftPlayer.java | 16 ++++++++ .../io/papermc/testplugin/TestPlugin.java | 38 +++++++++++++++++++ 6 files changed, 74 insertions(+), 3 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/entity/Player.java b/paper-api/src/main/java/org/bukkit/entity/Player.java index 7b9324d121d3..b73fd6018b3a 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Player.java +++ b/paper-api/src/main/java/org/bukkit/entity/Player.java @@ -3275,6 +3275,22 @@ default boolean hasResourcePack() { */ java.util.Locale locale(); // Paper end + + /** + * Returns the locale the server will use to send messages translated via the Adventure global translator. + * By default, the value of {@link Player#locale()} is used. + * + * @return the locale. + */ + java.util.Locale getEffectiveLocale(); + + /** + * Change the locale the server will be translating its messages to. + * + * @param locale the locale to translate to + */ + void setEffectiveLocale(java.util.@Nullable Locale locale); + /** * Gets the player's estimated ping in milliseconds. * diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index a19f70a2559d..b6e27f93551c 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -1,12 +1,13 @@ --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -235,7 +_,8 @@ +@@ -235,7 +_,9 @@ private int levitationStartTime; private boolean disconnected; private int requestedViewDistance = 2; - public String language = "en_us"; + public String language = null; // Paper - default to null + public java.util.Locale adventure$locale = java.util.Locale.US; // Paper ++ public java.util.Locale effectiveLocale = null; // Paper @Nullable private Vec3 startingToFallPosition; @Nullable diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch index 2ff7ea70fa34..c10234487e99 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch @@ -42,7 +42,7 @@ @Override public void handleClientInformation(ServerboundClientInformationPacket packet) { this.clientInformation = packet.information(); -+ this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper ++ this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(player.effectiveLocale != null ? player.effectiveLocale : net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper } @Override diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 8d173d9bbd39..6be62c080696 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -2513,7 +2513,7 @@ + // Paper end - do not accept invalid information boolean isModelPartShown = this.player.isModelPartShown(PlayerModelPart.HAT); this.player.updateOptions(packet.information()); -+ this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper ++ this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(player.effectiveLocale != null ? player.effectiveLocale : net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper if (this.player.isModelPartShown(PlayerModelPart.HAT) != isModelPartShown) { this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT, this.player)); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index df6612a86f7b..ac97c29b23fd 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -2996,6 +2996,22 @@ public java.util.Locale locale() { return getHandle().adventure$locale; } // Paper end + + + @Override + public java.util.Locale getEffectiveLocale() { + if (getHandle().effectiveLocale == null) { + return locale(); + } + return getHandle().effectiveLocale; + } + + @Override + public void setEffectiveLocale(final java.util.Locale locale) { + getHandle().effectiveLocale = locale; + getHandle().connection.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(getEffectiveLocale()); + } + @Override public int getPing() { return this.getHandle().connection.latency(); diff --git a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java index fd891f5b1fad..6aad3968d3f4 100644 --- a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java +++ b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java @@ -1,14 +1,52 @@ package io.papermc.testplugin; +import io.papermc.paper.event.player.AsyncChatEvent; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import net.kyori.adventure.translation.GlobalTranslator; +import net.kyori.adventure.translation.Translator; +import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.text.MessageFormat; +import java.util.Locale; public final class TestPlugin extends JavaPlugin implements Listener { @Override public void onEnable() { this.getServer().getPluginManager().registerEvents(this, this); + GlobalTranslator.translator().addSource(new Translator() { + @Override + public @NotNull Key name() { + return Key.key("testplugin"); + } + @Override + public @Nullable MessageFormat translate(@NotNull final String key, @NotNull final Locale locale) { + return new MessageFormat(key + " " + locale.toLanguageTag()); + } + }); // io.papermc.testplugin.brigtests.Registration.registerViaOnEnable(this); } + + @EventHandler + public void onChat(AsyncChatEvent event) { + var message = PlainTextComponentSerializer.plainText().serialize(event.message()); + + if (message.equalsIgnoreCase("null")) + event.getPlayer().setEffectiveLocale(null); + else + event.getPlayer().setEffectiveLocale(Locale.forLanguageTag(message)); + event.getPlayer().sendMessage(Component.text("Effective locale: " + event.getPlayer().getEffectiveLocale())); + } + + @EventHandler + public void onInteract(PlayerInteractEvent event) { + event.getPlayer().sendMessage(Component.translatable("test.string")); + } } From 146e69c86b6442319e4c078571171551dbe93e71 Mon Sep 17 00:00:00 2001 From: Lukas Hertkorn Date: Wed, 16 Apr 2025 19:37:41 +0200 Subject: [PATCH 2/4] reverted changes in test plugin --- .../io/papermc/testplugin/TestPlugin.java | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java index 6aad3968d3f4..fd891f5b1fad 100644 --- a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java +++ b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java @@ -1,52 +1,14 @@ package io.papermc.testplugin; -import io.papermc.paper.event.player.AsyncChatEvent; -import net.kyori.adventure.key.Key; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import net.kyori.adventure.translation.GlobalTranslator; -import net.kyori.adventure.translation.Translator; -import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.plugin.java.JavaPlugin; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.text.MessageFormat; -import java.util.Locale; public final class TestPlugin extends JavaPlugin implements Listener { @Override public void onEnable() { this.getServer().getPluginManager().registerEvents(this, this); - GlobalTranslator.translator().addSource(new Translator() { - @Override - public @NotNull Key name() { - return Key.key("testplugin"); - } - @Override - public @Nullable MessageFormat translate(@NotNull final String key, @NotNull final Locale locale) { - return new MessageFormat(key + " " + locale.toLanguageTag()); - } - }); // io.papermc.testplugin.brigtests.Registration.registerViaOnEnable(this); } - - @EventHandler - public void onChat(AsyncChatEvent event) { - var message = PlainTextComponentSerializer.plainText().serialize(event.message()); - - if (message.equalsIgnoreCase("null")) - event.getPlayer().setEffectiveLocale(null); - else - event.getPlayer().setEffectiveLocale(Locale.forLanguageTag(message)); - event.getPlayer().sendMessage(Component.text("Effective locale: " + event.getPlayer().getEffectiveLocale())); - } - - @EventHandler - public void onInteract(PlayerInteractEvent event) { - event.getPlayer().sendMessage(Component.translatable("test.string")); - } } From 62cb428ec5879c70c351bd669ddf283ab6b58436 Mon Sep 17 00:00:00 2001 From: Lukas Hertkorn Date: Thu, 24 Apr 2025 15:34:08 +0200 Subject: [PATCH 3/4] Fixed NPE when calling Player#setEffectiveLocale() during login --- .../main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index ac97c29b23fd..ba3d491a22e7 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -3009,7 +3009,10 @@ public java.util.Locale getEffectiveLocale() { @Override public void setEffectiveLocale(final java.util.Locale locale) { getHandle().effectiveLocale = locale; - getHandle().connection.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(getEffectiveLocale()); + + if (getHandle().connection != null) { + getHandle().connection.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(getEffectiveLocale()); + } } @Override From 695fe03224c8e25b5e83fadcfb40475906ec3e31 Mon Sep 17 00:00:00 2001 From: Lukas Hertkorn Date: Fri, 25 Apr 2025 12:45:45 +0200 Subject: [PATCH 4/4] Fixed NPE when calling Player#setEffectiveLocale() during login --- paper-api/src/main/java/org/bukkit/entity/Player.java | 6 ++++-- .../net/minecraft/server/level/ServerPlayer.java.patch | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/entity/Player.java b/paper-api/src/main/java/org/bukkit/entity/Player.java index b73fd6018b3a..8eb7b3824973 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Player.java +++ b/paper-api/src/main/java/org/bukkit/entity/Player.java @@ -7,6 +7,7 @@ import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -3282,14 +3283,15 @@ default boolean hasResourcePack() { * * @return the locale. */ - java.util.Locale getEffectiveLocale(); + Locale getEffectiveLocale(); /** * Change the locale the server will be translating its messages to. + * If set, the effective locale overrides the client locale for server-side translations. * * @param locale the locale to translate to */ - void setEffectiveLocale(java.util.@Nullable Locale locale); + void setEffectiveLocale(@Nullable Locale locale); /** * Gets the player's estimated ping in milliseconds. diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index b6e27f93551c..2ce663b13e76 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -1,12 +1,13 @@ --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -235,7 +_,9 @@ +@@ -235,7 +_,10 @@ private int levitationStartTime; private boolean disconnected; private int requestedViewDistance = 2; - public String language = "en_us"; + public String language = null; // Paper - default to null + public java.util.Locale adventure$locale = java.util.Locale.US; // Paper ++ @Nullable + public java.util.Locale effectiveLocale = null; // Paper @Nullable private Vec3 startingToFallPosition;