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

Merge pull request #65 from dualspiral/feature/forge-handshake-support

Forge Support
Dieser Commit ist enthalten in:
Andrew Steinborn 2018-09-07 17:49:52 -04:00 committet von GitHub
Commit a66246b83c
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 4AEE18F83AFDEB23
10 geänderte Dateien mit 114 neuen und 12 gelöschten Zeilen

Datei anzeigen

@ -57,7 +57,7 @@ public final class GameProfile {
'}'; '}';
} }
public final class Property { public final static class Property {
private final String name; private final String name;
private final String value; private final String value;
private final String signature; private final String signature;

Datei anzeigen

@ -45,7 +45,9 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
private MinecraftSessionHandler sessionHandler; private MinecraftSessionHandler sessionHandler;
private int protocolVersion; private int protocolVersion;
private MinecraftConnectionAssociation association; private MinecraftConnectionAssociation association;
private boolean isLegacyForge;
private final VelocityServer server; private final VelocityServer server;
private boolean canSendLegacyFMLResetPacket = false;
public MinecraftConnection(Channel channel, VelocityServer server) { public MinecraftConnection(Channel channel, VelocityServer server) {
this.channel = channel; this.channel = channel;
@ -222,4 +224,20 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
public void setAssociation(MinecraftConnectionAssociation association) { public void setAssociation(MinecraftConnectionAssociation association) {
this.association = association; this.association = association;
} }
public boolean isLegacyForge() {
return isLegacyForge;
}
public void setLegacyForge(boolean isForge) {
this.isLegacyForge = isForge;
}
public boolean canSendLegacyFMLResetPacket() {
return canSendLegacyFMLResetPacket;
}
public void setCanSendLegacyFMLResetPacket(boolean canSendLegacyFMLResetPacket) {
this.canSendLegacyFMLResetPacket = isLegacyForge && canSendLegacyFMLResetPacket;
}
} }

Datei anzeigen

@ -6,4 +6,8 @@ public class VelocityConstants {
} }
public static final String VELOCITY_IP_FORWARDING_CHANNEL = "velocity:player_info"; public static final String VELOCITY_IP_FORWARDING_CHANNEL = "velocity:player_info";
public static final String FORGE_LEGACY_HANDSHAKE_CHANNEL = "FML|HS";
public static final byte[] FORGE_LEGACY_HANDSHAKE_RESET_DATA = new byte[] { -2, 0 };
} }

Datei anzeigen

@ -4,6 +4,7 @@ import com.velocitypowered.api.event.player.ServerConnectedEvent;
import com.velocitypowered.api.proxy.messages.ChannelSide; import com.velocitypowered.api.proxy.messages.ChannelSide;
import com.velocitypowered.api.proxy.messages.MessageHandler; import com.velocitypowered.api.proxy.messages.MessageHandler;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.VelocityConstants;
import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler; import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolConstants;
@ -68,12 +69,26 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
return; return;
} }
if (!connection.hasCompletedJoin() && pm.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) {
if (!connection.isModded()) {
connection.setModded(true);
// We must always reset the handshake before a modded connection is established if
// we haven't done so already.
connection.getPlayer().sendLegacyForgeHandshakeResetPacket();
}
// Always forward these messages during login
connection.getPlayer().getConnection().write(pm);
return;
}
MessageHandler.ForwardStatus status = server.getChannelRegistrar().handlePluginMessage(connection, MessageHandler.ForwardStatus status = server.getChannelRegistrar().handlePluginMessage(connection,
ChannelSide.FROM_SERVER, pm); ChannelSide.FROM_SERVER, pm);
if (status == MessageHandler.ForwardStatus.FORWARD) { if (status == MessageHandler.ForwardStatus.FORWARD) {
connection.getPlayer().getConnection().write(pm); connection.getPlayer().getConnection().write(pm);
} }
} else { } else if (connection.hasCompletedJoin()) {
// Just forward the packet on. We don't have anything to handle at this time. // Just forward the packet on. We don't have anything to handle at this time.
connection.getPlayer().getConnection().write(packet); connection.getPlayer().getConnection().write(packet);
} }
@ -87,8 +102,11 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
connection.getMinecraftConnection().close(); connection.getMinecraftConnection().close();
return; return;
} }
if (connection.hasCompletedJoin()) {
connection.getPlayer().getConnection().write(buf.retain()); connection.getPlayer().getConnection().write(buf.retain());
} }
}
@Override @Override
public void exception(Throwable throwable) { public void exception(Throwable throwable) {
@ -98,13 +116,14 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
private boolean canForwardPluginMessage(PluginMessage message) { private boolean canForwardPluginMessage(PluginMessage message) {
ClientPlaySessionHandler playerHandler = ClientPlaySessionHandler playerHandler =
(ClientPlaySessionHandler) connection.getPlayer().getConnection().getSessionHandler(); (ClientPlaySessionHandler) connection.getPlayer().getConnection().getSessionHandler();
boolean isMCMessage; boolean isMCOrFMLMessage;
if (connection.getMinecraftConnection().getProtocolVersion() <= ProtocolConstants.MINECRAFT_1_12_2) { if (connection.getMinecraftConnection().getProtocolVersion() <= ProtocolConstants.MINECRAFT_1_12_2) {
isMCMessage = message.getChannel().startsWith("MC|"); String channel = message.getChannel();
isMCOrFMLMessage = channel.startsWith("MC|") || channel.startsWith(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL);
} else { } else {
isMCMessage = message.getChannel().startsWith("minecraft:"); isMCOrFMLMessage = message.getChannel().startsWith("minecraft:");
} }
return isMCMessage || playerHandler.getClientPluginMsgChannels().contains(message.getChannel()) || return isMCOrFMLMessage || playerHandler.getClientPluginMsgChannels().contains(message.getChannel()) ||
server.getChannelRegistrar().registered(message.getChannel()); server.getChannelRegistrar().registered(message.getChannel());
} }
} }

Datei anzeigen

@ -84,6 +84,10 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
connection.getPlayer().getConnection().setSessionHandler(new ClientPlaySessionHandler(server, connection.getPlayer())); connection.getPlayer().getConnection().setSessionHandler(new ClientPlaySessionHandler(server, connection.getPlayer()));
} else { } else {
// The previous server connection should become obsolete. // The previous server connection should become obsolete.
// Before we remove it, if the server we are departing is modded, we must always reset the client state.
if (existingConnection.isModded()) {
connection.getPlayer().sendLegacyForgeHandshakeResetPacket();
}
existingConnection.disconnect(); existingConnection.disconnect();
} }

Datei anzeigen

@ -43,6 +43,8 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
private final ConnectedPlayer proxyPlayer; private final ConnectedPlayer proxyPlayer;
private final VelocityServer server; private final VelocityServer server;
private MinecraftConnection minecraftConnection; private MinecraftConnection minecraftConnection;
private boolean isModded = false;
private boolean hasCompletedJoin = false;
public VelocityServerConnection(ServerInfo target, ConnectedPlayer proxyPlayer, VelocityServer server) { public VelocityServerConnection(ServerInfo target, ConnectedPlayer proxyPlayer, VelocityServer server) {
this.serverInfo = target; this.serverInfo = target;
@ -107,6 +109,8 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
handshake.setProtocolVersion(proxyPlayer.getConnection().getProtocolVersion()); handshake.setProtocolVersion(proxyPlayer.getConnection().getProtocolVersion());
if (forwardingMode == PlayerInfoForwarding.LEGACY) { if (forwardingMode == PlayerInfoForwarding.LEGACY) {
handshake.setServerAddress(createBungeeForwardingAddress()); handshake.setServerAddress(createBungeeForwardingAddress());
} else if (proxyPlayer.getConnection().isLegacyForge()) {
handshake.setServerAddress(handshake.getServerAddress() + "\0FML\0");
} else { } else {
handshake.setServerAddress(serverInfo.getAddress().getHostString()); handshake.setServerAddress(serverInfo.getAddress().getHostString());
} }
@ -154,4 +158,20 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
message.setData(data); message.setData(data);
minecraftConnection.write(message); minecraftConnection.write(message);
} }
public boolean isModded() {
return isModded;
}
public void setModded(boolean modded) {
isModded = modded;
}
public boolean hasCompletedJoin() {
return hasCompletedJoin;
}
public void setHasCompletedJoin(boolean hasCompletedJoin) {
this.hasCompletedJoin = hasCompletedJoin;
}
} }

Datei anzeigen

@ -61,6 +61,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
} }
player.setPing(System.currentTimeMillis() - lastPingSent); player.setPing(System.currentTimeMillis() - lastPingSent);
resetPingData(); resetPingData();
player.getConnectedServer().getMinecraftConnection().write(packet);
return;
} }
if (packet instanceof ClientSettings) { if (packet instanceof ClientSettings) {
@ -122,13 +124,17 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
} }
// If we don't want to handle this packet, just forward it on. // If we don't want to handle this packet, just forward it on.
if (player.getConnectedServer().hasCompletedJoin()) {
player.getConnectedServer().getMinecraftConnection().write(packet); player.getConnectedServer().getMinecraftConnection().write(packet);
} }
}
@Override @Override
public void handleUnknown(ByteBuf buf) { public void handleUnknown(ByteBuf buf) {
if (player.getConnectedServer().hasCompletedJoin()) {
player.getConnectedServer().getMinecraftConnection().write(buf.retain()); player.getConnectedServer().getMinecraftConnection().write(buf.retain());
} }
}
@Override @Override
public void disconnected() { public void disconnected() {
@ -197,6 +203,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
// Flush everything // Flush everything
player.getConnection().flush(); player.getConnection().flush();
player.getConnectedServer().getMinecraftConnection().flush(); player.getConnectedServer().getMinecraftConnection().flush();
player.getConnectedServer().setHasCompletedJoin(true);
player.getConnection().setCanSendLegacyFMLResetPacket(true);
} }
public List<UUID> getServerBossBars() { public List<UUID> getServerBossBars() {
@ -235,6 +243,12 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
return; return;
} }
if (player.getConnectedServer().isModded() && !player.getConnectedServer().hasCompletedJoin()) {
// Ensure that the messages are forwarded
player.getConnectedServer().getMinecraftConnection().write(packet);
return;
}
MessageHandler.ForwardStatus status = server.getChannelRegistrar().handlePluginMessage(player, MessageHandler.ForwardStatus status = server.getChannelRegistrar().handlePluginMessage(player,
ChannelSide.FROM_CLIENT, packet); ChannelSide.FROM_CLIENT, packet);
if (status == MessageHandler.ForwardStatus.FORWARD) { if (status == MessageHandler.ForwardStatus.FORWARD) {

Datei anzeigen

@ -15,6 +15,7 @@ import com.velocitypowered.api.util.MessagePosition;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
import com.velocitypowered.proxy.connection.VelocityConstants;
import com.velocitypowered.proxy.connection.util.ConnectionMessages; import com.velocitypowered.proxy.connection.util.ConnectionMessages;
import com.velocitypowered.proxy.connection.util.ConnectionRequestResults; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults;
import com.velocitypowered.api.util.GameProfile; import com.velocitypowered.api.util.GameProfile;
@ -294,6 +295,16 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
this.connectedServer = serverConnection; this.connectedServer = serverConnection;
} }
public void sendLegacyForgeHandshakeResetPacket() {
if (connection.canSendLegacyFMLResetPacket()) {
PluginMessage resetPacket = new PluginMessage();
resetPacket.setChannel(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL);
resetPacket.setData(VelocityConstants.FORGE_LEGACY_HANDSHAKE_RESET_DATA);
connection.write(resetPacket);
connection.setCanSendLegacyFMLResetPacket(false);
}
}
public void close(TextComponent reason) { public void close(TextComponent reason) {
connection.closeWith(Disconnect.create(reason)); connection.closeWith(Disconnect.create(reason));
} }

Datei anzeigen

@ -70,9 +70,12 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
return; return;
} }
// Make sure legacy forwarding is not in use on this connection. Make sure that we do _not_ reject Forge, // Determine if we're using Forge (1.8 to 1.12, may not be the case in 1.13) and store that in the connection
// although Velocity does not yet support Forge. boolean isForge = handshake.getServerAddress().endsWith("\0FML\0");
if (handshake.getServerAddress().contains("\0") && !handshake.getServerAddress().endsWith("\0FML\0")) { connection.setLegacyForge(isForge);
// Make sure legacy forwarding is not in use on this connection. Make sure that we do _not_ reject Forge
if (handshake.getServerAddress().contains("\0") && !isForge) {
connection.closeWith(Disconnect.create(TextComponent.of("Running Velocity behind Velocity is unsupported."))); connection.closeWith(Disconnect.create(TextComponent.of("Running Velocity behind Velocity is unsupported.")));
return; return;
} }

Datei anzeigen

@ -8,6 +8,7 @@ import com.velocitypowered.api.event.permission.PermissionsSetupEvent;
import com.velocitypowered.api.event.player.GameProfileRequestEvent; import com.velocitypowered.api.event.player.GameProfileRequestEvent;
import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.proxy.config.PlayerInfoForwarding;
import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.proxy.connection.VelocityConstants;
import com.velocitypowered.api.util.GameProfile; import com.velocitypowered.api.util.GameProfile;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
@ -31,7 +32,9 @@ import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyPair; import java.security.KeyPair;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@ -176,6 +179,12 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
} }
private void initializePlayer(GameProfile profile, boolean onlineMode) { private void initializePlayer(GameProfile profile, boolean onlineMode) {
if (inbound.isLegacyForge() && server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.LEGACY) {
// We want to add the FML token to the properties
List<GameProfile.Property> properties = new ArrayList<>(profile.getProperties());
properties.add(new GameProfile.Property("forgeClient", "true", ""));
profile = new GameProfile(profile.getId(), profile.getName(), properties);
}
GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEvent(apiInbound, profile, onlineMode); GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEvent(apiInbound, profile, onlineMode);
server.getEventManager().fire(profileRequestEvent).thenCompose(profileEvent -> { server.getEventManager().fire(profileRequestEvent).thenCompose(profileEvent -> {