forked from GeyserMC/Geyser
On demand downloading and loading of language files
This commit is contained in:
parent
2cd5472ff0
commit
c61d87714b
3 changed files with 116 additions and 55 deletions
|
@ -64,6 +64,7 @@ import org.geysermc.connector.network.session.cache.*;
|
||||||
import org.geysermc.connector.network.translators.Registry;
|
import org.geysermc.connector.network.translators.Registry;
|
||||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.ChunkUtils;
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
|
import org.geysermc.connector.utils.LocaleUtils;
|
||||||
import org.geysermc.connector.utils.Toolbox;
|
import org.geysermc.connector.utils.Toolbox;
|
||||||
import org.geysermc.floodgate.util.BedrockData;
|
import org.geysermc.floodgate.util.BedrockData;
|
||||||
import org.geysermc.floodgate.util.EncryptionUtil;
|
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());
|
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.setUuid(protocol.getProfile().getId());
|
||||||
playerEntity.setUsername(protocol.getProfile().getName());
|
playerEntity.setUsername(protocol.getProfile().getName());
|
||||||
|
|
||||||
|
// Download and load the language for the player
|
||||||
|
LocaleUtils.downloadAndLoadLocale(clientData.getLanguageCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -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;
|
package org.geysermc.connector.utils;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
@ -15,77 +40,70 @@ public class LocaleUtils {
|
||||||
|
|
||||||
public static final Map<String, Map<String, String>> LOCALE_MAPPINGS = new HashMap<>();
|
public static final Map<String, Map<String, String>> LOCALE_MAPPINGS = new HashMap<>();
|
||||||
|
|
||||||
|
private static final Map<String, Asset> ASSET_MAP = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
/* Load the language mappings */
|
// Create the locales folder
|
||||||
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/");
|
File localesFolder = new File("locales/");
|
||||||
|
localesFolder.mkdir();
|
||||||
|
|
||||||
if (!localesFolder.exists()) {
|
// Download the latest asset list and cache it
|
||||||
GeyserConnector.getInstance().getLogger().info("Locales not cached, downloading... (this may take some time depending on your internet connection)");
|
generateAssetCache();
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
downloadAndLoadLocale(GeyserConnector.getInstance().getConfig().getDefaultLocale());
|
||||||
try {
|
}
|
||||||
VersionManifest versionManifest = mapper.readValue(WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class);
|
|
||||||
String latestInfoURL = "";
|
private static void generateAssetCache() {
|
||||||
for (Version version : versionManifest.getVersions()) {
|
try {
|
||||||
if (version.getId().equals(versionManifest.getLatestVersion().getRelease())) {
|
VersionManifest versionManifest = Toolbox.JSON_MAPPER.readValue(WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class);
|
||||||
latestInfoURL = version.getUrl();
|
String latestInfoURL = "";
|
||||||
break;
|
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()) {
|
if (latestInfoURL.isEmpty()) {
|
||||||
for (JsonNode localeNode : locales.get("locales")) {
|
throw new Exception("Unable to get latest Minecraft version");
|
||||||
String currentLocale = localeNode.asText();
|
|
||||||
loadLocale(currentLocale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<Map.Entry<String, JsonNode>> assetIterator = assets.fields();
|
||||||
|
while (assetIterator.hasNext()) {
|
||||||
|
Map.Entry<String, JsonNode> 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) {
|
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);
|
downloadLocale(locale);
|
||||||
loadLocale(locale);
|
loadLocale(locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void downloadLocale(String locale) {
|
private static void downloadLocale(String locale) {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void loadLocale(String locale) {
|
|
||||||
File localeFile = new File("locales/" + locale + ".json");
|
File localeFile = new File("locales/" + locale + ".json");
|
||||||
|
|
||||||
|
if (localeFile.exists()) {
|
||||||
|
GeyserConnector.getInstance().getLogger().debug("Locale already downloaded: " + locale);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Create the en_us locale
|
// Create the en_us locale
|
||||||
if (!localeFile.exists() && locale.equals("en_us")) {
|
if (locale.equals("en_us")) {
|
||||||
try {
|
try {
|
||||||
InputStreamReader isReader = new InputStreamReader(Toolbox.getResource("mappings/lang/en_us.json"));
|
InputStreamReader isReader = new InputStreamReader(Toolbox.getResource("mappings/lang/en_us.json"));
|
||||||
BufferedReader reader = new BufferedReader(isReader);
|
BufferedReader reader = new BufferedReader(isReader);
|
||||||
|
@ -99,8 +117,22 @@ public class LocaleUtils {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to load en_us locale!", 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
|
// Load the locale
|
||||||
if (localeFile.exists()) {
|
if (localeFile.exists()) {
|
||||||
// Read the localefile
|
// Read the localefile
|
||||||
|
@ -112,15 +144,15 @@ public class LocaleUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the file as json
|
// Parse the file as json
|
||||||
JsonNode locale;
|
JsonNode localeObj;
|
||||||
try {
|
try {
|
||||||
locale = Toolbox.JSON_MAPPER.readTree(localeStream);
|
localeObj = Toolbox.JSON_MAPPER.readTree(localeStream);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to load Java lang map for " + locale, e);
|
throw new AssertionError("Unable to load Java lang map for " + locale, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse all the locale fields
|
// Parse all the locale fields
|
||||||
Iterator<Map.Entry<String, JsonNode>> localeIterator = locale.fields();
|
Iterator<Map.Entry<String, JsonNode>> localeIterator = localeObj.fields();
|
||||||
Map<String, String> langMap = new HashMap<>();
|
Map<String, String> langMap = new HashMap<>();
|
||||||
while (localeIterator.hasNext()) {
|
while (localeIterator.hasNext()) {
|
||||||
Map.Entry<String, JsonNode> entry = localeIterator.next();
|
Map.Entry<String, JsonNode> entry = localeIterator.next();
|
||||||
|
|
|
@ -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;
|
package org.geysermc.connector.utils;
|
||||||
|
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
|
Loading…
Reference in a new issue