Update to 26.3 #4
@@ -16,13 +16,49 @@
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.config;
|
||||
import com.electronwill.nightconfig.core.Config;
|
||||
|
||||
/**
|
||||
* Supported passthrough modes for ping passthrough.
|
||||
* Object to contain all the things that can be toggled for ping passthrough.
|
||||
*
|
||||
* @param version Whether the version should be passed through.
|
||||
* @param players Whether the player count should be passed through.
|
||||
* @param description Whether the description should be passed through.
|
||||
* @param favicon Whether the favicon should be passed through.
|
||||
* @param modinfo Whether the modinfo should be passed through.
|
||||
*/
|
||||
public enum PingPassthroughMode {
|
||||
DISABLED,
|
||||
MODS,
|
||||
DESCRIPTION,
|
||||
ALL
|
||||
public record PingPassthroughMode(boolean version, boolean players,
|
||||
boolean description, boolean favicon, boolean modinfo) {
|
||||
public static final PingPassthroughMode DEFAULT = new PingPassthroughMode();
|
||||
|
||||
/**
|
||||
* Creates a default PingPassthroughMode.
|
||||
*/
|
||||
private PingPassthroughMode() {
|
||||
this(false, false, false, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PingPassthroughMode from a config section, or the default if the section is null.
|
||||
* Based on the code for PacketLimiterConfig.
|
||||
*
|
||||
* @param config The configuration object to parse.
|
||||
* @return The PingPassthroughMode, or the default if {@code config} is null.
|
||||
*/
|
||||
public static PingPassthroughMode fromConfig(Config config) {
|
||||
if (config == null) {
|
||||
return DEFAULT;
|
||||
}
|
||||
return new PingPassthroughMode(
|
||||
config.getOrElse("version", DEFAULT.version()),
|
||||
config.getOrElse("players", DEFAULT.players()),
|
||||
config.getOrElse("description", DEFAULT.description()),
|
||||
config.getOrElse("favicon", DEFAULT.favicon()),
|
||||
config.getOrElse("modinfo", DEFAULT.modinfo()));
|
||||
}
|
||||
|
||||
public boolean enabled() {
|
||||
return this.version || this.players || this.description || this.favicon
|
||||
|| this.modinfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.velocitypowered.proxy.config.migration.KeyAuthenticationMigration;
|
||||
import com.velocitypowered.proxy.config.migration.MiniMessageTranslationsMigration;
|
||||
import com.velocitypowered.proxy.config.migration.MotdMigration;
|
||||
import com.velocitypowered.proxy.config.migration.PacketLimiterMigration;
|
||||
import com.velocitypowered.proxy.config.migration.PingPassthroughMigration;
|
||||
import com.velocitypowered.proxy.config.migration.TransferIntegrationMigration;
|
||||
import com.velocitypowered.proxy.util.AddressUtil;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
@@ -79,7 +80,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
@Expose
|
||||
private boolean onlineModeKickExistingPlayers = false;
|
||||
@Expose
|
||||
private PingPassthroughMode pingPassthrough = PingPassthroughMode.DISABLED;
|
||||
private PingPassthroughMode pingPassthrough = PingPassthroughMode.DEFAULT;
|
||||
@Expose
|
||||
private boolean samplePlayersInPing = false;
|
||||
private final Servers servers;
|
||||
@@ -513,7 +514,8 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
new MotdMigration(),
|
||||
new MiniMessageTranslationsMigration(),
|
||||
new TransferIntegrationMigration(),
|
||||
new PacketLimiterMigration()
|
||||
new PacketLimiterMigration(),
|
||||
new PingPassthroughMigration(),
|
||||
};
|
||||
|
||||
for (final ConfigurationMigration migration : migrations) {
|
||||
@@ -555,9 +557,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
final CommentedConfig metricsConfig = config.get("metrics");
|
||||
final PlayerInfoForwarding forwardingMode = config.getEnumOrElse(
|
||||
"player-info-forwarding-mode", PlayerInfoForwarding.NONE);
|
||||
final PingPassthroughMode pingPassthroughMode = config.getEnumOrElse("ping-passthrough",
|
||||
PingPassthroughMode.DISABLED);
|
||||
|
||||
final PingPassthroughMode pingPassthrough = PingPassthroughMode.fromConfig(config.get("ping-passthrough"));
|
||||
final boolean samplePlayersInPing = config.getOrElse("sample-players-in-ping", false);
|
||||
|
||||
final String bind = config.getOrElse("bind", "0.0.0.0:25565");
|
||||
@@ -590,7 +590,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
forwardingMode,
|
||||
forwardingSecret,
|
||||
kickExisting,
|
||||
pingPassthroughMode,
|
||||
pingPassthrough,
|
||||
samplePlayersInPing,
|
||||
enablePlayerAddressLogging,
|
||||
new Servers(serversConfig),
|
||||
|
||||
+2
-1
@@ -30,7 +30,8 @@ public sealed interface ConfigurationMigration
|
||||
MotdMigration,
|
||||
MiniMessageTranslationsMigration,
|
||||
TransferIntegrationMigration,
|
||||
PacketLimiterMigration {
|
||||
PacketLimiterMigration,
|
||||
PingPassthroughMigration {
|
||||
boolean shouldMigrate(CommentedFileConfig config);
|
||||
|
||||
void migrate(CommentedFileConfig config, Logger logger) throws IOException;
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2026 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.migration;
|
||||
|
||||
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||
import java.util.Locale;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Migrate the old ping passthrough entry to separate config entries.
|
||||
*/
|
||||
public final class PingPassthroughMigration implements ConfigurationMigration {
|
||||
@Override
|
||||
public boolean shouldMigrate(final CommentedFileConfig config) {
|
||||
return configVersion(config) < 2.9;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(final CommentedFileConfig config, final Logger logger) {
|
||||
// Get legacy ping passthrough value
|
||||
final String legacyMode = config.getOrElse("ping-passthrough", "DISABLED")
|
||||
.toUpperCase(Locale.ROOT);
|
||||
boolean version = false;
|
||||
boolean players = false;
|
||||
boolean description = false;
|
||||
boolean favicon = false;
|
||||
boolean modinfo = false;
|
||||
|
||||
switch (legacyMode) {
|
||||
case "ALL":
|
||||
version = true;
|
||||
players = true;
|
||||
description = true;
|
||||
favicon = true;
|
||||
modinfo = true;
|
||||
break;
|
||||
case "DESCRIPTION":
|
||||
description = true;
|
||||
modinfo = true;
|
||||
break;
|
||||
case "MODS":
|
||||
modinfo = true;
|
||||
break;
|
||||
default: // DISABLED
|
||||
break;
|
||||
}
|
||||
|
||||
config.removeComment("ping-passthrough");
|
||||
config.remove("ping-passthrough");
|
||||
|
||||
config.setComment("announce-forge",
|
||||
" Announce whether or not your server supports Forge. If you run a modded server, we\n"
|
||||
+ " suggest turning this on.\n"
|
||||
+ "\n"
|
||||
+ " If your network runs one modpack consistently, consider using ping-passthrough.modinfo = true\n"
|
||||
+ " instead for a nicer display in the server list.");
|
||||
|
||||
config.set("ping-passthrough.version", version);
|
||||
config.setComment(
|
||||
"ping-passthrough.version",
|
||||
" Should Velocity pass the version number from the backend server when responding to server list ping requests?"
|
||||
);
|
||||
|
||||
config.set("ping-passthrough.players", players);
|
||||
config.setComment(
|
||||
"ping-passthrough.players",
|
||||
" Should Velocity pass the player count from the backend server when responding to server list ping requests?"
|
||||
);
|
||||
|
||||
config.set("ping-passthrough.description", description);
|
||||
config.setComment(
|
||||
"ping-passthrough.description",
|
||||
" Should Velocity pass the description from the backend server when responding to server list ping requests?"
|
||||
);
|
||||
|
||||
config.set("ping-passthrough.favicon", favicon);
|
||||
config.setComment(
|
||||
"ping-passthrough.favicon",
|
||||
" Should Velocity pass the favicon (also known as the server icon) from the backend server when responding to server list ping requests?"
|
||||
);
|
||||
|
||||
config.set("ping-passthrough.modinfo", modinfo);
|
||||
config.setComment(
|
||||
"ping-passthrough.modinfo",
|
||||
" Should Velocity pass the mod list from the backend server when responding to server list ping requests?"
|
||||
);
|
||||
|
||||
config.set("config-version", "2.9");
|
||||
}
|
||||
}
|
||||
+59
-50
@@ -23,6 +23,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.server.PingOptions;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerPing;
|
||||
import com.velocitypowered.api.util.Favicon;
|
||||
import com.velocitypowered.api.util.ModInfo;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.config.PingPassthroughMode;
|
||||
@@ -100,60 +101,68 @@ public class ServerListPingHandler {
|
||||
|
||||
CompletableFuture<List<ServerPing>> pingResponses = CompletableFutures.successfulAsList(pings,
|
||||
(ex) -> fallback);
|
||||
return switch (mode) {
|
||||
case ALL -> pingResponses.thenApply(responses -> {
|
||||
// Find the first non-fallback
|
||||
for (ServerPing response : responses) {
|
||||
if (response == fallback) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (response.getDescriptionComponent() == null) {
|
||||
return response.asBuilder()
|
||||
.description(Component.empty())
|
||||
.build();
|
||||
}
|
||||
// Return early if ping passthrough is not enabled
|
||||
if (!mode.enabled()) {
|
||||
return CompletableFuture.completedFuture(fallback);
|
||||
}
|
||||
|
||||
return response;
|
||||
return pingResponses.thenApply(responses -> {
|
||||
// Find the first non-fallback
|
||||
for (ServerPing response : responses) {
|
||||
if (response == fallback) {
|
||||
continue;
|
||||
}
|
||||
return fallback;
|
||||
});
|
||||
case MODS -> pingResponses.thenApply(responses -> {
|
||||
// Find the first non-fallback that contains a mod list
|
||||
for (ServerPing response : responses) {
|
||||
if (response == fallback) {
|
||||
continue;
|
||||
}
|
||||
Optional<ModInfo> modInfo = response.getModinfo();
|
||||
if (modInfo.isPresent()) {
|
||||
return fallback.asBuilder().mods(modInfo.get()).build();
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
});
|
||||
case DESCRIPTION -> pingResponses.thenApply(responses -> {
|
||||
// Find the first non-fallback. If it includes a modlist, add it too.
|
||||
for (ServerPing response : responses) {
|
||||
if (response == fallback) {
|
||||
continue;
|
||||
}
|
||||
if (response.getDescriptionComponent() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return new ServerPing(
|
||||
fallback.getVersion(),
|
||||
fallback.getPlayers().orElse(null),
|
||||
response.getDescriptionComponent(),
|
||||
fallback.getFavicon().orElse(null),
|
||||
response.getModinfo().orElse(null)
|
||||
);
|
||||
ServerPing.Version version;
|
||||
if (mode.version()) {
|
||||
version = response.getVersion();
|
||||
} else {
|
||||
version = fallback.getVersion();
|
||||
}
|
||||
return fallback;
|
||||
});
|
||||
// Not possible, but covered for completeness.
|
||||
default -> CompletableFuture.completedFuture(fallback);
|
||||
};
|
||||
|
||||
ServerPing.Players players;
|
||||
if (mode.players()) {
|
||||
players = response.getPlayers().orElse(null);
|
||||
} else {
|
||||
players = fallback.getPlayers().orElse(null);
|
||||
}
|
||||
|
||||
Component description;
|
||||
if (mode.description()) {
|
||||
if (response.getDescriptionComponent() != null) {
|
||||
description = response.getDescriptionComponent();
|
||||
} else {
|
||||
description = Component.empty();
|
||||
}
|
||||
} else {
|
||||
description = fallback.getDescriptionComponent();
|
||||
}
|
||||
|
||||
Favicon favicon;
|
||||
if (mode.favicon()) {
|
||||
favicon = response.getFavicon().orElse(null);
|
||||
} else {
|
||||
favicon = fallback.getFavicon().orElse(null);
|
||||
}
|
||||
|
||||
ModInfo modinfo;
|
||||
if (mode.modinfo()) {
|
||||
modinfo = response.getModinfo().orElse(null);
|
||||
} else {
|
||||
modinfo = fallback.getModinfo().orElse(null);
|
||||
}
|
||||
|
||||
return new ServerPing(
|
||||
version,
|
||||
players,
|
||||
description,
|
||||
favicon,
|
||||
modinfo
|
||||
);
|
||||
}
|
||||
return fallback;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,7 +177,7 @@ public class ServerListPingHandler {
|
||||
? connection.getProtocolVersion() : ProtocolVersion.MAXIMUM_VERSION;
|
||||
PingPassthroughMode passthroughMode = configuration.getPingPassthrough();
|
||||
|
||||
if (passthroughMode == PingPassthroughMode.DISABLED) {
|
||||
if (!passthroughMode.enabled()) {
|
||||
return CompletableFuture.completedFuture(constructLocalPing(shownVersion));
|
||||
} else {
|
||||
String virtualHostStr = connection.getVirtualHost().map(InetSocketAddress::getHostString)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Config version. Do not change this
|
||||
config-version = "2.8"
|
||||
config-version = "2.9"
|
||||
|
||||
# What port should the proxy be bound to? By default, we'll bind to all addresses on port 25565.
|
||||
bind = "0.0.0.0:25565"
|
||||
@@ -43,7 +43,7 @@ forwarding-secret-file = "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"
|
||||
# If your network runs one modpack consistently, consider using ping-passthrough.modinfo = true
|
||||
# instead for a nicer display in the server list.
|
||||
announce-forge = false
|
||||
|
||||
@@ -51,21 +51,6 @@ announce-forge = false
|
||||
# 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"
|
||||
|
||||
# If enabled (default is false), then a sample of the online players on the proxy will be visible
|
||||
# when hovering over the player count in the server list.
|
||||
# This doesn't have any effect when ping passthrough is set to either "description" or "all".
|
||||
@@ -74,6 +59,18 @@ sample-players-in-ping = false
|
||||
# If not enabled (default is true) player IP addresses will be replaced by <ip address withheld> in logs
|
||||
enable-player-address-logging = true
|
||||
|
||||
[ping-passthrough]
|
||||
# Should Velocity pass the version number from the backend server when responding to server list ping requests?
|
||||
version = false
|
||||
# Should Velocity pass the player count from the backend server when responding to server list ping requests?
|
||||
players = false
|
||||
# Should Velocity pass the description from the backend server when responding to server list ping requests?
|
||||
description = false
|
||||
# Should Velocity pass the favicon (also known as the server icon) from the backend server when responding to server list ping requests?
|
||||
favicon = false
|
||||
# Should Velocity pass the mod list from the backend server when responding to server list ping requests?
|
||||
modinfo = false
|
||||
|
||||
[packet-limiter]
|
||||
# Size of the moving time window in seconds used to calculate average rates.
|
||||
# A larger window tolerates short bursts while still enforcing the configured limits over time.
|
||||
|
||||
Reference in New Issue
Block a user