mirror of
https://github.com/PaperMC/Velocity.git
synced 2026-02-17 14:37:43 +01:00
Add localization support. Fixes #230
This is less flexible, but it is an Adventure-native solution and doesn't require an onerous amount of work to maintain.
This commit is contained in:
@@ -78,6 +78,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -90,7 +91,11 @@ import java.util.function.IntFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.audience.ForwardingAudience;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import net.kyori.adventure.translation.TranslationRegistry;
|
||||
import net.kyori.adventure.util.UTF8ResourceBundleControl;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.asynchttpclient.AsyncHttpClient;
|
||||
@@ -193,6 +198,8 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
logger.info("Booting up {} {}...", version().getName(), version().getVersion());
|
||||
console.setupStreams();
|
||||
|
||||
registerTranslations();
|
||||
|
||||
serverKeyPair = EncryptionUtils.createRsaKeyPair(1024);
|
||||
|
||||
cm.logChannelInformation();
|
||||
@@ -236,6 +243,15 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
Metrics.VelocityMetrics.startMetrics(this, configuration.getMetrics());
|
||||
}
|
||||
|
||||
private void registerTranslations() {
|
||||
final TranslationRegistry translationRegistry = TranslationRegistry
|
||||
.create(Key.key("velocity", "translations"));
|
||||
translationRegistry.registerAll(Locale.US,
|
||||
ResourceBundle.getBundle("com/velocitypowered/proxy/messages", Locale.US,
|
||||
UTF8ResourceBundleControl.get()), false);
|
||||
GlobalTranslator.get().addSource(translationRegistry);
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("DM_EXIT")
|
||||
private void doStartupConfigLoad() {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command.builtin;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
public class CommandMessages {
|
||||
|
||||
public static final TranslatableComponent PLAYERS_ONLY = Component.translatable(
|
||||
"velocity.command.players-only", NamedTextColor.RED);
|
||||
public static final TranslatableComponent SERVER_DOES_NOT_EXIST = Component.translatable(
|
||||
"velocity.command.server-does-not-exist", NamedTextColor.RED);
|
||||
}
|
||||
@@ -78,11 +78,7 @@ public class GlistCommand {
|
||||
final CommandSource source = context.getSource();
|
||||
sendTotalProxyCount(source);
|
||||
source.sendMessage(Identity.nil(),
|
||||
Component.text().content("To view all players on servers, use ")
|
||||
.color(NamedTextColor.YELLOW)
|
||||
.append(Component.text("/glist all", NamedTextColor.DARK_AQUA))
|
||||
.append(Component.text(".", NamedTextColor.YELLOW))
|
||||
.build());
|
||||
Component.translatable("velocity.command.glist-view-all", NamedTextColor.YELLOW));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -98,7 +94,7 @@ public class GlistCommand {
|
||||
Optional<RegisteredServer> registeredServer = server.server(serverName);
|
||||
if (!registeredServer.isPresent()) {
|
||||
source.sendMessage(Identity.nil(),
|
||||
Component.text("Server " + serverName + " doesn't exist.", NamedTextColor.RED));
|
||||
CommandMessages.SERVER_DOES_NOT_EXIST.args(Component.text(serverName)));
|
||||
return -1;
|
||||
}
|
||||
sendServerPlayers(source, registeredServer.get(), false);
|
||||
@@ -107,10 +103,19 @@ public class GlistCommand {
|
||||
}
|
||||
|
||||
private void sendTotalProxyCount(CommandSource target) {
|
||||
int online = server.countConnectedPlayers();
|
||||
target.sendMessage(Identity.nil(), Component.text()
|
||||
.content("There are ").color(NamedTextColor.YELLOW)
|
||||
.append(Component.text(server.connectedPlayers().size(), NamedTextColor.GREEN))
|
||||
.append(Component.text(" player(s) online.", NamedTextColor.YELLOW))
|
||||
.append(Component.text(Integer.toString(online), NamedTextColor.GREEN))
|
||||
.append(Component.space())
|
||||
.append(Component.translatable(
|
||||
online == 1
|
||||
? "velocity.command.glist-player-singular"
|
||||
: "velocity.command.glist-player-plural",
|
||||
NamedTextColor.YELLOW
|
||||
))
|
||||
.append(Component.space())
|
||||
.append(Component.translatable("velocity.command.glist-total-suffix",
|
||||
NamedTextColor.YELLOW))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import java.util.stream.Stream;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
@@ -53,8 +54,7 @@ public class ServerCommand implements SimpleCommand {
|
||||
final String[] args = invocation.arguments();
|
||||
|
||||
if (!(source instanceof Player)) {
|
||||
source.sendMessage(Identity.nil(), Component.text("Only players may run this command.",
|
||||
NamedTextColor.RED));
|
||||
source.sendMessage(Identity.nil(), CommandMessages.PLAYERS_ONLY);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -64,8 +64,8 @@ public class ServerCommand implements SimpleCommand {
|
||||
String serverName = args[0];
|
||||
Optional<RegisteredServer> toConnect = server.server(serverName);
|
||||
if (!toConnect.isPresent()) {
|
||||
player.sendMessage(Identity.nil(),
|
||||
Component.text("Server " + serverName + " doesn't exist.", NamedTextColor.RED));
|
||||
player.sendMessage(Identity.nil(), CommandMessages.SERVER_DOES_NOT_EXIST
|
||||
.args(Component.text(serverName)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,19 +78,23 @@ public class ServerCommand implements SimpleCommand {
|
||||
private void outputServerInformation(Player executor) {
|
||||
String currentServer = executor.connectedServer().map(ServerConnection::serverInfo)
|
||||
.map(ServerInfo::name).orElse("<unknown>");
|
||||
executor.sendMessage(Identity.nil(), Component.text(
|
||||
"You are currently connected to " + currentServer + ".", NamedTextColor.YELLOW));
|
||||
executor.sendMessage(Identity.nil(), Component.translatable(
|
||||
"velocity.command.server-current-server",
|
||||
NamedTextColor.YELLOW,
|
||||
Component.text(currentServer)));
|
||||
|
||||
List<RegisteredServer> servers = BuiltinCommandUtil.sortedServerList(server);
|
||||
if (servers.size() > MAX_SERVERS_TO_LIST) {
|
||||
executor.sendMessage(Identity.nil(), Component.text(
|
||||
"Too many servers to list. Tab-complete to show all servers.", NamedTextColor.RED));
|
||||
executor.sendMessage(Identity.nil(), Component.translatable(
|
||||
"velocity.command.server-too-many", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
// Assemble the list of servers as components
|
||||
TextComponent.Builder serverListBuilder = Component.text().content("Available servers: ")
|
||||
.color(NamedTextColor.YELLOW);
|
||||
TextComponent.Builder serverListBuilder = Component.text()
|
||||
.append(Component.translatable("velocity.command.server-available",
|
||||
NamedTextColor.YELLOW))
|
||||
.append(Component.space());
|
||||
for (int i = 0; i < servers.size(); i++) {
|
||||
RegisteredServer rs = servers.get(i);
|
||||
serverListBuilder.append(formatServerComponent(currentServer, rs));
|
||||
@@ -106,17 +110,31 @@ public class ServerCommand implements SimpleCommand {
|
||||
ServerInfo serverInfo = server.serverInfo();
|
||||
TextComponent serverTextComponent = Component.text(serverInfo.name());
|
||||
|
||||
String playersText = server.connectedPlayers().size() + " player(s) online";
|
||||
int connectedPlayers = server.connectedPlayers().size();
|
||||
TranslatableComponent playersTextComponent;
|
||||
if (connectedPlayers == 1) {
|
||||
playersTextComponent = Component.translatable("velocity.command.server-tooltip-player-online");
|
||||
} else {
|
||||
playersTextComponent = Component.translatable("velocity.command.server-tooltip-players-online");
|
||||
}
|
||||
playersTextComponent = playersTextComponent.args(Component.text(connectedPlayers));
|
||||
|
||||
if (serverInfo.name().equals(currentPlayerServer)) {
|
||||
serverTextComponent = serverTextComponent.color(NamedTextColor.GREEN)
|
||||
.hoverEvent(
|
||||
showText(Component.text("Currently connected to this server\n" + playersText))
|
||||
showText(
|
||||
Component.translatable("velocity.command.server-tooltip-current-server")
|
||||
.append(Component.newline())
|
||||
.append(playersTextComponent))
|
||||
);
|
||||
} else {
|
||||
serverTextComponent = serverTextComponent.color(NamedTextColor.GRAY)
|
||||
.clickEvent(ClickEvent.runCommand("/server " + serverInfo.name()))
|
||||
.hoverEvent(
|
||||
showText(Component.text("Click to connect to this server\n" + playersText))
|
||||
showText(
|
||||
Component.translatable("velocity.command.server-tooltip-offer-connect-server")
|
||||
.append(Component.newline())
|
||||
.append(playersTextComponent))
|
||||
);
|
||||
}
|
||||
return serverTextComponent;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
package com.velocitypowered.proxy.command.builtin;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -49,6 +48,7 @@ import java.util.stream.Collectors;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
@@ -180,17 +180,15 @@ public class VelocityCommand implements SimpleCommand {
|
||||
public void execute(CommandSource source, String @NonNull [] args) {
|
||||
try {
|
||||
if (server.reloadConfiguration()) {
|
||||
source.sendMessage(Identity.nil(), Component.text(
|
||||
"Configuration reloaded.", NamedTextColor.GREEN));
|
||||
source.sendMessage(Component.translatable("velocity.command.reload-success",
|
||||
NamedTextColor.GREEN));
|
||||
} else {
|
||||
source.sendMessage(Identity.nil(), Component.text(
|
||||
"Unable to reload your configuration. Check the console for more details.",
|
||||
source.sendMessage(Component.translatable("velocity.command.reload-failure",
|
||||
NamedTextColor.RED));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Unable to reload configuration", e);
|
||||
source.sendMessage(Identity.nil(), Component.text(
|
||||
"Unable to reload your configuration. Check the console for more details.",
|
||||
source.sendMessage(Component.translatable("velocity.command.reload-failure",
|
||||
NamedTextColor.RED));
|
||||
}
|
||||
}
|
||||
@@ -219,33 +217,35 @@ public class VelocityCommand implements SimpleCommand {
|
||||
|
||||
ProxyVersion version = server.version();
|
||||
|
||||
TextComponent velocity = Component.text().content(version.getName() + " ")
|
||||
Component velocity = Component.text().content(version.getName() + " ")
|
||||
.decoration(TextDecoration.BOLD, true)
|
||||
.color(VELOCITY_COLOR)
|
||||
.append(Component.text(version.getVersion()).decoration(TextDecoration.BOLD, false))
|
||||
.build();
|
||||
TextComponent copyright = Component
|
||||
.text("Copyright 2018-2020 " + version.getVendor() + ". " + version.getName()
|
||||
+ " is licensed under the terms of the GNU General Public License v3.");
|
||||
Component copyright = Component
|
||||
.translatable("velocity.command.version-copyright",
|
||||
Component.text(version.getVendor()),
|
||||
Component.text(version.getName()));
|
||||
source.sendMessage(Identity.nil(), velocity);
|
||||
source.sendMessage(Identity.nil(), copyright);
|
||||
|
||||
if (version.getName().equals("Velocity")) {
|
||||
TextComponent velocityWebsite = Component.text()
|
||||
.content("Visit the ")
|
||||
.append(Component.text().content("Velocity website")
|
||||
TextComponent embellishment = Component.text()
|
||||
.append(Component.text().content("velocitypowered.com")
|
||||
.color(NamedTextColor.GREEN)
|
||||
.decoration(TextDecoration.UNDERLINED, true)
|
||||
.clickEvent(
|
||||
ClickEvent.openUrl("https://www.velocitypowered.com"))
|
||||
.build())
|
||||
.append(Component.text(" or the "))
|
||||
.append(Component.text().content("Velocity GitHub")
|
||||
.append(Component.text(" - "))
|
||||
.append(Component.text().content("GitHub")
|
||||
.color(NamedTextColor.GREEN)
|
||||
.decoration(TextDecoration.UNDERLINED, true)
|
||||
.clickEvent(ClickEvent.openUrl(
|
||||
"https://github.com/VelocityPowered/Velocity"))
|
||||
.build())
|
||||
.build();
|
||||
source.sendMessage(Identity.nil(), velocityWebsite);
|
||||
source.sendMessage(Identity.nil(), embellishment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,12 +274,13 @@ public class VelocityCommand implements SimpleCommand {
|
||||
int pluginCount = plugins.size();
|
||||
|
||||
if (pluginCount == 0) {
|
||||
source.sendMessage(Identity.nil(), Component.text(
|
||||
"No plugins installed.", NamedTextColor.YELLOW));
|
||||
source.sendMessage(Component.translatable("velocity.command.no-plugins",
|
||||
NamedTextColor.YELLOW));
|
||||
return;
|
||||
}
|
||||
|
||||
TextComponent.Builder output = Component.text().content("Plugins: ")
|
||||
TranslatableComponent.Builder output = Component.translatable()
|
||||
.key("velocity.command.plugins-list")
|
||||
.color(NamedTextColor.YELLOW);
|
||||
for (int i = 0; i < pluginCount; i++) {
|
||||
PluginContainer plugin = plugins.get(i);
|
||||
@@ -300,15 +301,21 @@ public class VelocityCommand implements SimpleCommand {
|
||||
|
||||
description.url().ifPresent(url -> {
|
||||
hoverText.append(Component.newline());
|
||||
hoverText.append(Component.text("Website: " + url));
|
||||
hoverText.append(Component.translatable(
|
||||
"velocity.command.plugin-tooltip-website",
|
||||
Component.text(url)));
|
||||
});
|
||||
if (!description.authors().isEmpty()) {
|
||||
hoverText.append(Component.newline());
|
||||
if (description.authors().size() == 1) {
|
||||
hoverText.append(Component.text("Author: " + description.authors().get(0)));
|
||||
hoverText.append(Component.translatable("velocity.command.plugin-tooltip-author",
|
||||
Component.text(description.authors().get(0))));
|
||||
} else {
|
||||
hoverText.append(Component.text("Authors: " + Joiner.on(", ")
|
||||
.join(description.authors())));
|
||||
hoverText.append(
|
||||
Component.translatable("velocity.command.plugin-tooltip-author",
|
||||
Component.text(String.join(", ", description.authors()))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
description.description().ifPresent(pdesc -> {
|
||||
@@ -352,8 +359,8 @@ public class VelocityCommand implements SimpleCommand {
|
||||
JsonArray connectOrder = new JsonArray();
|
||||
List<String> attemptedConnectionOrder = ImmutableList.copyOf(
|
||||
server.configuration().getAttemptConnectionOrder());
|
||||
for (int i = 0; i < attemptedConnectionOrder.size(); i++) {
|
||||
connectOrder.add(attemptedConnectionOrder.get(i));
|
||||
for (String s : attemptedConnectionOrder) {
|
||||
connectOrder.add(s);
|
||||
}
|
||||
|
||||
JsonObject proxyConfig = InformationUtils.collectProxyConfig(server.configuration());
|
||||
@@ -446,7 +453,7 @@ public class VelocityCommand implements SimpleCommand {
|
||||
e.getCause().printStackTrace();
|
||||
} catch (JsonParseException e) {
|
||||
source.sendMessage(Component.text()
|
||||
.content("An error occurred on the Velocity-servers and the dump could not "
|
||||
.content("An error occurred on the Velocity servers and the dump could not "
|
||||
+ "be completed. Please contact the Velocity staff about this problem. "
|
||||
+ "If you do, provide the details about this error from the Velocity "
|
||||
+ "console or server log.")
|
||||
|
||||
@@ -45,7 +45,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -72,25 +71,23 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
@Expose private final Advanced advanced;
|
||||
@Expose private final Query query;
|
||||
private final Metrics metrics;
|
||||
private final Messages messages;
|
||||
private net.kyori.adventure.text.@MonotonicNonNull Component motdAsComponent;
|
||||
private @Nullable Favicon favicon;
|
||||
|
||||
private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
|
||||
Query query, Metrics metrics, Messages messages) {
|
||||
Query query, Metrics metrics) {
|
||||
this.servers = servers;
|
||||
this.forcedHosts = forcedHosts;
|
||||
this.advanced = advanced;
|
||||
this.query = query;
|
||||
this.metrics = metrics;
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
private VelocityConfiguration(String bind, String motd, int showMaxPlayers, boolean onlineMode,
|
||||
boolean preventClientProxyConnections, boolean announceForge,
|
||||
PlayerInfoForwarding playerInfoForwardingMode, byte[] forwardingSecret,
|
||||
boolean onlineModeKickExistingPlayers, PingPassthroughMode pingPassthrough, Servers servers,
|
||||
ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics, Messages messages) {
|
||||
ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics) {
|
||||
this.bind = bind;
|
||||
this.motd = motd;
|
||||
this.showMaxPlayers = showMaxPlayers;
|
||||
@@ -106,7 +103,6 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
this.advanced = advanced;
|
||||
this.query = query;
|
||||
this.metrics = metrics;
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,10 +369,6 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
return advanced.isLogCommandExecutions();
|
||||
}
|
||||
|
||||
public Messages getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
@@ -450,7 +442,6 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
CommentedConfig advancedConfig = config.get("advanced");
|
||||
CommentedConfig queryConfig = config.get("query");
|
||||
CommentedConfig metricsConfig = config.get("metrics");
|
||||
CommentedConfig messagesConfig = config.get("messages");
|
||||
PlayerInfoForwarding forwardingMode = config.getEnumOrElse("player-info-forwarding-mode",
|
||||
PlayerInfoForwarding.NONE);
|
||||
PingPassthroughMode pingPassthroughMode = config.getEnumOrElse("ping-passthrough",
|
||||
@@ -480,8 +471,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
new ForcedHosts(forcedHostsConfig),
|
||||
new Advanced(advancedConfig),
|
||||
new Query(queryConfig),
|
||||
new Metrics(metricsConfig),
|
||||
new Messages(messagesConfig, defaultConfig.get("messages"))
|
||||
new Metrics(metricsConfig)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -793,73 +783,4 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
return enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Messages {
|
||||
|
||||
private final CommentedConfig toml;
|
||||
private final CommentedConfig defaultToml;
|
||||
|
||||
private final String kickPrefix;
|
||||
private final String disconnectPrefix;
|
||||
private final String onlineModeOnly;
|
||||
private final String noAvailableServers;
|
||||
private final String alreadyConnected;
|
||||
private final String movedToNewServerPrefix;
|
||||
private final String genericConnectionError;
|
||||
|
||||
private Messages(CommentedConfig toml, CommentedConfig defaultToml) {
|
||||
this.toml = toml;
|
||||
this.defaultToml = defaultToml;
|
||||
this.kickPrefix = getString("kick-prefix");
|
||||
this.disconnectPrefix = getString("disconnect-prefix");
|
||||
this.onlineModeOnly = getString("online-mode-only");
|
||||
this.noAvailableServers = getString("no-available-servers");
|
||||
this.alreadyConnected = getString("already-connected");
|
||||
this.movedToNewServerPrefix = getString("moved-to-new-server-prefix");
|
||||
this.genericConnectionError = getString("generic-connection-error");
|
||||
}
|
||||
|
||||
private String getString(String path) {
|
||||
String def = defaultToml.getOrElse(path, "");
|
||||
if (toml == null) {
|
||||
return def;
|
||||
}
|
||||
return toml.getOrElse(path, def);
|
||||
}
|
||||
|
||||
public Component getKickPrefix(String server) {
|
||||
return deserialize(String.format(kickPrefix, server));
|
||||
}
|
||||
|
||||
public Component getDisconnectPrefix(String server) {
|
||||
return deserialize(String.format(disconnectPrefix, server));
|
||||
}
|
||||
|
||||
public Component getOnlineModeOnly() {
|
||||
return deserialize(onlineModeOnly);
|
||||
}
|
||||
|
||||
public Component getNoAvailableServers() {
|
||||
return deserialize(noAvailableServers);
|
||||
}
|
||||
|
||||
public Component getAlreadyConnected() {
|
||||
return deserialize(alreadyConnected);
|
||||
}
|
||||
|
||||
public Component getMovedToNewServerPrefix() {
|
||||
return deserialize(movedToNewServerPrefix);
|
||||
}
|
||||
|
||||
public Component getGenericConnectionError() {
|
||||
return deserialize(genericConnectionError);
|
||||
}
|
||||
|
||||
private Component deserialize(String str) {
|
||||
if (str.startsWith("{")) {
|
||||
return GsonComponentSerializer.gson().deserialize(str);
|
||||
}
|
||||
return LegacyComponentSerializer.legacyAmpersand().deserialize(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ import net.kyori.adventure.text.TextComponent;
|
||||
|
||||
public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
private static final TextComponent MODERN_IP_FORWARDING_FAILURE = Component
|
||||
.text("Your server did not send a forwarding request to the proxy. Is it set up correctly?");
|
||||
private static final Component MODERN_IP_FORWARDING_FAILURE = Component
|
||||
.translatable("velocity.error.modern-forwarding-failed");
|
||||
|
||||
private final VelocityServer server;
|
||||
private final VelocityServerConnection serverConn;
|
||||
|
||||
@@ -168,9 +168,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
.exceptionally(e -> {
|
||||
logger.info("Exception occurred while running command for {}",
|
||||
player.username(), e);
|
||||
player.sendMessage(Identity.nil(),
|
||||
Component.text("An error occurred while running this command.",
|
||||
NamedTextColor.RED));
|
||||
player.sendMessage(Component.translatable("velocity.command.generic-error",
|
||||
NamedTextColor.RED));
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
@@ -335,7 +334,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public void exception(Throwable throwable) {
|
||||
player.disconnect(server.configuration().getMessages().getGenericConnectionError());
|
||||
player.disconnect(Component.translatable("velocity.error.player-connection-error",
|
||||
NamedTextColor.RED));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -446,18 +446,18 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
wrapped = cause;
|
||||
}
|
||||
}
|
||||
String userMessage;
|
||||
|
||||
Component friendlyError;
|
||||
if (connectedServer != null && connectedServer.serverInfo().equals(server.serverInfo())) {
|
||||
userMessage = "Your connection to " + server.serverInfo().name() + " encountered an "
|
||||
+ "error.";
|
||||
friendlyError = Component.translatable("velocity.error.connected-server-error",
|
||||
Component.text(server.serverInfo().name()));
|
||||
} else {
|
||||
logger.error("{}: unable to connect to server {}", this, server.serverInfo().name(),
|
||||
wrapped);
|
||||
userMessage = "Unable to connect to " + server.serverInfo().name() + ". Try again "
|
||||
+ "later.";
|
||||
friendlyError = Component.translatable("velocity.error.connecting-server-error",
|
||||
Component.text(server.serverInfo().name()));
|
||||
}
|
||||
handleConnectionException(server, null, Component.text(userMessage,
|
||||
NamedTextColor.RED), safe);
|
||||
handleConnectionException(server, null, friendlyError.color(NamedTextColor.RED), safe);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -473,26 +473,22 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
return;
|
||||
}
|
||||
|
||||
VelocityConfiguration.Messages messages = this.server.configuration().getMessages();
|
||||
Component disconnectReason = GsonComponentSerializer.gson().deserialize(disconnect.getReason());
|
||||
String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason);
|
||||
if (connectedServer != null && connectedServer.serverInfo().equals(server.serverInfo())) {
|
||||
logger.error("{}: kicked from server {}: {}", this, server.serverInfo().name(),
|
||||
plainTextReason);
|
||||
handleConnectionException(server, disconnectReason, Component.text()
|
||||
.append(messages.getKickPrefix(server.serverInfo().name())
|
||||
.colorIfAbsent(NamedTextColor.RED))
|
||||
.color(NamedTextColor.RED)
|
||||
.append(disconnectReason)
|
||||
.build(), safe);
|
||||
handleConnectionException(server, disconnectReason,
|
||||
Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED,
|
||||
Component.text(server.serverInfo().name()),
|
||||
disconnectReason), safe);
|
||||
} else {
|
||||
logger.error("{}: disconnected while connecting to {}: {}", this,
|
||||
server.serverInfo().name(), plainTextReason);
|
||||
handleConnectionException(server, disconnectReason, Component.text()
|
||||
.append(messages.getDisconnectPrefix(server.serverInfo().name())
|
||||
.colorIfAbsent(NamedTextColor.RED))
|
||||
.append(disconnectReason)
|
||||
.build(), safe);
|
||||
handleConnectionException(server, disconnectReason,
|
||||
Component.translatable("velocity.error.cant-connect", NamedTextColor.RED,
|
||||
Component.text(server.serverInfo().name()),
|
||||
disconnectReason), safe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,8 +572,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
protocolVersion()), ((Impl) status).isSafe());
|
||||
break;
|
||||
case SUCCESS:
|
||||
sendMessage(Identity.nil(), server.configuration().getMessages()
|
||||
.getMovedToNewServerPrefix().append(friendlyReason));
|
||||
sendMessage(Component.translatable("velocity.error.moved-to-new-server",
|
||||
NamedTextColor.RED,
|
||||
Component.text(originalEvent.server().serverInfo().name()),
|
||||
friendlyReason));
|
||||
break;
|
||||
default:
|
||||
// The only remaining value is successful (no need to do anything!)
|
||||
|
||||
@@ -70,7 +70,10 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
@Override
|
||||
public boolean handle(LegacyHandshakePacket packet) {
|
||||
connection.closeWith(LegacyDisconnectPacket
|
||||
.from(Component.text("Your client is old, please upgrade!", NamedTextColor.RED)));
|
||||
.from(Component.text(
|
||||
"Your client is extremely old. Please update to a newer version of Minecraft.",
|
||||
NamedTextColor.RED)
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -122,7 +125,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
InetAddress address = ((InetSocketAddress) connection.getRemoteAddress()).getAddress();
|
||||
if (!server.getIpAttemptLimiter().attempt(address)) {
|
||||
ic.disconnectQuietly(Component.text("You are logging in too fast, try again later."));
|
||||
ic.disconnectQuietly(Component.translatable("velocity.error.logging-in-too-fast"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -132,7 +135,8 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
// and lower, otherwise IP information will never get forwarded.
|
||||
if (server.configuration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN
|
||||
&& handshake.getProtocolVersion().lt(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
ic.disconnectQuietly(Component.text("This server is only compatible with 1.13 and above."));
|
||||
ic.disconnectQuietly(Component.translatable(
|
||||
"velocity.error.modern-forwarding-needs-new-client"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -152,7 +153,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
GameProfile.class), true);
|
||||
} else if (profileResponse.getStatusCode() == 204) {
|
||||
// Apparently an offline-mode user logged onto this online-mode proxy.
|
||||
inbound.disconnect(server.configuration().getMessages().getOnlineModeOnly());
|
||||
inbound.disconnect(Component.translatable("velocity.error.online-mode-only",
|
||||
NamedTextColor.RED));
|
||||
} else {
|
||||
// Something else went wrong
|
||||
logger.error(
|
||||
@@ -192,9 +194,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
Optional<Component> disconnectReason = result.denialReason();
|
||||
if (disconnectReason.isPresent()) {
|
||||
// The component is guaranteed to be provided if the connection was denied.
|
||||
Component disconnectReasonTranslated = GlobalTranslator.render(disconnectReason.get(),
|
||||
Locale.getDefault());
|
||||
inbound.disconnect(disconnectReasonTranslated);
|
||||
inbound.disconnect(disconnectReason.get());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -243,7 +243,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
mcConnection, inbound.connectedHost().orElse(null), onlineMode);
|
||||
this.connectedPlayer = player;
|
||||
if (!server.canRegisterConnection(player)) {
|
||||
player.disconnect0(server.configuration().getMessages().getAlreadyConnected(), true);
|
||||
player.disconnect0(Component.translatable("velocity.error.already-connected-proxy",
|
||||
NamedTextColor.RED), true);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@@ -304,8 +305,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
player.disconnect0(reason.get(), true);
|
||||
} else {
|
||||
if (!server.registerConnection(player)) {
|
||||
player.disconnect0(server.configuration().getMessages()
|
||||
.getAlreadyConnected(), true);
|
||||
player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"),
|
||||
true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -333,8 +334,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
.thenRunAsync(() -> {
|
||||
Optional<RegisteredServer> toTry = event.initialServer();
|
||||
if (!toTry.isPresent()) {
|
||||
player.disconnect0(server.configuration().getMessages()
|
||||
.getNoAvailableServers(), true);
|
||||
player.disconnect0(Component.translatable("velocity.error.no-available-servers",
|
||||
NamedTextColor.RED), true);
|
||||
return;
|
||||
}
|
||||
player.createConnectionRequest(toTry.get()).fireAndForget();
|
||||
|
||||
@@ -19,16 +19,17 @@ package com.velocitypowered.proxy.connection.util;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
public class ConnectionMessages {
|
||||
|
||||
public static final TextComponent ALREADY_CONNECTED = Component
|
||||
.text("You are already connected to this server!", NamedTextColor.RED);
|
||||
public static final TextComponent IN_PROGRESS = Component
|
||||
.text("You are already connecting to a server!", NamedTextColor.RED);
|
||||
public static final TextComponent INTERNAL_SERVER_CONNECTION_ERROR = Component
|
||||
.text("An internal server connection error occurred.", NamedTextColor.RED);
|
||||
public static final TranslatableComponent ALREADY_CONNECTED = Component
|
||||
.translatable("velocity.error.already-connected", NamedTextColor.RED);
|
||||
public static final TranslatableComponent IN_PROGRESS = Component
|
||||
.translatable("velocity.error.already-connecting", NamedTextColor.RED);
|
||||
public static final TranslatableComponent INTERNAL_SERVER_CONNECTION_ERROR = Component
|
||||
.translatable("velocity.error.internal-server-connection-error", NamedTextColor.RED);
|
||||
|
||||
private ConnectionMessages() {
|
||||
throw new AssertionError();
|
||||
|
||||
@@ -26,9 +26,12 @@ import com.velocitypowered.api.permission.PermissionFunction;
|
||||
import com.velocitypowered.api.permission.Tristate;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import net.minecrell.terminalconsole.SimpleTerminalConsole;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -52,8 +55,8 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NonNull Identity identity, @NonNull Component message) {
|
||||
logger.info(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()
|
||||
.serialize(message));
|
||||
Component translated = GlobalTranslator.render(message, Locale.getDefault());
|
||||
logger.info(LegacyComponentSerializer.legacySection().serialize(translated));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,7 +117,8 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
|
||||
protected void runCommand(String command) {
|
||||
try {
|
||||
if (!this.server.commandManager().execute(this, command).join()) {
|
||||
sendMessage(Component.text("Command not found.", NamedTextColor.RED));
|
||||
sendMessage(Component.translatable("velocity.command.command-does-not-exist",
|
||||
NamedTextColor.RED));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("An error occurred while running this command.", e);
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#
|
||||
# Copyright (C) 2018 Velocity Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
velocity.error.already-connected=You are already connected to this server!
|
||||
velocity.error.already-connected-proxy=You are already connected to this proxy!
|
||||
velocity.error.already-connecting=You are already trying to connect to a server!
|
||||
velocity.error.cant-connect=Unable to connect to {0}: {1}
|
||||
velocity.error.connecting-server-error=Unable to connect you to {0}. Please try again later.
|
||||
velocity.error.connected-server-error=Your connection to {0} encountered a problem.
|
||||
velocity.error.internal-server-connection-error=An internal server connection error occurred.
|
||||
velocity.error.logging-in-too-fast=You are logging in too fast, try again later.
|
||||
velocity.error.online-mode-only=You are not logged into your Minecraft account. If you are logged into your Minecraft account, try restarting your Minecraft client.
|
||||
velocity.error.player-connection-error=An internal error occurred in your connection.
|
||||
velocity.error.modern-forwarding-needs-new-client=This server is only compatible with Minecraft 1.13 and above.
|
||||
velocity.error.modern-forwarding-failed=Your server did not send a forwarding request to the proxy. Make sure the server is configured for Velocity forwarding.
|
||||
velocity.error.moved-to-new-server=YOu were kicked from {0}: {1}
|
||||
velocity.error.no-available-servers=There are no available servers to connect you to. Try again later or contact an admin.
|
||||
|
||||
# Commands
|
||||
velocity.command.generic-error=An error occurred while running this command.
|
||||
velocity.command.command-does-not-exist=This command does not exist.
|
||||
|
||||
velocity.command.players-only=Only players can run this command.
|
||||
velocity.command.server-does-not-exist=The specified server {0} does not exist.
|
||||
|
||||
velocity.command.server-current-server=You are currently connected to {0}.
|
||||
velocity.command.server-too-many=There are too many servers set up. Use tab completion to get individual server counts.
|
||||
velocity.command.server-available=Available servers:
|
||||
velocity.command.server-tooltip-player-online={0} player online
|
||||
velocity.command.server-tooltip-players-online={0} players online
|
||||
velocity.command.server-tooltip-current-server=Currently connected to this server
|
||||
velocity.command.server-tooltip-offer-connect-server=Click to connect to this server
|
||||
|
||||
velocity.command.glist-player-singular=player
|
||||
velocity.command.glist-player-plural=players
|
||||
velocity.command.glist-total-suffix= are currently connected to the proxy.
|
||||
velocity.command.glist-view-all=To view all players on servers, use /glist all.
|
||||
|
||||
velocity.command.reload-success=Velocity configuration successfully reloaded.
|
||||
velocity.command.reload-failure=Unable to reload your Velocity configuration. Check the console for more details.
|
||||
|
||||
velocity.command.version-copyright=Copyright 2018-2021 {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
||||
|
||||
velocity.command.no-plugins=There are no plugins currently installed.
|
||||
velocity.command.plugins-list=Plugins: {0}
|
||||
velocity.command.plugin-tooltip-website=Website: {0}
|
||||
velocity.command.plugin-tooltip-author=Author: {0}
|
||||
velocity.command.plugin-tooltip-authors=Authors: {0}
|
||||
@@ -141,20 +141,4 @@ port = 25577
|
||||
map = "Velocity"
|
||||
|
||||
# Whether plugins should be shown in query response by default or not
|
||||
show-plugins = false
|
||||
|
||||
# Legacy color codes and JSON are accepted in all messages.
|
||||
[messages]
|
||||
# Prefix when the player gets kicked from a server.
|
||||
# First argument '%s': the server name
|
||||
kick-prefix = "&cKicked from %s: "
|
||||
|
||||
# Prefix when the player is disconnected from a server.
|
||||
# First argument '%s': the server name
|
||||
disconnect-prefix = "&cCan't connect to %s: "
|
||||
|
||||
online-mode-only = "&cThis server only accepts connections from online-mode clients.\n\n&7Did you change your username? Sign out of Minecraft, sign back in, and try again."
|
||||
no-available-servers = "&cThere are no available servers."
|
||||
already-connected = "&cYou are already connected to this proxy!"
|
||||
moved-to-new-server-prefix = "&cThe server you were on kicked you: "
|
||||
generic-connection-error = "&cAn internal error occurred in your connection."
|
||||
show-plugins = false
|
||||
Reference in New Issue
Block a user