13
0
geforkt von Mirrors/Velocity

Merge pull request #61 from Leymooo/config

Allow config upgrading. Add annotations with reflection
Dieser Commit ist enthalten in:
Andrew Steinborn 2018-08-31 13:38:55 -04:00 committet von GitHub
Commit e86b2b711b
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 4AEE18F83AFDEB23
4 geänderte Dateien mit 547 neuen und 157 gelöschten Zeilen

Datei anzeigen

@ -21,6 +21,7 @@ import com.velocitypowered.proxy.config.VelocityConfiguration;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.connection.http.NettyHttpClient; import com.velocitypowered.proxy.connection.http.NettyHttpClient;
import com.velocitypowered.proxy.command.VelocityCommandManager; import com.velocitypowered.proxy.command.VelocityCommandManager;
import com.velocitypowered.proxy.config.AnnotatedConfig;
import com.velocitypowered.proxy.messages.VelocityChannelRegistrar; import com.velocitypowered.proxy.messages.VelocityChannelRegistrar;
import com.velocitypowered.proxy.plugin.VelocityEventManager; import com.velocitypowered.proxy.plugin.VelocityEventManager;
import com.velocitypowered.proxy.protocol.util.FaviconSerializer; import com.velocitypowered.proxy.protocol.util.FaviconSerializer;
@ -107,21 +108,18 @@ public class VelocityServer implements ProxyServer {
public void start() { public void start() {
try { try {
Path configPath = Paths.get("velocity.toml"); Path configPath = Paths.get("velocity.toml");
try {
configuration = VelocityConfiguration.read(configPath); configuration = VelocityConfiguration.read(configPath);
} catch (NoSuchFileException e) {
logger.info("No velocity.toml found, creating one for you...");
Files.copy(VelocityServer.class.getResourceAsStream("/velocity.toml"), configPath);
configuration = VelocityConfiguration.read(configPath);
}
if (!configuration.validate()) { if (!configuration.validate()) {
logger.error("Your configuration is invalid. Velocity will refuse to start up until the errors are resolved."); logger.error("Your configuration is invalid. Velocity will refuse to start up until the errors are resolved.");
LogManager.shutdown(); LogManager.shutdown();
System.exit(1); System.exit(1);
} }
} catch (IOException e) {
logger.error("Unable to load your velocity.toml. The server will shut down.", e); AnnotatedConfig.saveConfig(configuration.dumpConfig(), configPath); //Resave config to add new values
} catch (Throwable e) {
logger.error("Unable to read/load/save your velocity.toml. The server will shut down.", e);
LogManager.shutdown(); LogManager.shutdown();
System.exit(1); System.exit(1);
} }

Datei anzeigen

@ -0,0 +1,191 @@
package com.velocitypowered.proxy.config;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Only for simple configs
*/
public class AnnotatedConfig {
private static final Logger logger = LogManager.getLogger(AnnotatedConfig.class);
public static Logger getLogger() {
return logger;
}
/**
* Indicates that a field is a table
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Table {
String value();
}
/**
* Creates a comment
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Comment {
String[] value();
}
/**
* How field will be named in config
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface ConfigKey {
String value();
}
/**
* Indicates that a field is a map and we need to save all map data to
* config
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface IsMap {
}
/**
* Indicates that a field is a string converted to byte[]
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface StringAsBytes {
}
/**
* Indicates that a field should be skiped
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Ignore {
}
public List<String> dumpConfig() {
List<String> lines = new ArrayList<>();
dumpFields(this, lines);
return lines;
}
/**
* Dump all field and they annotations to List
*
* @param toSave object those we need to dump
* @param lines a list where store dumped lines
*/
private void dumpFields(Object toSave, List<String> lines) {
try {
for (Field field : toSave.getClass().getDeclaredFields()) {
if (field.getAnnotation(Ignore.class) != null) { //Skip this field
continue;
}
Comment comment = field.getAnnotation(Comment.class);
if (comment != null) { //Add comments
for (String line : comment.value()) {
lines.add("# " + line);
}
}
ConfigKey key = field.getAnnotation(ConfigKey.class); //Get a key name for config
String name = key == null ? field.getName() : key.value(); // Use a field name if name in annotation is not present
field.setAccessible(true); // Make field accessible
Table table = field.getAnnotation(Table.class);
if (table != null) { // Check if field is table.
lines.add(table.value()); // Write [name]
dumpFields(field.get(toSave), lines); // dump fields of table class
} else {
if (field.getAnnotation(IsMap.class) != null) { // check if field is map
Map<String, ?> map = (Map<String, ?>) field.get(toSave);
for (Entry<String, ?> entry : map.entrySet()) {
lines.add(entry.getKey() + " = " + toString(entry.getValue())); // Save a map data
}
lines.add(""); //Add empty line
continue;
}
Object value = field.get(toSave);
if (field.getAnnotation(StringAsBytes.class) != null) { // Check if field is a byte[] representation of a string
value = new String((byte[]) value, StandardCharsets.UTF_8);
}
lines.add(name + " = " + toString(value)); // save field to config
lines.add(""); // add empty line
}
}
} catch (IllegalAccessException | IllegalArgumentException | SecurityException e) {
throw new RuntimeException("Can not dump config", e);
}
}
private String toString(Object value) {
if (value instanceof List) {
Collection<?> listValue = (Collection<?>) value;
if (listValue.isEmpty()) {
return "[]";
}
StringBuilder m = new StringBuilder();
m.append("[");
for (Object obj : listValue) {
m.append(System.lineSeparator()).append(" ").append(toString(obj)).append(",");
}
m.deleteCharAt(m.length() - 1).append(System.lineSeparator()).append("]");
return m.toString();
}
if (value instanceof Enum) {
value = value.toString();
}
if (value instanceof String) {
String stringValue = (String) value;
if (stringValue.isEmpty()) {
return "\"\"";
}
return "\"" + stringValue.replace("\n", "\\n") + "\"";
}
return value != null ? value.toString() : "null";
}
/**
* Saves lines to file
*
* @param lines Lines to save
* @param to A path of file where to save lines
* @throws IOException if lines is empty or was error during saving
*/
public static void saveConfig(List<String> lines, Path to) throws IOException {
if (lines.isEmpty()) {
throw new IOException("Can not save config because list is empty");
}
Path temp = new File(to.toFile().getParent(), "__tmp").toPath();
Files.write(temp, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE);
try {
Files.move(temp, to, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
} catch (AtomicMoveNotSupportedException e) {
Files.move(temp, to, StandardCopyOption.REPLACE_EXISTING);
}
}
}

Datei anzeigen

@ -8,8 +8,6 @@ import com.velocitypowered.api.util.LegacyChatColorUtils;
import io.netty.buffer.ByteBufUtil; import io.netty.buffer.ByteBufUtil;
import net.kyori.text.Component; import net.kyori.text.Component;
import net.kyori.text.serializer.ComponentSerializers; import net.kyori.text.serializer.ComponentSerializers;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
@ -18,54 +16,89 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random;
import org.apache.logging.log4j.Logger;
public class VelocityConfiguration { public class VelocityConfiguration extends AnnotatedConfig {
private static final Logger logger = LogManager.getLogger(VelocityConfiguration.class);
private final String bind; @Comment("Config version. Do not change this")
private final String motd; @ConfigKey("config-version")
private final int showMaxPlayers; private final String configVersion = "1.0";
private final boolean onlineMode;
private final PlayerInfoForwarding playerInfoForwardingMode;
private final Map<String, String> servers;
private final List<String> attemptConnectionOrder;
private final int compressionThreshold;
private final int compressionLevel;
private final int loginRatelimit;
private final boolean queryEnabled; @Comment("What port should the proxy be bound to? By default, we'll bind to all addresses on port 25577.")
private final int queryPort; private String bind = "0.0.0.0:25577";
@Comment("What should be the MOTD? Legacy color codes and JSON are accepted.")
private String motd = "&3A Velocity Server";
@Comment({
"What should we display for the maximum number of players? (Velocity does not support a cap",
"on the number of players online.)"})
@ConfigKey("show-max-players")
private int showMaxPlayers = 500;
@Comment("Should we authenticate players with Mojang? By default, this is on.")
@ConfigKey("online-mode")
private boolean onlineMode = true;
@Comment({
"Should we forward IP addresses and other data to backend servers?",
"Available options:",
"- \"none\": No forwarding will be done. All players will appear to be Should we forward IP addresses and other data to backend servers?connecting from the proxy",
" and will have offline-mode UUIDs.",
"- \"legacy\": Forward player IPs and UUIDs in BungeeCord-compatible fashion. Use this if you run",
" servers using Minecraft 1.12 or lower.",
"- \"modern\": Forward player IPs and UUIDs as part of the login process using Velocity's native",
" forwarding. Only applicable for Minecraft 1.13 or higher."})
@ConfigKey("player-info-forwarding-mode")
private PlayerInfoForwarding playerInfoForwardingMode = PlayerInfoForwarding.MODERN;
@StringAsBytes
@Comment("If you are using modern IP forwarding, configure an unique secret here.")
@ConfigKey("forwarding-secret")
private byte[] forwardingSecret = generateRandomString(12).getBytes(StandardCharsets.UTF_8);
@Table("[servers]")
private final Servers servers;
@Table("[advanced]")
private final Advanced advanced;
@Table("[query]")
private final Query query;
@Ignore
private Component motdAsComponent; private Component motdAsComponent;
@Ignore
private Favicon favicon; private Favicon favicon;
private final byte[] forwardingSecret; public VelocityConfiguration(Servers servers, Advanced advanced, Query query) {
this.servers = servers;
this.advanced = advanced;
this.query = query;
}
private VelocityConfiguration(String bind, String motd, int showMaxPlayers, boolean onlineMode, private VelocityConfiguration(String bind, String motd, int showMaxPlayers, boolean onlineMode,
PlayerInfoForwarding playerInfoForwardingMode, Map<String, String> servers, PlayerInfoForwarding playerInfoForwardingMode, byte[] forwardingSecret, Servers servers,
List<String> attemptConnectionOrder, int compressionThreshold, Advanced advanced, Query query) {
int compressionLevel, int loginRatelimit, boolean queryEnabled,
int queryPort, byte[] forwardingSecret) {
this.bind = bind; this.bind = bind;
this.motd = motd; this.motd = motd;
this.showMaxPlayers = showMaxPlayers; this.showMaxPlayers = showMaxPlayers;
this.onlineMode = onlineMode; this.onlineMode = onlineMode;
this.playerInfoForwardingMode = playerInfoForwardingMode; this.playerInfoForwardingMode = playerInfoForwardingMode;
this.servers = servers;
this.attemptConnectionOrder = attemptConnectionOrder;
this.compressionThreshold = compressionThreshold;
this.compressionLevel = compressionLevel;
this.loginRatelimit = loginRatelimit;
this.queryEnabled = queryEnabled;
this.queryPort = queryPort;
this.forwardingSecret = forwardingSecret; this.forwardingSecret = forwardingSecret;
this.servers = servers;
this.advanced = advanced;
this.query = query;
} }
public boolean validate() { public boolean validate() {
boolean valid = true; boolean valid = true;
Logger logger = AnnotatedConfig.getLogger();
if (bind.isEmpty()) { if (bind.isEmpty()) {
logger.error("'bind' option is empty."); logger.error("'bind' option is empty.");
@ -95,16 +128,16 @@ public class VelocityConfiguration {
break; break;
} }
if (servers.isEmpty()) { if (servers.getServers().isEmpty()) {
logger.error("You have no servers configured. :("); logger.error("You have no servers configured. :(");
valid = false; valid = false;
} else { } else {
if (attemptConnectionOrder.isEmpty()) { if (servers.getAttemptConnectionOrder().isEmpty()) {
logger.error("No fallback servers are configured!"); logger.error("No fallback servers are configured!");
valid = false; valid = false;
} }
for (Map.Entry<String, String> entry : servers.entrySet()) { for (Map.Entry<String, String> entry : servers.getServers().entrySet()) {
try { try {
AddressUtil.parseAddress(entry.getValue()); AddressUtil.parseAddress(entry.getValue());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -113,8 +146,8 @@ public class VelocityConfiguration {
} }
} }
for (String s : attemptConnectionOrder) { for (String s : servers.getAttemptConnectionOrder()) {
if (!servers.containsKey(s)) { if (!servers.getServers().containsKey(s)) {
logger.error("Fallback server " + s + " doesn't exist!"); logger.error("Fallback server " + s + " doesn't exist!");
valid = false; valid = false;
} }
@ -128,22 +161,22 @@ public class VelocityConfiguration {
valid = false; valid = false;
} }
if (compressionLevel < -1 || compressionLevel > 9) { if (advanced.compressionLevel < -1 || advanced.compressionLevel > 9) {
logger.error("Invalid compression level {}", compressionLevel); logger.error("Invalid compression level {}", advanced.compressionLevel);
valid = false; valid = false;
} else if (compressionLevel == 0) { } else if (advanced.compressionLevel == 0) {
logger.warn("ALL packets going through the proxy are going to be uncompressed. This will increase bandwidth usage."); logger.warn("ALL packets going through the proxy are going to be uncompressed. This will increase bandwidth usage.");
} }
if (compressionThreshold < -1) { if (advanced.compressionThreshold < -1) {
logger.error("Invalid compression threshold {}", compressionLevel); logger.error("Invalid compression threshold {}", advanced.compressionLevel);
valid = false; valid = false;
} else if (compressionThreshold == 0) { } else if (advanced.compressionThreshold == 0) {
logger.warn("ALL packets going through the proxy are going to be compressed. This may hurt performance."); logger.warn("ALL packets going through the proxy are going to be compressed. This may hurt performance.");
} }
if (loginRatelimit < 0) { if (advanced.loginRatelimit < 0) {
logger.error("Invalid login ratelimit {}", loginRatelimit); logger.error("Invalid login ratelimit {}", advanced.loginRatelimit);
valid = false; valid = false;
} }
@ -158,7 +191,7 @@ public class VelocityConfiguration {
try { try {
this.favicon = Favicon.create(faviconPath); this.favicon = Favicon.create(faviconPath);
} catch (Exception e) { } catch (Exception e) {
logger.info("Unable to load your server-icon.png, continuing without it.", e); getLogger().info("Unable to load your server-icon.png, continuing without it.", e);
} }
} }
} }
@ -168,11 +201,11 @@ public class VelocityConfiguration {
} }
public boolean isQueryEnabled() { public boolean isQueryEnabled() {
return queryEnabled; return query.isQueryEnabled();
} }
public int getQueryPort() { public int getQueryPort() {
return queryPort; return query.getQueryPort();
} }
public String getMotd() { public String getMotd() {
@ -202,61 +235,153 @@ public class VelocityConfiguration {
return playerInfoForwardingMode; return playerInfoForwardingMode;
} }
public byte[] getForwardingSecret() {
return forwardingSecret;
}
public Map<String, String> getServers() { public Map<String, String> getServers() {
return servers; return servers.getServers();
} }
public List<String> getAttemptConnectionOrder() { public List<String> getAttemptConnectionOrder() {
return attemptConnectionOrder; return servers.getAttemptConnectionOrder();
} }
public int getCompressionThreshold() { public int getCompressionThreshold() {
return compressionThreshold; return advanced.getCompressionThreshold();
} }
public int getCompressionLevel() { public int getCompressionLevel() {
return compressionLevel; return advanced.getCompressionLevel();
} }
public int getLoginRatelimit() { public int getLoginRatelimit() {
return loginRatelimit; return advanced.getLoginRatelimit();
} }
public Favicon getFavicon() { public Favicon getFavicon() {
return favicon; return favicon;
} }
public byte[] getForwardingSecret() { private void setBind(String bind) {
return forwardingSecret; this.bind = bind;
}
private void setMotd(String motd) {
this.motd = motd;
}
private void setShowMaxPlayers(int showMaxPlayers) {
this.showMaxPlayers = showMaxPlayers;
}
private void setOnlineMode(boolean onlineMode) {
this.onlineMode = onlineMode;
}
private void setPlayerInfoForwardingMode(PlayerInfoForwarding playerInfoForwardingMode) {
this.playerInfoForwardingMode = playerInfoForwardingMode;
}
private void setForwardingSecret(byte[] forwardingSecret) {
this.forwardingSecret = forwardingSecret;
}
private void setMotdAsComponent(Component motdAsComponent) {
this.motdAsComponent = motdAsComponent;
}
private void setFavicon(Favicon favicon) {
this.favicon = favicon;
} }
@Override @Override
public String toString() { public String toString() {
return "VelocityConfiguration{" +
"bind='" + bind + '\'' + return "VelocityConfiguration{"
", motd='" + motd + '\'' + + "bind='" + bind + '\''
", showMaxPlayers=" + showMaxPlayers + + ", motd='" + motd + '\''
", onlineMode=" + onlineMode + + ", showMaxPlayers=" + showMaxPlayers
", playerInfoForwardingMode=" + playerInfoForwardingMode + + ", onlineMode=" + onlineMode
", servers=" + servers + + ", playerInfoForwardingMode=" + playerInfoForwardingMode
", attemptConnectionOrder=" + attemptConnectionOrder + + ", forwardingSecret=" + ByteBufUtil.hexDump(forwardingSecret)
", compressionThreshold=" + compressionThreshold + + ", servers=" + servers
", compressionLevel=" + compressionLevel + + ", advanced=" + advanced
", loginRatelimit=" + loginRatelimit + + ", query=" + query
", queryEnabled=" + queryEnabled + + ", motdAsComponent=" + motdAsComponent
", queryPort=" + queryPort + + ", favicon=" + favicon
", motdAsComponent=" + motdAsComponent + + '}';
", favicon=" + favicon +
", forwardingSecret=" + ByteBufUtil.hexDump(forwardingSecret) +
'}';
} }
public static VelocityConfiguration read(Path path) throws IOException { public static VelocityConfiguration read(Path path) throws IOException {
Toml toml;
if (!path.toFile().exists()) {
getLogger().info("No velocity.toml found, creating one for you...");
return new VelocityConfiguration(new Servers(), new Advanced(), new Query());
} else {
try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
Toml toml = new Toml().read(reader); toml = new Toml().read(reader);
}
}
Servers servers = new Servers(toml.getTable("servers"));
Advanced advanced = new Advanced(toml.getTable("advanced"));
Query query = new Query(toml.getTable("query"));
byte[] forwardingSecret = toml.getString("player-info-forwarding-secret", "5up3r53cr3t")
.getBytes(StandardCharsets.UTF_8);
VelocityConfiguration configuration = new VelocityConfiguration(
toml.getString("bind", "0.0.0.0:25577"),
toml.getString("motd", "&3A Velocity Server"),
toml.getLong("show-max-players", 500L).intValue(),
toml.getBoolean("online-mode", true),
PlayerInfoForwarding.valueOf(toml.getString("player-info-forwarding", "MODERN").toUpperCase()),
forwardingSecret,
servers,
advanced,
query
);
upgradeConfig(configuration, toml);
return configuration;
}
private static void upgradeConfig(VelocityConfiguration configuration, Toml toml) {
switch (toml.getString("config-version", configuration.configVersion)) {
case "1.0":
//TODO: Upgrade a 1.0 config to a new version. Maybe add a recursive support in future.
break;
default:
break;
}
}
private static String generateRandomString(int lenght) {
String chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890";
StringBuilder builder = new StringBuilder();
Random rnd = new Random();
for (int i = 0; i < lenght; i++) {
builder.append(chars.charAt(rnd.nextInt(chars.length())));
}
return builder.toString();
}
private static class Servers {
@IsMap
@Comment("Configure your servers here.")
private Map<String, String> servers = ImmutableMap.of("lobby", "127.0.0.1:30066", "factions", "127.0.0.1:30067", "minigames", "127.0.0.1:30068");
@Comment("In what order we should try servers when a player logs in or is kicked from a server.")
@ConfigKey("try")
private List<String> attemptConnectionOrder = Arrays.asList("lobby");
private Servers() {
}
private Servers(Toml toml) {
if (toml != null) {
Map<String, String> servers = new HashMap<>(); Map<String, String> servers = new HashMap<>();
for (Map.Entry<String, Object> entry : toml.getTable("servers").entrySet()) { for (Map.Entry<String, Object> entry : toml.entrySet()) {
if (entry.getValue() instanceof String) { if (entry.getValue() instanceof String) {
servers.put(entry.getKey(), (String) entry.getValue()); servers.put(entry.getKey(), (String) entry.getValue());
} else { } else {
@ -265,24 +390,155 @@ public class VelocityConfiguration {
} }
} }
} }
this.servers = ImmutableMap.copyOf(servers);
this.attemptConnectionOrder = toml.getList("try", attemptConnectionOrder);
}
}
byte[] forwardingSecret = toml.getString("player-info-forwarding-secret", "5up3r53cr3t") private Servers(Map<String, String> servers, List<String> attemptConnectionOrder) {
.getBytes(StandardCharsets.UTF_8); this.servers = servers;
this.attemptConnectionOrder = attemptConnectionOrder;
}
return new VelocityConfiguration( private Map<String, String> getServers() {
toml.getString("bind", "0.0.0.0:25577"), return servers;
toml.getString("motd", "&3A Velocity Server"), }
toml.getLong("show-max-players", 500L).intValue(),
toml.getBoolean("online-mode", true), public void setServers(Map<String, String> servers) {
PlayerInfoForwarding.valueOf(toml.getString("player-info-forwarding", "MODERN").toUpperCase()), this.servers = servers;
ImmutableMap.copyOf(servers), }
toml.getTable("servers").getList("try"),
toml.getTable("advanced").getLong("compression-threshold", 1024L).intValue(), public List<String> getAttemptConnectionOrder() {
toml.getTable("advanced").getLong("compression-level", -1L).intValue(), return attemptConnectionOrder;
toml.getTable("advanced").getLong("login-ratelimit", 3000L).intValue(), }
toml.getTable("query").getBoolean("enabled", false),
toml.getTable("query").getLong("port", 25577L).intValue(), public void setAttemptConnectionOrder(List<String> attemptConnectionOrder) {
forwardingSecret); this.attemptConnectionOrder = attemptConnectionOrder;
}
@Override
public String toString() {
return "Servers{"
+ "servers=" + servers
+ ", attemptConnectionOrder=" + attemptConnectionOrder
+ '}';
}
}
private static class Advanced {
@Comment({
"How large a Minecraft packet has to be before we compress it. Setting this to zero will compress all packets, and",
"setting it to -1 will disable compression entirely."})
@ConfigKey("compression-threshold")
private int compressionThreshold = 1024;
@Comment("How much compression should be done (from 0-9). The default is -1, which uses zlib's default level of 6.")
@ConfigKey("compression-level")
private int compressionLevel = -1;
@Comment({
"How fast (in miliseconds) are clients allowed to connect after the last connection? Default: 3000",
"Disable by setting to 0"})
@ConfigKey("login-ratelimit")
private int loginRatelimit = 3000;
private Advanced() {
}
private Advanced(int compressionThreshold, int compressionLevel, int loginRatelimit) {
this.compressionThreshold = compressionThreshold;
this.compressionLevel = compressionLevel;
this.loginRatelimit = loginRatelimit;
}
private Advanced(Toml toml) {
if (toml != null) {
this.compressionThreshold = toml.getLong("compression-threshold", 1024L).intValue();
this.compressionLevel = toml.getLong("compression-level", -1L).intValue();
this.loginRatelimit = toml.getLong("login-ratelimit", 3000L).intValue();
}
}
public int getCompressionThreshold() {
return compressionThreshold;
}
public void setCompressionThreshold(int compressionThreshold) {
this.compressionThreshold = compressionThreshold;
}
public int getCompressionLevel() {
return compressionLevel;
}
public void setCompressionLevel(int compressionLevel) {
this.compressionLevel = compressionLevel;
}
public int getLoginRatelimit() {
return loginRatelimit;
}
public void setLoginRatelimit(int loginRatelimit) {
this.loginRatelimit = loginRatelimit;
}
@Override
public String toString() {
return "Advanced{"
+ "compressionThreshold=" + compressionThreshold
+ ", compressionLevel=" + compressionLevel
+ ", loginRatelimit=" + loginRatelimit
+ '}';
}
}
private static class Query {
@Comment("Whether to enable responding to GameSpy 4 query responses or not")
@ConfigKey("enabled")
private boolean queryEnabled = false;
@Comment("If query responding is enabled, on what port should query response listener listen on?")
@ConfigKey("port")
private int queryPort = 25577;
private Query() {
}
private Query(boolean queryEnabled, int queryPort) {
this.queryEnabled = queryEnabled;
this.queryPort = queryPort;
}
private Query(Toml toml) {
if (toml != null) {
this.queryEnabled = toml.getBoolean("enabled", false);
this.queryPort = toml.getLong("port", 25577L).intValue();
}
}
public boolean isQueryEnabled() {
return queryEnabled;
}
public void setQueryEnabled(boolean queryEnabled) {
this.queryEnabled = queryEnabled;
}
public int getQueryPort() {
return queryPort;
}
public void setQueryPort(int queryPort) {
this.queryPort = queryPort;
}
@Override
public String toString() {
return "Query{"
+ "queryEnabled=" + queryEnabled
+ ", queryPort=" + queryPort
+ '}';
} }
} }
} }

Datei anzeigen

@ -1,55 +0,0 @@
# What port should the proxy be bound to? By default, we'll bind to all addresses on port 25577.
bind = "0.0.0.0:25577"
# What should be the MOTD? Legacy color codes and JSON are accepted.
motd = "&3A Velocity Server"
# What should we display for the maximum number of players? (Velocity does not support a cap
# on the number of players online.)
show-max-players = 500
# Should we authenticate players with Mojang? By default, this is on.
online-mode = true
# Should we forward IP addresses and other data to backend servers?
# Available options:
# - "none": No forwarding will be done. All players will appear to be connecting from the proxy
# and will have offline-mode UUIDs.
# - "legacy": Forward player IPs and UUIDs in BungeeCord-compatible fashion. Use this if you run
# servers using Minecraft 1.12 or lower.
# - "modern": Forward player IPs and UUIDs as part of the login process using Velocity's native
# forwarding. Only applicable for Minecraft 1.13 or higher.
player-info-forwarding = "modern"
# If you are using modern IP forwarding, configure an unique secret here.
player-info-forwarding-secret = "5up3r53cr3t"
[servers]
# Configure your servers here.
lobby = "127.0.0.1:30066"
factions = "127.0.0.1:30067"
minigames = "127.0.0.1:30068"
# In what order we should try servers when a player logs in or is kicked from a server.
try = [
"lobby"
]
[advanced]
# How large a Minecraft packet has to be before we compress it. Setting this to zero will compress all packets, and
# setting it to -1 will disable compression entirely.
compression-threshold = 1024
# How much compression should be done (from 0-9). The default is -1, which uses zlib's default level of 6.
compression-level = -1
# How fast (in miliseconds) are clients allowed to connect after the last connection? Default: 3000
# Disable by setting to 0
login-ratelimit = 3000
[query]
# Whether to enable responding to GameSpy 4 query responses or not
enabled = false
# If query responding is enabled, on what port should query response listener listen on?
port = 25577