Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-17 05:20:14 +01:00
Switch Velocity from existing toml4j+homebrew TOML serializer to night-config.
This allows us to allow many more valid configurations and allows us to eliminate a bunch of ugly hacks.
Dieser Commit ist enthalten in:
Ursprung
4bebda2549
Commit
28d2366c73
@ -71,6 +71,8 @@ dependencies {
|
|||||||
|
|
||||||
compile 'com.spotify:completable-futures:0.3.2'
|
compile 'com.spotify:completable-futures:0.3.2'
|
||||||
|
|
||||||
|
compile 'com.electronwill.night-config:toml:3.6.3'
|
||||||
|
|
||||||
testCompile "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
|
testCompile "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
|
||||||
testCompile "org.junit.jupiter:junit-jupiter-engine:${junitVersion}"
|
testCompile "org.junit.jupiter:junit-jupiter-engine:${junitVersion}"
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ import com.velocitypowered.proxy.command.ServerCommand;
|
|||||||
import com.velocitypowered.proxy.command.ShutdownCommand;
|
import com.velocitypowered.proxy.command.ShutdownCommand;
|
||||||
import com.velocitypowered.proxy.command.VelocityCommand;
|
import com.velocitypowered.proxy.command.VelocityCommand;
|
||||||
import com.velocitypowered.proxy.command.VelocityCommandManager;
|
import com.velocitypowered.proxy.command.VelocityCommandManager;
|
||||||
import com.velocitypowered.proxy.config.AnnotatedConfig;
|
|
||||||
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
||||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||||
import com.velocitypowered.proxy.console.VelocityConsole;
|
import com.velocitypowered.proxy.console.VelocityConsole;
|
||||||
@ -80,7 +79,6 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
|||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|
||||||
|
|
||||||
public class VelocityServer implements ProxyServer {
|
public class VelocityServer implements ProxyServer {
|
||||||
|
|
||||||
@ -185,9 +183,6 @@ public class VelocityServer implements ProxyServer {
|
|||||||
Path configPath = Paths.get("velocity.toml");
|
Path configPath = Paths.get("velocity.toml");
|
||||||
configuration = VelocityConfiguration.read(configPath);
|
configuration = VelocityConfiguration.read(configPath);
|
||||||
|
|
||||||
// Resave config to add new values
|
|
||||||
AnnotatedConfig.saveConfig(configuration.dumpConfig(), configPath);
|
|
||||||
|
|
||||||
if (!configuration.validate()) {
|
if (!configuration.validate()) {
|
||||||
logger.error("Your configuration is invalid. Velocity will not start up until the errors "
|
logger.error("Your configuration is invalid. Velocity will not start up until the errors "
|
||||||
+ "are resolved.");
|
+ "are resolved.");
|
||||||
|
@ -1,267 +0,0 @@
|
|||||||
package com.velocitypowered.proxy.config;
|
|
||||||
|
|
||||||
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.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple annotation and fields based TOML configuration serializer.
|
|
||||||
*/
|
|
||||||
public abstract class AnnotatedConfig {
|
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(AnnotatedConfig.class);
|
|
||||||
private static final Pattern STRING_NEEDS_ESCAPE
|
|
||||||
= Pattern.compile("(\"|\\\\|[\\u0000-\\u0008]|[\\u000a-\\u001f]|\\u007f)");
|
|
||||||
|
|
||||||
public static Logger getLogger() {
|
|
||||||
return logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that a field is a table.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
|
||||||
public @interface Table {
|
|
||||||
/**
|
|
||||||
* The table's name.
|
|
||||||
* @return the table's name
|
|
||||||
*/
|
|
||||||
String value();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a comment.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
|
||||||
public @interface Comment {
|
|
||||||
/**
|
|
||||||
* The comments to include with this key. Each entry is considered a line.
|
|
||||||
* @return the comments
|
|
||||||
*/
|
|
||||||
String[] value();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How field will be named in config.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
|
||||||
public @interface ConfigKey {
|
|
||||||
/**
|
|
||||||
* The name of this field in the configuration.
|
|
||||||
* @return the field's name
|
|
||||||
*/
|
|
||||||
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 skipped.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target({ElementType.FIELD})
|
|
||||||
public @interface Ignore {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dumps this configuration to list of strings using {@link #dumpConfig(Object)}.
|
|
||||||
*
|
|
||||||
* @return configuration dump
|
|
||||||
*/
|
|
||||||
public List<String> dumpConfig() {
|
|
||||||
return dumpConfig(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates TOML configuration from supplied <pre>dumpable</pre> object.
|
|
||||||
*
|
|
||||||
* @param dumpable object which is going to be dumped
|
|
||||||
* @return string list of configuration file lines
|
|
||||||
* @throws RuntimeException if reading field value(s) fail
|
|
||||||
*/
|
|
||||||
private static List<String> dumpConfig(Object dumpable) {
|
|
||||||
List<String> lines = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
for (Field field : dumpable.getClass().getDeclaredFields()) {
|
|
||||||
// Skip fields with @Ignore annotation
|
|
||||||
if (field.getAnnotation(Ignore.class) != null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make field accessible
|
|
||||||
field.setAccessible(true);
|
|
||||||
|
|
||||||
// Add comments
|
|
||||||
Comment comment = field.getAnnotation(Comment.class);
|
|
||||||
if (comment != null) {
|
|
||||||
for (String line : comment.value()) {
|
|
||||||
lines.add("# " + line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a key name for config. Use field name if @ConfigKey annotation is not present.
|
|
||||||
ConfigKey key = field.getAnnotation(ConfigKey.class);
|
|
||||||
final String name = escapeKeyIfNeeded(key == null ? field.getName() : key.value());
|
|
||||||
|
|
||||||
Object value = field.get(dumpable);
|
|
||||||
|
|
||||||
// Check if field is table.
|
|
||||||
Table table = field.getAnnotation(Table.class);
|
|
||||||
if (table != null) {
|
|
||||||
lines.add(table.value()); // Write [name]
|
|
||||||
lines.addAll(dumpConfig(value)); // Dump fields of table
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field.getAnnotation(IsMap.class) != null) { // Check if field is a map
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Map<String, ?> map = (Map<String, ?>) value;
|
|
||||||
for (Entry<String, ?> entry : map.entrySet()) {
|
|
||||||
lines.add(escapeKeyIfNeeded(entry.getKey()) + " = " + serialize(entry.getValue()));
|
|
||||||
}
|
|
||||||
lines.add(""); // Add empty line
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if field is a byte[] representation of a string
|
|
||||||
if (field.getAnnotation(StringAsBytes.class) != null) {
|
|
||||||
value = new String((byte[]) value, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save field to config
|
|
||||||
lines.add(name + " = " + serialize(value));
|
|
||||||
lines.add(""); // Add empty line
|
|
||||||
}
|
|
||||||
} catch (IllegalAccessException | IllegalArgumentException | SecurityException e) {
|
|
||||||
throw new RuntimeException("Could not dump configuration", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes <pre>value</pre> so it can be parsed as a TOML value.
|
|
||||||
*
|
|
||||||
* @param value object to serialize
|
|
||||||
* @return Serialized object
|
|
||||||
*/
|
|
||||||
private static String serialize(Object value) {
|
|
||||||
if (value instanceof List) {
|
|
||||||
List<?> listValue = (List<?>) value;
|
|
||||||
if (listValue.isEmpty()) {
|
|
||||||
return "[]";
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder m = new StringBuilder();
|
|
||||||
m.append("[");
|
|
||||||
|
|
||||||
for (Object obj : listValue) {
|
|
||||||
m.append(System.lineSeparator()).append(" ").append(serialize(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) {
|
|
||||||
return writeString((String) value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value != null ? value.toString() : "null";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static String escapeKeyIfNeeded(String key) {
|
|
||||||
if ((key.contains(".") || key.contains(" "))
|
|
||||||
&& !(key.indexOf('"') == 0 && key.lastIndexOf('"') == (key.length() - 1))) {
|
|
||||||
return '"' + key + '"';
|
|
||||||
}
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String writeString(String str) {
|
|
||||||
if (str.isEmpty()) {
|
|
||||||
return "\"\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
// According to the TOML specification (https://toml.io/en/v1.0.0-rc.1#section-7):
|
|
||||||
//
|
|
||||||
// Any Unicode character may be used except those that must be escaped: quotation mark,
|
|
||||||
// backslash, and the control characters other than tab (U+0000 to U+0008, U+000A to U+001F,
|
|
||||||
// U+007F).
|
|
||||||
if (STRING_NEEDS_ESCAPE.matcher(str).find()) {
|
|
||||||
return "'" + str + "'";
|
|
||||||
} else {
|
|
||||||
return "\"" + str.replace("\n", "\\n") + "\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static String unescapeKeyIfNeeded(String key) {
|
|
||||||
int lastIndex;
|
|
||||||
if (key.indexOf('"') == 0 && (lastIndex = key.lastIndexOf('"')) == (key.length() - 1)) {
|
|
||||||
return key.substring(1, lastIndex);
|
|
||||||
}
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes list of strings to file.
|
|
||||||
*
|
|
||||||
* @param lines list of strings to write
|
|
||||||
* @param to Path of file where lines should be written
|
|
||||||
* @throws IOException if error occurred during writing
|
|
||||||
* @throws IllegalArgumentException if <pre>lines</pre> is empty list
|
|
||||||
*/
|
|
||||||
public static void saveConfig(List<String> lines, Path to) throws IOException {
|
|
||||||
if (lines.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("lines cannot be empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
Path temp = to.toAbsolutePath().getParent().resolve(to.getFileName().toString() + "__tmp");
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,16 @@
|
|||||||
package com.velocitypowered.proxy.config;
|
package com.velocitypowered.proxy.config;
|
||||||
|
|
||||||
|
import com.electronwill.nightconfig.core.CommentedConfig;
|
||||||
|
import com.electronwill.nightconfig.core.Config;
|
||||||
|
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||||
|
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||||
import com.google.common.base.MoreObjects;
|
import com.google.common.base.MoreObjects;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.moandjiezana.toml.Toml;
|
import com.moandjiezana.toml.Toml;
|
||||||
import com.velocitypowered.api.proxy.config.ProxyConfig;
|
import com.velocitypowered.api.proxy.config.ProxyConfig;
|
||||||
import com.velocitypowered.api.util.Favicon;
|
import com.velocitypowered.api.util.Favicon;
|
||||||
|
import com.velocitypowered.proxy.Velocity;
|
||||||
import com.velocitypowered.proxy.util.AddressUtil;
|
import com.velocitypowered.proxy.util.AddressUtil;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
@ -25,116 +30,31 @@ import java.util.UUID;
|
|||||||
import net.kyori.text.Component;
|
import net.kyori.text.Component;
|
||||||
import net.kyori.text.serializer.gson.GsonComponentSerializer;
|
import net.kyori.text.serializer.gson.GsonComponentSerializer;
|
||||||
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfig {
|
public class VelocityConfiguration implements ProxyConfig {
|
||||||
|
|
||||||
@Comment("Config version. Do not change this")
|
private static final Logger logger = LogManager.getLogger(VelocityConfiguration.class);
|
||||||
@ConfigKey("config-version")
|
|
||||||
private final String configVersion = "1.0";
|
|
||||||
|
|
||||||
@Comment("What port should the proxy be bound to? By default, we'll bind to all addresses on"
|
|
||||||
+ " port 25577.")
|
|
||||||
private String bind = "0.0.0.0:25577";
|
private String bind = "0.0.0.0:25577";
|
||||||
|
|
||||||
@Comment({"What should be the MOTD? This gets displayed when the player adds your server to",
|
|
||||||
"their server list. Legacy color codes and JSON are accepted."})
|
|
||||||
private String motd = "&3A Velocity Server";
|
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;
|
private int showMaxPlayers = 500;
|
||||||
|
|
||||||
@Comment("Should we authenticate players with Mojang? By default, this is on.")
|
|
||||||
@ConfigKey("online-mode")
|
|
||||||
private boolean onlineMode = true;
|
private boolean onlineMode = true;
|
||||||
|
|
||||||
@Comment({
|
|
||||||
"If client's ISP/AS sent from this proxy is different from the one from Mojang's",
|
|
||||||
"authentication server, the player is kicked. This disallows some VPN and proxy",
|
|
||||||
"connections but is a weak form of protection."
|
|
||||||
})
|
|
||||||
@ConfigKey("prevent-client-proxy-connections")
|
|
||||||
private boolean preventClientProxyConnections = false;
|
private boolean preventClientProxyConnections = false;
|
||||||
|
|
||||||
@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 connecting",
|
|
||||||
" from the proxy and will have offline-mode UUIDs.",
|
|
||||||
"- \"legacy\": Forward player IPs and UUIDs in a BungeeCord-compatible format. Use this",
|
|
||||||
" if you run servers using Minecraft 1.12 or lower.",
|
|
||||||
"- \"bungeeguard\": Forward player IPs and UUIDs in a format supported by the BungeeGuard",
|
|
||||||
" plugin. Use this if you run servers using Minecraft 1.12 or lower, and are",
|
|
||||||
" unable to implement network level firewalling (on a shared host).",
|
|
||||||
"- \"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.NONE;
|
private PlayerInfoForwarding playerInfoForwardingMode = PlayerInfoForwarding.NONE;
|
||||||
|
|
||||||
@StringAsBytes
|
|
||||||
@Comment("If you are using modern or BungeeGuard IP forwarding, configure an unique secret here.")
|
|
||||||
@ConfigKey("forwarding-secret")
|
|
||||||
private byte[] forwardingSecret = generateRandomString(12).getBytes(StandardCharsets.UTF_8);
|
private byte[] forwardingSecret = generateRandomString(12).getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
@Comment({
|
|
||||||
"Announce whether or not your server supports Forge. If you run a modded server, we",
|
|
||||||
"suggest turning this on.",
|
|
||||||
"",
|
|
||||||
"If your network runs one modpack consistently, consider using ping-passthrough = \"mods\"",
|
|
||||||
"instead for a nicer display in the server list."
|
|
||||||
})
|
|
||||||
@ConfigKey("announce-forge")
|
|
||||||
private boolean announceForge = false;
|
private boolean announceForge = false;
|
||||||
|
|
||||||
@Comment({"If enabled (default is false) and the proxy is in online mode, Velocity will kick",
|
|
||||||
"any existing player who is online if a duplicate connection attempt is made."})
|
|
||||||
@ConfigKey("kick-existing-players")
|
|
||||||
private boolean onlineModeKickExistingPlayers = false;
|
private boolean onlineModeKickExistingPlayers = false;
|
||||||
|
|
||||||
@Comment({
|
|
||||||
"Should Velocity pass server list ping requests to a backend server?",
|
|
||||||
"Available options:",
|
|
||||||
"- \"disabled\": No pass-through will be done. The velocity.toml and server-icon.png",
|
|
||||||
" will determine the initial server list ping response.",
|
|
||||||
"- \"mods\": Passes only the mod list from your backend server into the response.",
|
|
||||||
" The first server in your try list (or forced host) with a mod list will be",
|
|
||||||
" used. If no backend servers can be contacted, Velocity won't display any",
|
|
||||||
" mod information.",
|
|
||||||
"- \"description\": Uses the description and mod list from the backend server. The first",
|
|
||||||
" server in the try (or forced host) list that responds is used for the",
|
|
||||||
" description and mod list.",
|
|
||||||
"- \"all\": Uses the backend server's response as the proxy response. The Velocity",
|
|
||||||
" configuration is used if no servers could be contacted."
|
|
||||||
})
|
|
||||||
@ConfigKey("ping-passthrough")
|
|
||||||
private PingPassthroughMode pingPassthrough = PingPassthroughMode.DISABLED;
|
private PingPassthroughMode pingPassthrough = PingPassthroughMode.DISABLED;
|
||||||
|
|
||||||
@Table("[servers]")
|
|
||||||
private final Servers servers;
|
private final Servers servers;
|
||||||
|
|
||||||
@Table("[forced-hosts]")
|
|
||||||
private final ForcedHosts forcedHosts;
|
private final ForcedHosts forcedHosts;
|
||||||
|
|
||||||
@Table("[advanced]")
|
|
||||||
private final Advanced advanced;
|
private final Advanced advanced;
|
||||||
|
|
||||||
@Table("[query]")
|
|
||||||
private final Query query;
|
private final Query query;
|
||||||
|
|
||||||
@Table("[metrics]")
|
|
||||||
private final Metrics metrics;
|
private final Metrics metrics;
|
||||||
|
|
||||||
@Ignore
|
|
||||||
private @MonotonicNonNull Component motdAsComponent;
|
private @MonotonicNonNull Component motdAsComponent;
|
||||||
|
|
||||||
@Ignore
|
|
||||||
private @Nullable Favicon favicon;
|
private @Nullable Favicon favicon;
|
||||||
|
|
||||||
private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
|
private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
|
||||||
@ -172,7 +92,6 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
*/
|
*/
|
||||||
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.");
|
||||||
@ -280,7 +199,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
try {
|
try {
|
||||||
this.favicon = Favicon.create(faviconPath);
|
this.favicon = Favicon.create(faviconPath);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
getLogger().info("Unable to load your server-icon.png, continuing without it.", e);
|
logger.info("Unable to load your server-icon.png, continuing without it.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -430,7 +349,6 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return MoreObjects.toStringHelper(this)
|
return MoreObjects.toStringHelper(this)
|
||||||
.add("configVersion", configVersion)
|
|
||||||
.add("bind", bind)
|
.add("bind", bind)
|
||||||
.add("motd", motd)
|
.add("motd", motd)
|
||||||
.add("showMaxPlayers", showMaxPlayers)
|
.add("showMaxPlayers", showMaxPlayers)
|
||||||
@ -453,45 +371,67 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
* @throws IOException if we could not read from the {@code path}.
|
* @throws IOException if we could not read from the {@code path}.
|
||||||
*/
|
*/
|
||||||
public static VelocityConfiguration read(Path path) throws IOException {
|
public static VelocityConfiguration read(Path path) throws IOException {
|
||||||
Toml toml;
|
boolean mustResave = false;
|
||||||
if (!path.toFile().exists()) {
|
CommentedFileConfig config = CommentedFileConfig.builder(path)
|
||||||
getLogger().info("No velocity.toml found, creating one for you...");
|
.defaultResource("/default-velocity.toml")
|
||||||
return new VelocityConfiguration(new Servers(), new ForcedHosts(), new Advanced(),
|
.autosave()
|
||||||
new Query(), new Metrics());
|
.preserveInsertionOrder()
|
||||||
} else {
|
.sync()
|
||||||
try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
|
.build();
|
||||||
toml = new Toml().read(reader);
|
config.load();
|
||||||
|
|
||||||
|
// Handle any cases where the config needs to be saved again
|
||||||
|
byte[] forwardingSecret;
|
||||||
|
String forwardingSecretString = config.get("forwarding-secret");
|
||||||
|
if (forwardingSecretString.isEmpty()) {
|
||||||
|
forwardingSecretString = generateRandomString(12);
|
||||||
|
config.set("forwarding-secret", forwardingSecretString);
|
||||||
|
mustResave = true;
|
||||||
}
|
}
|
||||||
|
forwardingSecret = forwardingSecretString.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
if (config.<String>get("metrics.id").isEmpty()) {
|
||||||
|
config.set("metrics.id", UUID.randomUUID().toString());
|
||||||
|
mustResave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Servers servers = new Servers(toml.getTable("servers"));
|
if (mustResave) {
|
||||||
ForcedHosts forcedHosts = new ForcedHosts(toml.getTable("forced-hosts"));
|
config.save();
|
||||||
Advanced advanced = new Advanced(toml.getTable("advanced"));
|
}
|
||||||
Query query = new Query(toml.getTable("query"));
|
|
||||||
Metrics metrics = new Metrics(toml.getTable("metrics"));
|
|
||||||
byte[] forwardingSecret = toml.getString("forwarding-secret", generateRandomString(12))
|
|
||||||
.getBytes(StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
String forwardingModeName = toml.getString("player-info-forwarding-mode", "MODERN")
|
// Read the rest of the config
|
||||||
.toUpperCase(Locale.US);
|
CommentedConfig serversConfig = config.get("servers");
|
||||||
String passThroughName = toml.getString("ping-passthrough", "DISABLED")
|
CommentedConfig forcedHostsConfig = config.get("forced-hosts");
|
||||||
.toUpperCase(Locale.US);
|
CommentedConfig advancedConfig = config.get("advanced");
|
||||||
|
CommentedConfig queryConfig = config.get("query");
|
||||||
|
CommentedConfig metricsConfig = config.get("metrics");
|
||||||
|
PlayerInfoForwarding forwardingMode = config.getEnumOrElse("player-info-forwarding-mode",
|
||||||
|
PlayerInfoForwarding.NONE);
|
||||||
|
PingPassthroughMode pingPassthroughMode = config.getEnumOrElse("ping-passthrough",
|
||||||
|
PingPassthroughMode.DISABLED);
|
||||||
|
|
||||||
|
String bind = config.getOrElse("bind", "0.0.0.0:25577");
|
||||||
|
String motd = config.getOrElse("motd", "&3A Velocity Server");
|
||||||
|
int maxPlayers = config.getIntOrElse("show-max-players", 500);
|
||||||
|
Boolean onlineMode = config.getOrElse("online-mode", true);
|
||||||
|
Boolean announceForge = config.getOrElse("announce-forge", true);
|
||||||
|
Boolean kickExisting = config.getOrElse("kick-existing-players", false);
|
||||||
|
|
||||||
return new VelocityConfiguration(
|
return new VelocityConfiguration(
|
||||||
toml.getString("bind", "0.0.0.0:25577"),
|
bind,
|
||||||
toml.getString("motd", "&3A Velocity Server"),
|
motd,
|
||||||
toml.getLong("show-max-players", 500L).intValue(),
|
maxPlayers,
|
||||||
toml.getBoolean("online-mode", true),
|
onlineMode,
|
||||||
toml.getBoolean("announce-forge", false),
|
announceForge,
|
||||||
PlayerInfoForwarding.valueOf(forwardingModeName),
|
forwardingMode,
|
||||||
forwardingSecret,
|
forwardingSecret,
|
||||||
toml.getBoolean("kick-existing-players", false),
|
kickExisting,
|
||||||
PingPassthroughMode.valueOf(passThroughName),
|
pingPassthroughMode,
|
||||||
servers,
|
new Servers(serversConfig),
|
||||||
forcedHosts,
|
new ForcedHosts(forcedHostsConfig),
|
||||||
advanced,
|
new Advanced(advancedConfig),
|
||||||
query,
|
new Query(queryConfig),
|
||||||
metrics
|
new Metrics(metricsConfig)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,29 +451,22 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
|
|
||||||
private static class Servers {
|
private static class Servers {
|
||||||
|
|
||||||
@IsMap
|
|
||||||
@Comment({"Configure your servers here. Each key represents the server's name, and the value",
|
|
||||||
"represents the IP address of the server to connect to."})
|
|
||||||
private Map<String, String> servers = ImmutableMap.of(
|
private Map<String, String> servers = ImmutableMap.of(
|
||||||
"lobby", "127.0.0.1:30066",
|
"lobby", "127.0.0.1:30066",
|
||||||
"factions", "127.0.0.1:30067",
|
"factions", "127.0.0.1:30067",
|
||||||
"minigames", "127.0.0.1:30068"
|
"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 List<String> attemptConnectionOrder = Arrays.asList("lobby");
|
||||||
|
|
||||||
private Servers() {
|
private Servers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Servers(Toml toml) {
|
private Servers(CommentedConfig config) {
|
||||||
if (toml != null) {
|
if (config != null) {
|
||||||
Map<String, String> servers = new HashMap<>();
|
Map<String, String> servers = new HashMap<>();
|
||||||
for (Map.Entry<String, Object> entry : toml.entrySet()) {
|
for (UnmodifiableConfig.Entry entry : config.entrySet()) {
|
||||||
if (entry.getValue() instanceof String) {
|
if (entry.getValue() instanceof String) {
|
||||||
servers.put(cleanServerName(entry.getKey()), (String) entry.getValue());
|
servers.put(cleanServerName(entry.getKey()), entry.getValue());
|
||||||
} else {
|
} else {
|
||||||
if (!entry.getKey().equalsIgnoreCase("try")) {
|
if (!entry.getKey().equalsIgnoreCase("try")) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
@ -542,7 +475,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.servers = ImmutableMap.copyOf(servers);
|
this.servers = ImmutableMap.copyOf(servers);
|
||||||
this.attemptConnectionOrder = toml.getList("try", attemptConnectionOrder);
|
this.attemptConnectionOrder = config.getOrElse("try", attemptConnectionOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,8 +524,6 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
|
|
||||||
private static class ForcedHosts {
|
private static class ForcedHosts {
|
||||||
|
|
||||||
@IsMap
|
|
||||||
@Comment("Configure your forced hosts here.")
|
|
||||||
private Map<String, List<String>> forcedHosts = ImmutableMap.of(
|
private Map<String, List<String>> forcedHosts = ImmutableMap.of(
|
||||||
"lobby.example.com", ImmutableList.of("lobby"),
|
"lobby.example.com", ImmutableList.of("lobby"),
|
||||||
"factions.example.com", ImmutableList.of("factions"),
|
"factions.example.com", ImmutableList.of("factions"),
|
||||||
@ -602,16 +533,14 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
private ForcedHosts() {
|
private ForcedHosts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ForcedHosts(Toml toml) {
|
private ForcedHosts(CommentedConfig config) {
|
||||||
if (toml != null) {
|
if (config != null) {
|
||||||
Map<String, List<String>> forcedHosts = new HashMap<>();
|
Map<String, List<String>> forcedHosts = new HashMap<>();
|
||||||
for (Map.Entry<String, Object> entry : toml.entrySet()) {
|
for (UnmodifiableConfig.Entry entry : config.entrySet()) {
|
||||||
if (entry.getValue() instanceof String) {
|
if (entry.getValue() instanceof String) {
|
||||||
forcedHosts.put(unescapeKeyIfNeeded(entry.getKey()), ImmutableList.of(
|
forcedHosts.put(entry.getKey(), ImmutableList.of(entry.getValue()));
|
||||||
(String) entry.getValue()));
|
|
||||||
} else if (entry.getValue() instanceof List) {
|
} else if (entry.getValue() instanceof List) {
|
||||||
forcedHosts.put(unescapeKeyIfNeeded(entry.getKey()),
|
forcedHosts.put(entry.getKey(), ImmutableList.copyOf((List<String>) entry.getValue()));
|
||||||
ImmutableList.copyOf((List<String>) entry.getValue()));
|
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Invalid value of type " + entry.getValue().getClass() + " in forced hosts!");
|
"Invalid value of type " + entry.getValue().getClass() + " in forced hosts!");
|
||||||
@ -643,64 +572,30 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
|
|
||||||
private static class Advanced {
|
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 = 256;
|
private int compressionThreshold = 256;
|
||||||
|
|
||||||
@Comment({"How much compression should be done (from 0-9). The default is -1, which uses the",
|
|
||||||
"default level of 6."})
|
|
||||||
@ConfigKey("compression-level")
|
|
||||||
private int compressionLevel = -1;
|
private int compressionLevel = -1;
|
||||||
|
|
||||||
@Comment({
|
|
||||||
"How fast (in milliseconds) are clients allowed to connect after the last connection? By",
|
|
||||||
"default, this is three seconds. Disable this by setting this to 0."
|
|
||||||
})
|
|
||||||
@ConfigKey("login-ratelimit")
|
|
||||||
private int loginRatelimit = 3000;
|
private int loginRatelimit = 3000;
|
||||||
|
|
||||||
@Comment({
|
|
||||||
"Specify a custom timeout for connection timeouts here. The default is five seconds."})
|
|
||||||
@ConfigKey("connection-timeout")
|
|
||||||
private int connectionTimeout = 5000;
|
private int connectionTimeout = 5000;
|
||||||
|
|
||||||
@Comment({"Specify a read timeout for connections here. The default is 30 seconds."})
|
|
||||||
@ConfigKey("read-timeout")
|
|
||||||
private int readTimeout = 30000;
|
private int readTimeout = 30000;
|
||||||
|
|
||||||
@Comment("Enables compatibility with HAProxy.")
|
|
||||||
@ConfigKey("proxy-protocol")
|
|
||||||
private boolean proxyProtocol = false;
|
private boolean proxyProtocol = false;
|
||||||
|
|
||||||
@Comment("Enables TCP fast open support on the proxy. Requires the proxy to run on Linux.")
|
|
||||||
@ConfigKey("tcp-fast-open")
|
|
||||||
private boolean tcpFastOpen = false;
|
private boolean tcpFastOpen = false;
|
||||||
|
|
||||||
@Comment("Enables BungeeCord plugin messaging channel support on Velocity.")
|
|
||||||
@ConfigKey("bungee-plugin-message-channel")
|
|
||||||
private boolean bungeePluginMessageChannel = true;
|
private boolean bungeePluginMessageChannel = true;
|
||||||
|
|
||||||
@Comment("Shows ping requests to the proxy from clients.")
|
|
||||||
@ConfigKey("show-ping-requests")
|
|
||||||
private boolean showPingRequests = false;
|
private boolean showPingRequests = false;
|
||||||
|
|
||||||
private Advanced() {
|
private Advanced() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Advanced(Toml toml) {
|
private Advanced(CommentedConfig config) {
|
||||||
if (toml != null) {
|
if (config != null) {
|
||||||
this.compressionThreshold = toml.getLong("compression-threshold", 256L).intValue();
|
this.compressionThreshold = config.getIntOrElse("compression-threshold", 256);
|
||||||
this.compressionLevel = toml.getLong("compression-level", -1L).intValue();
|
this.compressionLevel = config.getIntOrElse("compression-level", -1);
|
||||||
this.loginRatelimit = toml.getLong("login-ratelimit", 3000L).intValue();
|
this.loginRatelimit = config.getIntOrElse("login-ratelimit", 3000);
|
||||||
this.connectionTimeout = toml.getLong("connection-timeout", 5000L).intValue();
|
this.connectionTimeout = config.getIntOrElse("connection-timeout", 5000);
|
||||||
this.readTimeout = toml.getLong("read-timeout", 30000L).intValue();
|
this.readTimeout = config.getIntOrElse("read-timeout", 30000);
|
||||||
this.proxyProtocol = toml.getBoolean("proxy-protocol", false);
|
this.proxyProtocol = config.getOrElse("proxy-protocol", false);
|
||||||
this.tcpFastOpen = toml.getBoolean("tcp-fast-open", false);
|
this.tcpFastOpen = config.getOrElse("tcp-fast-open", false);
|
||||||
this.bungeePluginMessageChannel = toml.getBoolean("bungee-plugin-message-channel", true);
|
this.bungeePluginMessageChannel = config.getOrElse("bungee-plugin-message-channel", true);
|
||||||
this.showPingRequests = toml.getBoolean("show-ping-requests", false);
|
this.showPingRequests = config.getOrElse("show-ping-requests", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,20 +653,9 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
|
|
||||||
private static class Query {
|
private static class Query {
|
||||||
|
|
||||||
@Comment("Whether to enable responding to GameSpy 4 query responses or not.")
|
|
||||||
@ConfigKey("enabled")
|
|
||||||
private boolean queryEnabled = false;
|
private boolean queryEnabled = false;
|
||||||
|
|
||||||
@Comment("If query is enabled, on what port should the query protocol listen on?")
|
|
||||||
@ConfigKey("port")
|
|
||||||
private int queryPort = 25577;
|
private int queryPort = 25577;
|
||||||
|
|
||||||
@Comment("This is the map name that is reported to the query services.")
|
|
||||||
@ConfigKey("map")
|
|
||||||
private String queryMap = "Velocity";
|
private String queryMap = "Velocity";
|
||||||
|
|
||||||
@Comment("Whether plugins should be shown in query response by default or not")
|
|
||||||
@ConfigKey("show-plugins")
|
|
||||||
private boolean showPlugins = false;
|
private boolean showPlugins = false;
|
||||||
|
|
||||||
private Query() {
|
private Query() {
|
||||||
@ -784,12 +668,12 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
this.showPlugins = showPlugins;
|
this.showPlugins = showPlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Query(Toml toml) {
|
private Query(CommentedConfig config) {
|
||||||
if (toml != null) {
|
if (config != null) {
|
||||||
this.queryEnabled = toml.getBoolean("enabled", false);
|
this.queryEnabled = config.getOrElse("enabled", false);
|
||||||
this.queryPort = toml.getLong("port", 25577L).intValue();
|
this.queryPort = config.getIntOrElse("port", 25577);
|
||||||
this.queryMap = toml.getString("map", "Velocity");
|
this.queryMap = config.getOrElse("map", "Velocity");
|
||||||
this.showPlugins = toml.getBoolean("show-plugins", false);
|
this.showPlugins = config.getOrElse("show-plugins", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,34 +705,21 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Metrics {
|
public static class Metrics {
|
||||||
|
|
||||||
@Comment({"Whether metrics will be reported to bStats (https://bstats.org).",
|
|
||||||
"bStats collects some basic information, like how many people use Velocity and their",
|
|
||||||
"player count. We recommend keeping bStats enabled, but if you're not comfortable with",
|
|
||||||
"this, you can turn this setting off. There is no performance penalty associated with",
|
|
||||||
"having metrics enabled, and data sent to bStats can't identify your server."})
|
|
||||||
@ConfigKey("enabled")
|
|
||||||
private boolean enabled = true;
|
private boolean enabled = true;
|
||||||
|
|
||||||
@Comment("A unique, anonymous ID to identify this proxy with.")
|
|
||||||
@ConfigKey("id")
|
|
||||||
private String id = UUID.randomUUID().toString();
|
private String id = UUID.randomUUID().toString();
|
||||||
|
|
||||||
@ConfigKey("log-failure")
|
|
||||||
private boolean logFailure = false;
|
private boolean logFailure = false;
|
||||||
|
|
||||||
@Ignore
|
|
||||||
private boolean fromConfig;
|
private boolean fromConfig;
|
||||||
|
|
||||||
private Metrics() {
|
private Metrics() {
|
||||||
this.fromConfig = false;
|
this.fromConfig = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Metrics(Toml toml) {
|
private Metrics(CommentedConfig toml) {
|
||||||
if (toml != null) {
|
if (toml != null) {
|
||||||
this.enabled = toml.getBoolean("enabled", false);
|
this.enabled = toml.getOrElse("enabled", false);
|
||||||
this.id = toml.getString("id", UUID.randomUUID().toString());
|
this.id = toml.getOrElse("id", UUID.randomUUID().toString());
|
||||||
this.logFailure = toml.getBoolean("log-failure", false);
|
this.logFailure = toml.getOrElse("log-failure", false);
|
||||||
this.fromConfig = true;
|
this.fromConfig = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
145
proxy/src/main/resources/default-velocity.toml
Normale Datei
145
proxy/src/main/resources/default-velocity.toml
Normale Datei
@ -0,0 +1,145 @@
|
|||||||
|
# Config version. Do not change this
|
||||||
|
config-version = "1.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? This gets displayed when the player adds your server to
|
||||||
|
# their server list. 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
|
||||||
|
|
||||||
|
# If client's ISP/AS sent from this proxy is different from the one from Mojang's
|
||||||
|
# authentication server, the player is kicked. This disallows some VPN and proxy
|
||||||
|
# connections but is a weak form of protection.
|
||||||
|
prevent-client-proxy-connections = false
|
||||||
|
|
||||||
|
# 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 a BungeeCord-compatible format. Use this
|
||||||
|
# if you run servers using Minecraft 1.12 or lower.
|
||||||
|
# - "bungeeguard": Forward player IPs and UUIDs in a format supported by the BungeeGuard
|
||||||
|
# plugin. Use this if you run servers using Minecraft 1.12 or lower, and are
|
||||||
|
# unable to implement network level firewalling (on a shared host).
|
||||||
|
# - "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-mode = "NONE"
|
||||||
|
|
||||||
|
# If you are using modern or BungeeGuard IP forwarding, configure an unique secret here.
|
||||||
|
forwarding-secret = ""
|
||||||
|
|
||||||
|
# Announce whether or not your server supports Forge. If you run a modded server, we
|
||||||
|
# suggest turning this on.
|
||||||
|
#
|
||||||
|
# If your network runs one modpack consistently, consider using ping-passthrough = "mods"
|
||||||
|
# instead for a nicer display in the server list.
|
||||||
|
announce-forge = false
|
||||||
|
|
||||||
|
# If enabled (default is false) and the proxy is in online mode, Velocity will kick
|
||||||
|
# any existing player who is online if a duplicate connection attempt is made.
|
||||||
|
kick-existing-players = false
|
||||||
|
|
||||||
|
# Should Velocity pass server list ping requests to a backend server?
|
||||||
|
# Available options:
|
||||||
|
# - "disabled": No pass-through will be done. The velocity.toml and server-icon.png
|
||||||
|
# will determine the initial server list ping response.
|
||||||
|
# - "mods": Passes only the mod list from your backend server into the response.
|
||||||
|
# The first server in your try list (or forced host) with a mod list will be
|
||||||
|
# used. If no backend servers can be contacted, Velocity won't display any
|
||||||
|
# mod information.
|
||||||
|
# - "description": Uses the description and mod list from the backend server. The first
|
||||||
|
# server in the try (or forced host) list that responds is used for the
|
||||||
|
# description and mod list.
|
||||||
|
# - "all": Uses the backend server's response as the proxy response. The Velocity
|
||||||
|
# configuration is used if no servers could be contacted.
|
||||||
|
ping-passthrough = "DISABLED"
|
||||||
|
|
||||||
|
[servers]
|
||||||
|
# Configure your servers here. Each key represents the server's name, and the value
|
||||||
|
# represents the IP address of the server to connect to.
|
||||||
|
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 aserver.
|
||||||
|
try = [
|
||||||
|
"lobby"
|
||||||
|
]
|
||||||
|
|
||||||
|
[forced-hosts]
|
||||||
|
# Configure your forced hosts here.
|
||||||
|
"lobby.example.com" = [
|
||||||
|
"lobby"
|
||||||
|
]
|
||||||
|
"factions.example.com" = [
|
||||||
|
"factions"
|
||||||
|
]
|
||||||
|
"minigames.example.com" = [
|
||||||
|
"minigames"
|
||||||
|
]
|
||||||
|
|
||||||
|
[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 = 256
|
||||||
|
|
||||||
|
# How much compression should be done (from 0-9). The default is -1, which uses the
|
||||||
|
# default level of 6.
|
||||||
|
compression-level = -1
|
||||||
|
|
||||||
|
# How fast (in milliseconds) are clients allowed to connect after the last connection? By
|
||||||
|
# default, this is three seconds. Disable this by setting this to 0.
|
||||||
|
login-ratelimit = 3000
|
||||||
|
|
||||||
|
# Specify a custom timeout for connection timeouts here. The default is five seconds.
|
||||||
|
connection-timeout = 5000
|
||||||
|
|
||||||
|
# Specify a read timeout for connections here. The default is 30 seconds.
|
||||||
|
read-timeout = 30000
|
||||||
|
|
||||||
|
# Enables compatibility with HAProxy.
|
||||||
|
proxy-protocol = false
|
||||||
|
|
||||||
|
# Enables TCP fast open support on the proxy. Requires the proxy to run on Linux.
|
||||||
|
tcp-fast-open = false
|
||||||
|
|
||||||
|
# Enables BungeeCord plugin messaging channel support on Velocity.
|
||||||
|
bungee-plugin-message-channel = true
|
||||||
|
|
||||||
|
# Shows ping requests to the proxy from clients.
|
||||||
|
show-ping-requests = false
|
||||||
|
|
||||||
|
[query]
|
||||||
|
# Whether to enable responding to GameSpy 4 query responses or not.
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
# If query is enabled, on what port should the query protocol listen on?
|
||||||
|
port = 25577
|
||||||
|
|
||||||
|
# This is the map name that is reported to the query services.
|
||||||
|
map = "Velocity"
|
||||||
|
|
||||||
|
# Whether plugins should be shown in query response by default or not
|
||||||
|
show-plugins = false
|
||||||
|
|
||||||
|
[metrics]
|
||||||
|
# Whether metrics will be reported to bStats (https://bstats.org).
|
||||||
|
# bStats collects some basic information, like how many people use Velocity and their
|
||||||
|
# player count. We recommend keeping bStats enabled, but if you're not comfortable with
|
||||||
|
# this, you can turn this setting off. There is no performance penalty associated with
|
||||||
|
# having metrics enabled, and data sent to bStats can't identify your server.
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
# A unique, anonymous ID to identify this proxy with.
|
||||||
|
id = ""
|
||||||
|
|
||||||
|
log-failure = false
|
||||||
|
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren