Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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,46 @@
/*
* Copyright (C) 2018-2021 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/

package com.velocitypowered.api.proxy.config;

import static java.util.Objects.requireNonNull;

import com.velocitypowered.api.proxy.server.ServerInfoForwardingMode;
import org.jspecify.annotations.NullMarked;

/**
* Exposes server configuration information that plugins may use.<br>
*
* <b>What's the forwarding mode?</b><br>
* The server can use a different mode to obtain and forward player info.<br>
* For instance, if you are running a 1.12 (or lower version) server on a velocity proxy with MODERN player info forwarding
* the server doesn't support MODERN forwarding. So you need to set LEGACY forwarding mode for that server
* and velocity will use ONLY FOR THAT SERVER the legacy forwarding mode.<br><br>
*
* @param address The address of the backend server.
* @param forwardingMode The forwarding mode of the backend server.
* @since 3.4.0
* @see ServerInfoForwardingMode
* @see com.velocitypowered.api.proxy.server.ServerInfo#ServerInfo(String, java.net.InetSocketAddress, ServerInfoForwardingMode)
* @apiNote <i><b>TIP:</b> If you need to set this value when creating dynamic servers in your plugins
* you can do that by adding the {@link ServerInfoForwardingMode} value as the last parameter
* while creating a new {@link com.velocitypowered.api.proxy.server.ServerInfo}.</i>
*/
@NullMarked
public record BackendServerConfig(
String address,
ServerInfoForwardingMode forwardingMode
) {
public BackendServerConfig {
requireNonNull(address);
requireNonNull(forwardingMode);
}

public BackendServerConfig(final String address) {
this(address, ServerInfoForwardingMode.FOLLOWUP);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,23 @@ public interface ProxyConfig {
* does. For a view of all registered servers, see {@link ProxyServer#getAllServers()}.
*
* @return registered servers map
* @deprecated use {@link #getBackendServers()} instead.
*/
@Deprecated(forRemoval = true, since = "3.4.0")
Map<String, String> getServers();

/**
* Get a Map of all servers registered in <code>velocity.toml</code>. This method does
* <strong>not</strong> return all the servers currently in memory, although in most cases it
* does. For a view of all registered servers, see {@link ProxyServer#getAllServers()}.
*
* @return registered servers map with, instead of the only address, the Backend Server Object for each
* of them which contains the address of the server and its info forwarding mode.
* @since 3.4.0
* @see com.velocitypowered.api.proxy.server.ServerInfoForwardingMode
*/
Map<String, BackendServerConfig> getBackendServers();

/**
* Get the order of servers that players will be connected to.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@ public final class ServerInfo implements Comparable<ServerInfo> {

private final String name;
private final InetSocketAddress address;
private final ServerInfoForwardingMode forwardingMode;

/**
* Creates a new ServerInfo object.
*
* @param name the name for the server
* @param address the address of the server to connect to
* @param forwardingMode the server info forwarding mode
* @since 3.4.0
*/
public ServerInfo(String name, InetSocketAddress address, ServerInfoForwardingMode forwardingMode) {
this.name = Preconditions.checkNotNull(name, "name");
this.address = Preconditions.checkNotNull(address, "address");
this.forwardingMode = Preconditions.checkNotNull(forwardingMode, "forwardingMode");
}

/**
* Creates a new ServerInfo object.
Expand All @@ -30,6 +45,7 @@ public final class ServerInfo implements Comparable<ServerInfo> {
public ServerInfo(String name, InetSocketAddress address) {
this.name = Preconditions.checkNotNull(name, "name");
this.address = Preconditions.checkNotNull(address, "address");
this.forwardingMode = ServerInfoForwardingMode.FOLLOWUP;
}

public final String getName() {
Expand All @@ -40,11 +56,21 @@ public final InetSocketAddress getAddress() {
return address;
}

/**
* Get what mode will the backend server use to communicate with velocity.
*
* @return FOLLOWUP mode if the server uses the same mode as set in the main config else one of the available modes
*/
public final ServerInfoForwardingMode getServerInfoForwardingMode() {
return forwardingMode;
}

@Override
public String toString() {
return "ServerInfo{"
+ "name='" + name + '\''
+ ", address=" + address
+ ", forwarding=" + forwardingMode
+ '}';
}

Expand All @@ -53,17 +79,17 @@ public final boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if (!(o instanceof final ServerInfo that)) {
return false;
}
ServerInfo that = (ServerInfo) o;
return Objects.equals(name, that.name)
&& Objects.equals(address, that.address);
&& Objects.equals(address, that.address)
&& Objects.equals(forwardingMode, that.forwardingMode);
}

@Override
public final int hashCode() {
return Objects.hash(name, address);
return Objects.hash(name, address, forwardingMode);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2018-2021 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/

package com.velocitypowered.api.proxy.server;

/**
* Supported per-server player info forwarding methods.
*
* @since 3.4.0
*/
public enum ServerInfoForwardingMode {
/**
* This type will follow the value of the player-info-forwarding-mode in the velocity configuration.
*/
FOLLOWUP,
MODERN,
BUNGEEGUARD,
LEGACY,
NONE
}

23 changes: 18 additions & 5 deletions proxy/src/main/java/com/velocitypowered/proxy/ProxyOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.velocitypowered.proxy;

import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.proxy.server.ServerInfoForwardingMode;
import com.velocitypowered.proxy.util.AddressUtil;
import java.io.IOException;
import java.net.InetSocketAddress;
Expand Down Expand Up @@ -105,17 +106,29 @@ private static class ServerInfoConverter implements ValueConverter<ServerInfo> {

@Override
public ServerInfo convert(String s) {
String[] split = s.split(":", 2);
String[] split = s.split(":", 4);
if (split.length < 2) {
throw new ValueConversionException("Invalid server format. Use <name>:<address>");
throw new ValueConversionException("Invalid server format. Use <name>:<host>:[port]:[forwardingmode]");
}
InetSocketAddress address;
ServerInfoForwardingMode mode = ServerInfoForwardingMode.FOLLOWUP;
try {
address = AddressUtil.parseAddress(split[1]);
if (split.length >= 3) {
address = AddressUtil.parseAddress(split[1] + ":" + split[2]);
} else {
address = AddressUtil.parseAddress(split[1]);
}
} catch (IllegalStateException e) {
throw new ValueConversionException("Invalid hostname for server flag with name: " + split[0]);
}
return new ServerInfo(split[0], address);
if (split.length == 4) {
try {
mode = ServerInfoForwardingMode.valueOf(split[3].toUpperCase());
} catch (IllegalStateException e) {
throw new ValueConversionException("Invalid forwarding mode for server flag with name: " + split[0]);
}
}
return new ServerInfo(split[0], address, mode);
}

@Override
Expand All @@ -125,7 +138,7 @@ public Class<? extends ServerInfo> valueType() {

@Override
public String valuePattern() {
return "name>:<address";
return "name>:<host>:[port]:[forwardingmode]";
}
}
}
17 changes: 13 additions & 4 deletions proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.velocitypowered.api.plugin.PluginManager;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.config.BackendServerConfig;
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
Expand Down Expand Up @@ -297,8 +298,12 @@ void start() {
}

if (!options.isIgnoreConfigServers()) {
for (Map.Entry<String, String> entry : configuration.getServers().entrySet()) {
servers.register(new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue())));
for (Map.Entry<String, BackendServerConfig> entry : configuration.getBackendServers().entrySet()) {
servers.register(new ServerInfo(
entry.getKey(),
AddressUtil.parseAddress(entry.getValue().address()),
entry.getValue().forwardingMode())
);
}
}

Expand Down Expand Up @@ -489,8 +494,12 @@ public boolean reloadConfiguration() throws IOException {
// Re-register servers. If a server is being replaced, make sure to note what players need to
// move back to a fallback server.
Collection<ConnectedPlayer> evacuate = new ArrayList<>();
for (Map.Entry<String, String> entry : newConfiguration.getServers().entrySet()) {
ServerInfo newInfo = new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue()));
for (Map.Entry<String, BackendServerConfig> entry : newConfiguration.getBackendServers().entrySet()) {
ServerInfo newInfo = new ServerInfo(
entry.getKey(),
AddressUtil.parseAddress(entry.getValue().address()),
entry.getValue().forwardingMode()
);
Optional<RegisteredServer> rs = servers.getServer(entry.getKey());
if (rs.isEmpty()) {
servers.register(newInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.Expose;
import com.velocitypowered.api.proxy.config.BackendServerConfig;
import com.velocitypowered.api.proxy.config.ProxyConfig;
import com.velocitypowered.api.proxy.server.ServerInfoForwardingMode;
import com.velocitypowered.api.util.Favicon;
import com.velocitypowered.proxy.config.migration.ConfigurationMigration;
import com.velocitypowered.proxy.config.migration.ForwardingMigration;
Expand Down Expand Up @@ -171,17 +173,27 @@ public boolean validate() {
break;
}

if (servers.getServers().isEmpty()) {
if (servers.getBackendServers().isEmpty()) {
logger.warn("You don't have any servers configured.");
}

for (Map.Entry<String, String> entry : servers.getServers().entrySet()) {
for (Map.Entry<String, BackendServerConfig> entry : servers.getBackendServers().entrySet()) {
try {
AddressUtil.parseAddress(entry.getValue());
AddressUtil.parseAddress(entry.getValue().address());
} catch (IllegalArgumentException e) {
logger.error("Server {} does not have a valid IP address.", entry.getKey(), e);
valid = false;
}

ServerInfoForwardingMode mode = entry.getValue().forwardingMode();
if (mode == ServerInfoForwardingMode.MODERN
|| mode == ServerInfoForwardingMode.BUNGEEGUARD) {
if (forwardingSecret == null || forwardingSecret.length == 0) {
logger.error("You don't have a forwarding secret set. This is required if "
+ "you are using MODERN or BUNGEEGUARD forwarding modes.");
valid = false;
}
}
}

for (String s : servers.getAttemptConnectionOrder()) {
Expand Down Expand Up @@ -315,6 +327,11 @@ public Map<String, String> getServers() {
return servers.getServers();
}

@Override
public Map<String, BackendServerConfig> getBackendServers() {
return servers.getBackendServers();
}

@Override
public List<String> getAttemptConnectionOrder() {
return servers.getAttemptConnectionOrder();
Expand Down Expand Up @@ -611,10 +628,10 @@ public boolean isOnlineModeKickExistingPlayers() {

private static class Servers {

private Map<String, String> servers = ImmutableMap.of(
"lobby", "127.0.0.1:30066",
"factions", "127.0.0.1:30067",
"minigames", "127.0.0.1:30068"
private Map<String, BackendServerConfig> servers = ImmutableMap.of(
"lobby", new BackendServerConfig("127.0.0.1:30066"),
"factions", new BackendServerConfig("127.0.0.1:30067", ServerInfoForwardingMode.MODERN),
"minigames", new BackendServerConfig("127.0.0.1:30068", ServerInfoForwardingMode.LEGACY)
);
private List<String> attemptConnectionOrder = ImmutableList.of("lobby");

Expand All @@ -623,14 +640,31 @@ private Servers() {

private Servers(CommentedConfig config) {
if (config != null) {
Map<String, String> servers = new HashMap<>();
Map<String, BackendServerConfig> servers = new HashMap<>();
for (UnmodifiableConfig.Entry entry : config.entrySet()) {
if (entry.getValue() instanceof String) {
servers.put(cleanServerName(entry.getKey()), entry.getValue());
if (entry.getValue() instanceof com.electronwill.nightconfig.core.CommentedConfig c) {
String address = null;
ServerInfoForwardingMode forwardingMode = ServerInfoForwardingMode.FOLLOWUP;
for (UnmodifiableConfig.Entry entry2 : c.entrySet()) {
if (entry2.getKey().equalsIgnoreCase("address")) {
address = entry2.getValue();
}
if (entry2.getKey().equalsIgnoreCase("forwarding-mode")) {
forwardingMode = ServerInfoForwardingMode.valueOf(ServerInfoForwardingMode.class, entry2.getValue());
}
}
if (address == null) {
throw new IllegalArgumentException(
"Server entry " + entry.getKey() + " is missing address!");
}
servers.put(cleanServerName(entry.getKey()), new BackendServerConfig(address, forwardingMode));
//support for old server config system (forwarding mode will be followup)
} else if (entry.getValue() instanceof String v) {
servers.put(cleanServerName(entry.getKey()), new BackendServerConfig(v));
} else {
if (!entry.getKey().equalsIgnoreCase("try")) {
throw new IllegalArgumentException(
"Server entry " + entry.getKey() + " is not a string!");
"Server entry " + entry.getKey() + " is not a server!");
}
}
}
Expand All @@ -639,16 +673,22 @@ private Servers(CommentedConfig config) {
}
}

private Servers(Map<String, String> servers, List<String> attemptConnectionOrder) {
private Servers(Map<String, BackendServerConfig> servers, List<String> attemptConnectionOrder) {
this.servers = servers;
this.attemptConnectionOrder = attemptConnectionOrder;
}

private Map<String, String> getServers() {
Map<String, String> serverAddresses = new HashMap<>();
servers.forEach((k, v) -> serverAddresses.put(k, v.address()));
return serverAddresses;
}

private Map<String, BackendServerConfig> getBackendServers() {
return servers;
}

public void setServers(Map<String, String> servers) {
public void setServers(Map<String, BackendServerConfig> servers) {
this.servers = servers;
}

Expand Down
Loading