Now works with reset packet
This commit is contained in:
parent
31e374c1e9
commit
75ea344fda
|
|
@ -4,7 +4,7 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
group 'org.adde0109'
|
group 'org.adde0109'
|
||||||
version '0.4.0'
|
version '0.5.0'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
|
|
@ -21,6 +21,8 @@ dependencies {
|
||||||
implementation 'com.electronwill.night-config:toml:3.6.5'
|
implementation 'com.electronwill.night-config:toml:3.6.5'
|
||||||
implementation 'org.bstats:bstats-velocity:3.0.0'
|
implementation 'org.bstats:bstats-velocity:3.0.0'
|
||||||
implementation 'org.apache.commons:commons-collections4:4.4'
|
implementation 'org.apache.commons:commons-collections4:4.4'
|
||||||
|
implementation 'io.netty:netty-buffer:4.1.79.Final'
|
||||||
|
implementation 'io.netty:netty-transport:4.1.79.Final'
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
import com.velocitypowered.api.proxy.server.ServerPing;
|
import com.velocitypowered.api.proxy.server.ServerPing;
|
||||||
import com.velocitypowered.api.util.ModInfo;
|
import com.velocitypowered.api.util.ModInfo;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
@ -60,6 +62,12 @@ public class ForgeHandshakeUtils {
|
||||||
return stream.toByteArray();
|
return stream.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] generateResetPacket() {
|
||||||
|
ByteArrayDataOutput dataAndPacketIdStream = ByteStreams.newDataOutput();
|
||||||
|
writeVarInt(dataAndPacketIdStream,98);
|
||||||
|
return dataAndPacketIdStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
public static class HandshakeReceiver {
|
public static class HandshakeReceiver {
|
||||||
|
|
||||||
private int partLength;
|
private int partLength;
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,38 @@ package org.adde0109.ambassador.forge;
|
||||||
import com.velocitypowered.api.event.Continuation;
|
import com.velocitypowered.api.event.Continuation;
|
||||||
import com.velocitypowered.api.event.PostOrder;
|
import com.velocitypowered.api.event.PostOrder;
|
||||||
import com.velocitypowered.api.event.Subscribe;
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||||
|
import com.velocitypowered.api.event.player.ServerConnectedEvent;
|
||||||
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
|
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
|
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||||
import com.velocitypowered.api.util.GameProfile;
|
import com.velocitypowered.api.util.GameProfile;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.util.UuidUtils;
|
||||||
|
import com.velocitypowered.proxy.config.PlayerInfoForwarding;
|
||||||
|
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.channel.EventLoop;
|
||||||
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.adde0109.ambassador.Ambassador;
|
import org.adde0109.ambassador.Ambassador;
|
||||||
|
|
@ -40,6 +61,11 @@ public class ForgeServerSwitchHandler {
|
||||||
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> forgeConnection = ambassador.forgeHandshakeHandler.getForgeConnection(event.getPlayer());
|
||||||
if (forgeConnection.isPresent()) {
|
if (forgeConnection.isPresent()) {
|
||||||
|
//TODO: If the client can resync without kick, we don't need to check the server.
|
||||||
|
if (true) {
|
||||||
|
continuation.resume();
|
||||||
|
return;
|
||||||
|
}
|
||||||
ForgeServerConnection forgeServerConnection = forgeServerConnectionOptional.orElseGet(() -> new ForgeServerConnection(event.getOriginalServer()));
|
ForgeServerConnection forgeServerConnection = forgeServerConnectionOptional.orElseGet(() -> new ForgeServerConnection(event.getOriginalServer()));
|
||||||
forgeServerConnection.getHandshake().whenComplete((msg, ex) -> {
|
forgeServerConnection.getHandshake().whenComplete((msg, ex) -> {
|
||||||
if (ex != null) {
|
if (ex != null) {
|
||||||
|
|
@ -62,11 +88,7 @@ public class ForgeServerSwitchHandler {
|
||||||
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.get().getTransmittedHandshake().isEmpty() || !msg.equals(forgeConnection.get().getTransmittedHandshake().get())) {
|
||||||
event.setResult(ServerPreConnectEvent.ServerResult.denied());
|
event.setResult(ServerPreConnectEvent.ServerResult.denied());
|
||||||
try {
|
kickReSync(event.getPlayer(), forgeServerConnection);
|
||||||
reSync(event.getPlayer(),forgeServerConnection);
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
continuation.resumeWithException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,9 +104,94 @@ public class ForgeServerSwitchHandler {
|
||||||
continuation.resume();
|
continuation.resume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void reSync(Player player, ForgeServerConnection forgeServerConnection) throws ReflectiveOperationException {
|
private void kickReSync(Player player, ForgeServerConnection forgeServerConnection){
|
||||||
ambassador.logger.info("Kicking {} because of re-sync needed", player);
|
ambassador.logger.info("Kicking {} because of re-sync needed", player);
|
||||||
player.disconnect(Component.text("Please reconnect"));
|
player.disconnect(Component.text("Please reconnect"));
|
||||||
reSyncMap.put(player.getUsername(),forgeServerConnection);
|
reSyncMap.put(player.getUsername(),forgeServerConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onServerConnectedEvent(ServerConnectedEvent event, Continuation continuation) {
|
||||||
|
ConnectedPlayer player = ((ConnectedPlayer) event.getPlayer());
|
||||||
|
Optional<ForgeServerConnection> forgeServerConnection = ambassador.forgeHandshakeHandler.getForgeServerConnection(event.getServer());
|
||||||
|
Optional<ForgeConnection> forgeConnection = ambassador.forgeHandshakeHandler.getForgeConnection(player);
|
||||||
|
if (forgeConnection.isPresent() && forgeServerConnection.isPresent() && event.getPreviousServer().isPresent()) {
|
||||||
|
Future<ForgeHandshakeUtils.CachedServerHandshake> handshakeFuture = forgeServerConnection.get().getHandshake();
|
||||||
|
player.getConnection().eventLoop().submit(() -> {
|
||||||
|
reSync(player,handshakeFuture,continuation);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
continuation.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reSync(ConnectedPlayer player, Future<ForgeHandshakeUtils.CachedServerHandshake> handshakeFuture, Continuation continuation) {
|
||||||
|
MinecraftConnection connection = player.getConnection();
|
||||||
|
connection.setSessionHandler(new ReSyncHandler(player,handshakeFuture,continuation));
|
||||||
|
connection.write(new PluginMessage("fml:handshake", Unpooled.wrappedBuffer(ForgeHandshakeUtils.generateResetPacket())));
|
||||||
|
connection.setState(StateRegistry.LOGIN);
|
||||||
|
}
|
||||||
|
private class ReSyncHandler implements MinecraftSessionHandler {
|
||||||
|
|
||||||
|
|
||||||
|
private final Player player;
|
||||||
|
|
||||||
|
private final MinecraftConnection connection;
|
||||||
|
private final Future<ForgeHandshakeUtils.CachedServerHandshake> handshakeFuture;
|
||||||
|
private final MinecraftSessionHandler originalHandler;
|
||||||
|
private final Continuation continuation;
|
||||||
|
private int sent = 0;
|
||||||
|
|
||||||
|
ReSyncHandler(ConnectedPlayer player, Future<ForgeHandshakeUtils.CachedServerHandshake> handshakeFuture, Continuation continuation) {
|
||||||
|
this.player = player;
|
||||||
|
this.connection = player.getConnection();
|
||||||
|
this.handshakeFuture = handshakeFuture;
|
||||||
|
this.originalHandler = this.connection.getSessionHandler();
|
||||||
|
this.continuation = continuation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(LoginPluginResponse packet) {
|
||||||
|
if (sent == 0) {
|
||||||
|
ForgeHandshakeUtils.CachedServerHandshake handshake;
|
||||||
|
try {
|
||||||
|
handshake = handshakeFuture.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
sent = sendHandshake(connection, handshake);
|
||||||
|
} else {
|
||||||
|
if (sent == 1) {
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
sent--;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int sendHandshake(MinecraftConnection connection, ForgeHandshakeUtils.CachedServerHandshake handshake) {
|
||||||
|
int transactionId = 1;
|
||||||
|
connection.delayedWrite(new LoginPluginMessage(transactionId, "fml:loginwrapper", Unpooled.wrappedBuffer(handshake.modListPacket)));
|
||||||
|
for (byte[] data : handshake.otherPackets) {
|
||||||
|
transactionId++;
|
||||||
|
connection.delayedWrite(new LoginPluginMessage(transactionId, "fml:loginwrapper", Unpooled.wrappedBuffer(data)));
|
||||||
|
}
|
||||||
|
connection.flush();
|
||||||
|
return transactionId;
|
||||||
|
}
|
||||||
|
private void complete() {
|
||||||
|
VelocityConfiguration configuration = (VelocityConfiguration) ambassador.server.getConfiguration();
|
||||||
|
UUID playerUniqueId = player.getUniqueId();
|
||||||
|
if (configuration.getPlayerInfoForwardingMode() == PlayerInfoForwarding.NONE) {
|
||||||
|
playerUniqueId = UuidUtils.generateOfflinePlayerUuid(player.getUsername());
|
||||||
|
}
|
||||||
|
ServerLoginSuccess success = new ServerLoginSuccess();
|
||||||
|
success.setUsername(player.getUsername());
|
||||||
|
success.setUuid(playerUniqueId);
|
||||||
|
connection.write(success);
|
||||||
|
connection.setState(StateRegistry.PLAY);
|
||||||
|
connection.setSessionHandler(originalHandler);
|
||||||
|
continuation.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user