Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2018-2023 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;

/**
* Legacy modes for ping passthrough.
*/
public enum LegacyPingPassthroughMode {
DISABLED,
MODS,
DESCRIPTION,
ALL
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,36 @@
package com.velocitypowered.proxy.config;

/**
* Supported passthrough modes for ping passthrough.
* Object to contain all the things that can be toggled for ping passthrough.
*/
public enum PingPassthroughMode {
DISABLED,
MODS,
DESCRIPTION,
ALL
public class PingPassthroughMode {
public boolean version;
public boolean players;
public boolean description;
public boolean favicon;
public boolean modinfo;

/**
* Passthrough mode constructor.
* Looking at other code, I'm not sure the constructor is supposed to need a javadoc style comment,
* but checkstyle was yelling at me because I didn't include one.
* Probably for the best.
*
* @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 PingPassthroughMode(boolean version, boolean players, boolean description, boolean favicon, boolean modinfo) {
this.version = version;
this.players = players;
this.description = description;
this.favicon = favicon;
this.modinfo = modinfo;
}

public boolean enabled() {
return this.version || this.players || this.description || this.favicon || this.modinfo;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.velocitypowered.proxy.config.migration.ForwardingMigration;
import com.velocitypowered.proxy.config.migration.KeyAuthenticationMigration;
import com.velocitypowered.proxy.config.migration.MotdMigration;
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;
Expand Down Expand Up @@ -77,7 +78,7 @@ public class VelocityConfiguration implements ProxyConfig {
@Expose
private boolean onlineModeKickExistingPlayers = false;
@Expose
private PingPassthroughMode pingPassthrough = PingPassthroughMode.DISABLED;
private PingPassthroughMode pingPassthrough = new PingPassthroughMode(false, false, false, false, false);
@Expose
private boolean samplePlayersInPing = false;
private final Servers servers;
Expand Down Expand Up @@ -108,8 +109,7 @@ private VelocityConfiguration(String bind, String motd, int showMaxPlayers, bool
PlayerInfoForwarding playerInfoForwardingMode, byte[] forwardingSecret,
boolean onlineModeKickExistingPlayers, PingPassthroughMode pingPassthrough,
boolean samplePlayersInPing, boolean enablePlayerAddressLogging, Servers servers,
ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics,
boolean forceKeyAuthentication) {
ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics, boolean forceKeyAuthentication) {
this.bind = bind;
this.motd = motd;
this.showMaxPlayers = showMaxPlayers;
Expand Down Expand Up @@ -504,7 +504,8 @@ public static VelocityConfiguration read(Path path) throws IOException {
new ForwardingMigration(),
new KeyAuthenticationMigration(),
new MotdMigration(),
new TransferIntegrationMigration()
new TransferIntegrationMigration(),
new PingPassthroughMigration()
};

for (final ConfigurationMigration migration : migrations) {
Expand Down Expand Up @@ -542,9 +543,12 @@ public static VelocityConfiguration read(Path path) throws IOException {
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 = new PingPassthroughMode(
config.getOrElse("ping-passthrough-version", false),
config.getOrElse("ping-passthrough-players", false),
config.getOrElse("ping-passthrough-description", false),
config.getOrElse("ping-passthrough-favicon", false),
config.getOrElse("ping-passthrough-modinfo", false));
final boolean samplePlayersInPing = config.getOrElse("sample-players-in-ping", false);

final String bind = config.getOrElse("bind", "0.0.0.0:25565");
Expand Down Expand Up @@ -576,7 +580,7 @@ public static VelocityConfiguration read(Path path) throws IOException {
forwardingMode,
forwardingSecret,
kickExisting,
pingPassthroughMode,
pingPassthrough,
samplePlayersInPing,
enablePlayerAddressLogging,
new Servers(serversConfig),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public sealed interface ConfigurationMigration
permits ForwardingMigration,
KeyAuthenticationMigration,
MotdMigration,
TransferIntegrationMigration {
TransferIntegrationMigration,
PingPassthroughMigration {
boolean shouldMigrate(CommentedFileConfig config);

void migrate(CommentedFileConfig config, Logger logger) throws IOException;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* 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.migration;

import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.velocitypowered.proxy.config.LegacyPingPassthroughMode;
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.8;
}

@Override
public void migrate(final CommentedFileConfig config, final Logger logger) {
// Get legacy ping passthrough value
final LegacyPingPassthroughMode legacyMode = config.getEnumOrElse("ping-passthrough",
LegacyPingPassthroughMode.DISABLED);

config.removeComment("ping-passthrough");
config.remove("ping-passthrough");

// Create ping passthrough entry for the version
config.set("ping-passthrough-version", legacyMode.equals(LegacyPingPassthroughMode.ALL));
config.setComment(
"ping-passthrough-version",
" Should Velocity pass the version number from the backend server when responding to server list ping requests?"
);

// Create ping passthrough entry for the players
config.set("ping-passthrough-players", legacyMode.equals(LegacyPingPassthroughMode.ALL));
config.setComment(
"ping-passthrough-players",
" Should Velocity pass the player count from the backend server when responding to server list ping requests?"
);

// Create ping passthrough entry for the description
config.set("ping-passthrough-description",
legacyMode.equals(LegacyPingPassthroughMode.ALL)
|| legacyMode.equals(LegacyPingPassthroughMode.DESCRIPTION)
);
config.setComment(
"ping-passthrough-description",
" Should Velocity pass the description from the backend server when responding to server list ping requests?"
);

// Create ping passthrough entry for the favicon
config.set("ping-passthrough-favicon", legacyMode.equals(LegacyPingPassthroughMode.ALL));
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?"
);

// Create ping passthrough entry for the mods info
config.set("ping-passthrough-modinfo",
legacyMode.equals(LegacyPingPassthroughMode.ALL)
|| legacyMode.equals(LegacyPingPassthroughMode.MODS)
|| legacyMode.equals(LegacyPingPassthroughMode.DESCRIPTION)
);
config.setComment(
"ping-passthrough-modinfo",
" Should Velocity pass the mod list from the backend server when responding to server list ping requests?"
);

// Update config version
config.set("config-version", "2.8");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
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;
Expand Down Expand Up @@ -99,58 +100,64 @@ private CompletableFuture<ServerPing> attemptPingPassthrough(VelocityInboundConn

CompletableFuture<List<ServerPing>> pingResponses = CompletableFutures.successfulAsList(pings,
(ex) -> fallback);
switch (mode) {
case ALL:
return pingResponses.thenApply(responses -> {
// Find the first non-fallback
for (ServerPing response : responses) {
if (response == fallback) {
continue;
}
return response;
}
return fallback;
});
case MODS:
return 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:
return 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)
);
}
return fallback;
});
// Not possible, but covered for completeness.
default:
return CompletableFuture.completedFuture(fallback);

// Return early if ping passthrough is not enabled
if (!mode.enabled()) {
return CompletableFuture.completedFuture(fallback);
}

return pingResponses.thenApply(responses -> {
// Find the first non-fallback
for (ServerPing response : responses) {
if (response == fallback) {
continue;
}

ServerPing.Version version;
if (mode.version) {
version = response.getVersion();
} else {
version = fallback.getVersion();
}

ServerPing.Players players;
if (mode.players) {
players = response.getPlayers().orElse(null);
} else {
players = fallback.getPlayers().orElse(null);
}

net.kyori.adventure.text.Component description;
if (mode.description && response.getDescriptionComponent() != null) {
description = response.getDescriptionComponent();
} 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;
});
}

/**
Expand All @@ -165,7 +172,7 @@ public CompletableFuture<ServerPing> getInitialPing(VelocityInboundConnection co
? 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)
Expand Down
Loading