3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-11-17 05:20:14 +01:00

Merge branch 'dev/1.1.0' into decode-multiple

Dieser Commit ist enthalten in:
Andrew Steinborn 2020-05-24 11:41:17 -04:00
Commit a98a7dd67e
18 geänderte Dateien mit 465 neuen und 53 gelöschten Zeilen

Datei anzeigen

@ -1,5 +1,7 @@
package com.velocitypowered.api.command;
import java.util.concurrent.CompletableFuture;
/**
* Represents an interface to register a command executor with the proxy.
*/
@ -34,11 +36,52 @@ public interface CommandManager {
void unregister(String alias);
/**
* Attempts to execute a command from the specified {@code cmdLine}.
* Calls CommandExecuteEvent and attempts to execute a command using the specified {@code cmdLine}
* in a blocking fashion.
*
* @param source the command's source
* @param cmdLine the command to run
* @return true if the command was found and executed, false if it was not
*
* @deprecated This method will block current thread during event call and command execution.
* Prefer {@link #executeAsync(CommandSource, String)} instead.
*/
@Deprecated
boolean execute(CommandSource source, String cmdLine);
/**
* Attempts to execute a command using the specified {@code cmdLine} in a blocking fashion without
* calling CommandExecuteEvent.
*
* @param source the command's source
* @param cmdLine the command to run
* @return true if the command was found and executed, false if it was not
*
* @deprecated This method will block current thread during event and command execution.
* Prefer {@link #executeImmediatelyAsync(CommandSource, String)} instead.
*/
@Deprecated
boolean executeImmediately(CommandSource source, String cmdLine);
/**
* Calls CommandExecuteEvent and attempts to execute a command from the specified {@code cmdLine}
* async.
*
* @param source the command's source
* @param cmdLine the command to run
* @return A future that will be completed with the result of the command execution.
* Can be completed exceptionally if exception was thrown during execution.
*/
CompletableFuture<Boolean> executeAsync(CommandSource source, String cmdLine);
/**
* Attempts to execute a command from the specified {@code cmdLine} async
* without calling CommandExecuteEvent.
*
* @param source the command's source
* @param cmdLine the command to run
* @return A future that will be completed with the result of the command execution.
* Can be completed exceptionally if exception was thrown during execution.
*/
CompletableFuture<Boolean> executeImmediatelyAsync(CommandSource source, String cmdLine);
}

Datei anzeigen

@ -0,0 +1,143 @@
package com.velocitypowered.api.event.command;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.event.command.CommandExecuteEvent.CommandResult;
import java.util.Optional;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* This event is fired when someone executing command.
*/
public final class CommandExecuteEvent implements ResultedEvent<CommandResult> {
private final CommandSource commandSource;
private final String command;
private CommandResult result;
/**
* Constructs a CommandExecuteEvent.
* @param commandSource the source executing the command
* @param command the command being executed without first slash
*/
public CommandExecuteEvent(CommandSource commandSource, String command) {
this.commandSource = Preconditions.checkNotNull(commandSource, "commandSource");
this.command = Preconditions.checkNotNull(command, "command");
this.result = CommandResult.allowed();
}
public CommandSource getCommandSource() {
return commandSource;
}
/**
* Gets the original command being executed without first slash.
* @return the original command being executed
*/
public String getCommand() {
return command;
}
@Override
public CommandResult getResult() {
return result;
}
@Override
public void setResult(CommandResult result) {
this.result = Preconditions.checkNotNull(result, "result");
}
@Override
public String toString() {
return "CommandExecuteEvent{"
+ "commandSource=" + commandSource
+ ", command=" + command
+ ", result=" + result
+ '}';
}
/**
* Represents the result of the {@link CommandExecuteEvent}.
*/
public static final class CommandResult implements Result {
private static final CommandResult ALLOWED = new CommandResult(true, false,null);
private static final CommandResult DENIED = new CommandResult(false, false,null);
private static final CommandResult FORWARD_TO_SERVER = new CommandResult(false, true, null);
private @Nullable String command;
private final boolean status;
private final boolean forward;
private CommandResult(boolean status, boolean forward, @Nullable String command) {
this.status = status;
this.forward = forward;
this.command = command;
}
public Optional<String> getCommand() {
return Optional.ofNullable(command);
}
public boolean isForwardToServer() {
return forward;
}
@Override
public boolean isAllowed() {
return status;
}
@Override
public String toString() {
return status ? "allowed" : "denied";
}
/**
* Allows the command to be sent, without modification.
* @return the allowed result
*/
public static CommandResult allowed() {
return ALLOWED;
}
/**
* Prevents the command from being executed.
* @return the denied result
*/
public static CommandResult denied() {
return DENIED;
}
/**
* Prevents the command from being executed, but forward command to server.
* @return the forward result
*/
public static CommandResult forwardToServer() {
return FORWARD_TO_SERVER;
}
/**
* Prevents the command from being executed on proxy, but forward command to server.
* @param newCommand the command without first slash to use instead
* @return a result with a new command being forwarded to server
*/
public static CommandResult forwardToServer(@NonNull String newCommand) {
Preconditions.checkNotNull(newCommand, "newCommand");
return new CommandResult(false, true, newCommand);
}
/**
* Allows the command to be executed, but silently replaced old command with another.
* @param newCommand the command to use instead without first slash
* @return a result with a new command
*/
public static CommandResult command(@NonNull String newCommand) {
Preconditions.checkNotNull(newCommand, "newCommand");
return new CommandResult(true, false, newCommand);
}
}
}

Datei anzeigen

@ -60,13 +60,11 @@ public final class GameProfileRequestEvent {
}
/**
* Sets the game profile to use for this connection. It is invalid to use this method on an
* online-mode connection.
* Sets the game profile to use for this connection.
*
* @param gameProfile the profile for this connection, {@code null} uses the original profile
*/
public void setGameProfile(@Nullable GameProfile gameProfile) {
Preconditions.checkState(!onlineMode, "Profiles can not be faked in online mode!");
this.gameProfile = gameProfile;
}

Datei anzeigen

@ -70,6 +70,10 @@ public final class PlayerChatEvent implements ResultedEvent<PlayerChatEvent.Chat
this.message = message;
}
public Optional<String> getMessage() {
return Optional.ofNullable(message);
}
@Override
public boolean isAllowed() {
return status;
@ -96,10 +100,6 @@ public final class PlayerChatEvent implements ResultedEvent<PlayerChatEvent.Chat
return DENIED;
}
public Optional<String> getMessage() {
return Optional.ofNullable(message);
}
/**
* Allows the message to be sent, but silently replaced with another.
* @param message the message to use instead
@ -110,6 +110,4 @@ public final class PlayerChatEvent implements ResultedEvent<PlayerChatEvent.Chat
return new ChatResult(true, message);
}
}
}

Datei anzeigen

@ -62,6 +62,15 @@ public interface ProxyConfig {
*/
boolean isOnlineMode();
/**
* 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.
*
* @return whether to prevent client proxy connections by checking the IP with Mojang servers
*/
boolean shouldPreventClientProxyConnections();
/**
* 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

Datei anzeigen

@ -44,6 +44,8 @@ import com.velocitypowered.proxy.util.bossbar.VelocityBossBar;
import com.velocitypowered.proxy.util.ratelimit.Ratelimiter;
import com.velocitypowered.proxy.util.ratelimit.Ratelimiters;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import java.io.IOException;
import java.net.InetSocketAddress;
@ -93,7 +95,7 @@ public class VelocityServer implements ProxyServer {
private @MonotonicNonNull VelocityConfiguration configuration;
private @MonotonicNonNull KeyPair serverKeyPair;
private final ServerMap servers;
private final VelocityCommandManager commandManager = new VelocityCommandManager();
private final VelocityCommandManager commandManager;
private final AtomicBoolean shutdownInProgress = new AtomicBoolean(false);
private boolean shutdown = false;
private final VelocityPluginManager pluginManager;
@ -109,6 +111,7 @@ public class VelocityServer implements ProxyServer {
VelocityServer(final ProxyOptions options) {
pluginManager = new VelocityPluginManager(this);
eventManager = new VelocityEventManager(pluginManager);
commandManager = new VelocityCommandManager(eventManager);
scheduler = new VelocityScheduler(pluginManager);
console = new VelocityConsole(this);
cm = new ConnectionManager(this);
@ -268,6 +271,10 @@ public class VelocityServer implements ProxyServer {
return this.cm.createWorker(group);
}
public ChannelInitializer<Channel> getBackendChannelInitializer() {
return this.cm.backendChannelInitializer.get();
}
public boolean isShutdown() {
return shutdown;
}

Datei anzeigen

@ -12,8 +12,6 @@ import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@ -25,6 +23,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
public class ServerCommand implements Command {
public static final int MAX_SERVERS_TO_LIST = 50;
private final ProxyServer server;
public ServerCommand(ProxyServer server) {
@ -61,10 +60,16 @@ public class ServerCommand implements Command {
executor.sendMessage(of("You are currently connected to " + currentServer + ".",
TextColor.YELLOW));
List<RegisteredServer> servers = BuiltinCommandUtil.sortedServerList(server);
if (servers.size() > MAX_SERVERS_TO_LIST) {
executor.sendMessage(of("Too many servers to list. Tab-complete to show all servers.",
TextColor.RED));
return;
}
// Assemble the list of servers as components
TextComponent.Builder serverListBuilder = TextComponent.builder("Available servers: ")
.color(TextColor.YELLOW);
List<RegisteredServer> servers = BuiltinCommandUtil.sortedServerList(server);
for (int i = 0; i < servers.size(); i++) {
RegisteredServer rs = servers.get(i);
serverListBuilder.append(formatServerComponent(currentServer, rs));

Datei anzeigen

@ -7,16 +7,26 @@ import com.velocitypowered.api.command.Command;
import com.velocitypowered.api.command.CommandManager;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.RawCommand;
import com.velocitypowered.api.event.command.CommandExecuteEvent;
import com.velocitypowered.api.event.command.CommandExecuteEvent.CommandResult;
import com.velocitypowered.proxy.plugin.VelocityEventManager;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
public class VelocityCommandManager implements CommandManager {
private final Map<String, RawCommand> commands = new HashMap<>();
private final VelocityEventManager eventManager;
public VelocityCommandManager(VelocityEventManager eventManager) {
this.eventManager = eventManager;
}
@Override
@Deprecated
@ -47,9 +57,36 @@ public class VelocityCommandManager implements CommandManager {
this.commands.remove(alias.toLowerCase(Locale.ENGLISH));
}
/**
* Calls CommandExecuteEvent.
* @param source the command's source
* @param cmd the command
* @return CompletableFuture of event
*/
public CompletableFuture<CommandExecuteEvent> callCommandEvent(CommandSource source, String cmd) {
Preconditions.checkNotNull(source, "source");
Preconditions.checkNotNull(cmd, "cmd");
return eventManager.fire(new CommandExecuteEvent(source, cmd));
}
@Override
public boolean execute(CommandSource source, String cmdLine) {
Preconditions.checkNotNull(source, "invoker");
Preconditions.checkNotNull(source, "source");
Preconditions.checkNotNull(cmdLine, "cmdLine");
CommandExecuteEvent event = callCommandEvent(source, cmdLine).join();
CommandResult commandResult = event.getResult();
if (commandResult.isForwardToServer() || !commandResult.isAllowed()) {
return false;
}
cmdLine = commandResult.getCommand().orElse(event.getCommand());
return executeImmediately(source, cmdLine);
}
@Override
public boolean executeImmediately(CommandSource source, String cmdLine) {
Preconditions.checkNotNull(source, "source");
Preconditions.checkNotNull(cmdLine, "cmdLine");
String alias = cmdLine;
@ -75,6 +112,40 @@ public class VelocityCommandManager implements CommandManager {
}
}
@Override
public CompletableFuture<Boolean> executeAsync(CommandSource source, String cmdLine) {
CompletableFuture<Boolean> result = new CompletableFuture<>();
callCommandEvent(source, cmdLine).thenAccept(event -> {
CommandResult commandResult = event.getResult();
if (commandResult.isForwardToServer() || !commandResult.isAllowed()) {
result.complete(false);
}
String command = commandResult.getCommand().orElse(event.getCommand());
try {
result.complete(executeImmediately(source, command));
} catch (Exception e) {
result.completeExceptionally(e);
}
});
return result;
}
@Override
public CompletableFuture<Boolean> executeImmediatelyAsync(CommandSource source, String cmdLine) {
Preconditions.checkNotNull(source, "source");
Preconditions.checkNotNull(cmdLine, "cmdLine");
CompletableFuture<Boolean> result = new CompletableFuture<>();
eventManager.getService().execute(() -> {
try {
result.complete(executeImmediately(source, cmdLine));
} catch (Exception e) {
result.completeExceptionally(e);
}
});
return result;
}
public boolean hasCommand(String command) {
return commands.containsKey(command);
}
@ -167,7 +238,14 @@ public class VelocityCommandManager implements CommandManager {
if (line.isEmpty()) {
return new String[0];
}
return line.trim().split(" ", -1);
String[] trimmed = line.trim().split(" ", -1);
if (line.endsWith(" ") && !line.trim().isEmpty()) {
// To work around a 1.13+ specific bug we have to inject a space at the end of the arguments
trimmed = Arrays.copyOf(trimmed, trimmed.length + 1);
trimmed[trimmed.length - 1] = "";
}
return trimmed;
}
@Override

Datei anzeigen

@ -54,6 +54,14 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
@ConfigKey("online-mode")
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;
@Comment({
"Should we forward IP addresses and other data to backend servers?",
"Available options:",
@ -328,6 +336,11 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
return onlineMode;
}
@Override
public boolean shouldPreventClientProxyConnections() {
return preventClientProxyConnections;
}
public PlayerInfoForwarding getPlayerInfoForwardingMode() {
return playerInfoForwardingMode;
}
@ -402,6 +415,10 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
return pingPassthrough;
}
public boolean isBungeePluginChannelEnabled() {
return advanced.isBungeePluginMessageChannel();
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
@ -654,6 +671,10 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
@ConfigKey("tcp-fast-open")
private boolean tcpFastOpen = false;
@Comment("Enables BungeeCord plugin messaging channel support on Velocity.")
@ConfigKey("bungee-plugin-message-channel")
private boolean bungeePluginMessageChannel = true;
private Advanced() {
}
@ -666,6 +687,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
this.readTimeout = toml.getLong("read-timeout", 30000L).intValue();
this.proxyProtocol = toml.getBoolean("proxy-protocol", false);
this.tcpFastOpen = toml.getBoolean("tcp-fast-open", false);
this.bungeePluginMessageChannel = toml.getBoolean("bungee-plugin-message-channel", true);
}
}
@ -697,6 +719,10 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
return tcpFastOpen;
}
public boolean isBungeePluginMessageChannel() {
return bungeePluginMessageChannel;
}
@Override
public String toString() {
return "Advanced{"
@ -707,6 +733,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
+ ", readTimeout=" + readTimeout
+ ", proxyProtocol=" + proxyProtocol
+ ", tcpFastOpen=" + tcpFastOpen
+ ", bungeePluginMessageChannel=" + bungeePluginMessageChannel
+ '}';
}
}

Datei anzeigen

@ -15,6 +15,7 @@ import com.velocitypowered.proxy.protocol.util.ByteBufDataOutput;
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.util.Optional;
import java.util.StringJoiner;
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
@ -43,8 +44,11 @@ class BungeeCordMessageResponder {
String playerName = in.readUTF();
String serverName = in.readUTF();
proxy.getPlayer(playerName).flatMap(player -> proxy.getServer(serverName))
.ifPresent(server -> player.createConnectionRequest(server).fireAndForget());
Optional<Player> referencedPlayer = proxy.getPlayer(playerName);
Optional<RegisteredServer> referencedServer = proxy.getServer(serverName);
if (referencedPlayer.isPresent() && referencedServer.isPresent()) {
referencedPlayer.get().createConnectionRequest(referencedServer.get()).fireAndForget();
}
}
private void processIp(ByteBufDataInput in) {
@ -269,6 +273,10 @@ class BungeeCordMessageResponder {
}
boolean process(PluginMessage message) {
if (!proxy.getConfiguration().isBungeePluginChannelEnabled()) {
return false;
}
if (!MODERN_CHANNEL.getId().equals(message.getChannel()) && !LEGACY_CHANNEL.getId()
.equals(message.getChannel())) {
return false;

Datei anzeigen

@ -80,22 +80,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
// Note: we use the event loop for the connection the player is on. This reduces context
// switches.
server.createBootstrap(proxyPlayer.getConnection().eventLoop())
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline()
.addLast(READ_TIMEOUT,
new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(),
TimeUnit.MILLISECONDS))
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
.addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE)
.addLast(FLOW_HANDLER, new FlowControlHandler())
.addLast(MINECRAFT_DECODER,
new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND))
.addLast(MINECRAFT_ENCODER,
new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND));
}
})
.handler(server.getBackendChannelInitializer())
.connect(registeredServer.getServerInfo().getAddress())
.addListener((ChannelFutureListener) future -> {
if (future.isSuccess()) {

Datei anzeigen

@ -4,6 +4,7 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8;
import static com.velocitypowered.proxy.protocol.util.PluginMessageUtil.constructChannelsPacket;
import com.velocitypowered.api.event.command.CommandExecuteEvent;
import com.velocitypowered.api.event.connection.PluginMessageEvent;
import com.velocitypowered.api.event.player.PlayerChatEvent;
import com.velocitypowered.api.event.player.PlayerResourcePackStatusEvent;
@ -123,17 +124,30 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
String msg = packet.getMessage();
if (msg.startsWith("/")) {
try {
if (!server.getCommandManager().execute(player, msg.substring(1))) {
return false;
}
} catch (Exception e) {
logger.info("Exception occurred while running command for {}", player.getUsername(),
e);
player.sendMessage(
TextComponent.of("An error occurred while running this command.", TextColor.RED));
return true;
}
server.getCommandManager().callCommandEvent(player, msg.substring(1))
.thenAcceptAsync(event -> {
CommandExecuteEvent.CommandResult commandResult = event.getResult();
Optional<String> eventCommand = event.getResult().getCommand();
String command = eventCommand.orElse(event.getCommand());
if (commandResult.isForwardToServer()) {
smc.write(Chat.createServerbound("/" + command));
return;
}
if (commandResult.isAllowed()) {
try {
if (!server.getCommandManager().executeImmediately(player, command)) {
smc.write(Chat.createServerbound("/" + command));
}
} catch (Exception e) {
logger.info("Exception occurred while running command for {}", player.getUsername(),
e);
player.sendMessage(
TextComponent.of("An error occurred while running this command.",
TextColor.RED));
}
}
}, smc.eventLoop());
} else {
PlayerChatEvent event = new PlayerChatEvent(player, msg);
server.getEventManager().fire(event)
@ -371,12 +385,12 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
private boolean handleCommandTabComplete(TabCompleteRequest packet) {
// In 1.13+, we need to do additional work for the richer suggestions available.
String command = packet.getCommand().substring(1);
int spacePos = command.indexOf(' ');
if (spacePos == -1) {
spacePos = command.length();
int commandEndPosition = command.indexOf(' ');
if (commandEndPosition == -1) {
commandEndPosition = command.length();
}
String commandLabel = command.substring(0, spacePos);
String commandLabel = command.substring(0, commandEndPosition);
if (!server.getCommandManager().hasCommand(commandLabel)) {
if (player.getProtocolVersion().compareTo(MINECRAFT_1_13) < 0) {
// Outstanding tab completes are recorded for use with 1.12 clients and below to provide

Datei anzeigen

@ -50,7 +50,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
private static final Logger logger = LogManager.getLogger(LoginSessionHandler.class);
private static final String MOJANG_HASJOINED_URL =
"https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s";
"https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s";
private final VelocityServer server;
private final MinecraftConnection mcConnection;
@ -96,8 +96,11 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
String playerIp = ((InetSocketAddress) mcConnection.getRemoteAddress()).getHostString();
String url = String.format(MOJANG_HASJOINED_URL,
urlFormParameterEscaper().escape(login.getUsername()), serverId,
urlFormParameterEscaper().escape(playerIp));
urlFormParameterEscaper().escape(login.getUsername()), serverId);
if (server.getConfiguration().shouldPreventClientProxyConnections()) {
url += "&ip=" + urlFormParameterEscaper().escape(playerIp);
}
ListenableFuture<Response> hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url)
.execute();

Datei anzeigen

@ -8,6 +8,8 @@ import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.api.proxy.ConsoleCommandSource;
import com.velocitypowered.proxy.VelocityServer;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.format.TextColor;

Datei anzeigen

@ -0,0 +1,45 @@
package com.velocitypowered.proxy.network;
import static com.velocitypowered.proxy.network.Connections.FLOW_HANDLER;
import static com.velocitypowered.proxy.network.Connections.FRAME_DECODER;
import static com.velocitypowered.proxy.network.Connections.FRAME_ENCODER;
import static com.velocitypowered.proxy.network.Connections.MINECRAFT_DECODER;
import static com.velocitypowered.proxy.network.Connections.MINECRAFT_ENCODER;
import static com.velocitypowered.proxy.network.Connections.READ_TIMEOUT;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.handler.flow.FlowControlHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("WeakerAccess")
public class BackendChannelInitializer extends ChannelInitializer<Channel> {
private final VelocityServer server;
public BackendChannelInitializer(VelocityServer server) {
this.server = server;
}
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline()
.addLast(READ_TIMEOUT,
new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(),
TimeUnit.MILLISECONDS))
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
.addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE)
.addLast(FLOW_HANDLER, new FlowControlHandler())
.addLast(MINECRAFT_DECODER,
new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND))
.addLast(MINECRAFT_ENCODER,
new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND));
}
}

Datei anzeigen

@ -0,0 +1,35 @@
package com.velocitypowered.proxy.network;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import java.util.function.Supplier;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class BackendChannelInitializerHolder implements Supplier<ChannelInitializer<Channel>> {
private static final Logger LOGGER = LogManager.getLogger(ConnectionManager.class);
private ChannelInitializer<Channel> initializer;
BackendChannelInitializerHolder(final ChannelInitializer<Channel> initializer) {
this.initializer = initializer;
}
@Override
public ChannelInitializer<Channel> get() {
return this.initializer;
}
/**
* Sets the channel initializer.
*
* @param initializer the new initializer to use
* @deprecated Internal implementation detail
*/
@Deprecated
public void set(final ChannelInitializer<Channel> initializer) {
LOGGER.warn("The backend channel initializer has been replaced by {}",
Thread.currentThread().getStackTrace()[2]);
this.initializer = initializer;
}
}

Datei anzeigen

@ -42,10 +42,12 @@ public final class ConnectionManager {
private final EventLoopGroup bossGroup;
private final EventLoopGroup workerGroup;
private final VelocityServer server;
// This is intentionally made public for plugins like ViaVersion, which inject their own
// These are intentionally made public for plugins like ViaVersion, which inject their own
// protocol logic into the proxy.
@SuppressWarnings("WeakerAccess")
public final ServerChannelInitializerHolder serverChannelInitializer;
@SuppressWarnings("WeakerAccess")
public final BackendChannelInitializerHolder backendChannelInitializer;
private final DnsAddressResolverGroup resolverGroup;
private final AsyncHttpClient httpClient;
@ -62,6 +64,8 @@ public final class ConnectionManager {
this.workerGroup = this.transportType.createEventLoopGroup(TransportType.Type.WORKER);
this.serverChannelInitializer = new ServerChannelInitializerHolder(
new ServerChannelInitializer(this.server));
this.backendChannelInitializer = new BackendChannelInitializerHolder(
new BackendChannelInitializer(this.server));
this.resolverGroup = new DnsAddressResolverGroup(new DnsNameResolverBuilder()
.channelType(this.transportType.datagramChannelClass)
.negativeTtl(15)
@ -204,4 +208,8 @@ public final class ConnectionManager {
public AsyncHttpClient getHttpClient() {
return httpClient;
}
public BackendChannelInitializerHolder getBackendChannelInitializer() {
return this.backendChannelInitializer;
}
}

Datei anzeigen

@ -185,6 +185,10 @@ public class VelocityEventManager implements EventManager {
fireEvent(new ProxyShutdownEvent());
}
public ExecutorService getService() {
return service;
}
private static class VelocityMethodScanner implements MethodScanner<Object> {
@Override