From 55e0a6612257b24d21601a85dd736a3e70841bb0 Mon Sep 17 00:00:00 2001 From: Adrian Bergqvist Date: Tue, 28 Nov 2023 00:13:06 +0100 Subject: [PATCH] Avoid resets --- .../ambassador/forge/ForgeHandshake.java | 22 ++++---- .../VelocityForgeBackendConnectionPhase.java | 53 +++++++++++++++---- .../VelocityForgeClientConnectionPhase.java | 17 ++++-- .../forge/packet/ModListPacket.java | 3 ++ .../forge/packet/RegistryPacket.java | 5 ++ 5 files changed, 76 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/adde0109/ambassador/forge/ForgeHandshake.java b/src/main/java/org/adde0109/ambassador/forge/ForgeHandshake.java index 5a6f6e0..3054c33 100644 --- a/src/main/java/org/adde0109/ambassador/forge/ForgeHandshake.java +++ b/src/main/java/org/adde0109/ambassador/forge/ForgeHandshake.java @@ -2,25 +2,19 @@ package org.adde0109.ambassador.forge; import org.adde0109.ambassador.forge.packet.ModListPacket; import org.adde0109.ambassador.forge.packet.ModListReplyPacket; +import org.adde0109.ambassador.forge.packet.RegistryPacket; import java.util.List; +import java.util.zip.Adler32; +import java.util.zip.Checksum; public class ForgeHandshake { - - private ModListPacket modListPacket; private ModListReplyPacket modListReplyPacket; + private final Checksum registryChecksum = new Adler32(); public ForgeHandshake() { } - public ModListPacket getModListPacket() { - return modListPacket; - } - - public void setModListPacket(ModListPacket modListPacket) { - this.modListPacket = modListPacket; - } - public ModListReplyPacket getModListReplyPacket() { return modListReplyPacket; } @@ -28,4 +22,12 @@ public class ForgeHandshake { public void setModListReplyPacket(ModListReplyPacket modListReplyPacket) { this.modListReplyPacket = modListReplyPacket; } + + public void addRegistry(RegistryPacket packet) { + registryChecksum.update(packet.getSnapshot()); + } + + public Checksum getRegistryChecksum() { + return registryChecksum; + } } diff --git a/src/main/java/org/adde0109/ambassador/forge/VelocityForgeBackendConnectionPhase.java b/src/main/java/org/adde0109/ambassador/forge/VelocityForgeBackendConnectionPhase.java index 6786dbe..9bdee59 100644 --- a/src/main/java/org/adde0109/ambassador/forge/VelocityForgeBackendConnectionPhase.java +++ b/src/main/java/org/adde0109/ambassador/forge/VelocityForgeBackendConnectionPhase.java @@ -9,10 +9,15 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.AvailableCommands; import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; import com.velocitypowered.proxy.protocol.packet.PluginMessage; -import org.adde0109.ambassador.forge.packet.Context; -import org.adde0109.ambassador.forge.packet.IForgeLoginWrapperPacket; +import org.adde0109.ambassador.forge.packet.*; import org.adde0109.ambassador.forge.pipeline.CommandDecoderErrorCatcher; import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperCodec; +import org.checkerframework.checker.units.qual.A; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.zip.Adler32; +import java.util.zip.Checksum; public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhase { NOT_STARTED() { @@ -54,7 +59,8 @@ public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhas } }; - + public Checksum registryChecksum; + CountDownLatch remainingRegistries; VelocityForgeBackendConnectionPhase() { } @@ -66,17 +72,46 @@ public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhas //Reset client if not ready to receive new handshake VelocityForgeClientConnectionPhase clientPhase = (VelocityForgeClientConnectionPhase) player.getPhase(); - if (clientPhase != VelocityForgeClientConnectionPhase.NOT_STARTED) { + if (clientPhase == VelocityForgeClientConnectionPhase.RESETTABLE) { //Initial Forge //Forge -> Forge clientPhase.resetConnectionPhase(player); - if (clientPhase == VelocityForgeClientConnectionPhase.COMPLETE) - { - //Do not continue if the client can't reset. - return; + } + + if (clientPhase != VelocityForgeClientConnectionPhase.COMPLETE) { + if (message instanceof ModListPacket modListPacket) { + clientPhase.forgeHandshake = new ForgeHandshake(); + } + if (message instanceof RegistryPacket registryPacket) { + clientPhase.forgeHandshake.addRegistry(registryPacket); + } + player.getConnection().write(message); + } else { + if (message instanceof ModListPacket modListPacket) { + registryChecksum = new Adler32(); + remainingRegistries = new CountDownLatch(modListPacket.getRegistries().size()); + CompletableFuture.runAsync(() -> { + try { + remainingRegistries.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }).thenAcceptAsync((v) -> { + if (clientPhase.forgeHandshake.getRegistryChecksum().getValue() == registryChecksum.getValue()) { + server.ensureConnected().write(clientPhase.forgeHandshake.getModListReplyPacket()); + } else { + //Player needs to be kicked in order to continue. + server.disconnect(); + } + }, server.ensureConnected().eventLoop()); + } else if (message instanceof RegistryPacket registryPacket) { + server.getConnection().write(new ACKPacket(Context.createContext(message.getContext().getResponseID(), true))); + registryChecksum.update(registryPacket.getSnapshot()); + remainingRegistries.countDown(); + } else if (message instanceof ConfigDataPacket) { + server.getConnection().write(new ACKPacket(Context.createContext(message.getContext().getResponseID(), true))); } } - player.getConnection().write(message); //Forge server //To avoid unnecessary resets, we wait until we get the handshake even if we know that we should //reset because that the previous server was Forge. diff --git a/src/main/java/org/adde0109/ambassador/forge/VelocityForgeClientConnectionPhase.java b/src/main/java/org/adde0109/ambassador/forge/VelocityForgeClientConnectionPhase.java index cddb665..a5c0f21 100644 --- a/src/main/java/org/adde0109/ambassador/forge/VelocityForgeClientConnectionPhase.java +++ b/src/main/java/org/adde0109/ambassador/forge/VelocityForgeClientConnectionPhase.java @@ -22,6 +22,7 @@ import org.adde0109.ambassador.velocity.client.FML2CRPMResetCompleteDecoder; import org.adde0109.ambassador.velocity.client.OutboundSuccessHolder; import org.adde0109.ambassador.velocity.client.ClientPacketQueue; +import javax.swing.*; import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; @@ -144,18 +145,20 @@ public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase public boolean consideredComplete() { return true; } + + public void complete(ConnectedPlayer player, boolean resettable) { } + }; - public ModListReplyPacket clientModList; + public ForgeHandshake forgeHandshake = new ForgeHandshake(); public boolean handle(ConnectedPlayer player, IForgeLoginWrapperPacket msg, VelocityServerConnection server) { - player.setPhase(nextPhase()); if (msg instanceof ModListReplyPacket replyPacket) { ModInfo modInfo = new ModInfo("FML2", replyPacket.getMods().stream().map( (v) -> new ModInfo.Mod(v,"1")).toList()); player.setModInfo(modInfo); - this.clientModList = replyPacket; + forgeHandshake.setModListReplyPacket(replyPacket); if (!(server.getConnection().getType() instanceof ForgeFMLConnectionType)) { complete(player); player.getConnectionInFlight().getConnection().getChannel().config().setAutoRead(true); @@ -165,6 +168,10 @@ public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase } player.getConnectionInFlight().getConnection().write(msg); + + player.setPhase(nextPhase()); + nextPhase().forgeHandshake = this.forgeHandshake; + return true; } @@ -181,11 +188,11 @@ public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase if (resettable) { player.setPhase(RESETTABLE); RESETTABLE.onTransitionToNewPhase(player); - RESETTABLE.clientModList = clientModList; + RESETTABLE.forgeHandshake = forgeHandshake; } else { player.setPhase(COMPLETE); COMPLETE.onTransitionToNewPhase(player); - COMPLETE.clientModList = clientModList; + COMPLETE.forgeHandshake = forgeHandshake; } } diff --git a/src/main/java/org/adde0109/ambassador/forge/packet/ModListPacket.java b/src/main/java/org/adde0109/ambassador/forge/packet/ModListPacket.java index 008176e..42617fc 100644 --- a/src/main/java/org/adde0109/ambassador/forge/packet/ModListPacket.java +++ b/src/main/java/org/adde0109/ambassador/forge/packet/ModListPacket.java @@ -95,5 +95,8 @@ public class ModListPacket implements IForgeLoginWrapperPacket { return channels; } + public List getRegistries() { + return registries; + } } diff --git a/src/main/java/org/adde0109/ambassador/forge/packet/RegistryPacket.java b/src/main/java/org/adde0109/ambassador/forge/packet/RegistryPacket.java index 42f42bc..1d9dc22 100644 --- a/src/main/java/org/adde0109/ambassador/forge/packet/RegistryPacket.java +++ b/src/main/java/org/adde0109/ambassador/forge/packet/RegistryPacket.java @@ -7,6 +7,7 @@ import io.netty.buffer.Unpooled; public class RegistryPacket implements IForgeLoginWrapperPacket { private final String registryName; + private final byte[] snapshot; private final Context context; @@ -48,4 +49,8 @@ public class RegistryPacket implements IForgeLoginWrapperPacket { public Context getContext() { return context; } + + public byte[] getSnapshot() { + return snapshot; + } }