From 65277dc82aea3e53a5f24789efb51af62b8cf277 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sat, 4 Apr 2020 17:25:38 +0100 Subject: [PATCH 01/19] Added java -> bedrock lang conversions --- .../translators/java/JavaChatTranslator.java | 2 +- .../connector/utils/MessageUtils.java | 36 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java index 226bd971..c787b8ed 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java @@ -62,7 +62,7 @@ public class JavaChatTranslator extends PacketTranslator { textPacket.setType(TextPacket.Type.TRANSLATION); textPacket.setNeedsTranslation(true); textPacket.setParameters(MessageUtils.getTranslationParams(((TranslationMessage) packet.getMessage()).getTranslationParams())); - textPacket.setMessage(MessageUtils.getBedrockMessage(packet.getMessage())); + textPacket.setMessage(MessageUtils.getBedrockMessageWithTranslate(packet.getMessage(), true)); } else { textPacket.setNeedsTranslation(false); textPacket.setMessage(MessageUtils.getBedrockMessage(packet.getMessage())); diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 7b4c84a7..50d29beb 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -76,14 +76,19 @@ public class MessageUtils { + "%" + message.getTranslationKey(); } - public static String getBedrockMessage(Message message) { + public static String getBedrockMessageWithTranslate(Message message, boolean convertLangStrings) { JsonParser parser = new JsonParser(); if (isMessage(message.getText())) { JsonObject object = parser.parse(message.getText()).getAsJsonObject(); message = Message.fromJson(formatJson(object)); } - StringBuilder builder = new StringBuilder(message.getText()); + String messageText = message.getText(); + if (convertLangStrings) { + messageText = getLangConversion(messageText); + } + + StringBuilder builder = new StringBuilder(messageText); for (Message msg : message.getExtra()) { builder.append(getFormat(msg.getStyle().getFormats())); builder.append(getColor(msg.getStyle().getColor())); @@ -94,6 +99,33 @@ public class MessageUtils { return builder.toString(); } + private static String getLangConversion(String messageText) { + switch (messageText) { + case "block.minecraft.bed.occupied": + return "tile.bed.occupied"; + case "block.minecraft.bed.too_far_away": + return "tile.bed.tooFar"; + case "block.minecraft.bed.not_safe": + return "tile.bed.notSafe"; + case "block.minecraft.bed.no_sleep": + return "tile.bed.noSleep"; + case "block.minecraft.bed.not_valid": + return "tile.bed.notValid"; + case "block.minecraft.bed.set_spawn": + return "tile.bed.respawnSet"; + + case "chat.type.advancement.task": + return "chat.type.achievement"; + + default: + return messageText; + } + } + + public static String getBedrockMessage(Message message) { + return getBedrockMessageWithTranslate(message, false); + } + private static String getColor(ChatColor color) { String base = "\u00a7"; switch (color) { From 7298e2ff3f760d24b23b34d669ba52bf489f8a6a Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sat, 4 Apr 2020 17:44:41 +0100 Subject: [PATCH 02/19] Added a few more lang string translations --- .../java/org/geysermc/connector/utils/MessageUtils.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 50d29beb..aeaed692 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -115,8 +115,15 @@ public class MessageUtils { return "tile.bed.respawnSet"; case "chat.type.advancement.task": + case "chat.type.advancement.challenge": + case "chat.type.advancement.goal": return "chat.type.achievement"; + case "commands.teleport.success.entity.single": + return "commands.tp.success"; + case "commands.teleport.success.location.single": + return "commands.tp.success.coordinates"; + default: return messageText; } From c1e00e3614e80bb922cf3c9b655100be16406622 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sat, 4 Apr 2020 19:39:14 +0100 Subject: [PATCH 03/19] Moved to json file lang mapping --- .../connector/utils/MessageUtils.java | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index aeaed692..978f15c0 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -25,6 +25,7 @@ package org.geysermc.connector.utils; +import com.fasterxml.jackson.databind.JsonNode; import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; import com.github.steveice10.mc.protocol.data.message.ChatColor; import com.github.steveice10.mc.protocol.data.message.ChatFormat; @@ -36,11 +37,28 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.io.InputStream; +import java.util.*; public class MessageUtils { + private static final HashMap LANG_MAPPINGS = new HashMap<>(); + + static { + /* Load the language mappings */ + InputStream stream = Toolbox.getResource("mappings/lang.json"); + JsonNode lang; + try { + lang = Toolbox.JSON_MAPPER.readTree(stream); + } catch (Exception e) { + throw new AssertionError("Unable to load Java lang mappings", e); + } + + Iterator> langIterator = lang.fields(); + while (langIterator.hasNext()) { + Map.Entry entry = langIterator.next(); + LANG_MAPPINGS.put(entry.getKey(), entry.getValue().asText()); + } + } public static List getTranslationParams(Message[] messages) { List strings = new ArrayList<>(); @@ -100,33 +118,7 @@ public class MessageUtils { } private static String getLangConversion(String messageText) { - switch (messageText) { - case "block.minecraft.bed.occupied": - return "tile.bed.occupied"; - case "block.minecraft.bed.too_far_away": - return "tile.bed.tooFar"; - case "block.minecraft.bed.not_safe": - return "tile.bed.notSafe"; - case "block.minecraft.bed.no_sleep": - return "tile.bed.noSleep"; - case "block.minecraft.bed.not_valid": - return "tile.bed.notValid"; - case "block.minecraft.bed.set_spawn": - return "tile.bed.respawnSet"; - - case "chat.type.advancement.task": - case "chat.type.advancement.challenge": - case "chat.type.advancement.goal": - return "chat.type.achievement"; - - case "commands.teleport.success.entity.single": - return "commands.tp.success"; - case "commands.teleport.success.location.single": - return "commands.tp.success.coordinates"; - - default: - return messageText; - } + return LANG_MAPPINGS.getOrDefault(messageText, messageText); } public static String getBedrockMessage(Message message) { From 7f1fb3d43caf3456988b86caef70aebc55e5ec84 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 5 Apr 2020 02:36:25 +0100 Subject: [PATCH 04/19] Added new locale loading system --- .../connector/network/translators/java/JavaChatTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java index c787b8ed..5db4a44e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java @@ -62,7 +62,7 @@ public class JavaChatTranslator extends PacketTranslator { textPacket.setType(TextPacket.Type.TRANSLATION); textPacket.setNeedsTranslation(true); textPacket.setParameters(MessageUtils.getTranslationParams(((TranslationMessage) packet.getMessage()).getTranslationParams())); - textPacket.setMessage(MessageUtils.getBedrockMessageWithTranslate(packet.getMessage(), true)); + textPacket.setMessage(MessageUtils.getBedrockMessageWithTranslate(packet.getMessage(), session.getClientData().getLanguageCode())); } else { textPacket.setNeedsTranslation(false); textPacket.setMessage(MessageUtils.getBedrockMessage(packet.getMessage())); From b5ce83bbe23bec035ff595b65a9383801aed93ef Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 5 Apr 2020 02:37:39 +0100 Subject: [PATCH 05/19] Missed changes --- .../connector/utils/MessageUtils.java | 57 ++++++++++++++----- .../org/geysermc/connector/utils/Toolbox.java | 2 +- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 978f15c0..0872d076 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -36,27 +36,43 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; +import org.geysermc.connector.GeyserConnector; import java.io.InputStream; import java.util.*; public class MessageUtils { - private static final HashMap LANG_MAPPINGS = new HashMap<>(); + private static final HashMap> LOCALE_MAPPINGS = new HashMap<>(); static { /* Load the language mappings */ - InputStream stream = Toolbox.getResource("mappings/lang.json"); - JsonNode lang; + InputStream languagesStream = Toolbox.getResource("mappings/locales.json"); + JsonNode locales; try { - lang = Toolbox.JSON_MAPPER.readTree(stream); + locales = Toolbox.JSON_MAPPER.readTree(languagesStream); } catch (Exception e) { - throw new AssertionError("Unable to load Java lang mappings", e); + throw new AssertionError("Unable to load Java locale list", e); } - Iterator> langIterator = lang.fields(); - while (langIterator.hasNext()) { - Map.Entry entry = langIterator.next(); - LANG_MAPPINGS.put(entry.getKey(), entry.getValue().asText()); + for (JsonNode localeNode : locales.get("locales")) { + String currentLocale = localeNode.asText(); + + InputStream stream = Toolbox.getResource("mappings/lang/" + currentLocale + ".json"); + JsonNode lang; + try { + lang = Toolbox.JSON_MAPPER.readTree(stream); + } catch (Exception e) { + throw new AssertionError("Unable to load Java lang map for " + currentLocale, e); + } + + Iterator> langIterator = lang.fields(); + HashMap langMap = new HashMap<>(); + while (langIterator.hasNext()) { + Map.Entry entry = langIterator.next(); + langMap.put(entry.getKey(), entry.getValue().asText()); + } + + LOCALE_MAPPINGS.put(currentLocale.toLowerCase(), langMap); } } @@ -94,7 +110,7 @@ public class MessageUtils { + "%" + message.getTranslationKey(); } - public static String getBedrockMessageWithTranslate(Message message, boolean convertLangStrings) { + public static String getBedrockMessageWithTranslate(Message message, String locale) { JsonParser parser = new JsonParser(); if (isMessage(message.getText())) { JsonObject object = parser.parse(message.getText()).getAsJsonObject(); @@ -102,8 +118,8 @@ public class MessageUtils { } String messageText = message.getText(); - if (convertLangStrings) { - messageText = getLangConversion(messageText); + if (locale != null) { + messageText = getLocaleString(messageText, locale); } StringBuilder builder = new StringBuilder(messageText); @@ -117,12 +133,23 @@ public class MessageUtils { return builder.toString(); } - private static String getLangConversion(String messageText) { - return LANG_MAPPINGS.getOrDefault(messageText, messageText); + public static String getBedrockMessageWithTranslate(Message message) { + return getBedrockMessageWithTranslate(message, null); + } + + private static String getLocaleString(String messageText, String locale) { + HashMap localeStrings = LOCALE_MAPPINGS.get(locale.toLowerCase()); + if (localeStrings == null) + localeStrings = LOCALE_MAPPINGS.get("en_us"); + + String newLocaleString = localeStrings.getOrDefault(messageText, messageText); + + GeyserConnector.getInstance().getLogger().info("Converting '" + messageText + "' -> '" + newLocaleString + "'"); + return newLocaleString; } public static String getBedrockMessage(Message message) { - return getBedrockMessageWithTranslate(message, false); + return getBedrockMessageWithTranslate(message); } private static String getColor(ChatColor color) { diff --git a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java index 45802196..b48d5b54 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java +++ b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java @@ -40,7 +40,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.translators.item.ItemEntry; -import java.io.InputStream; +import java.io.*; import java.util.*; public class Toolbox { From 845c914492a23698ca090c44e9253bd5b0dafec1 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 5 Apr 2020 02:58:23 +0100 Subject: [PATCH 06/19] Moved loading and added default locale config option --- .../bukkit/GeyserBukkitConfiguration.java | 3 ++ .../bungeecord/GeyserBungeeConfiguration.java | 3 ++ .../sponge/GeyserSpongeConfiguration.java | 3 ++ .../standalone/GeyserConfiguration.java | 3 ++ .../velocity/GeyserVelocityConfiguration.java | 3 ++ .../geysermc/common/IGeyserConfiguration.java | 2 + .../connector/utils/MessageUtils.java | 37 +------------------ .../org/geysermc/connector/utils/Toolbox.java | 32 ++++++++++++++++ connector/src/main/resources/config.yml | 3 ++ 9 files changed, 54 insertions(+), 35 deletions(-) diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java index e38a982d..a99ac1e5 100644 --- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java @@ -101,6 +101,9 @@ public class GeyserBukkitConfiguration implements IGeyserConfiguration { return config.getBoolean("allow-third-party-capes", true); } + @Override + public String getDefaultLocale() { return config.getString("default-locale", "en_us"); } + @Override public Path getFloodgateKeyFile() { return Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem")); diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java index 94580e58..17a6ae0c 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java @@ -102,6 +102,9 @@ public class GeyserBungeeConfiguration implements IGeyserConfiguration { return config.getBoolean("allow-third-party-capes", true); } + @Override + public String getDefaultLocale() { return config.getString("default-locale", "en_us"); } + @Override public Path getFloodgateKeyFile() { return Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem")); diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java index dbc83fbe..18fb7308 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java @@ -105,6 +105,9 @@ public class GeyserSpongeConfiguration implements IGeyserConfiguration { return node.getNode("allow-third-party-capes").getBoolean(true); } + @Override + public String getDefaultLocale() { return node.getNode("default-locale").getString("en_us"); } + @Override public Path getFloodgateKeyFile() { return Paths.get(dataFolder.toString(), node.getNode("floodgate-key-file").getString("public-key.pem")); diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserConfiguration.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserConfiguration.java index 06cb711c..a1362c7a 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserConfiguration.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserConfiguration.java @@ -63,6 +63,9 @@ public class GeyserConfiguration implements IGeyserConfiguration { @JsonProperty("allow-third-party-capes") private boolean allowThirdPartyCapes; + @JsonProperty("default-locale") + private String defaultLocale; + private MetricsInfo metrics; @Override diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java index 2fab448d..920c6537 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java @@ -63,6 +63,9 @@ public class GeyserVelocityConfiguration implements IGeyserConfiguration { @JsonProperty("allow-third-party-capes") private boolean allowThirdPartyCapes; + @JsonProperty("default-locale") + private String defaultLocale; + private MetricsInfo metrics; @Override diff --git a/common/src/main/java/org/geysermc/common/IGeyserConfiguration.java b/common/src/main/java/org/geysermc/common/IGeyserConfiguration.java index db5d831b..41534457 100644 --- a/common/src/main/java/org/geysermc/common/IGeyserConfiguration.java +++ b/common/src/main/java/org/geysermc/common/IGeyserConfiguration.java @@ -46,6 +46,8 @@ public interface IGeyserConfiguration { boolean isAllowThirdPartyCapes(); + String getDefaultLocale(); + Path getFloodgateKeyFile(); IMetricsInfo getMetrics(); diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 0872d076..854b3c1a 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -42,39 +42,6 @@ import java.io.InputStream; import java.util.*; public class MessageUtils { - private static final HashMap> LOCALE_MAPPINGS = new HashMap<>(); - - static { - /* Load the language mappings */ - InputStream languagesStream = Toolbox.getResource("mappings/locales.json"); - JsonNode locales; - try { - locales = Toolbox.JSON_MAPPER.readTree(languagesStream); - } catch (Exception e) { - throw new AssertionError("Unable to load Java locale list", e); - } - - for (JsonNode localeNode : locales.get("locales")) { - String currentLocale = localeNode.asText(); - - InputStream stream = Toolbox.getResource("mappings/lang/" + currentLocale + ".json"); - JsonNode lang; - try { - lang = Toolbox.JSON_MAPPER.readTree(stream); - } catch (Exception e) { - throw new AssertionError("Unable to load Java lang map for " + currentLocale, e); - } - - Iterator> langIterator = lang.fields(); - HashMap langMap = new HashMap<>(); - while (langIterator.hasNext()) { - Map.Entry entry = langIterator.next(); - langMap.put(entry.getKey(), entry.getValue().asText()); - } - - LOCALE_MAPPINGS.put(currentLocale.toLowerCase(), langMap); - } - } public static List getTranslationParams(Message[] messages) { List strings = new ArrayList<>(); @@ -138,9 +105,9 @@ public class MessageUtils { } private static String getLocaleString(String messageText, String locale) { - HashMap localeStrings = LOCALE_MAPPINGS.get(locale.toLowerCase()); + HashMap localeStrings = Toolbox.LOCALE_MAPPINGS.get(locale.toLowerCase()); if (localeStrings == null) - localeStrings = LOCALE_MAPPINGS.get("en_us"); + localeStrings = Toolbox.LOCALE_MAPPINGS.get(GeyserConnector.getInstance().getConfig().getDefaultLocale()); String newLocaleString = localeStrings.getOrDefault(messageText, messageText); diff --git a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java index b48d5b54..8ccd3aa3 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java +++ b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java @@ -52,6 +52,8 @@ public class Toolbox { public static final Int2ObjectMap ITEM_ENTRIES = new Int2ObjectOpenHashMap<>(); + public static final HashMap> LOCALE_MAPPINGS = new HashMap<>(); + static { /* Load biomes */ InputStream biomestream = GeyserConnector.class.getClassLoader().getResourceAsStream("bedrock/biome_definitions.dat"); @@ -103,6 +105,36 @@ public class Toolbox { entry.getValue().get("bedrock_id").intValue(), entry.getValue().get("bedrock_data").intValue())); itemIndex++; } + + /* Load the language mappings */ + stream = Toolbox.getResource("mappings/locales.json"); + JsonNode locales; + try { + locales = Toolbox.JSON_MAPPER.readTree(stream); + } catch (Exception e) { + throw new AssertionError("Unable to load Java locale list", e); + } + + for (JsonNode localeNode : locales.get("locales")) { + String currentLocale = localeNode.asText(); + + InputStream localeStream = Toolbox.getResource("mappings/lang/" + currentLocale + ".json"); + JsonNode locale; + try { + locale = Toolbox.JSON_MAPPER.readTree(localeStream); + } catch (Exception e) { + throw new AssertionError("Unable to load Java lang map for " + currentLocale, e); + } + + Iterator> localeIterator = locale.fields(); + HashMap langMap = new HashMap<>(); + while (localeIterator.hasNext()) { + Map.Entry entry = localeIterator.next(); + langMap.put(entry.getKey(), entry.getValue().asText()); + } + + LOCALE_MAPPINGS.put(currentLocale.toLowerCase(), langMap); + } } public static InputStream getResource(String resource) { diff --git a/connector/src/main/resources/config.yml b/connector/src/main/resources/config.yml index ba5700e2..ae0cbed8 100644 --- a/connector/src/main/resources/config.yml +++ b/connector/src/main/resources/config.yml @@ -57,6 +57,9 @@ general-thread-pool: 32 # OptiFine capes, LabyMod capes, 5Zig capes and MinecraftCapes allow-third-party-capes: true +# The default locale if we dont have the one the client requested +default-locale: en_us + # bStats is a stat tracker that is entirely anonymous and tracks only basic information # about Geyser, such as how many people are online, how many servers are using Geyser, # what OS is being used, etc. You can learn more about bStats here: https://bstats.org/. From c809ddb6183a31dc30953fa914283263c0718e53 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 5 Apr 2020 10:13:47 +0100 Subject: [PATCH 07/19] Renamed translation method and cleaned up variable declaration --- .../platform/bukkit/GeyserBukkitConfiguration.java | 4 +++- .../bungeecord/GeyserBungeeConfiguration.java | 4 +++- .../platform/sponge/GeyserSpongeConfiguration.java | 4 +++- .../network/translators/java/JavaChatTranslator.java | 2 +- .../org/geysermc/connector/utils/MessageUtils.java | 12 +++++------- .../java/org/geysermc/connector/utils/Toolbox.java | 4 ++-- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java index a99ac1e5..1ddda652 100644 --- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java @@ -102,7 +102,9 @@ public class GeyserBukkitConfiguration implements IGeyserConfiguration { } @Override - public String getDefaultLocale() { return config.getString("default-locale", "en_us"); } + public String getDefaultLocale() { + return config.getString("default-locale", "en_us"); + } @Override public Path getFloodgateKeyFile() { diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java index 17a6ae0c..420f8347 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java @@ -103,7 +103,9 @@ public class GeyserBungeeConfiguration implements IGeyserConfiguration { } @Override - public String getDefaultLocale() { return config.getString("default-locale", "en_us"); } + public String getDefaultLocale() { + return config.getString("default-locale", "en_us"); + } @Override public Path getFloodgateKeyFile() { diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java index 18fb7308..7b6a89f1 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java @@ -106,7 +106,9 @@ public class GeyserSpongeConfiguration implements IGeyserConfiguration { } @Override - public String getDefaultLocale() { return node.getNode("default-locale").getString("en_us"); } + public String getDefaultLocale() { + return node.getNode("default-locale").getString("en_us"); + } @Override public Path getFloodgateKeyFile() { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java index 5db4a44e..f58c61c9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java @@ -62,7 +62,7 @@ public class JavaChatTranslator extends PacketTranslator { textPacket.setType(TextPacket.Type.TRANSLATION); textPacket.setNeedsTranslation(true); textPacket.setParameters(MessageUtils.getTranslationParams(((TranslationMessage) packet.getMessage()).getTranslationParams())); - textPacket.setMessage(MessageUtils.getBedrockMessageWithTranslate(packet.getMessage(), session.getClientData().getLanguageCode())); + textPacket.setMessage(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), session.getClientData().getLanguageCode())); } else { textPacket.setNeedsTranslation(false); textPacket.setMessage(MessageUtils.getBedrockMessage(packet.getMessage())); diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 854b3c1a..8b32f000 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -25,7 +25,6 @@ package org.geysermc.connector.utils; -import com.fasterxml.jackson.databind.JsonNode; import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; import com.github.steveice10.mc.protocol.data.message.ChatColor; import com.github.steveice10.mc.protocol.data.message.ChatFormat; @@ -38,7 +37,6 @@ import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import org.geysermc.connector.GeyserConnector; -import java.io.InputStream; import java.util.*; public class MessageUtils { @@ -77,7 +75,7 @@ public class MessageUtils { + "%" + message.getTranslationKey(); } - public static String getBedrockMessageWithTranslate(Message message, String locale) { + public static String getTranslatedBedrockMessage(Message message, String locale) { JsonParser parser = new JsonParser(); if (isMessage(message.getText())) { JsonObject object = parser.parse(message.getText()).getAsJsonObject(); @@ -100,12 +98,12 @@ public class MessageUtils { return builder.toString(); } - public static String getBedrockMessageWithTranslate(Message message) { - return getBedrockMessageWithTranslate(message, null); + public static String getTranslatedBedrockMessage(Message message) { + return getTranslatedBedrockMessage(message, null); } private static String getLocaleString(String messageText, String locale) { - HashMap localeStrings = Toolbox.LOCALE_MAPPINGS.get(locale.toLowerCase()); + Map localeStrings = Toolbox.LOCALE_MAPPINGS.get(locale.toLowerCase()); if (localeStrings == null) localeStrings = Toolbox.LOCALE_MAPPINGS.get(GeyserConnector.getInstance().getConfig().getDefaultLocale()); @@ -116,7 +114,7 @@ public class MessageUtils { } public static String getBedrockMessage(Message message) { - return getBedrockMessageWithTranslate(message); + return getTranslatedBedrockMessage(message); } private static String getColor(ChatColor color) { diff --git a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java index 8ccd3aa3..674a8bf7 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java +++ b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java @@ -52,7 +52,7 @@ public class Toolbox { public static final Int2ObjectMap ITEM_ENTRIES = new Int2ObjectOpenHashMap<>(); - public static final HashMap> LOCALE_MAPPINGS = new HashMap<>(); + public static final Map> LOCALE_MAPPINGS = new HashMap<>(); static { /* Load biomes */ @@ -127,7 +127,7 @@ public class Toolbox { } Iterator> localeIterator = locale.fields(); - HashMap langMap = new HashMap<>(); + Map langMap = new HashMap<>(); while (localeIterator.hasNext()) { Map.Entry entry = localeIterator.next(); langMap.put(entry.getKey(), entry.getValue().asText()); From 18311e3c1cf6b682f9c08e0d04d7aa03ff52dfeb Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 5 Apr 2020 12:19:20 +0100 Subject: [PATCH 08/19] Added argument parsing to serverside language processing --- .../translators/java/JavaChatTranslator.java | 17 ++++++++-- .../connector/utils/MessageUtils.java | 31 ++++++++++++++++--- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java index f58c61c9..017e0178 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java @@ -34,6 +34,8 @@ import com.github.steveice10.mc.protocol.data.message.TranslationMessage; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket; import com.nukkitx.protocol.bedrock.packet.TextPacket; +import java.util.List; + @Translator(packet = ServerChatPacket.class) public class JavaChatTranslator extends PacketTranslator { @@ -61,10 +63,21 @@ public class JavaChatTranslator extends PacketTranslator { if (packet.getMessage() instanceof TranslationMessage) { textPacket.setType(TextPacket.Type.TRANSLATION); textPacket.setNeedsTranslation(true); - textPacket.setParameters(MessageUtils.getTranslationParams(((TranslationMessage) packet.getMessage()).getTranslationParams())); - textPacket.setMessage(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), session.getClientData().getLanguageCode())); + + String locale = session.getClientData().getLanguageCode(); + + List paramsTranslated = MessageUtils.getTranslationParams(((TranslationMessage) packet.getMessage()).getTranslationParams(), locale); + textPacket.setParameters(paramsTranslated); + + textPacket.setMessage(MessageUtils.insertParams(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale), paramsTranslated)); } else { textPacket.setNeedsTranslation(false); + + // This make every message get translated which fixes alot of formatting issues + // but also causes players to be able to send translation strings as messages + // if thats all they send + // textPacket.setMessage(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), session.getClientData().getLanguageCode())); + textPacket.setMessage(MessageUtils.getBedrockMessage(packet.getMessage())); } diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 8b32f000..48ac8ab7 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -41,14 +41,16 @@ import java.util.*; public class MessageUtils { - public static List getTranslationParams(Message[] messages) { + public static List getTranslationParams(Message[] messages, String locale) { List strings = new ArrayList<>(); for (Message message : messages) { if (message instanceof TranslationMessage) { TranslationMessage translation = (TranslationMessage) message; - String builder = "%" + translation.getTranslationKey(); - strings.add(builder); + if (locale == null) { + String builder = "%" + translation.getTranslationKey(); + strings.add(builder); + } if (translation.getTranslationKey().equals("commands.gamemode.success.other")) { strings.add(""); @@ -58,7 +60,12 @@ public class MessageUtils { strings.add(" - no permission or invalid command!"); } - strings.addAll(getTranslationParams(translation.getTranslationParams())); + List furtherParams = getTranslationParams(translation.getTranslationParams()); + if (locale != null) { + strings.add(insertParams(getLocaleString(translation.getTranslationKey(), locale), furtherParams)); + }else{ + strings.addAll(furtherParams); + } } else { String builder = getFormat(message.getStyle().getFormats()) + getColor(message.getStyle().getColor()) + @@ -70,6 +77,10 @@ public class MessageUtils { return strings; } + public static List getTranslationParams(Message[] messages) { + return getTranslationParams(messages, null); + } + public static String getTranslationText(TranslationMessage message) { return getFormat(message.getStyle().getFormats()) + getColor(message.getStyle().getColor()) + "%" + message.getTranslationKey(); @@ -92,7 +103,7 @@ public class MessageUtils { builder.append(getFormat(msg.getStyle().getFormats())); builder.append(getColor(msg.getStyle().getColor())); if (!(msg.getText() == null)) { - builder.append(getBedrockMessage(msg)); + builder.append(getTranslatedBedrockMessage(msg, locale)); } } return builder.toString(); @@ -117,6 +128,16 @@ public class MessageUtils { return getTranslatedBedrockMessage(message); } + public static String insertParams(String message, List params) { + String newMessage = message; + + for (String text : params) { + newMessage = newMessage.replaceFirst("%s", text); + } + + return newMessage; + } + private static String getColor(ChatColor color) { String base = "\u00a7"; switch (color) { From 49df48fcf087106abb14708d34573af7764e24d5 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 5 Apr 2020 22:47:03 +0100 Subject: [PATCH 09/19] Fixed some strings getting missed --- .../java/org/geysermc/connector/utils/MessageUtils.java | 8 ++++++-- connector/src/main/resources/mappings | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 48ac8ab7..06ba8104 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -68,8 +68,12 @@ public class MessageUtils { } } else { String builder = getFormat(message.getStyle().getFormats()) + - getColor(message.getStyle().getColor()) + - getBedrockMessage(message); + getColor(message.getStyle().getColor()); + if (locale != null) { + builder += getTranslatedBedrockMessage(message, locale); + }else { + builder += getBedrockMessage(message); + } strings.add(builder); } } diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 278c7344..c1745b63 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 278c73449aeeb4064c7513a68f98a49a5f463f0a +Subproject commit c1745b639500e8a9434c2239074acc36784f7c40 From 9a6b537e8919117467cf9af13571a8fb98baded5 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 5 Apr 2020 22:49:10 +0100 Subject: [PATCH 10/19] Removed debugging line --- .../main/java/org/geysermc/connector/utils/MessageUtils.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 06ba8104..572c00fc 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -122,10 +122,7 @@ public class MessageUtils { if (localeStrings == null) localeStrings = Toolbox.LOCALE_MAPPINGS.get(GeyserConnector.getInstance().getConfig().getDefaultLocale()); - String newLocaleString = localeStrings.getOrDefault(messageText, messageText); - - GeyserConnector.getInstance().getLogger().info("Converting '" + messageText + "' -> '" + newLocaleString + "'"); - return newLocaleString; + return localeStrings.getOrDefault(messageText, messageText); } public static String getBedrockMessage(Message message) { From 28217adfdfc9a6a77dffa220248c7320c6453d09 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 5 Apr 2020 23:37:41 +0100 Subject: [PATCH 11/19] Added support for numbered param replacements --- .../org/geysermc/connector/utils/MessageUtils.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 572c00fc..ef2a661d 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -38,6 +38,8 @@ import com.google.gson.JsonPrimitive; import org.geysermc.connector.GeyserConnector; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class MessageUtils { @@ -132,6 +134,16 @@ public class MessageUtils { public static String insertParams(String message, List params) { String newMessage = message; + Pattern p = Pattern.compile("%([1-9])\\$s"); + Matcher m = p.matcher(message); + while (m.find()) { + try { + newMessage = newMessage.replaceFirst("%" + m.group(1) + "\\$s" , params.get(Integer.parseInt(m.group(1)) - 1)); + } catch (Exception e) { + // Couldnt find the param to replace + } + } + for (String text : params) { newMessage = newMessage.replaceFirst("%s", text); } From 2cd5472ff0fe535509d2c2ddcd80b8627d004f42 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Wed, 8 Apr 2020 21:11:56 +0100 Subject: [PATCH 12/19] Started work on the locale fetching and loading system --- .../geysermc/connector/utils/FileUtils.java | 19 ++ .../geysermc/connector/utils/LocaleUtils.java | 235 ++++++++++++++++++ .../connector/utils/MessageUtils.java | 12 +- .../org/geysermc/connector/utils/Toolbox.java | 31 +-- .../geysermc/connector/utils/WebUtils.java | 39 +++ connector/src/main/resources/mappings | 2 +- 6 files changed, 298 insertions(+), 40 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java create mode 100644 connector/src/main/java/org/geysermc/connector/utils/WebUtils.java diff --git a/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java b/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java index 3070e743..0938fa7c 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java @@ -65,4 +65,23 @@ public class FileUtils { return file; } + + public static void writeFile(File file, char[] data) throws IOException { + if (!file.exists()) { + file.createNewFile(); + } + + FileOutputStream fos = new FileOutputStream(file); + + for (char c : data) { + fos.write(c); + } + + fos.flush(); + fos.close(); + } + + public static void writeFile(String name, char[] data) throws IOException { + writeFile(new File(name), data); + } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java new file mode 100644 index 00000000..55540ea3 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java @@ -0,0 +1,235 @@ +package org.geysermc.connector.utils; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import org.geysermc.connector.GeyserConnector; + +import java.io.*; +import java.time.OffsetDateTime; +import java.util.*; + +public class LocaleUtils { + + public static final Map> LOCALE_MAPPINGS = new HashMap<>(); + + static { + /* Load the language mappings */ + InputStream stream = Toolbox.getResource("mappings/locales.json"); + JsonNode locales; + try { + locales = Toolbox.JSON_MAPPER.readTree(stream); + } catch (Exception e) { + throw new AssertionError("Unable to load Java locale list", e); + } + + File localesFolder = new File("locales/"); + + if (!localesFolder.exists()) { + GeyserConnector.getInstance().getLogger().info("Locales not cached, downloading... (this may take some time depending on your internet connection)"); + ObjectMapper mapper = new ObjectMapper(); + try { + VersionManifest versionManifest = mapper.readValue(WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class); + String latestInfoURL = ""; + for (Version version : versionManifest.getVersions()) { + if (version.getId().equals(versionManifest.getLatestVersion().getRelease())) { + latestInfoURL = version.getUrl(); + break; + } + } + + if (latestInfoURL.isEmpty()) { + throw new Exception("Unable to get latest Minecraft version"); + } + + VersionInfo versionInfo = mapper.readValue(WebUtils.getBody(latestInfoURL), VersionInfo.class); + JsonNode assets = mapper.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects"); + + localesFolder.mkdir(); + + for (JsonNode localeNode : locales.get("locales")) { + String currentLocale = localeNode.asText(); + + if (currentLocale.equals("en_us")) { continue; } + + GeyserConnector.getInstance().getLogger().info("Downloading locale: " + currentLocale); + Asset asset = mapper.treeToValue(assets.get("minecraft/lang/" + currentLocale + ".json"), Asset.class); + String hash = asset.getHash(); + FileUtils.writeFile("locales/" + currentLocale + ".json", WebUtils.getBody("http://resources.download.minecraft.net/" + hash.substring(0, 2) + "/" + hash).toCharArray()); + } + } catch (Exception e) { + GeyserConnector.getInstance().getLogger().info("Failed to load locales: " + (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace())); + } + } + + if (localesFolder.exists()) { + for (JsonNode localeNode : locales.get("locales")) { + String currentLocale = localeNode.asText(); + loadLocale(currentLocale); + } + } + } + + public static void downloadAndLoadLocale(String locale) { + downloadLocale(locale); + loadLocale(locale); + } + + private static void downloadLocale(String locale) { + + } + + private static void loadLocale(String locale) { + File localeFile = new File("locales/" + locale + ".json"); + + // Create the en_us locale + if (!localeFile.exists() && locale.equals("en_us")) { + try { + InputStreamReader isReader = new InputStreamReader(Toolbox.getResource("mappings/lang/en_us.json")); + BufferedReader reader = new BufferedReader(isReader); + StringBuffer sb = new StringBuffer(); + String str; + while((str = reader.readLine())!= null){ + sb.append(str); + } + + FileUtils.writeFile(localeFile, sb.toString().toCharArray()); + } catch (Exception e) { + throw new AssertionError("Unable to load en_us locale!", e); + } + } + + // Load the locale + if (localeFile.exists()) { + // Read the localefile + InputStream localeStream; + try { + localeStream = new FileInputStream(localeFile); + } catch (FileNotFoundException e) { + throw new AssertionError("Unable to load locale: " + locale + " (" + e.getMessage() + ")"); + } + + // Parse the file as json + JsonNode locale; + try { + locale = Toolbox.JSON_MAPPER.readTree(localeStream); + } catch (Exception e) { + throw new AssertionError("Unable to load Java lang map for " + locale, e); + } + + // Parse all the locale fields + Iterator> localeIterator = locale.fields(); + Map langMap = new HashMap<>(); + while (localeIterator.hasNext()) { + Map.Entry entry = localeIterator.next(); + langMap.put(entry.getKey(), entry.getValue().asText()); + } + + // Insert the locale into the mappings + LOCALE_MAPPINGS.put(locale.toLowerCase(), langMap); + } else { + GeyserConnector.getInstance().getLogger().warning("Missing locale file: " + locale); + } + } + + public static String getLocaleString(String messageText, String locale) { + Map localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(locale.toLowerCase()); + if (localeStrings == null) + localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(GeyserConnector.getInstance().getConfig().getDefaultLocale()); + + return localeStrings.getOrDefault(messageText, messageText); + } + + public static void init() { + // no-op + } +} + +@JsonIgnoreProperties(ignoreUnknown = true) +@Getter +class VersionManifest { + @JsonProperty("latest") + private LatestVersion latestVersion; + + @JsonProperty("versions") + private List versions; +} + +@JsonIgnoreProperties(ignoreUnknown = true) +@Getter +class LatestVersion { + @JsonProperty("release") + private String release; + + @JsonProperty("snapshot") + private String snapshot; +} + +@JsonIgnoreProperties(ignoreUnknown = true) +@Getter +class Version { + @JsonProperty("id") + private String id; + + @JsonProperty("type") + private String type; + + @JsonProperty("url") + private String url; + + @JsonProperty("time") + private String time; + + @JsonProperty("releaseTime") + private String releaseTime; +} + +@JsonIgnoreProperties(ignoreUnknown = true) +@Getter +class VersionInfo { + @JsonProperty("id") + private String id; + + @JsonProperty("type") + private String type; + + @JsonProperty("time") + private String time; + + @JsonProperty("releaseTime") + private String releaseTime; + + @JsonProperty("assetIndex") + private AssetIndex assetIndex; +} + +@JsonIgnoreProperties(ignoreUnknown = true) +@Getter +class AssetIndex { + @JsonProperty("id") + private String id; + + @JsonProperty("sha1") + private String sha1; + + @JsonProperty("size") + private int size; + + @JsonProperty("totalSize") + private int totalSize; + + @JsonProperty("url") + private String url; +} + +@JsonIgnoreProperties(ignoreUnknown = true) +@Getter +class Asset { + @JsonProperty("hash") + private String hash; + + @JsonProperty("size") + private int size; +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index ef2a661d..6e78321c 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -64,7 +64,7 @@ public class MessageUtils { List furtherParams = getTranslationParams(translation.getTranslationParams()); if (locale != null) { - strings.add(insertParams(getLocaleString(translation.getTranslationKey(), locale), furtherParams)); + strings.add(insertParams(LocaleUtils.getLocaleString(translation.getTranslationKey(), locale), furtherParams)); }else{ strings.addAll(furtherParams); } @@ -101,7 +101,7 @@ public class MessageUtils { String messageText = message.getText(); if (locale != null) { - messageText = getLocaleString(messageText, locale); + messageText = LocaleUtils.getLocaleString(messageText, locale); } StringBuilder builder = new StringBuilder(messageText); @@ -119,14 +119,6 @@ public class MessageUtils { return getTranslatedBedrockMessage(message, null); } - private static String getLocaleString(String messageText, String locale) { - Map localeStrings = Toolbox.LOCALE_MAPPINGS.get(locale.toLowerCase()); - if (localeStrings == null) - localeStrings = Toolbox.LOCALE_MAPPINGS.get(GeyserConnector.getInstance().getConfig().getDefaultLocale()); - - return localeStrings.getOrDefault(messageText, messageText); - } - public static String getBedrockMessage(Message message) { return getTranslatedBedrockMessage(message); } diff --git a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java index 674a8bf7..9c1e10f6 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java +++ b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java @@ -106,35 +106,8 @@ public class Toolbox { itemIndex++; } - /* Load the language mappings */ - stream = Toolbox.getResource("mappings/locales.json"); - JsonNode locales; - try { - locales = Toolbox.JSON_MAPPER.readTree(stream); - } catch (Exception e) { - throw new AssertionError("Unable to load Java locale list", e); - } - - for (JsonNode localeNode : locales.get("locales")) { - String currentLocale = localeNode.asText(); - - InputStream localeStream = Toolbox.getResource("mappings/lang/" + currentLocale + ".json"); - JsonNode locale; - try { - locale = Toolbox.JSON_MAPPER.readTree(localeStream); - } catch (Exception e) { - throw new AssertionError("Unable to load Java lang map for " + currentLocale, e); - } - - Iterator> localeIterator = locale.fields(); - Map langMap = new HashMap<>(); - while (localeIterator.hasNext()) { - Map.Entry entry = localeIterator.next(); - langMap.put(entry.getKey(), entry.getValue().asText()); - } - - LOCALE_MAPPINGS.put(currentLocale.toLowerCase(), langMap); - } + // Load the locale data + LocaleUtils.init(); } public static InputStream getResource(String resource) { diff --git a/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java b/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java new file mode 100644 index 00000000..9a6556be --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java @@ -0,0 +1,39 @@ +package org.geysermc.connector.utils; + +import org.geysermc.connector.GeyserConnector; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +public class WebUtils { + + public static String getBody(String reqURL) { + URL url = null; + try { + url = new URL(reqURL); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("GET"); + + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + StringBuffer content = new StringBuffer(); + + while ((inputLine = in.readLine()) != null) { + content.append(inputLine); + content.append("\n"); + } + + in.close(); + con.disconnect(); + + return content.toString(); + } catch (Exception e) { + return e.getMessage(); + } + } +} diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index c1745b63..1c45d021 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit c1745b639500e8a9434c2239074acc36784f7c40 +Subproject commit 1c45d021c69da23fdb68d1196365cad4f75b5d90 From c61d87714be5fad45f71dacd60b5d3d5fe378cb7 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 9 Apr 2020 00:20:41 +0100 Subject: [PATCH 13/19] On demand downloading and loading of language files --- .../network/session/GeyserSession.java | 4 + .../geysermc/connector/utils/LocaleUtils.java | 142 +++++++++++------- .../geysermc/connector/utils/WebUtils.java | 25 +++ 3 files changed, 116 insertions(+), 55 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 7ce1f4c6..7b133e48 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -64,6 +64,7 @@ import org.geysermc.connector.network.session.cache.*; import org.geysermc.connector.network.translators.Registry; import org.geysermc.connector.network.translators.block.BlockTranslator; import org.geysermc.connector.utils.ChunkUtils; +import org.geysermc.connector.utils.LocaleUtils; import org.geysermc.connector.utils.Toolbox; import org.geysermc.floodgate.util.BedrockData; import org.geysermc.floodgate.util.EncryptionUtil; @@ -251,6 +252,9 @@ public class GeyserSession implements CommandSender { connector.getLogger().info(authData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress()); playerEntity.setUuid(protocol.getProfile().getId()); playerEntity.setUsername(protocol.getProfile().getName()); + + // Download and load the language for the player + LocaleUtils.downloadAndLoadLocale(clientData.getLanguageCode()); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java index 55540ea3..c057d4f7 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java @@ -1,3 +1,28 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + package org.geysermc.connector.utils; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -15,77 +40,70 @@ public class LocaleUtils { public static final Map> LOCALE_MAPPINGS = new HashMap<>(); + private static final Map ASSET_MAP = new HashMap<>(); + static { - /* Load the language mappings */ - InputStream stream = Toolbox.getResource("mappings/locales.json"); - JsonNode locales; - try { - locales = Toolbox.JSON_MAPPER.readTree(stream); - } catch (Exception e) { - throw new AssertionError("Unable to load Java locale list", e); - } - + // Create the locales folder File localesFolder = new File("locales/"); + localesFolder.mkdir(); - if (!localesFolder.exists()) { - GeyserConnector.getInstance().getLogger().info("Locales not cached, downloading... (this may take some time depending on your internet connection)"); - ObjectMapper mapper = new ObjectMapper(); - try { - VersionManifest versionManifest = mapper.readValue(WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class); - String latestInfoURL = ""; - for (Version version : versionManifest.getVersions()) { - if (version.getId().equals(versionManifest.getLatestVersion().getRelease())) { - latestInfoURL = version.getUrl(); - break; - } + // Download the latest asset list and cache it + generateAssetCache(); + downloadAndLoadLocale(GeyserConnector.getInstance().getConfig().getDefaultLocale()); + } + + private static void generateAssetCache() { + try { + VersionManifest versionManifest = Toolbox.JSON_MAPPER.readValue(WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class); + String latestInfoURL = ""; + for (Version version : versionManifest.getVersions()) { + if (version.getId().equals(versionManifest.getLatestVersion().getRelease())) { + latestInfoURL = version.getUrl(); + break; } - - if (latestInfoURL.isEmpty()) { - throw new Exception("Unable to get latest Minecraft version"); - } - - VersionInfo versionInfo = mapper.readValue(WebUtils.getBody(latestInfoURL), VersionInfo.class); - JsonNode assets = mapper.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects"); - - localesFolder.mkdir(); - - for (JsonNode localeNode : locales.get("locales")) { - String currentLocale = localeNode.asText(); - - if (currentLocale.equals("en_us")) { continue; } - - GeyserConnector.getInstance().getLogger().info("Downloading locale: " + currentLocale); - Asset asset = mapper.treeToValue(assets.get("minecraft/lang/" + currentLocale + ".json"), Asset.class); - String hash = asset.getHash(); - FileUtils.writeFile("locales/" + currentLocale + ".json", WebUtils.getBody("http://resources.download.minecraft.net/" + hash.substring(0, 2) + "/" + hash).toCharArray()); - } - } catch (Exception e) { - GeyserConnector.getInstance().getLogger().info("Failed to load locales: " + (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace())); } - } - if (localesFolder.exists()) { - for (JsonNode localeNode : locales.get("locales")) { - String currentLocale = localeNode.asText(); - loadLocale(currentLocale); + if (latestInfoURL.isEmpty()) { + throw new Exception("Unable to get latest Minecraft version"); } + + VersionInfo versionInfo = Toolbox.JSON_MAPPER.readValue(WebUtils.getBody(latestInfoURL), VersionInfo.class); + JsonNode assets = Toolbox.JSON_MAPPER.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects"); + + Iterator> assetIterator = assets.fields(); + while (assetIterator.hasNext()) { + Map.Entry entry = assetIterator.next(); + Asset asset = Toolbox.JSON_MAPPER.treeToValue(entry.getValue(), Asset.class); + ASSET_MAP.put(entry.getKey(), asset); + } + } catch (Exception e) { + GeyserConnector.getInstance().getLogger().info("Failed to load locale asset cache: " + (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace())); } } public static void downloadAndLoadLocale(String locale) { + locale = locale.toLowerCase(); + if (!ASSET_MAP.containsKey("minecraft/lang/" + locale + ".json") && !locale.equals("en_us")) { + GeyserConnector.getInstance().getLogger().warning("Invalid locale requested to download and load: " + locale); + return; + } + + GeyserConnector.getInstance().getLogger().debug("Downloading and loading locale: " + locale); + downloadLocale(locale); loadLocale(locale); } private static void downloadLocale(String locale) { - - } - - private static void loadLocale(String locale) { File localeFile = new File("locales/" + locale + ".json"); + if (localeFile.exists()) { + GeyserConnector.getInstance().getLogger().debug("Locale already downloaded: " + locale); + return; + } + // Create the en_us locale - if (!localeFile.exists() && locale.equals("en_us")) { + if (locale.equals("en_us")) { try { InputStreamReader isReader = new InputStreamReader(Toolbox.getResource("mappings/lang/en_us.json")); BufferedReader reader = new BufferedReader(isReader); @@ -99,8 +117,22 @@ public class LocaleUtils { } catch (Exception e) { throw new AssertionError("Unable to load en_us locale!", e); } + + return; } + String hash = ASSET_MAP.get("minecraft/lang/" + locale + ".json").getHash(); + + try { + FileUtils.writeFile("locales/" + locale + ".json", WebUtils.getBody("http://resources.download.minecraft.net/" + hash.substring(0, 2) + "/" + hash).toCharArray()); + } catch (Exception e) { + GeyserConnector.getInstance().getLogger().warning("Failed to download locale " + locale + ": " + (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace())); + } + } + + private static void loadLocale(String locale) { + File localeFile = new File("locales/" + locale + ".json"); + // Load the locale if (localeFile.exists()) { // Read the localefile @@ -112,15 +144,15 @@ public class LocaleUtils { } // Parse the file as json - JsonNode locale; + JsonNode localeObj; try { - locale = Toolbox.JSON_MAPPER.readTree(localeStream); + localeObj = Toolbox.JSON_MAPPER.readTree(localeStream); } catch (Exception e) { throw new AssertionError("Unable to load Java lang map for " + locale, e); } // Parse all the locale fields - Iterator> localeIterator = locale.fields(); + Iterator> localeIterator = localeObj.fields(); Map langMap = new HashMap<>(); while (localeIterator.hasNext()) { Map.Entry entry = localeIterator.next(); diff --git a/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java b/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java index 9a6556be..17029fd9 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java @@ -1,3 +1,28 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + package org.geysermc.connector.utils; import org.geysermc.connector.GeyserConnector; From 70a71b2ee8f9d8868565b4213e2bdb0ac9b833dc Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 9 Apr 2020 00:23:21 +0100 Subject: [PATCH 14/19] Updated mappings commit --- connector/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 1c45d021..c25f11c5 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 1c45d021c69da23fdb68d1196365cad4f75b5d90 +Subproject commit c25f11c5653b1db06594218d7a1a31a3bfd68c6c From bc67675d160787e9f1cdfcdcd7cde6123ced57a4 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 9 Apr 2020 01:30:27 +0100 Subject: [PATCH 15/19] Added translation of extra message parts --- .../translators/java/JavaChatTranslator.java | 13 ++++--------- .../geysermc/connector/utils/LocaleUtils.java | 6 ++++-- .../connector/utils/MessageUtils.java | 19 ++++++------------- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java index 017e0178..ae58830c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java @@ -60,25 +60,20 @@ public class JavaChatTranslator extends PacketTranslator { break; } + String locale = session.getClientData().getLanguageCode(); + if (packet.getMessage() instanceof TranslationMessage) { textPacket.setType(TextPacket.Type.TRANSLATION); textPacket.setNeedsTranslation(true); - String locale = session.getClientData().getLanguageCode(); - List paramsTranslated = MessageUtils.getTranslationParams(((TranslationMessage) packet.getMessage()).getTranslationParams(), locale); textPacket.setParameters(paramsTranslated); - textPacket.setMessage(MessageUtils.insertParams(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale), paramsTranslated)); + textPacket.setMessage(MessageUtils.insertParams(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale, false), paramsTranslated)); } else { textPacket.setNeedsTranslation(false); - // This make every message get translated which fixes alot of formatting issues - // but also causes players to be able to send translation strings as messages - // if thats all they send - // textPacket.setMessage(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), session.getClientData().getLanguageCode())); - - textPacket.setMessage(MessageUtils.getBedrockMessage(packet.getMessage())); + textPacket.setMessage(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale, false)); } session.getUpstream().sendPacket(textPacket); diff --git a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java index c057d4f7..3c6ca19b 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java @@ -42,6 +42,8 @@ public class LocaleUtils { private static final Map ASSET_MAP = new HashMap<>(); + private static final String DEFAULT_LOCALE = (GeyserConnector.getInstance().getConfig().getDefaultLocale() != null ? GeyserConnector.getInstance().getConfig().getDefaultLocale() : "en_us"); + static { // Create the locales folder File localesFolder = new File("locales/"); @@ -49,7 +51,7 @@ public class LocaleUtils { // Download the latest asset list and cache it generateAssetCache(); - downloadAndLoadLocale(GeyserConnector.getInstance().getConfig().getDefaultLocale()); + downloadAndLoadLocale(DEFAULT_LOCALE); } private static void generateAssetCache() { @@ -169,7 +171,7 @@ public class LocaleUtils { public static String getLocaleString(String messageText, String locale) { Map localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(locale.toLowerCase()); if (localeStrings == null) - localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(GeyserConnector.getInstance().getConfig().getDefaultLocale()); + localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(DEFAULT_LOCALE); return localeStrings.getOrDefault(messageText, messageText); } diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 6e78321c..76563dd6 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -71,11 +71,7 @@ public class MessageUtils { } else { String builder = getFormat(message.getStyle().getFormats()) + getColor(message.getStyle().getColor()); - if (locale != null) { - builder += getTranslatedBedrockMessage(message, locale); - }else { - builder += getBedrockMessage(message); - } + builder += getTranslatedBedrockMessage(message, locale, false); strings.add(builder); } } @@ -92,7 +88,7 @@ public class MessageUtils { + "%" + message.getTranslationKey(); } - public static String getTranslatedBedrockMessage(Message message, String locale) { + public static String getTranslatedBedrockMessage(Message message, String locale, boolean shouldTranslate) { JsonParser parser = new JsonParser(); if (isMessage(message.getText())) { JsonObject object = parser.parse(message.getText()).getAsJsonObject(); @@ -100,7 +96,7 @@ public class MessageUtils { } String messageText = message.getText(); - if (locale != null) { + if (locale != null && shouldTranslate) { messageText = LocaleUtils.getLocaleString(messageText, locale); } @@ -109,18 +105,15 @@ public class MessageUtils { builder.append(getFormat(msg.getStyle().getFormats())); builder.append(getColor(msg.getStyle().getColor())); if (!(msg.getText() == null)) { - builder.append(getTranslatedBedrockMessage(msg, locale)); + boolean isTranslationMessage = (msg instanceof TranslationMessage); + builder.append(getTranslatedBedrockMessage(msg, locale, isTranslationMessage)); } } return builder.toString(); } - public static String getTranslatedBedrockMessage(Message message) { - return getTranslatedBedrockMessage(message, null); - } - public static String getBedrockMessage(Message message) { - return getTranslatedBedrockMessage(message); + return getTranslatedBedrockMessage(message, null, false); } public static String insertParams(String message, List params) { From 1ef50cbb95f00dd315444c845425b032af1da134 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 9 Apr 2020 14:36:32 +0100 Subject: [PATCH 16/19] Added automatic en_us download and extraction from JAR --- .../geysermc/connector/utils/LocaleUtils.java | 92 +++++++++++++++---- .../geysermc/connector/utils/WebUtils.java | 13 +++ connector/src/main/resources/mappings | 2 +- 3 files changed, 87 insertions(+), 20 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java index 3c6ca19b..d19c4672 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java @@ -33,8 +33,13 @@ import lombok.Getter; import org.geysermc.connector.GeyserConnector; import java.io.*; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.time.OffsetDateTime; import java.util.*; +import java.util.zip.ZipFile; public class LocaleUtils { @@ -44,6 +49,8 @@ public class LocaleUtils { private static final String DEFAULT_LOCALE = (GeyserConnector.getInstance().getConfig().getDefaultLocale() != null ? GeyserConnector.getInstance().getConfig().getDefaultLocale() : "en_us"); + private static String smallestURL = ""; + static { // Create the locales folder File localesFolder = new File("locales/"); @@ -51,6 +58,9 @@ public class LocaleUtils { // Download the latest asset list and cache it generateAssetCache(); + if (!DEFAULT_LOCALE.equals("en_us")) { + downloadAndLoadLocale("en_us"); + } downloadAndLoadLocale(DEFAULT_LOCALE); } @@ -70,6 +80,15 @@ public class LocaleUtils { } VersionInfo versionInfo = Toolbox.JSON_MAPPER.readValue(WebUtils.getBody(latestInfoURL), VersionInfo.class); + + int currentSize = Integer.MAX_VALUE; + for (VersionDownload download : versionInfo.getDownloads().values()) { + if (download.getUrl().endsWith(".jar") && download.getSize() < currentSize) { + smallestURL = download.getUrl(); + currentSize = download.getSize(); + } + } + JsonNode assets = Toolbox.JSON_MAPPER.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects"); Iterator> assetIterator = assets.fields(); @@ -106,30 +125,14 @@ public class LocaleUtils { // Create the en_us locale if (locale.equals("en_us")) { - try { - InputStreamReader isReader = new InputStreamReader(Toolbox.getResource("mappings/lang/en_us.json")); - BufferedReader reader = new BufferedReader(isReader); - StringBuffer sb = new StringBuffer(); - String str; - while((str = reader.readLine())!= null){ - sb.append(str); - } - - FileUtils.writeFile(localeFile, sb.toString().toCharArray()); - } catch (Exception e) { - throw new AssertionError("Unable to load en_us locale!", e); - } + downloadEN_US(localeFile); return; } + // Get the hash and download the locale String hash = ASSET_MAP.get("minecraft/lang/" + locale + ".json").getHash(); - - try { - FileUtils.writeFile("locales/" + locale + ".json", WebUtils.getBody("http://resources.download.minecraft.net/" + hash.substring(0, 2) + "/" + hash).toCharArray()); - } catch (Exception e) { - GeyserConnector.getInstance().getLogger().warning("Failed to download locale " + locale + ": " + (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace())); - } + WebUtils.downloadFile("http://resources.download.minecraft.net/" + hash.substring(0, 2) + "/" + hash, "locales/" + locale + ".json"); } private static void loadLocale(String locale) { @@ -168,6 +171,41 @@ public class LocaleUtils { } } + private static void downloadEN_US(File localeFile) { + try { + // Let the user know we are downloading the JAR + GeyserConnector.getInstance().getLogger().info("Downloading Minecraft JAR to extract en_us locale, please wait... (this may take some time depending on the speed of your internet connection)"); + GeyserConnector.getInstance().getLogger().debug("Download URL: " + smallestURL); + + // Download the smallest JAR (client or server) + WebUtils.downloadFile(smallestURL, "tmp_locale.jar"); + + // Load in the JAR as a zip and extract the file + ZipFile localeJar = new ZipFile("tmp_locale.jar"); + InputStream inputStream = localeJar.getInputStream(localeJar.getEntry("assets/minecraft/lang/en_us.json")); + FileOutputStream outputStream = new FileOutputStream(localeFile); + + // Write the file to the locale dir + int data = inputStream.read(); + while(data != -1){ + outputStream.write(data); + data = inputStream.read(); + } + + // Flush all changes to disk and cleanup + outputStream.flush(); + outputStream.close(); + + inputStream.close(); + localeJar.close(); + + // Delete the nolonger needed client/server jar + Files.delete(Paths.get("tmp_locale.jar")); + } catch (Exception e) { + throw new AssertionError("Unable to download and extract en_us locale!", e); + } + } + public static String getLocaleString(String messageText, String locale) { Map localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(locale.toLowerCase()); if (localeStrings == null) @@ -237,6 +275,22 @@ class VersionInfo { @JsonProperty("assetIndex") private AssetIndex assetIndex; + + @JsonProperty("downloads") + private Map downloads; +} + +@JsonIgnoreProperties(ignoreUnknown = true) +@Getter +class VersionDownload { + @JsonProperty("sha1") + private String sha1; + + @JsonProperty("size") + private int size; + + @JsonProperty("url") + private String url; } @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java b/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java index 17029fd9..a155f0b9 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java @@ -28,12 +28,16 @@ package org.geysermc.connector.utils; import org.geysermc.connector.GeyserConnector; import java.io.BufferedReader; +import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; public class WebUtils { @@ -61,4 +65,13 @@ public class WebUtils { return e.getMessage(); } } + + public static void downloadFile(String reqURL, String fileLocation) { + try { + InputStream in = new URL(reqURL).openStream(); + Files.copy(in, Paths.get(fileLocation), StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + throw new AssertionError("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e); + } + } } diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index c25f11c5..efc9db6b 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit c25f11c5653b1db06594218d7a1a31a3bfd68c6c +Subproject commit efc9db6b7d51bdf145230933ac23b321ac1c132d From 013bca024c1dfb93f62066f72a0a59cea06263ef Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 9 Apr 2020 17:06:17 +0100 Subject: [PATCH 17/19] Removed auto download and load of en_us --- .../org/geysermc/connector/network/session/GeyserSession.java | 3 +++ .../main/java/org/geysermc/connector/utils/LocaleUtils.java | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index b2421e4e..36e3a5b0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -254,6 +254,9 @@ public class GeyserSession implements CommandSender { playerEntity.setUuid(protocol.getProfile().getId()); playerEntity.setUsername(protocol.getProfile().getName()); + // Should probably let the user know if there locale is + // en_us that it might take time to download it + // Download and load the language for the player LocaleUtils.downloadAndLoadLocale(clientData.getLanguageCode()); } diff --git a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java index d19c4672..b5329dff 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java @@ -58,9 +58,6 @@ public class LocaleUtils { // Download the latest asset list and cache it generateAssetCache(); - if (!DEFAULT_LOCALE.equals("en_us")) { - downloadAndLoadLocale("en_us"); - } downloadAndLoadLocale(DEFAULT_LOCALE); } From 81c1533ee2c7952d8644b8d2c5d1691195395ad4 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 9 Apr 2020 17:21:51 +0100 Subject: [PATCH 18/19] en_us user now gets a chat message if the locale isnt already loaded --- .../connector/network/session/GeyserSession.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 36e3a5b0..9761f92e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -254,11 +254,17 @@ public class GeyserSession implements CommandSender { playerEntity.setUuid(protocol.getProfile().getId()); playerEntity.setUsername(protocol.getProfile().getName()); - // Should probably let the user know if there locale is - // en_us that it might take time to download it + String locale = clientData.getLanguageCode(); + + // Let the user know there locale may take some time to download + // as it has to be extracted from a JAR + if (locale.toLowerCase().equals("en_us") && !LocaleUtils.LOCALE_MAPPINGS.containsKey("en_us")) { + connector.getLogger().info("warning user"); + sendMessage("Downloading your locale (en_us) this may take some time"); + } // Download and load the language for the player - LocaleUtils.downloadAndLoadLocale(clientData.getLanguageCode()); + LocaleUtils.downloadAndLoadLocale(locale); } @Override From 78fdab209090cd5df3bb5d22b82e31fbf8def6f7 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 9 Apr 2020 17:34:49 +0100 Subject: [PATCH 19/19] Removed left in debug line --- .../org/geysermc/connector/network/session/GeyserSession.java | 1 - 1 file changed, 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 9761f92e..749dacb2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -259,7 +259,6 @@ public class GeyserSession implements CommandSender { // Let the user know there locale may take some time to download // as it has to be extracted from a JAR if (locale.toLowerCase().equals("en_us") && !LocaleUtils.LOCALE_MAPPINGS.containsKey("en_us")) { - connector.getLogger().info("warning user"); sendMessage("Downloading your locale (en_us) this may take some time"); }