mirror of
https://github.com/PaperMC/Velocity.git
synced 2026-06-21 09:47:44 +02:00
feat(config): map VelocityConfiguration to YAML via Configurate ObjectMapper
Wire up the Configurate ObjectMapper path for the new velocity.yml format: - Make VelocityConfiguration ObjectMapper-friendly: no-arg constructor, non-final nested fields, transient on non-config fields (forwardingSecret, motdAsComponent, favicon), and drop the dead gson @Expose annotations. - Annotate Advanced/Query/Metrics @ConfigSerializable and add @Setting for the keys the lower-case-dashed naming scheme can't derive (kick-existing-players, packet-limiter, haproxy-protocol, accepts-transfers, query enabled/port/map). - Add ConfigurationLoader with a LOWER_CASE_DASHED ObjectMapper factory, a YAML loader builder, load/save helpers, and custom TypeSerializers for the dynamic sections that don't fit object mapping: Servers (entries + try), ForcedHosts, and PacketLimiterConfig (renamed keys). - Add ConfigurationLoaderTest: loads the bundled default, and round-trips a config with non-default values for every renamed/custom-mapped key so a wrong mapping can't silently fall back to an identical default. Part of the velocity.toml -> velocity.yml Configurate migration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -17,30 +17,209 @@
|
||||
|
||||
package com.velocitypowered.proxy.config;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
import org.spongepowered.configurate.util.NamingSchemes;
|
||||
import org.spongepowered.configurate.yaml.NodeStyle;
|
||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
|
||||
/**
|
||||
* Velocity Configurate Loader entry utils.
|
||||
* Velocity Configurate (YAML) loader entry utils.
|
||||
*/
|
||||
public class ConfigurationLoader {
|
||||
public final class ConfigurationLoader {
|
||||
|
||||
/**
|
||||
* ObjectMapper factory configured to map {@code camelCase} fields onto {@code lower-case-dashed}
|
||||
* configuration keys, matching the historical TOML key style.
|
||||
*/
|
||||
private static final ObjectMapper.Factory OBJECT_MAPPER_FACTORY = ObjectMapper.factoryBuilder()
|
||||
.defaultNamingScheme(NamingSchemes.LOWER_CASE_DASHED)
|
||||
.build();
|
||||
|
||||
private ConfigurationLoader() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* performs legacy configuration migration if needed.
|
||||
* Builds a YAML loader for the given {@code path}, wired with the serializers needed to map a
|
||||
* {@link VelocityConfiguration}.
|
||||
*
|
||||
* @return {@code true} if a migration was performed, {@code false} otherwise
|
||||
* @param path the configuration file path
|
||||
* @return the configured loader builder
|
||||
*/
|
||||
public static boolean migrateIfNeeded() {
|
||||
return false;
|
||||
static YamlConfigurationLoader.Builder yamlLoader(final Path path) {
|
||||
return YamlConfigurationLoader.builder()
|
||||
.path(path)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.indent(2)
|
||||
.defaultOptions(opts -> opts.serializers(builder -> builder
|
||||
.register(VelocityConfiguration.Servers.class, new ServersSerializer())
|
||||
.register(VelocityConfiguration.ForcedHosts.class, new ForcedHostsSerializer())
|
||||
.register(VelocityConfiguration.PacketLimiterConfig.class,
|
||||
new PacketLimiterConfigSerializer())
|
||||
.registerAnnotatedObjects(OBJECT_MAPPER_FACTORY)));
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the velocity configuration.
|
||||
* Reads a {@link VelocityConfiguration} from the YAML file at {@code path}.
|
||||
*
|
||||
* @return the loaded configuration
|
||||
* @param path the configuration file path
|
||||
* @return the deserialized configuration
|
||||
* @throws IOException if the file could not be read or deserialized
|
||||
*/
|
||||
public static VelocityConfiguration loadConfiguration() {
|
||||
return null;
|
||||
static VelocityConfiguration load(final Path path) throws IOException {
|
||||
final CommentedConfigurationNode node = yamlLoader(path).build().load();
|
||||
final VelocityConfiguration config = node.get(VelocityConfiguration.class);
|
||||
if (config == null) {
|
||||
throw new IOException("Unable to deserialize configuration from " + path);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@link VelocityConfiguration} to the YAML file at {@code path}.
|
||||
*
|
||||
* @param config the configuration to write
|
||||
* @param path the configuration file path
|
||||
* @throws IOException if the file could not be written
|
||||
*/
|
||||
static void save(final VelocityConfiguration config, final Path path) throws IOException {
|
||||
final YamlConfigurationLoader loader = yamlLoader(path).build();
|
||||
final CommentedConfigurationNode node = loader.createNode();
|
||||
node.set(VelocityConfiguration.class, config);
|
||||
loader.save(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes {@code config} onto the provided {@code node}. Exposed for migration tooling.
|
||||
*
|
||||
* @param config the configuration to serialize
|
||||
* @param node the node to write to
|
||||
* @throws SerializationException if serialization fails
|
||||
*/
|
||||
static void write(final VelocityConfiguration config, final ConfigurationNode node)
|
||||
throws SerializationException {
|
||||
node.set(VelocityConfiguration.class, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the dynamic {@code [servers]} section, where named server entries live alongside the
|
||||
* {@code try} fallback order in a single node.
|
||||
*/
|
||||
static final class ServersSerializer implements TypeSerializer<VelocityConfiguration.Servers> {
|
||||
|
||||
@Override
|
||||
public VelocityConfiguration.Servers deserialize(final Type type, final ConfigurationNode node)
|
||||
throws SerializationException {
|
||||
final Map<String, String> servers = new LinkedHashMap<>();
|
||||
List<String> attemptConnectionOrder = ImmutableList.of("lobby");
|
||||
for (final Map.Entry<Object, ? extends ConfigurationNode> entry
|
||||
: node.childrenMap().entrySet()) {
|
||||
final String key = entry.getKey().toString();
|
||||
final ConfigurationNode value = entry.getValue();
|
||||
if (key.equalsIgnoreCase("try")) {
|
||||
attemptConnectionOrder = value.getList(String.class, ImmutableList.of());
|
||||
} else {
|
||||
final String address = value.getString();
|
||||
if (address == null) {
|
||||
throw new SerializationException("Server entry " + key + " is not a string!");
|
||||
}
|
||||
servers.put(VelocityConfiguration.Servers.cleanServerName(key), address);
|
||||
}
|
||||
}
|
||||
return new VelocityConfiguration.Servers(ImmutableMap.copyOf(servers),
|
||||
ImmutableList.copyOf(attemptConnectionOrder));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(final Type type, final VelocityConfiguration.@Nullable Servers obj,
|
||||
final ConfigurationNode node) throws SerializationException {
|
||||
if (obj == null) {
|
||||
node.raw(null);
|
||||
return;
|
||||
}
|
||||
for (final Map.Entry<String, String> entry : obj.getServers().entrySet()) {
|
||||
node.node(entry.getKey()).set(entry.getValue());
|
||||
}
|
||||
node.node("try").setList(String.class, obj.getAttemptConnectionOrder());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the dynamic {@code [forced-hosts]} section (host pattern to server list map).
|
||||
*/
|
||||
static final class ForcedHostsSerializer
|
||||
implements TypeSerializer<VelocityConfiguration.ForcedHosts> {
|
||||
|
||||
@Override
|
||||
public VelocityConfiguration.ForcedHosts deserialize(final Type type,
|
||||
final ConfigurationNode node) throws SerializationException {
|
||||
final Map<String, List<String>> forcedHosts = new LinkedHashMap<>();
|
||||
for (final Map.Entry<Object, ? extends ConfigurationNode> entry
|
||||
: node.childrenMap().entrySet()) {
|
||||
final String key = entry.getKey().toString().toLowerCase(Locale.ROOT);
|
||||
forcedHosts.put(key,
|
||||
ImmutableList.copyOf(entry.getValue().getList(String.class, ImmutableList.of())));
|
||||
}
|
||||
return new VelocityConfiguration.ForcedHosts(ImmutableMap.copyOf(forcedHosts));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(final Type type, final VelocityConfiguration.@Nullable ForcedHosts obj,
|
||||
final ConfigurationNode node) throws SerializationException {
|
||||
if (obj == null) {
|
||||
node.raw(null);
|
||||
return;
|
||||
}
|
||||
for (final Map.Entry<String, List<String>> entry : obj.getForcedHosts().entrySet()) {
|
||||
node.node(entry.getKey()).setList(String.class, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the {@code [packet-limiter]} section, whose keys do not follow the field naming
|
||||
* scheme (for example {@code packets-per-second} maps to {@code pps}).
|
||||
*/
|
||||
static final class PacketLimiterConfigSerializer
|
||||
implements TypeSerializer<VelocityConfiguration.PacketLimiterConfig> {
|
||||
|
||||
@Override
|
||||
public VelocityConfiguration.PacketLimiterConfig deserialize(final Type type,
|
||||
final ConfigurationNode node) {
|
||||
final VelocityConfiguration.PacketLimiterConfig def =
|
||||
VelocityConfiguration.PacketLimiterConfig.DEFAULT;
|
||||
return new VelocityConfiguration.PacketLimiterConfig(
|
||||
node.node("interval").getInt(def.interval()),
|
||||
node.node("packets-per-second").getInt(def.pps()),
|
||||
node.node("bytes-per-second").getInt(def.bytes()),
|
||||
node.node("decompressed-bytes-per-second").getInt(def.bytesAfterDecompression()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(final Type type,
|
||||
final VelocityConfiguration.@Nullable PacketLimiterConfig obj, final ConfigurationNode node)
|
||||
throws SerializationException {
|
||||
if (obj == null) {
|
||||
node.raw(null);
|
||||
return;
|
||||
}
|
||||
node.node("interval").set(obj.interval());
|
||||
node.node("packets-per-second").set(obj.pps());
|
||||
node.node("bytes-per-second").set(obj.bytes());
|
||||
node.node("decompressed-bytes-per-second").set(obj.bytesAfterDecompression());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.electronwill.nightconfig.core.CommentedConfig;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.velocitypowered.api.proxy.config.ProxyConfig;
|
||||
import com.velocitypowered.api.util.Favicon;
|
||||
import com.velocitypowered.proxy.util.AddressUtil;
|
||||
@@ -40,6 +39,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Setting;
|
||||
|
||||
/**
|
||||
* Velocity's configuration.
|
||||
@@ -49,50 +49,32 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(VelocityConfiguration.class);
|
||||
|
||||
@Expose
|
||||
private String bind = "0.0.0.0:25565";
|
||||
@Expose
|
||||
private String motd = "<aqua>A Velocity Server";
|
||||
@Expose
|
||||
private int showMaxPlayers = 500;
|
||||
@Expose
|
||||
private boolean onlineMode = true;
|
||||
@Expose
|
||||
private boolean preventClientProxyConnections = false;
|
||||
@Expose
|
||||
private PlayerInfoForwarding playerInfoForwardingMode = PlayerInfoForwarding.NONE;
|
||||
private byte[] forwardingSecret = generateRandomString(12).getBytes(StandardCharsets.UTF_8);
|
||||
@Expose
|
||||
private transient byte[] forwardingSecret =
|
||||
generateRandomString(12).getBytes(StandardCharsets.UTF_8);
|
||||
private boolean announceForge = false;
|
||||
@Expose
|
||||
@Setting("kick-existing-players")
|
||||
private boolean onlineModeKickExistingPlayers = false;
|
||||
@Expose
|
||||
private PingPassthroughMode pingPassthrough = PingPassthroughMode.DISABLED;
|
||||
@Expose
|
||||
private boolean samplePlayersInPing = false;
|
||||
private final Servers servers;
|
||||
private final ForcedHosts forcedHosts;
|
||||
@Expose
|
||||
private final Advanced advanced;
|
||||
@Expose
|
||||
private final Query query;
|
||||
private final Metrics metrics;
|
||||
@Expose
|
||||
private Servers servers = new Servers();
|
||||
private ForcedHosts forcedHosts = new ForcedHosts();
|
||||
private Advanced advanced = new Advanced();
|
||||
private Query query = new Query();
|
||||
private Metrics metrics = new Metrics();
|
||||
private boolean enablePlayerAddressLogging = true;
|
||||
private net.kyori.adventure.text.@MonotonicNonNull Component motdAsComponent;
|
||||
private @Nullable Favicon favicon;
|
||||
@Expose
|
||||
private transient net.kyori.adventure.text.@MonotonicNonNull Component motdAsComponent;
|
||||
private transient @Nullable Favicon favicon;
|
||||
private boolean forceKeyAuthentication = true; // Added in 1.19
|
||||
@Expose
|
||||
@Setting("packet-limiter")
|
||||
private PacketLimiterConfig packetLimiterConfig = PacketLimiterConfig.DEFAULT;
|
||||
|
||||
private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
|
||||
Query query, Metrics metrics) {
|
||||
this.servers = servers;
|
||||
this.forcedHosts = forcedHosts;
|
||||
this.advanced = advanced;
|
||||
this.query = query;
|
||||
this.metrics = metrics;
|
||||
VelocityConfiguration() {
|
||||
}
|
||||
|
||||
VelocityConfiguration(String bind, String motd, int showMaxPlayers, boolean onlineMode,
|
||||
@@ -501,7 +483,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
this.attemptConnectionOrder = attemptConnectionOrder;
|
||||
}
|
||||
|
||||
private Map<String, String> getServers() {
|
||||
Map<String, String> getServers() {
|
||||
return servers;
|
||||
}
|
||||
|
||||
@@ -553,7 +535,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
this.forcedHosts = forcedHosts;
|
||||
}
|
||||
|
||||
private Map<String, List<String>> getForcedHosts() {
|
||||
Map<String, List<String>> getForcedHosts() {
|
||||
return forcedHosts;
|
||||
}
|
||||
|
||||
@@ -569,47 +551,30 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
}
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
static class Advanced {
|
||||
|
||||
@Expose
|
||||
private int compressionThreshold = 256;
|
||||
@Expose
|
||||
private int compressionLevel = -1;
|
||||
@Expose
|
||||
private int loginRatelimit = 3000;
|
||||
@Expose
|
||||
private int connectionTimeout = 5000;
|
||||
@Expose
|
||||
private int readTimeout = 30000;
|
||||
@Expose
|
||||
@Setting("haproxy-protocol")
|
||||
private boolean proxyProtocol = false;
|
||||
@Expose
|
||||
private boolean tcpFastOpen = false;
|
||||
@Expose
|
||||
private boolean bungeePluginMessageChannel = true;
|
||||
@Expose
|
||||
private boolean showPingRequests = false;
|
||||
@Expose
|
||||
private boolean failoverOnUnexpectedServerDisconnect = true;
|
||||
@Expose
|
||||
private boolean announceProxyCommands = true;
|
||||
@Expose
|
||||
private boolean logCommandExecutions = false;
|
||||
@Expose
|
||||
private boolean logPlayerConnections = true;
|
||||
@Expose
|
||||
@Setting("accepts-transfers")
|
||||
private boolean acceptTransfers = false;
|
||||
@Expose
|
||||
private boolean enableReusePort = false;
|
||||
@Expose
|
||||
private int commandRateLimit = 50;
|
||||
@Expose
|
||||
private boolean forwardCommandsIfRateLimited = true;
|
||||
@Expose
|
||||
private int kickAfterRateLimitedCommands = 5;
|
||||
@Expose
|
||||
private int tabCompleteRateLimit = 50;
|
||||
@Expose
|
||||
private int kickAfterRateLimitedTabCompletes = 10;
|
||||
|
||||
Advanced() {
|
||||
@@ -752,15 +717,15 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
}
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
static class Query {
|
||||
|
||||
@Expose
|
||||
@Setting("enabled")
|
||||
private boolean queryEnabled = false;
|
||||
@Expose
|
||||
@Setting("port")
|
||||
private int queryPort = 25565;
|
||||
@Expose
|
||||
@Setting("map")
|
||||
private String queryMap = "Velocity";
|
||||
@Expose
|
||||
private boolean showPlugins = false;
|
||||
|
||||
Query() {
|
||||
@@ -803,6 +768,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
/**
|
||||
* Configuration for metrics.
|
||||
*/
|
||||
@ConfigSerializable
|
||||
public static class Metrics {
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.config;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.velocitypowered.proxy.config.VelocityConfiguration.PacketLimiterConfig;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
class ConfigurationLoaderTest {
|
||||
|
||||
/**
|
||||
* The bundled default config must deserialize cleanly via the ObjectMapper and custom
|
||||
* serializers, preserving the dynamic {@code servers}/{@code try} and {@code forced-hosts}
|
||||
* sections.
|
||||
*/
|
||||
@Test
|
||||
void bundledDefaultLoads(@TempDir final Path dir) throws IOException {
|
||||
final Path path = dir.resolve("velocity.yml");
|
||||
try (InputStream in = ConfigurationLoaderTest.class.getClassLoader()
|
||||
.getResourceAsStream("default-velocity.yml")) {
|
||||
assertNotNull(in, "default-velocity.yml is missing from resources");
|
||||
Files.copy(in, path);
|
||||
}
|
||||
|
||||
final VelocityConfiguration config = ConfigurationLoader.load(path);
|
||||
|
||||
assertEquals(500, config.getShowMaxPlayers());
|
||||
assertEquals(ImmutableMap.of(
|
||||
"lobby", "127.0.0.1:30066",
|
||||
"factions", "127.0.0.1:30067",
|
||||
"minigames", "127.0.0.1:30068"), config.getServers());
|
||||
assertEquals(ImmutableList.of("lobby"), config.getAttemptConnectionOrder());
|
||||
assertEquals(ImmutableMap.of(
|
||||
"lobby.example.com", ImmutableList.of("lobby"),
|
||||
"factions.example.com", ImmutableList.of("factions"),
|
||||
"minigames.example.com", ImmutableList.of("minigames")), config.getForcedHosts());
|
||||
assertEquals(7, config.getPacketLimiterConfig().interval());
|
||||
assertEquals(5242880, config.getPacketLimiterConfig().bytesAfterDecompression());
|
||||
assertTrue(config.getMetrics().isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the non-trivial key mappings (renamed via {@code @Setting} and the custom
|
||||
* serializers) using values that differ from the Java field defaults, so a wrong mapping cannot
|
||||
* silently fall back to an identical default. Also exercises a save/reload round trip.
|
||||
*/
|
||||
@Test
|
||||
void renamedKeysRoundTrip(@TempDir final Path dir) throws IOException {
|
||||
final String yaml = """
|
||||
config-version: 1
|
||||
bind: "0.0.0.0:25577"
|
||||
show-max-players: 123
|
||||
online-mode: false
|
||||
kick-existing-players: true
|
||||
player-info-forwarding-mode: "MODERN"
|
||||
ping-passthrough: "ALL"
|
||||
sample-players-in-ping: true
|
||||
enable-player-address-logging: false
|
||||
force-key-authentication: false
|
||||
announce-forge: true
|
||||
packet-limiter:
|
||||
interval: 9
|
||||
packets-per-second: 100
|
||||
bytes-per-second: 200
|
||||
decompressed-bytes-per-second: 300
|
||||
servers:
|
||||
alpha: "1.2.3.4:25565"
|
||||
beta: "5.6.7.8:25565"
|
||||
try:
|
||||
- beta
|
||||
- alpha
|
||||
forced-hosts:
|
||||
"host.example.com":
|
||||
- alpha
|
||||
- beta
|
||||
advanced:
|
||||
haproxy-protocol: true
|
||||
accepts-transfers: true
|
||||
compression-threshold: 128
|
||||
command-rate-limit: 99
|
||||
enable-reuse-port: true
|
||||
query:
|
||||
enabled: true
|
||||
port: 12345
|
||||
map: "CustomMap"
|
||||
show-plugins: true
|
||||
metrics:
|
||||
enabled: false
|
||||
""";
|
||||
final Path path = dir.resolve("velocity.yml");
|
||||
Files.writeString(path, yaml, StandardCharsets.UTF_8);
|
||||
|
||||
assertConfig(ConfigurationLoader.load(path));
|
||||
|
||||
// Round trip: save the loaded config out and read it back; everything must still match.
|
||||
final Path roundTripped = dir.resolve("velocity-roundtrip.yml");
|
||||
ConfigurationLoader.save(ConfigurationLoader.load(path), roundTripped);
|
||||
assertConfig(ConfigurationLoader.load(roundTripped));
|
||||
}
|
||||
|
||||
private static void assertConfig(final VelocityConfiguration config) {
|
||||
assertEquals(123, config.getShowMaxPlayers());
|
||||
assertFalse(config.isOnlineMode());
|
||||
assertTrue(config.isOnlineModeKickExistingPlayers());
|
||||
assertEquals(PlayerInfoForwarding.MODERN, config.getPlayerInfoForwardingMode());
|
||||
assertEquals(PingPassthroughMode.ALL, config.getPingPassthrough());
|
||||
assertTrue(config.getSamplePlayersInPing());
|
||||
assertFalse(config.isPlayerAddressLoggingEnabled());
|
||||
assertFalse(config.isForceKeyAuthentication());
|
||||
assertTrue(config.isAnnounceForge());
|
||||
|
||||
final PacketLimiterConfig limiter = config.getPacketLimiterConfig();
|
||||
assertEquals(9, limiter.interval());
|
||||
assertEquals(100, limiter.pps());
|
||||
assertEquals(200, limiter.bytes());
|
||||
assertEquals(300, limiter.bytesAfterDecompression());
|
||||
|
||||
assertEquals(ImmutableMap.of(
|
||||
"alpha", "1.2.3.4:25565",
|
||||
"beta", "5.6.7.8:25565"), config.getServers());
|
||||
assertEquals(ImmutableList.of("beta", "alpha"), config.getAttemptConnectionOrder());
|
||||
assertEquals(ImmutableMap.of(
|
||||
"host.example.com", ImmutableList.of("alpha", "beta")), config.getForcedHosts());
|
||||
|
||||
assertTrue(config.isProxyProtocol());
|
||||
assertTrue(config.isAcceptTransfers());
|
||||
assertEquals(128, config.getCompressionThreshold());
|
||||
assertEquals(99, config.getCommandRatelimit());
|
||||
assertTrue(config.isEnableReusePort());
|
||||
|
||||
assertTrue(config.isQueryEnabled());
|
||||
assertEquals(12345, config.getQueryPort());
|
||||
assertEquals("CustomMap", config.getQueryMap());
|
||||
assertTrue(config.shouldQueryShowPlugins());
|
||||
|
||||
assertFalse(config.getMetrics().isEnabled());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user