Add Translation support (#504)

Adds full multi-language support to any Bedrock-supported language.

Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
This commit is contained in:
rtm516 2020-07-06 00:35:51 +01:00 committed by GitHub
parent d1e5960d69
commit cfaf4051b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 504 additions and 191 deletions

3
.gitmodules vendored
View file

@ -2,3 +2,6 @@
path = connector/src/main/resources/mappings
url = https://github.com/GeyserMC/mappings.git
branch = feature/1.16
[submodule "connector/src/main/resources/languages"]
path = connector/src/main/resources/languages
url = https://github.com/GeyserMC/languages.git

View file

@ -39,6 +39,7 @@ import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandExecutor;
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager;
@ -71,7 +72,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new File(getDataFolder(), "config.yml"));
} catch (IOException ex) {
getLogger().log(Level.WARNING, "Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
getLogger().log(Level.WARNING, LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace();
}
@ -93,7 +94,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && getProxy().getPluginManager().getPlugin("floodgate-bungee") == null) {
geyserLogger.severe("Auth type set to Floodgate but Floodgate not found! Disabling...");
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
return;
}

View file

@ -33,6 +33,8 @@ import net.md_5.bungee.api.plugin.TabExecutor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList;
import java.util.Arrays;
@ -52,7 +54,14 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor
if (args.length > 0) {
if (getCommand(args[0]) != null) {
if (!sender.hasPermission(getCommand(args[0]).getPermission())) {
sender.sendMessage(TextComponent.fromLegacyText(ChatColor.RED + "You do not have permission to execute this command!"));
String message = "";
if (sender instanceof GeyserSession) {
message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", ((GeyserSession) sender).getClientData().getLanguageCode());
} else {
message = LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail");
}
sender.sendMessage(TextComponent.fromLegacyText(ChatColor.RED + message));
return;
}
getCommand(args[0]).execute(new BungeeCommandSender(sender), args);

View file

@ -37,6 +37,7 @@ import org.geysermc.connector.network.translators.world.WorldManager;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.spigot.command.GeyserSpigotCommandExecutor;
import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager;
import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener;
@ -68,15 +69,15 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
getDataFolder().mkdir();
File bukkitConfig = new File("plugins/Geyser-Bukkit/config.yml");
if (bukkitConfig.exists()) { // Copy over old configs
getLogger().log(Level.INFO, "Existing config found in the Geyser-Bukkit folder; copying over...");
getLogger().log(Level.INFO, LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.copy_bukkit_config"));
Files.copy(bukkitConfig.toPath(), new File(getDataFolder().toString() + "/config.yml").toPath());
getLogger().log(Level.INFO, "Copied!");
getLogger().log(Level.INFO, LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.copied_bukkit_config"));
}
}
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
} catch (IOException ex) {
getLogger().log(Level.WARNING, "Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
getLogger().log(Level.WARNING, LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace();
}
@ -92,7 +93,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && Bukkit.getPluginManager().getPlugin("floodgate-bukkit") == null) {
geyserLogger.severe("Auth type set to Floodgate but Floodgate not found! Disabling...");
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
this.getPluginLoader().disablePlugin(this);
return;
}

View file

@ -26,13 +26,14 @@
package org.geysermc.platform.spigot.command;
import lombok.AllArgsConstructor;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList;
import java.util.Arrays;
@ -48,7 +49,14 @@ public class GeyserSpigotCommandExecutor implements TabExecutor {
if (args.length > 0) {
if (getCommand(args[0]) != null) {
if (!sender.hasPermission(getCommand(args[0]).getPermission())) {
sender.sendMessage(ChatColor.RED + "You do not have permission to execute this command!");
String message = "";
if (sender instanceof GeyserSession) {
message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", ((GeyserSession) sender).getClientData().getLanguageCode());
} else {
message = LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail");
}
sender.sendMessage(ChatColor.RED + message);
return true;
}
getCommand(args[0]).execute(new SpigotCommandSender(sender), args);

View file

@ -38,6 +38,7 @@ import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.sponge.command.GeyserSpongeCommandExecutor;
import org.geysermc.platform.sponge.command.GeyserSpongeCommandManager;
import org.slf4j.Logger;
@ -80,7 +81,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
try {
configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml", (file) -> file.replaceAll("generateduuid", UUID.randomUUID().toString()));
} catch (IOException ex) {
logger.warn("Failed to copy config.yml from jar path!");
logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed"));
ex.printStackTrace();
}
@ -90,7 +91,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
config = loader.load();
this.geyserConfig = new GeyserSpongeConfiguration(configDir, config);
} catch (IOException ex) {
logger.warn("Failed to load config.yml!");
logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed"));
ex.printStackTrace();
return;
}

View file

@ -26,10 +26,10 @@
package org.geysermc.platform.sponge.command;
import lombok.AllArgsConstructor;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.utils.LanguageUtils;
import org.spongepowered.api.command.CommandCallable;
import org.spongepowered.api.command.CommandException;
import org.spongepowered.api.command.CommandResult;
@ -55,7 +55,8 @@ public class GeyserSpongeCommandExecutor implements CommandCallable {
if (args.length > 0) {
if (getCommand(args[0]) != null) {
if (!source.hasPermission(getCommand(args[0]).getPermission())) {
source.sendMessage(Text.of(ChatColor.RED + "You do not have permission to execute this command!"));
// Not ideal to use log here but we dont get a session
source.sendMessage(Text.of(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail")));
return CommandResult.success();
}
getCommand(args[0]).execute(new SpongeCommandSender(source), args);

View file

@ -40,6 +40,7 @@ import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.standalone.command.GeyserCommandManager;
import org.geysermc.platform.standalone.gui.GeyserStandaloneGUI;
@ -107,7 +108,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
File configFile = FileUtils.fileOrCopiedFromResource("config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
} catch (IOException ex) {
geyserLogger.severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
System.exit(0);
}
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);

View file

@ -1,12 +1,13 @@
package org.geysermc.platform.standalone;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.utils.LanguageUtils;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Paths;
import org.geysermc.connector.common.ChatColor;
public class LoopbackUtil {
private static final String checkExemption = "powershell -Command \"CheckNetIsolation LoopbackExempt -s\""; // Java's Exec feature runs as CMD, NetIsolation is only accessible from PowerShell.
private static final String loopbackCommand = "powershell -Command \"CheckNetIsolation LoopbackExempt -a -n='Microsoft.MinecraftUWP_8wekyb3d8bbwe'\"";
@ -31,12 +32,12 @@ public class LoopbackUtil {
Files.write(Paths.get(System.getenv("temp") + "/loopback_minecraft.bat"), loopbackCommand.getBytes(), new OpenOption[0]);
process = Runtime.getRuntime().exec(startScript);
geyserLogger.info(ChatColor.AQUA + "Added loopback exemption to Windows!");
geyserLogger.info(ChatColor.AQUA + LanguageUtils.getLocaleStringLog("geyser.bootstrap.loopback.added"));
}
} catch (Exception e) {
e.printStackTrace();
geyserLogger.error("Couldn't auto add loopback exemption to Windows!");
geyserLogger.error(LanguageUtils.getLocaleStringLog("geyser.bootstrap.loopback.failed"));
}
}
}

View file

@ -29,6 +29,7 @@ package org.geysermc.platform.standalone.gui;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.standalone.GeyserStandaloneLogger;
import org.geysermc.platform.standalone.command.GeyserCommandManager;
@ -52,7 +53,9 @@ import java.util.concurrent.TimeUnit;
public class GeyserStandaloneGUI {
private static final String[] playerTableHeadings = new String[] {"IP", "Username"};
private static final String[] playerTableHeadings = new String[] {
LanguageUtils.getLocaleStringLog("geyser.gui.table.ip"),
LanguageUtils.getLocaleStringLog("geyser.gui.table.username")};
private static final List<Integer> ramValues = new ArrayList<>();
private static final ColorPane consolePane = new ColorPane();
@ -67,7 +70,7 @@ public class GeyserStandaloneGUI {
public GeyserStandaloneGUI() {
// Create the frame and setup basic settings
JFrame frame = new JFrame("Geyser Standalone");
JFrame frame = new JFrame(LanguageUtils.getLocaleStringLog("geyser.gui.title"));
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setSize(800, 400);
frame.setMinimumSize(frame.getSize());
@ -82,8 +85,8 @@ public class GeyserStandaloneGUI {
@Override
public void windowClosing(WindowEvent we)
{
String[] buttons = {"Yes", "No"};
int result = JOptionPane.showOptionDialog(frame, "Are you sure you want to exit?", frame.getTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, buttons, buttons[1]);
String[] buttons = {LanguageUtils.getLocaleStringLog("geyser.gui.exit.confirm"), LanguageUtils.getLocaleStringLog("geyser.gui.exit.deny")};
int result = JOptionPane.showOptionDialog(frame, LanguageUtils.getLocaleStringLog("geyser.gui.exit.message"), frame.getTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, buttons, buttons[1]);
if (result == JOptionPane.YES_OPTION) {
System.exit(0);
}
@ -124,12 +127,12 @@ public class GeyserStandaloneGUI {
JMenuBar menuBar = new JMenuBar();
// Create 'File'
JMenu fileMenu = new JMenu("File");
JMenu fileMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.file"));
fileMenu.setMnemonic(KeyEvent.VK_F);
menuBar.add(fileMenu);
// 'Open Geyser folder' button
JMenuItem openButton = new JMenuItem("Open Geyser folder", KeyEvent.VK_O);
JMenuItem openButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.file.open_folder"), KeyEvent.VK_O);
openButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
openButton.addActionListener(e -> {
try {
@ -141,40 +144,40 @@ public class GeyserStandaloneGUI {
fileMenu.addSeparator();
// 'Exit' button
JMenuItem exitButton = new JMenuItem("Exit", KeyEvent.VK_X);
JMenuItem exitButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.file.exit"), KeyEvent.VK_X);
exitButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.ALT_MASK));
exitButton.addActionListener(e -> System.exit(0));
fileMenu.add(exitButton);
// Create 'Commands'
commandsMenu = new JMenu("Commands");
commandsMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.commands"));
commandsMenu.setMnemonic(KeyEvent.VK_C);
menuBar.add(commandsMenu);
// Create 'View'
JMenu viewMenu = new JMenu("View");
JMenu viewMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view"));
viewMenu.setMnemonic(KeyEvent.VK_V);
menuBar.add(viewMenu);
// 'Zoom in' button
JMenuItem zoomInButton = new JMenuItem("Zoom In");
JMenuItem zoomInButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view.zoom_in"));
zoomInButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.CTRL_DOWN_MASK));
zoomInButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), consolePane.getFont().getSize() + 1)));
viewMenu.add(zoomInButton);
// 'Zoom in' button
JMenuItem zoomOutButton = new JMenuItem("Zoom Out");
JMenuItem zoomOutButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view.zoom_out"));
zoomOutButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, InputEvent.CTRL_DOWN_MASK));
zoomOutButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), consolePane.getFont().getSize() - 1)));
viewMenu.add(zoomOutButton);
// 'Reset Zoom' button
JMenuItem resetZoomButton = new JMenuItem("Reset Zoom");
JMenuItem resetZoomButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view.reset_zoom"));
resetZoomButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), originalFontSize)));
viewMenu.add(resetZoomButton);
// create 'Options'
optionsMenu = new JMenu("Options");
optionsMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.options"));
viewMenu.setMnemonic(KeyEvent.VK_O);
menuBar.add(optionsMenu);
@ -195,7 +198,7 @@ public class GeyserStandaloneGUI {
ramValues.add(0);
}
ramGraph.setValues(ramValues);
ramGraph.setXLabel("Loading...");
ramGraph.setXLabel(LanguageUtils.getLocaleStringLog("geyser.gui.graph.loading"));
rightContentPane.add(ramGraph);
JScrollPane playerScrollPane = new JScrollPane(playerTable);
@ -270,7 +273,7 @@ public class GeyserStandaloneGUI {
}
// 'Debug Mode' toggle
JCheckBoxMenuItem debugMode = new JCheckBoxMenuItem("Debug Mode");
JCheckBoxMenuItem debugMode = new JCheckBoxMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.options.toggle_debug_mode"));
debugMode.setSelected(geyserStandaloneLogger.isDebug());
debugMode.addActionListener(e -> geyserStandaloneLogger.setDebug(!geyserStandaloneLogger.isDebug()));
optionsMenu.add(debugMode);
@ -305,7 +308,7 @@ public class GeyserStandaloneGUI {
final int freePercent = (int)(freeMemory * 100.0 / totalMemory + 0.5);
ramValues.add(100 - freePercent);
ramGraph.setXLabel("Usage: " + String.format("%,d", (totalMemory - freeMemory) / MEGABYTE) + "mb (" + freePercent + "% free)");
ramGraph.setXLabel(LanguageUtils.getLocaleStringLog("geyser.gui.graph.usage", String.format("%,d", (totalMemory - freeMemory) / MEGABYTE), freePercent));
// Trim the list
int k = ramValues.size();

View file

@ -43,6 +43,7 @@ import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.velocity.command.GeyserVelocityCommandExecutor;
import org.geysermc.platform.velocity.command.GeyserVelocityCommandManager;
import org.slf4j.Logger;
@ -85,7 +86,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
File configFile = FileUtils.fileOrCopiedFromResource(configFolder.resolve("config.yml").toFile(), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class);
} catch (IOException ex) {
logger.warn("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace();
}
@ -103,7 +104,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && !proxyServer.getPluginManager().getPlugin("floodgate").isPresent()) {
geyserLogger.severe("Auth type set to Floodgate but Floodgate not found! Disabling...");
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
return;
}

View file

@ -35,6 +35,7 @@ import net.kyori.text.TextComponent;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.utils.LanguageUtils;
@AllArgsConstructor
public class GeyserVelocityCommandExecutor implements Command {
@ -46,7 +47,8 @@ public class GeyserVelocityCommandExecutor implements Command {
if (args.length > 0) {
if (getCommand(args[0]) != null) {
if (!source.hasPermission(getCommand(args[0]).getPermission())) {
source.sendMessage(TextComponent.of(ChatColor.RED + "You do not have permission to execute this command!"));
// Not ideal to use log here but we dont get a session
source.sendMessage(TextComponent.of(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail")));
return;
}
getCommand(args[0]).execute(new VelocityCommandSender(source), args);

View file

@ -1,18 +0,0 @@
--------------------------------------------------------------------------------
Oops! You attempted to run a plugin version of Geyser directly!
This jar file is a plugin for ${plugin_type}. You can run this file as a
plugin by dropping the jar file into the "${plugin_folder}" directory.
There is also a standalone version available that doesn't need to
be installed as a plugin, you can find it on our build server:
http://ci.geysermc.org/
If you need more help, you should check out our discord:
http://discord.geysermc.org/
--------------------------------------------------------------------------------

View file

@ -26,6 +26,7 @@
package org.geysermc.connector;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.connector.configuration.GeyserConfiguration;
import java.nio.file.Files;
@ -37,13 +38,13 @@ public class FloodgateKeyLoader {
if (floodgate != null) {
Path autoKey = floodgateFolder.resolve("public-key.pem");
if (Files.exists(autoKey)) {
logger.info("Auto-loaded floodgate key");
logger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded"));
floodgateKey = autoKey;
} else {
logger.error("Auth-type set to floodgate and the public key is missing!");
logger.error(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.missing_key"));
}
} else {
logger.error("Auth-type set to floodgate but floodgate is not installed!");
logger.error(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed"));
}
}

View file

@ -50,6 +50,7 @@ import org.geysermc.connector.network.translators.item.ItemTranslator;
import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry;
import org.geysermc.connector.network.translators.sound.SoundRegistry;
import org.geysermc.connector.network.translators.world.WorldManager;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
import org.geysermc.connector.utils.DimensionUtils;
@ -107,7 +108,7 @@ public class GeyserConnector {
logger.info("******************************************");
logger.info("");
logger.info("Loading " + NAME + " version " + VERSION);
logger.info(LanguageUtils.getLocaleStringLog("geyser.core.load", NAME, VERSION));
logger.info("");
logger.info("******************************************");
@ -143,9 +144,9 @@ public class GeyserConnector {
bedrockServer.setHandler(new ConnectorServerEventHandler(this));
bedrockServer.bind().whenComplete((avoid, throwable) -> {
if (throwable == null) {
logger.info("Started Geyser on " + config.getBedrock().getAddress() + ":" + config.getBedrock().getPort());
logger.info(LanguageUtils.getLocaleStringLog("geyser.core.start", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort())));
} else {
logger.severe("Failed to start Geyser on " + config.getBedrock().getAddress() + ":" + config.getBedrock().getPort());
logger.severe(LanguageUtils.getLocaleStringLog("geyser.core.fail", config.getBedrock().getAddress(), config.getBedrock().getPort()));
throwable.printStackTrace();
}
}).join();
@ -168,24 +169,24 @@ public class GeyserConnector {
}
double completeTime = (System.currentTimeMillis() - startupTime) / 1000D;
String message = String.format("Done (%ss)!", new DecimalFormat("#.###").format(completeTime));
String message = LanguageUtils.getLocaleStringLog("geyser.core.finish.done", new DecimalFormat("#.###").format(completeTime)) + " ";
if (isGui) {
message += " Run Commands -> help for help!";
message += LanguageUtils.getLocaleStringLog("geyser.core.finish.gui");
} else {
message += " Run /geyser help for help!";
message += LanguageUtils.getLocaleStringLog("geyser.core.finish.console");
}
logger.info(message);
}
public void shutdown() {
bootstrap.getGeyserLogger().info("Shutting down Geyser.");
bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown"));
shuttingDown = true;
if (players.size() >= 1) {
bootstrap.getGeyserLogger().info("Kicking " + players.size() + " player(s)");
bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.kick.log", players.size()));
for (GeyserSession playerSession : players.values()) {
playerSession.disconnect("Geyser Proxy shutting down.");
playerSession.disconnect(LanguageUtils.getPlayerLocaleString("geyser.core.shutdown.kick.message", playerSession.getClientData().getLanguageCode()));
}
CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() {
@ -209,7 +210,7 @@ public class GeyserConnector {
// Block and wait for the future to complete
try {
future.get();
bootstrap.getGeyserLogger().info("Kicked all players");
bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.kick.done"));
} catch (Exception e) {
// Quietly fail
}
@ -222,7 +223,7 @@ public class GeyserConnector {
authType = null;
this.getCommandManager().getCommands().clear();
bootstrap.getGeyserLogger().info("Geyser shutdown successfully.");
bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.done"));
}
public void addPlayer(GeyserSession player) {

View file

@ -29,6 +29,7 @@ import lombok.Getter;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.defaults.*;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.Collections;
import java.util.HashMap;
@ -44,17 +45,17 @@ public abstract class CommandManager {
public CommandManager(GeyserConnector connector) {
this.connector = connector;
registerCommand(new HelpCommand(connector, "help", "Shows help for all registered commands.", "geyser.command.help"));
registerCommand(new ListCommand(connector, "list", "List all players connected through Geyser.", "geyser.command.list"));
registerCommand(new ReloadCommand(connector, "reload", "Reloads the Geyser configurations. Kicks all players when used!", "geyser.command.reload"));
registerCommand(new StopCommand(connector, "stop", "Shuts down Geyser.", "geyser.command.stop"));
registerCommand(new OffhandCommand(connector, "offhand", "Puts an items in your offhand.", "geyser.command.offhand"));
registerCommand(new DumpCommand(connector, "dump", "Dumps Geyser debug infomation for bug reports.", "geyser.command.dump"));
registerCommand(new HelpCommand(connector, "help", LanguageUtils.getLocaleStringLog("geyser.commands.help.desc"), "geyser.command.help"));
registerCommand(new ListCommand(connector, "list", LanguageUtils.getLocaleStringLog("geyser.commands.list.desc"), "geyser.command.list"));
registerCommand(new ReloadCommand(connector, "reload", LanguageUtils.getLocaleStringLog("geyser.commands.reload.desc"), "geyser.command.reload"));
registerCommand(new StopCommand(connector, "stop", LanguageUtils.getLocaleStringLog("geyser.commands.stop.desc"), "geyser.command.stop"));
registerCommand(new OffhandCommand(connector, "offhand", LanguageUtils.getLocaleStringLog("geyser.commands.offhand.desc"), "geyser.command.offhand"));
registerCommand(new DumpCommand(connector, "dump", LanguageUtils.getLocaleStringLog("geyser.commands.dump.desc"), "geyser.command.dump"));
}
public void registerCommand(GeyserCommand command) {
commands.put(command.getName(), command);
connector.getLogger().debug("Registered command " + command.getName());
connector.getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.commands.registered", command.getName()));
if (command.getAliases().isEmpty())
return;
@ -82,7 +83,7 @@ public abstract class CommandManager {
GeyserCommand cmd = commands.get(label);
if (cmd == null) {
connector.getLogger().error("Invalid Command! Try /geyser help for a list of commands.");
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.invalid"));
return;
}

View file

@ -34,6 +34,7 @@ import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.dump.DumpInfo;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.connector.utils.WebUtils;
import java.io.IOException;
@ -57,37 +58,37 @@ public class DumpCommand extends GeyserCommand {
@Override
public void execute(CommandSender sender, String[] args) {
sender.sendMessage("Collecting dump info");
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collecting"));
String dumpData = "";
try {
dumpData = MAPPER.writeValueAsString(new DumpInfo());
} catch (IOException e) {
sender.sendMessage(ChatColor.RED + "Failed to collect dump info, check console for more information");
connector.getLogger().error("Failed to collect dump info", e);
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error"));
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e);
return;
}
sender.sendMessage("Uploading dump");
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.uploading"));
String response;
JsonNode responseNode;
try {
response = WebUtils.post(DUMP_URL + "documents", dumpData);
responseNode = MAPPER.readTree(response);
} catch (IOException e) {
sender.sendMessage(ChatColor.RED + "Failed to upload dump, check console for more information");
connector.getLogger().error("Failed to upload dump", e);
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error"));
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e);
return;
}
if (!responseNode.has("key")) {
sender.sendMessage(ChatColor.RED + "Failed to upload dump: " + (responseNode.has("message") ? responseNode.get("message").asText() : response));
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short") + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response));
return;
}
String uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText();
sender.sendMessage("We've made a dump with useful information, report your issue and provide this url: " + ChatColor.DARK_AQUA + uploadedDumpUrl);
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.message") + " " + ChatColor.DARK_AQUA + uploadedDumpUrl);
if (!sender.isConsole()) {
connector.getLogger().info(sender.getName() + " created a GeyserDump at " + uploadedDumpUrl);
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.commands.dump.created", sender.getName(), uploadedDumpUrl));
}
}
}

View file

@ -29,6 +29,8 @@ import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.Collections;
import java.util.List;
@ -48,7 +50,17 @@ public class HelpCommand extends GeyserCommand {
@Override
public void execute(CommandSender sender, String[] args) {
sender.sendMessage("---- Showing Help For: Geyser (Page 1/1) ----");
int page = 1;
int maxPage = 1;
String header = "";
if (sender instanceof GeyserSession) {
header = LanguageUtils.getPlayerLocaleString("geyser.commands.help.header", ((GeyserSession) sender).getClientData().getLanguageCode(), page, maxPage);
} else {
header = LanguageUtils.getLocaleStringLog("geyser.commands.help.header", page, maxPage);
}
sender.sendMessage(header);
Map<String, GeyserCommand> cmds = connector.getCommandManager().getCommands();
List<String> commands = connector.getCommandManager().getCommands().keySet().stream().sorted().collect(Collectors.toList());
commands.forEach(cmd -> sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmd + ChatColor.WHITE + ": " + cmds.get(cmd).getDescription()));

View file

@ -25,11 +25,11 @@
package org.geysermc.connector.command.defaults;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.stream.Collectors;
@ -45,6 +45,13 @@ public class ListCommand extends GeyserCommand {
@Override
public void execute(CommandSender sender, String[] args) {
sender.sendMessage(ChatColor.YELLOW + "Online Players (" + connector.getPlayers().size() + "): " + ChatColor.WHITE + connector.getPlayers().values().stream().map(GeyserSession::getName).collect(Collectors.joining(" ")));
String message = "";
if (sender instanceof GeyserSession) {
message = LanguageUtils.getPlayerLocaleString("geyser.commands.list.message", ((GeyserSession) sender).getClientData().getLanguageCode(), connector.getPlayers().size(), connector.getPlayers().values().stream().map(GeyserSession::getName).collect(Collectors.joining(" ")));
} else {
message = LanguageUtils.getLocaleStringLog("geyser.commands.list.message", connector.getPlayers().size(), connector.getPlayers().values().stream().map(GeyserSession::getName).collect(Collectors.joining(" ")));
}
sender.sendMessage(message);
}
}

View file

@ -25,12 +25,12 @@
package org.geysermc.connector.command.defaults;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.common.PlatformType;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
public class ReloadCommand extends GeyserCommand {
@ -46,9 +46,18 @@ public class ReloadCommand extends GeyserCommand {
if (!sender.isConsole() && connector.getPlatformType() == PlatformType.STANDALONE) {
return;
}
sender.sendMessage(ChatColor.YELLOW + "Reloading Geyser configurations... all connected bedrock clients will be kicked.");
String message = "";
if (sender instanceof GeyserSession) {
message = LanguageUtils.getPlayerLocaleString("geyser.commands.reload.message", ((GeyserSession) sender).getClientData().getLanguageCode());
} else {
message = LanguageUtils.getLocaleStringLog("geyser.commands.reload.message");
}
sender.sendMessage(message);
for (GeyserSession session : connector.getPlayers().values()) {
session.disconnect("Geyser has been reloaded... sorry for the inconvenience!");
session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.commands.reload.kick", session.getClientData().getLanguageCode()));
}
connector.reload();
}

View file

@ -28,24 +28,39 @@ package org.geysermc.connector.common.main;
import javax.swing.*;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Scanner;
public class IGeyserMain {
/**
* Displays the run help message in the console and a message box if running with a gui
*/
public void displayMessage() {
String message = createMessage();
if (System.console() == null) {
if (System.console() == null && !isHeadless()) {
JOptionPane.showMessageDialog(null, message, "GeyserMC Plugin: " + this.getPluginType(), JOptionPane.ERROR_MESSAGE);
}
printMessage(message);
}
/**
* Load and format the run help text
*
* @return The formatted message
*/
private String createMessage() {
String message = "";
InputStream helpStream = IGeyserMain.class.getClassLoader().getResourceAsStream("help.txt");
InputStream helpStream = IGeyserMain.class.getClassLoader().getResourceAsStream("languages/run-help/" + Locale.getDefault().toString() + ".txt");
if (helpStream == null) {
helpStream = IGeyserMain.class.getClassLoader().getResourceAsStream("languages/run-help/en_US.txt");
}
Scanner help = new Scanner(helpStream).useDelimiter("\\Z");
String line = "";
while (help.hasNext()) {
@ -60,14 +75,44 @@ public class IGeyserMain {
return message;
}
/**
* Check if we are in a headless environment
*
* @return Are we in a headless environment?
*/
private boolean isHeadless() {
try {
Class<?> graphicsEnvironment = Class.forName("java.awt.GraphicsEnvironment");
Method isHeadless = graphicsEnvironment.getDeclaredMethod("isHeadless");
return (Boolean)isHeadless.invoke(null);
} catch (Exception ex) { }
return true;
}
/**
* Simply print a message to console
*
* @param message The message to print
*/
private void printMessage(String message) {
System.out.print(message);
}
/**
* Get the platform the plugin is for
*
* @return The string representation of the plugin platforms name
*/
public String getPluginType() {
return "unknown";
}
/**
* Get the folder name the plugin should go into
*
* @return The string representation of the folder
*/
public String getPluginFolder() {
return "unknown";
}

View file

@ -28,6 +28,8 @@ package org.geysermc.connector.configuration;
import org.geysermc.connector.GeyserLogger;
import org.geysermc.connector.utils.LanguageUtils;
import java.nio.file.Path;
import java.util.Map;
@ -111,9 +113,9 @@ public interface GeyserConfiguration {
static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) {
if (geyserConfig.getConfigVersion() < CURRENT_CONFIG_VERSION) {
geyserLogger.warning("Your Geyser config is out of date! Please regenerate your config when possible.");
geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.outdated"));
} else if (geyserConfig.getConfigVersion() > CURRENT_CONFIG_VERSION) {
geyserLogger.warning("Your Geyser config is too new! Errors may occur.");
geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.too_new"));
}
}
}

View file

@ -37,6 +37,7 @@ import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.MessageUtils;
import org.geysermc.connector.utils.LanguageUtils;
import java.net.InetSocketAddress;
@ -50,13 +51,13 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
@Override
public boolean onConnectionRequest(InetSocketAddress inetSocketAddress) {
connector.getLogger().info(inetSocketAddress + " tried to connect!");
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.attempt_connect", inetSocketAddress));
return true;
}
@Override
public BedrockPong onQuery(InetSocketAddress inetSocketAddress) {
connector.getLogger().debug(inetSocketAddress + " has pinged you!");
connector.getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.pinged", inetSocketAddress));
GeyserConfiguration config = connector.getConfig();
@ -108,7 +109,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
bedrockServerSession.setLogging(true);
bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(connector, new GeyserSession(connector, bedrockServerSession)));
bedrockServerSession.addDisconnectHandler(disconnectReason -> {
connector.getLogger().info("Bedrock user with ip: " + bedrockServerSession.getAddress().getAddress() + " has disconnected for reason " + disconnectReason);
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.disconnect", bedrockServerSession.getAddress().getAddress(), disconnectReason));
GeyserSession player = connector.getPlayers().get(bedrockServerSession.getAddress());
if (player != null) {

View file

@ -33,6 +33,7 @@ import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
import org.geysermc.connector.utils.LoginEncryptionUtils;
import org.geysermc.connector.utils.LanguageUtils;
public class UpstreamPacketHandler extends LoggingPacketHandler {
@ -47,10 +48,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override
public boolean handle(LoginPacket loginPacket) {
if (loginPacket.getProtocolVersion() > GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()) {
session.disconnect("Outdated Geyser proxy! I'm still on " + GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion());
session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.outdated.server", session.getClientData().getLanguageCode(), GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion()));
return true;
} else if (loginPacket.getProtocolVersion() < GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()) {
session.disconnect("Outdated Bedrock client! Please use " + GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion());
session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.outdated.client", session.getClientData().getLanguageCode(), GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion()));
return true;
}
@ -70,7 +71,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
switch (packet.getStatus()) {
case COMPLETED:
session.connect(connector.getRemoteServer());
connector.getLogger().info("Player connected with username " + session.getAuthData().getName());
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.connect", session.getAuthData().getName()));
break;
case HAVE_ALL_PACKS:
ResourcePackStackPacket stack = new ResourcePackStackPacket();
@ -97,7 +98,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
GeyserConfiguration.IUserAuthenticationInfo info = connector.getConfig().getUserAuths().get(bedrockUsername);
if (info != null) {
connector.getLogger().info("using stored credentials for bedrock user " + session.getAuthData().getName());
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().getName()));
session.authenticate(info.getEmail(), info.getPassword());
// TODO send a message to bedrock user telling them they are connected (if nothing like a motd
@ -111,6 +112,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override
public boolean handle(SetLocalPlayerAsInitializedPacket packet) {
LanguageUtils.loadGeyserLocale(session.getClientData().getLanguageCode());
if (!session.isLoggedIn() && !session.isLoggingIn() && session.getConnector().getAuthType() == AuthType.ONLINE) {
// TODO it is safer to key authentication on something that won't change (UUID, not username)
if (!couldLoginUserByName(session.getAuthData().getName())) {
@ -124,7 +127,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override
public boolean handle(MovePlayerPacket packet) {
if (session.isLoggingIn()) {
session.sendMessage("Please wait until you are logged in...");
session.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.auth.login.wait", session.getClientData().getLanguageCode()));
}
return translateAndDefault(packet);

View file

@ -258,12 +258,11 @@ public class GeyserSession implements CommandSender {
public void login() {
if (connector.getAuthType() != AuthType.ONLINE) {
connector.getLogger().info(
"Attempting to login using " + connector.getAuthType().name().toLowerCase() + " mode... " +
(connector.getAuthType() == AuthType.OFFLINE ?
"authentication is disabled." : "authentication will be encrypted"
)
);
if (connector.getAuthType() == AuthType.OFFLINE) {
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.login.offline"));
} else {
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.login.floodgate"));
}
authenticate(authData.getName());
}
}
@ -274,7 +273,7 @@ public class GeyserSession implements CommandSender {
public void authenticate(String username, String password) {
if (loggedIn) {
connector.getLogger().severe(username + " is already logged in!");
connector.getLogger().severe(LanguageUtils.getLocaleStringLog("geyser.auth.already_loggedin", username));
return;
}
@ -299,13 +298,13 @@ public class GeyserSession implements CommandSender {
PublicKey.class
);
} catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException e) {
connector.getLogger().error("Error while reading Floodgate key file", e);
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.bad_key"), e);
}
publicKey = key;
} else publicKey = null;
if (publicKey != null) {
connector.getLogger().info("Loaded Floodgate key!");
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.loaded_key"));
}
downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory());
@ -326,7 +325,7 @@ public class GeyserSession implements CommandSender {
upstream.getSession().getAddress().getAddress().getHostAddress()
));
} catch (Exception e) {
connector.getLogger().error("Failed to encrypt message", e);
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.encrypt_fail"), e);
}
HandshakePacket handshakePacket = event.getPacket();
@ -343,7 +342,7 @@ public class GeyserSession implements CommandSender {
public void connected(ConnectedEvent event) {
loggingIn = false;
loggedIn = true;
connector.getLogger().info(authData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress());
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.remote.connect", authData.getName(), protocol.getProfile().getName(), remoteServer.getAddress()));
playerEntity.setUuid(protocol.getProfile().getId());
playerEntity.setUsername(protocol.getProfile().getName());
@ -352,6 +351,7 @@ 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")) {
// This should probably be left hardcoded as it will only show for en_us clients
sendMessage("Downloading your locale (en_us) this may take some time");
}
@ -363,7 +363,7 @@ public class GeyserSession implements CommandSender {
public void disconnected(DisconnectedEvent event) {
loggingIn = false;
loggedIn = false;
connector.getLogger().info(authData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress() + " because of " + event.getReason());
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.remote.disconnect", authData.getName(), remoteServer.getAddress(), event.getReason()));
if (event.getCause() != null) {
event.getCause().printStackTrace();
}
@ -402,7 +402,7 @@ public class GeyserSession implements CommandSender {
@Override
public void packetError(PacketErrorEvent event) {
connector.getLogger().warning("Downstream packet error! " + event.getCause().getMessage());
connector.getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.network.downstream_error", event.getCause().getMessage()));
if (connector.getConfig().isDebugMode())
event.getCause().printStackTrace();
event.setSuppress(true);
@ -412,8 +412,8 @@ public class GeyserSession implements CommandSender {
downstream.getSession().connect();
connector.addPlayer(this);
} catch (InvalidCredentialsException | IllegalArgumentException e) {
connector.getLogger().info("User '" + username + "' entered invalid login info, kicking.");
disconnect("Invalid/incorrect login info");
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.login.invalid", username));
disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.login.invalid.kick", getClientData().getLanguageCode()));
} catch (RequestException ex) {
ex.printStackTrace();
}
@ -442,7 +442,7 @@ public class GeyserSession implements CommandSender {
}
public void close() {
disconnect("Server closed.");
disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.close", getClientData().getLanguageCode()));
}
public void setAuthenticationData(AuthData authData) {

View file

@ -31,6 +31,7 @@ import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtUtils;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import java.io.InputStream;
import java.util.Arrays;
@ -59,7 +60,7 @@ public class BiomeTranslator {
biomesTag = (NbtMap) biomenbtInputStream.readTag();
BIOMES = biomesTag;
} catch (Exception ex) {
GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?");
GeyserConnector.getInstance().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.biome_read"));
throw new AssertionError(ex);
}
}

View file

@ -30,6 +30,7 @@ import com.nukkitx.nbt.NBTInputStream;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtUtils;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import java.io.InputStream;
@ -54,7 +55,7 @@ public class EntityIdentifierRegistry {
try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) {
ENTITY_IDENTIFIERS = (NbtMap) nbtInputStream.readTag();
} catch (Exception e) {
throw new AssertionError("Unable to get entities from entity identifiers", e);
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.entity"), e);
}
}
}

View file

@ -33,6 +33,7 @@ import com.nukkitx.protocol.bedrock.BedrockPacket;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import org.reflections.Reflections;
import java.util.HashMap;
@ -66,10 +67,10 @@ public class PacketTranslatorRegistry<T> {
BEDROCK_TRANSLATOR.translators.put(targetPacket, translator);
} else {
GeyserConnector.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet.");
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.invalid_target", clazz.getCanonicalName()));
}
} catch (InstantiationException | IllegalAccessException e) {
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated translator " + clazz.getCanonicalName() + ".");
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.failed", clazz.getCanonicalName()));
}
}
@ -97,7 +98,7 @@ public class PacketTranslatorRegistry<T> {
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
}
} catch (Throwable ex) {
GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.packet.failed", packet.getClass().getSimpleName()), ex);
ex.printStackTrace();
}
}

View file

@ -36,6 +36,7 @@ public class BedrockPacketViolationWarningTranslator extends PacketTranslator<Pa
@Override
public void translate(PacketViolationWarningPacket packet, GeyserSession session) {
// Not translated since this is something that the developers need to know
session.getConnector().getLogger().error("Packet violation warning sent from client! " + packet.toString());
}
}

View file

@ -35,6 +35,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.NonNull;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import java.io.InputStream;
import java.util.HashMap;
@ -80,7 +81,7 @@ public class EffectRegistry {
+ entry.getValue().asText()
+ ", it will take effect.");
} catch (IllegalArgumentException e2){
GeyserConnector.getInstance().getLogger().warning("Fail to map particle " + entry.getKey() + "=>" + entry.getValue().asText());
GeyserConnector.getInstance().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.particle.failed_map", entry.getKey(), entry.getValue().asText()));
}
}
}

View file

@ -39,12 +39,12 @@ import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator;
import org.geysermc.connector.network.translators.item.ItemTranslator;
import org.geysermc.connector.utils.InventoryUtils;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.List;
public class PlayerInventoryTranslator extends InventoryTranslator {
private static final ItemData UNUSUABLE_CRAFTING_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(
"The creative crafting grid is\nunavailable in Java Edition");
private static final ItemData UNUSUABLE_CRAFTING_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.creative"));
public PlayerInventoryTranslator() {
super(46);

View file

@ -34,11 +34,11 @@ import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
import org.geysermc.connector.network.translators.item.ItemTranslator;
import org.geysermc.connector.utils.InventoryUtils;
import org.geysermc.connector.utils.LanguageUtils;
@AllArgsConstructor
public class ChestInventoryUpdater extends InventoryUpdater {
private static final ItemData UNUSUABLE_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(
"This slot does not exist in the inventory\non Java Edition, as there is less\nrows than possible in Bedrock");
private static final ItemData UNUSUABLE_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.slot"));
private final int paddedSize;

View file

@ -37,16 +37,12 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* Registry for anything item related.
@ -82,7 +78,7 @@ public class ItemRegistry {
try {
itemEntries = GeyserConnector.JSON_MAPPER.readValue(stream, itemEntriesType);
} catch (Exception e) {
throw new AssertionError("Unable to load Bedrock runtime item IDs", e);
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_bedrock"), e);
}
for (JsonNode entry : itemEntries) {
@ -95,7 +91,7 @@ public class ItemRegistry {
try {
items = GeyserConnector.JSON_MAPPER.readTree(stream);
} catch (Exception e) {
throw new AssertionError("Unable to load Java runtime item IDs", e);
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
}
int itemIndex = 0;
@ -144,7 +140,7 @@ public class ItemRegistry {
try {
creativeItemEntries = GeyserConnector.JSON_MAPPER.readTree(stream).get("items");
} catch (Exception e) {
throw new AssertionError("Unable to load creative items", e);
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.creative"), e);
}
List<ItemData> creativeItems = new ArrayList<>();

View file

@ -50,6 +50,7 @@ import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.ItemRemapper;
import org.geysermc.connector.utils.MessageUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.reflections.Reflections;
import java.util.*;
@ -88,14 +89,13 @@ public abstract class ItemTranslator {
for (ItemEntry item : appliedItems) {
ItemTranslator registered = ITEM_STACK_TRANSLATORS.get(item.getJavaId());
if (registered != null) {
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + "." +
" Item translator " + registered.getClass().getCanonicalName() + " is already registered for the item " + item.getJavaIdentifier());
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.item.already_registered", clazz.getCanonicalName(), registered.getClass().getCanonicalName(), item.getJavaIdentifier()));
continue;
}
ITEM_STACK_TRANSLATORS.put(item.getJavaId(), itemStackTranslator);
}
} catch (InstantiationException | IllegalAccessException e) {
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + ".");
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.item.failed", clazz.getCanonicalName()));
}
}

View file

@ -41,6 +41,7 @@ import org.geysermc.connector.network.session.cache.TeleportCache;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.utils.ChunkUtils;
import org.geysermc.connector.utils.LanguageUtils;
@Translator(packet = ServerPlayerPositionRotationPacket.class)
public class JavaPlayerPositionRotationTranslator extends PacketTranslator<ServerPlayerPositionRotationPacket> {
@ -90,7 +91,7 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
ChunkUtils.updateChunkPosition(session, pos.toInt());
session.getConnector().getLogger().info("Spawned player at " + packet.getX() + " " + packet.getY() + " " + packet.getZ());
session.getConnector().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.entity.player.spawn", packet.getX(), packet.getY(), packet.getZ()));
return;
}

View file

@ -36,6 +36,7 @@ import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.utils.EntityUtils;
import org.geysermc.connector.utils.LanguageUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@ -52,7 +53,7 @@ public class JavaSpawnEntityTranslator extends PacketTranslator<ServerSpawnEntit
org.geysermc.connector.entity.type.EntityType type = EntityUtils.toBedrockEntity(packet.getType());
if (type == null) {
session.getConnector().getLogger().warning("Entity type " + packet.getType() + " was null.");
session.getConnector().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.entity.type_null", packet.getType()));
return;
}

View file

@ -33,6 +33,7 @@ import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.utils.EntityUtils;
import org.geysermc.connector.utils.LanguageUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@ -48,7 +49,7 @@ public class JavaSpawnLivingEntityTranslator extends PacketTranslator<ServerSpaw
EntityType type = EntityUtils.toBedrockEntity(packet.getType());
if (type == null) {
session.getConnector().getLogger().warning("Entity type " + packet.getType() + " was null.");
session.getConnector().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.entity.type_null", packet.getType()));
return;
}

View file

@ -32,6 +32,7 @@ import org.geysermc.connector.entity.PlayerEntity;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.connector.utils.SkinUtils;
@Translator(packet = ServerSpawnPlayerPacket.class)
@ -44,7 +45,7 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlaye
PlayerEntity entity = session.getEntityCache().getPlayerEntity(packet.getUuid());
if (entity == null) {
GeyserConnector.getInstance().getLogger().error("Haven't received PlayerListEntry packet before spawning player! We ignore the player " + packet.getUuid());
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.entity.player.failed_list", packet.getUuid()));
return;
}

View file

@ -25,9 +25,8 @@
package org.geysermc.connector.network.translators.java.scoreboard;
import java.util.Arrays;
import java.util.Set;
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerTeamPacket;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
@ -35,11 +34,11 @@ import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.scoreboard.Scoreboard;
import org.geysermc.connector.scoreboard.Team;
import org.geysermc.connector.scoreboard.UpdateType;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.connector.utils.MessageUtils;
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerTeamPacket;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import java.util.Arrays;
import java.util.Set;
@Translator(packet = ServerTeamPacket.class)
public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
@ -66,21 +65,21 @@ public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
.setSuffix(MessageUtils.getBedrockMessage(packet.getSuffix()))
.setUpdateType(UpdateType.UPDATE);
} else {
GeyserConnector.getInstance().getLogger().error("Error while translating Team Packet " + packet.getAction() + "! Scoreboard Team " + packet.getTeamName() + " is not registered.");
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName()));
}
break;
case ADD_PLAYER:
if(team != null){
team.addEntities(packet.getPlayers());
} else {
GeyserConnector.getInstance().getLogger().error("Error while translating Team Packet " + packet.getAction() + "! Scoreboard Team " + packet.getTeamName() + " is not registered.");
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName()));
}
break;
case REMOVE_PLAYER:
if(team != null){
team.removeEntities(packet.getPlayers());
} else {
GeyserConnector.getInstance().getLogger().error("Error while translating Team Packet " + packet.getAction() + "! Scoreboard Team " + packet.getTeamName() + " is not registered.");
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName()));
}
break;
case REMOVE:

View file

@ -34,6 +34,7 @@ import org.geysermc.connector.scoreboard.Scoreboard;
import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardAction;
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket;
import org.geysermc.connector.utils.LanguageUtils;
@Translator(packet = ServerUpdateScorePacket.class)
public class JavaUpdateScoreTranslator extends PacketTranslator<ServerUpdateScorePacket> {
@ -45,7 +46,7 @@ public class JavaUpdateScoreTranslator extends PacketTranslator<ServerUpdateScor
Objective objective = scoreboard.getObjective(packet.getObjective());
if (objective == null && packet.getAction() != ScoreboardAction.REMOVE) {
GeyserConnector.getInstance().getLogger().info("Tried to update score without the existence of its requested objective '" + packet.getObjective() + '\'');
GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.translator.score.failed_objective", packet.getObjective()));
return;
}

View file

@ -34,6 +34,7 @@ import com.nukkitx.nbt.NbtMapBuilder;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.utils.BlockEntityUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.reflections.Reflections;
import java.util.HashMap;
@ -72,7 +73,7 @@ public abstract class BlockEntityTranslator {
try {
BLOCK_ENTITY_TRANSLATORS.put(clazz.getAnnotation(BlockEntity.class).name(), (BlockEntityTranslator) clazz.newInstance());
} catch (InstantiationException | IllegalAccessException e) {
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated block entity " + clazz.getCanonicalName() + ".");
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.block_entity.failed", clazz.getCanonicalName()));
}
}
for (Class<?> clazz : ref.getSubTypesOf(RequiresBlockState.class)) {
@ -81,7 +82,7 @@ public abstract class BlockEntityTranslator {
try {
REQUIRES_BLOCK_STATE_LIST.add((RequiresBlockState) clazz.newInstance());
} catch (InstantiationException | IllegalAccessException e) {
GeyserConnector.getInstance().getLogger().error("Could not instantiate required block state " + clazz.getCanonicalName() + ".");
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.block_state.failed", clazz.getCanonicalName()));
}
}
}

View file

@ -34,6 +34,7 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import lombok.Getter;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
@ -78,7 +79,7 @@ public class Scoreboard {
public Team registerNewTeam(String teamName, Set<String> players) {
if (teams.containsKey(teamName)) {
session.getConnector().getLogger().info("Ignoring team " + teamName + ". It overrides without removing old team.");
session.getConnector().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_overrides", teamName));
return getTeam(teamName);
}

View file

@ -49,8 +49,8 @@ public class DockerCheck {
String output = new String(Files.readAllBytes(Paths.get("/proc/1/cgroup")));
if (output.contains("docker")) {
bootstrap.getGeyserLogger().warning("You are most likely in a Docker container, this may cause connection issues from Geyser to the Java server");
bootstrap.getGeyserLogger().warning("We recommended using the following IP as the remote address: " + ipAddress);
bootstrap.getGeyserLogger().warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.docker_warn.line1"));
bootstrap.getGeyserLogger().warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.docker_warn.line2", ipAddress));
}
}
} catch (Exception e) { } // Ignore any errors, inc ip failed to fetch, process could not run or access denied

View file

@ -135,7 +135,7 @@ public class FileUtils {
public static InputStream getResource(String resource) {
InputStream stream = FileUtils.class.getClassLoader().getResourceAsStream(resource);
if (stream == null) {
throw new AssertionError("Unable to find resource: " + resource);
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.resource", resource));
}
return stream;
}

View file

@ -140,7 +140,8 @@ public class InventoryUtils {
NbtMapBuilder root = NbtMap.builder();
NbtMapBuilder display = NbtMap.builder();
display.putString("Name", ChatColor.RESET + "Unusable inventory space");
// Not ideal to use log here but we dont get a session
display.putString("Name", ChatColor.RESET + LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.name"));
display.putList("Lore", NbtType.STRING, Collections.singletonList(ChatColor.RESET + ChatColor.DARK_PURPLE + description));
root.put("display", display.build());

View file

@ -0,0 +1,207 @@
/*
* 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;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
public class LanguageUtils {
/**
* If we determine the locale that the user wishes to use, use that locale
*/
private static String CACHED_LOCALE;
private static final Map<String, Properties> LOCALE_MAPPINGS = new HashMap<>();
static {
// Load it as a backup in case something goes really wrong
if (!"en_US".equals(formatLocale(getDefaultLocale()))) { // getDefaultLocale() loads the locale automatically
loadGeyserLocale("en_US");
}
}
/**
* Loads a Geyser locale from resources, if the file doesn't exist it just logs a warning
*
* @param locale Locale to load
*/
public static void loadGeyserLocale(String locale) {
locale = formatLocale(locale);
InputStream localeStream = GeyserConnector.class.getClassLoader().getResourceAsStream("languages/texts/" + locale + ".properties");
// Load the locale
if (localeStream != null) {
Properties localeProp = new Properties();
try {
localeProp.load(new InputStreamReader(localeStream, StandardCharsets.UTF_8));
} catch (Exception e) {
throw new AssertionError(getLocaleStringLog("geyser.language.load_failed", locale), e);
}
// Insert the locale into the mappings
LOCALE_MAPPINGS.put(locale, localeProp);
} else {
if (!locale.toLowerCase().equals(getDefaultLocale().toLowerCase())) { // The default locale was invalid fallback to en_us
GeyserConnector.getInstance().getLogger().warning(getLocaleStringLog("geyser.language.missing_file", locale));
}
}
}
/**
* Get a formatted language string with the default locale for Geyser
*
* @param key Language string to translate
* @param values Values to put into the string
* @return Translated string or the original message if it was not found in the given locale
*/
public static String getLocaleStringLog(String key, Object... values) {
return getPlayerLocaleString(key, getDefaultLocale(), values);
}
/**
* Get a formatted language string with the given locale for Geyser
*
* @param key Language string to translate
* @param locale Locale to translate to
* @param values Values to put into the string
* @return Translated string or the original message if it was not found in the given locale
*/
public static String getPlayerLocaleString(String key, String locale, Object... values) {
locale = formatLocale(locale);
Properties properties = LOCALE_MAPPINGS.get(locale);
String formatString = properties.getProperty(key);
// Try and get the key from the default locale
if (formatString == null) {
properties = LOCALE_MAPPINGS.get(formatLocale(getDefaultLocale()));
formatString = properties.getProperty(key);
}
// Try and get the key from en_US (this should only ever happen in development)
if (formatString == null) {
properties = LOCALE_MAPPINGS.get("en_US");
formatString = properties.getProperty(key);
}
// Final fallback
if (formatString == null) {
formatString = key;
}
return MessageFormat.format(formatString.replace("&", "\u00a7"), values);
}
/**
* Cleans up and formats a locale string
*
* @param locale The locale to format
* @return The formatted locale
*/
private static String formatLocale(String locale) {
try {
String[] parts = locale.toLowerCase().split("_");
String newLocale = parts[0] + "_" + parts[1].toUpperCase();
switch (newLocale) { // Fallback to the closest language if we don't support it but Bedrock does.
case "es_MX":
return "es_ES";
case "pt_BR":
return "pt_PT";
case "fr_CA":
return "fr_FR";
default:
return newLocale;
}
} catch (Exception e) {
return locale;
}
}
/**
* Get the default locale that Geyser should use
* @return the current default locale
*/
public static String getDefaultLocale() {
if (CACHED_LOCALE != null) return CACHED_LOCALE; // We definitely know the locale the user is using
String locale;
boolean isValid = true;
if (GeyserConnector.getInstance() != null &&
GeyserConnector.getInstance().getConfig() != null &&
GeyserConnector.getInstance().getConfig().getDefaultLocale() != null) { // If the config option for getDefaultLocale does not equal null, use that
locale = formatLocale(GeyserConnector.getInstance().getConfig().getDefaultLocale());
if (isValidLanguage(locale)) {
CACHED_LOCALE = locale;
return locale;
} else {
isValid = false;
}
}
locale = formatLocale(Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry());
if (!isValidLanguage(locale)) { // Bedrock does not support this language
locale = "en_US";
}
if (GeyserConnector.getInstance() != null &&
GeyserConnector.getInstance().getConfig() != null && (GeyserConnector.getInstance().getConfig().getDefaultLocale() == null || !isValid)) { // Means we should use the system locale for sure
CACHED_LOCALE = locale;
}
return locale;
}
/**
* Ensures that the given locale is supported by Bedrock
* @param locale the locale to validate
* @return true if the given locale is supported by Bedrock and by extension Geyser
*/
private static boolean isValidLanguage(String locale) {
boolean result = true;
if (FileUtils.class.getResource("/languages/texts/" + locale + ".properties") == null) {
result = false;
if (GeyserConnector.getInstance() != null && GeyserConnector.getInstance().getLogger() != null) { // Could be too early for these to be initialized
GeyserConnector.getInstance().getLogger().warning(locale + " is not a valid Bedrock language."); // We can't translate this since we just loaded an invalid language
}
} else {
if (!LOCALE_MAPPINGS.containsKey(locale)) {
loadGeyserLocale(locale);
}
}
return result;
}
public static void init() {
// no-op
}
}

View file

@ -48,8 +48,6 @@ public class LocaleUtils {
private static final Map<String, Asset> ASSET_MAP = new HashMap<>();
private static final String DEFAULT_LOCALE = (GeyserConnector.getInstance().getConfig().getDefaultLocale() != null ? GeyserConnector.getInstance().getConfig().getDefaultLocale() : "en_us");
private static String smallestURL = "";
static {
@ -60,7 +58,7 @@ public class LocaleUtils {
// Download the latest asset list and cache it
generateAssetCache();
downloadAndLoadLocale(DEFAULT_LOCALE);
downloadAndLoadLocale(LanguageUtils.getDefaultLocale());
}
/**
@ -82,7 +80,7 @@ public class LocaleUtils {
// Make sure we definitely got a version
if (latestInfoURL.isEmpty()) {
throw new Exception("Unable to get latest Minecraft version");
throw new Exception(LanguageUtils.getLocaleStringLog("geyser.locale.fail.latest_version"));
}
// Get the individual version manifest
@ -105,7 +103,7 @@ public class LocaleUtils {
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()));
GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.locale.fail.asset_cache", (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace())));
}
}
@ -119,7 +117,7 @@ public class LocaleUtils {
// Check the locale isn't already loaded
if (!ASSET_MAP.containsKey("minecraft/lang/" + locale + ".json") && !locale.equals("en_us")) {
GeyserConnector.getInstance().getLogger().warning("Invalid locale requested to download and load: " + locale);
GeyserConnector.getInstance().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.locale.fail.invalid", locale));
return;
}
@ -170,7 +168,7 @@ public class LocaleUtils {
try {
localeStream = new FileInputStream(localeFile);
} catch (FileNotFoundException e) {
throw new AssertionError("Unable to load locale: " + locale + " (" + e.getMessage() + ")");
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.locale.fail.file", locale, e.getMessage()));
}
// Parse the file as json
@ -178,7 +176,7 @@ public class LocaleUtils {
try {
localeObj = GeyserConnector.JSON_MAPPER.readTree(localeStream);
} catch (Exception e) {
throw new AssertionError("Unable to load Java edition lang map for " + locale, e);
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.locale.fail.json", locale), e);
}
// Parse all the locale fields
@ -192,7 +190,7 @@ public class LocaleUtils {
// Insert the locale into the mappings
LOCALE_MAPPINGS.put(locale.toLowerCase(), langMap);
} else {
GeyserConnector.getInstance().getLogger().warning("Missing locale file: " + locale);
GeyserConnector.getInstance().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.locale.fail.missing", locale));
}
}
@ -204,7 +202,7 @@ 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().info(LanguageUtils.getLocaleStringLog("geyser.locale.download.en_us"));
GeyserConnector.getInstance().getLogger().debug("Download URL: " + smallestURL);
// Download the smallest JAR (client or server)
@ -233,7 +231,7 @@ public class LocaleUtils {
// Delete the nolonger needed client/server jar
Files.delete(tmpFilePath);
} catch (Exception e) {
throw new AssertionError("Unable to download and extract en_us locale!", e);
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.locale.fail.en_us"), e);
}
}
@ -247,7 +245,7 @@ public class LocaleUtils {
public static String getLocaleString(String messageText, String locale) {
Map<String, String> localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(locale.toLowerCase());
if (localeStrings == null)
localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(DEFAULT_LOCALE);
localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(LanguageUtils.getDefaultLocale());
return localeStrings.getOrDefault(messageText, messageText);
}

View file

@ -156,18 +156,20 @@ public class LoginEncryptionUtils {
private static int AUTH_DETAILS_FORM_ID = 1337;
public static void showLoginWindow(GeyserSession session) {
SimpleFormWindow window = new SimpleFormWindow("Login", "You need a Java Edition account to play on this server.");
window.getButtons().add(new FormButton("Login with Minecraft"));
window.getButtons().add(new FormButton("Disconnect"));
String userLanguage = session.getClientData().getLanguageCode();
SimpleFormWindow window = new SimpleFormWindow(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.title", userLanguage), LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.desc", userLanguage));
window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.btn_login", userLanguage)));
window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.btn_disconnect", userLanguage)));
session.sendForm(window, AUTH_FORM_ID);
}
public static void showLoginDetailsWindow(GeyserSession session) {
CustomFormWindow window = new CustomFormBuilder("Login Details")
.addComponent(new LabelComponent("Enter the credentials for your Minecraft: Java Edition account below."))
.addComponent(new InputComponent("Email/Username", "account@geysermc.org", ""))
.addComponent(new InputComponent("Password", "123456", ""))
String userLanguage = session.getClientData().getLanguageCode();
CustomFormWindow window = new CustomFormBuilder(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.details.title", userLanguage))
.addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.details.desc", userLanguage)))
.addComponent(new InputComponent(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.details.email", userLanguage), "account@geysermc.org", ""))
.addComponent(new InputComponent(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.details.pass", userLanguage), "123456", ""))
.build();
session.sendForm(window, AUTH_DETAILS_FORM_ID);
@ -204,7 +206,7 @@ public class LoginEncryptionUtils {
if (response.getClickedButtonId() == 0) {
showLoginDetailsWindow(session);
} else if(response.getClickedButtonId() == 1) {
session.disconnect("Login is required");
session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getClientData().getLanguageCode()));
}
} else {
showLoginWindow(session);

View file

@ -246,7 +246,7 @@ public class SkinUtils {
}
}
} catch (Exception e) {
GeyserConnector.getInstance().getLogger().error("Failed getting skin for " + entity.getUuid(), e);
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), e);
}
if (skinAndCapeConsumer != null) skinAndCapeConsumer.accept(skinAndCape);
@ -257,7 +257,7 @@ public class SkinUtils {
public static void handleBedrockSkin(PlayerEntity playerEntity, BedrockClientData clientData) {
GameProfileData data = GameProfileData.from(playerEntity.getProfile());
GeyserConnector.getInstance().getLogger().info("Registering bedrock skin for " + playerEntity.getUsername() + " (" + playerEntity.getUuid() + ")");
GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.skin.bedrock.register", playerEntity.getUsername(), playerEntity.getUuid()));
try {
byte[] skinBytes = com.github.steveice10.mc.auth.util.Base64.decode(clientData.getSkinData().getBytes("UTF-8"));
@ -270,7 +270,7 @@ public class SkinUtils {
SkinProvider.storeBedrockSkin(playerEntity.getUuid(), data.getSkinUrl(), skinBytes);
SkinProvider.storeBedrockGeometry(playerEntity.getUuid(), geometryNameBytes, geometryBytes);
} else {
GeyserConnector.getInstance().getLogger().info("Unable to load bedrock skin for '" + playerEntity.getUsername() + "' as they are likely using a customised skin");
GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.skin.bedrock.fail", playerEntity.getUsername()));
GeyserConnector.getInstance().getLogger().debug("The size of '" + playerEntity.getUsername() + "' skin is: " + clientData.getSkinImageWidth() + "x" + clientData.getSkinImageHeight());
}

View file

@ -78,8 +78,8 @@ allow-third-party-ears: false
# Allow a fake cooldown indicator to be sent. Bedrock players do not see a cooldown as they still use 1.8 combat
show-cooldown: true
# The default locale if we dont have the one the client requested
default-locale: en_us
# The default locale if we dont have the one the client requested. Uncomment to not use the default system language.
# default-locale: en_us
# Configures if chunk caching should be enabled or not. This keeps an individual
# record of each block the client loads in. While this feature does allow for a few

@ -0,0 +1 @@
Subproject commit 08be7fdd7bd3c1ade46fa8968c04d3d67bb0d378