refined reset packet handler

This commit is contained in:
Adrian Bergqvist 2022-08-24 22:37:25 +02:00
parent 75ea344fda
commit cd952139bc
No known key found for this signature in database
GPG Key ID: FAE7D8EDE225E686
3 changed files with 49 additions and 23 deletions

View File

@ -6,9 +6,13 @@ import com.velocitypowered.api.event.player.ServerLoginPluginMessageEvent;
import com.velocitypowered.api.proxy.LoginPhaseConnection; import com.velocitypowered.api.proxy.LoginPhaseConnection;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.slf4j.Logger; import org.slf4j.Logger;
import java.io.EOFException; import java.io.EOFException;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -26,6 +30,7 @@ public class ForgeConnection {
private boolean forced = false; private boolean forced = false;
private Optional<RegisteredServer> syncedTo = Optional.empty(); private Optional<RegisteredServer> syncedTo = Optional.empty();
private boolean resettable;
public ForgeConnection(LoginPhaseConnection connection, Logger logger) { public ForgeConnection(LoginPhaseConnection connection, Logger logger) {
this.connection = connection; this.connection = connection;
@ -59,7 +64,16 @@ public class ForgeConnection {
if (!ignoreSyncExepction && response == null) { if (!ignoreSyncExepction && response == null) {
logger.warn("Sync Exception: Client responded with an empty body."); logger.warn("Sync Exception: Client responded with an empty body.");
} }
recivedClientModlist = Optional.ofNullable(response); if (response != null) {
recivedClientModlist = Optional.of(response);
//If the client is resettable.
ByteBuf clientModListPacket = Unpooled.wrappedBuffer(response);
clientModListPacket.readBytes(14); //Channel Identifier
ProtocolUtils.readVarInt(clientModListPacket); //Length
int packetID = ProtocolUtils.readVarInt(clientModListPacket);
String[] mods = ProtocolUtils.readStringArray(clientModListPacket);
resettable = Arrays.stream(mods).anyMatch((s) -> s.equals("clientresetpacket"));
}
}); });
//This gets also sent to vanilla //This gets also sent to vanilla
sendOther(msg.otherPackets).thenAccept((response) -> { sendOther(msg.otherPackets).thenAccept((response) -> {
@ -126,6 +140,10 @@ public class ForgeConnection {
return connection; return connection;
} }
public boolean isResettable() {
return resettable;
}
public Optional<ForgeHandshakeUtils.CachedServerHandshake> getTransmittedHandshake() { public Optional<ForgeHandshakeUtils.CachedServerHandshake> getTransmittedHandshake() {
return transmittedHandshake; return transmittedHandshake;
} }

View File

@ -19,7 +19,6 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import org.adde0109.ambassador.Ambassador; import org.adde0109.ambassador.Ambassador;
import org.bstats.velocity.Metrics;
public class ForgeHandshakeHandler { public class ForgeHandshakeHandler {

View File

@ -31,6 +31,7 @@ import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import com.velocitypowered.proxy.protocol.packet.PluginMessage; import com.velocitypowered.proxy.protocol.packet.PluginMessage;
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess; import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
import io.netty.channel.EventLoop; import io.netty.channel.EventLoop;
@ -59,10 +60,10 @@ public class ForgeServerSwitchHandler {
return; return;
} }
Optional<ForgeServerConnection> forgeServerConnectionOptional = ambassador.forgeHandshakeHandler.getForgeServerConnection(event.getOriginalServer()); Optional<ForgeServerConnection> forgeServerConnectionOptional = ambassador.forgeHandshakeHandler.getForgeServerConnection(event.getOriginalServer());
Optional<ForgeConnection> forgeConnection = ambassador.forgeHandshakeHandler.getForgeConnection(event.getPlayer()); Optional<ForgeConnection> forgeConnectionOptional = ambassador.forgeHandshakeHandler.getForgeConnection(event.getPlayer());
if (forgeConnection.isPresent()) { if (forgeConnectionOptional.isPresent()) {
//TODO: If the client can resync without kick, we don't need to check the server. ForgeConnection forgeConnection = forgeConnectionOptional.get();
if (true) { if (forgeConnection.isResettable()) {
continuation.resume(); continuation.resume();
return; return;
} }
@ -86,7 +87,7 @@ public class ForgeServerSwitchHandler {
event.getPlayer().setGameProfileProperties(properties); event.getPlayer().setGameProfileProperties(properties);
if (ambassador.config.reSyncOptionForge() != AmbassadorConfig.reSyncOption.NEVER) { if (ambassador.config.reSyncOptionForge() != AmbassadorConfig.reSyncOption.NEVER) {
if (forgeConnection.get().getTransmittedHandshake().isEmpty() || !msg.equals(forgeConnection.get().getTransmittedHandshake().get())) { if (forgeConnection.getTransmittedHandshake().isEmpty() || !msg.equals(forgeConnection.getTransmittedHandshake().get())) {
event.setResult(ServerPreConnectEvent.ServerResult.denied()); event.setResult(ServerPreConnectEvent.ServerResult.denied());
kickReSync(event.getPlayer(), forgeServerConnection); kickReSync(event.getPlayer(), forgeServerConnection);
} }
@ -113,9 +114,14 @@ public class ForgeServerSwitchHandler {
@Subscribe @Subscribe
public void onServerConnectedEvent(ServerConnectedEvent event, Continuation continuation) { public void onServerConnectedEvent(ServerConnectedEvent event, Continuation continuation) {
ConnectedPlayer player = ((ConnectedPlayer) event.getPlayer()); ConnectedPlayer player = ((ConnectedPlayer) event.getPlayer());
Optional<ForgeServerConnection> forgeServerConnection = ambassador.forgeHandshakeHandler.getForgeServerConnection(event.getServer());
Optional<ForgeConnection> forgeConnection = ambassador.forgeHandshakeHandler.getForgeConnection(player); Optional<ForgeConnection> forgeConnection = ambassador.forgeHandshakeHandler.getForgeConnection(player);
if (forgeConnection.isPresent() && forgeServerConnection.isPresent() && event.getPreviousServer().isPresent()) { if (forgeConnection.isEmpty() || !forgeConnection.get().isResettable()) {
//Don't bother unless the client can be reset.
continuation.resume();
return;
}
Optional<ForgeServerConnection> forgeServerConnection = ambassador.forgeHandshakeHandler.getForgeServerConnection(event.getServer());
if (forgeServerConnection.isPresent() && event.getPreviousServer().isPresent()) {
Future<ForgeHandshakeUtils.CachedServerHandshake> handshakeFuture = forgeServerConnection.get().getHandshake(); Future<ForgeHandshakeUtils.CachedServerHandshake> handshakeFuture = forgeServerConnection.get().getHandshake();
player.getConnection().eventLoop().submit(() -> { player.getConnection().eventLoop().submit(() -> {
reSync(player,handshakeFuture,continuation); reSync(player,handshakeFuture,continuation);
@ -140,7 +146,8 @@ public class ForgeServerSwitchHandler {
private final Future<ForgeHandshakeUtils.CachedServerHandshake> handshakeFuture; private final Future<ForgeHandshakeUtils.CachedServerHandshake> handshakeFuture;
private final MinecraftSessionHandler originalHandler; private final MinecraftSessionHandler originalHandler;
private final Continuation continuation; private final Continuation continuation;
private int sent = 0;
private List<Integer> inTransit = new ArrayList<>();
ReSyncHandler(ConnectedPlayer player, Future<ForgeHandshakeUtils.CachedServerHandshake> handshakeFuture, Continuation continuation) { ReSyncHandler(ConnectedPlayer player, Future<ForgeHandshakeUtils.CachedServerHandshake> handshakeFuture, Continuation continuation) {
this.player = player; this.player = player;
@ -152,32 +159,34 @@ public class ForgeServerSwitchHandler {
@Override @Override
public boolean handle(LoginPluginResponse packet) { public boolean handle(LoginPluginResponse packet) {
if (sent == 0) { if (!inTransit.removeIf((s) -> s==packet.getId())) {
ForgeHandshakeUtils.CachedServerHandshake handshake; if (packet.getId() == 98) {
try { ForgeHandshakeUtils.CachedServerHandshake handshake;
handshake = handshakeFuture.get(); try {
} catch (Exception e) { handshake = handshakeFuture.get();
} catch (Exception e) {
return true;
}
sendHandshake(connection, handshake);
return true; return true;
} }
sent = sendHandshake(connection, handshake); return false;
} else { } else if (inTransit.isEmpty()) {
if (sent == 1) { complete();
complete();
}
sent--;
} }
return true; return true;
} }
private int sendHandshake(MinecraftConnection connection, ForgeHandshakeUtils.CachedServerHandshake handshake) { private void sendHandshake(MinecraftConnection connection, ForgeHandshakeUtils.CachedServerHandshake handshake) {
int transactionId = 1; int transactionId = 1;
connection.delayedWrite(new LoginPluginMessage(transactionId, "fml:loginwrapper", Unpooled.wrappedBuffer(handshake.modListPacket))); connection.delayedWrite(new LoginPluginMessage(transactionId, "fml:loginwrapper", Unpooled.wrappedBuffer(handshake.modListPacket)));
inTransit.add(transactionId);
for (byte[] data : handshake.otherPackets) { for (byte[] data : handshake.otherPackets) {
transactionId++; transactionId++;
connection.delayedWrite(new LoginPluginMessage(transactionId, "fml:loginwrapper", Unpooled.wrappedBuffer(data))); connection.delayedWrite(new LoginPluginMessage(transactionId, "fml:loginwrapper", Unpooled.wrappedBuffer(data)));
inTransit.add(transactionId);
} }
connection.flush(); connection.flush();
return transactionId;
} }
private void complete() { private void complete() {
VelocityConfiguration configuration = (VelocityConfiguration) ambassador.server.getConfiguration(); VelocityConfiguration configuration = (VelocityConfiguration) ambassador.server.getConfiguration();