Avoid resets

This commit is contained in:
Adrian Bergqvist 2023-11-28 00:13:06 +01:00
parent ba3132c1bd
commit 55e0a66122
No known key found for this signature in database
GPG Key ID: FAE7D8EDE225E686
5 changed files with 76 additions and 24 deletions

View File

@ -2,25 +2,19 @@ package org.adde0109.ambassador.forge;
import org.adde0109.ambassador.forge.packet.ModListPacket; import org.adde0109.ambassador.forge.packet.ModListPacket;
import org.adde0109.ambassador.forge.packet.ModListReplyPacket; import org.adde0109.ambassador.forge.packet.ModListReplyPacket;
import org.adde0109.ambassador.forge.packet.RegistryPacket;
import java.util.List; import java.util.List;
import java.util.zip.Adler32;
import java.util.zip.Checksum;
public class ForgeHandshake { public class ForgeHandshake {
private ModListPacket modListPacket;
private ModListReplyPacket modListReplyPacket; private ModListReplyPacket modListReplyPacket;
private final Checksum registryChecksum = new Adler32();
public ForgeHandshake() { public ForgeHandshake() {
} }
public ModListPacket getModListPacket() {
return modListPacket;
}
public void setModListPacket(ModListPacket modListPacket) {
this.modListPacket = modListPacket;
}
public ModListReplyPacket getModListReplyPacket() { public ModListReplyPacket getModListReplyPacket() {
return modListReplyPacket; return modListReplyPacket;
} }
@ -28,4 +22,12 @@ public class ForgeHandshake {
public void setModListReplyPacket(ModListReplyPacket modListReplyPacket) { public void setModListReplyPacket(ModListReplyPacket modListReplyPacket) {
this.modListReplyPacket = modListReplyPacket; this.modListReplyPacket = modListReplyPacket;
} }
public void addRegistry(RegistryPacket packet) {
registryChecksum.update(packet.getSnapshot());
}
public Checksum getRegistryChecksum() {
return registryChecksum;
}
} }

View File

@ -9,10 +9,15 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.packet.AvailableCommands; import com.velocitypowered.proxy.protocol.packet.AvailableCommands;
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import com.velocitypowered.proxy.protocol.packet.PluginMessage; import com.velocitypowered.proxy.protocol.packet.PluginMessage;
import org.adde0109.ambassador.forge.packet.Context; import org.adde0109.ambassador.forge.packet.*;
import org.adde0109.ambassador.forge.packet.IForgeLoginWrapperPacket;
import org.adde0109.ambassador.forge.pipeline.CommandDecoderErrorCatcher; import org.adde0109.ambassador.forge.pipeline.CommandDecoderErrorCatcher;
import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperCodec; 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 { public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhase {
NOT_STARTED() { NOT_STARTED() {
@ -54,7 +59,8 @@ public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhas
} }
}; };
public Checksum registryChecksum;
CountDownLatch remainingRegistries;
VelocityForgeBackendConnectionPhase() { VelocityForgeBackendConnectionPhase() {
} }
@ -66,17 +72,46 @@ public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhas
//Reset client if not ready to receive new handshake //Reset client if not ready to receive new handshake
VelocityForgeClientConnectionPhase clientPhase = (VelocityForgeClientConnectionPhase) player.getPhase(); VelocityForgeClientConnectionPhase clientPhase = (VelocityForgeClientConnectionPhase) player.getPhase();
if (clientPhase != VelocityForgeClientConnectionPhase.NOT_STARTED) { if (clientPhase == VelocityForgeClientConnectionPhase.RESETTABLE) {
//Initial Forge //Initial Forge
//Forge -> Forge //Forge -> Forge
clientPhase.resetConnectionPhase(player); clientPhase.resetConnectionPhase(player);
if (clientPhase == VelocityForgeClientConnectionPhase.COMPLETE) }
{
//Do not continue if the client can't reset. if (clientPhase != VelocityForgeClientConnectionPhase.COMPLETE) {
return; 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 //Forge server
//To avoid unnecessary resets, we wait until we get the handshake even if we know that we should //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. //reset because that the previous server was Forge.

View File

@ -22,6 +22,7 @@ import org.adde0109.ambassador.velocity.client.FML2CRPMResetCompleteDecoder;
import org.adde0109.ambassador.velocity.client.OutboundSuccessHolder; import org.adde0109.ambassador.velocity.client.OutboundSuccessHolder;
import org.adde0109.ambassador.velocity.client.ClientPacketQueue; import org.adde0109.ambassador.velocity.client.ClientPacketQueue;
import javax.swing.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -144,18 +145,20 @@ public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase
public boolean consideredComplete() { public boolean consideredComplete() {
return true; return true;
} }
public void complete(ConnectedPlayer player, boolean resettable) { }
}; };
public ModListReplyPacket clientModList; public ForgeHandshake forgeHandshake = new ForgeHandshake();
public boolean handle(ConnectedPlayer player, IForgeLoginWrapperPacket<Context.ClientContext> msg, VelocityServerConnection server) { public boolean handle(ConnectedPlayer player, IForgeLoginWrapperPacket<Context.ClientContext> msg, VelocityServerConnection server) {
player.setPhase(nextPhase());
if (msg instanceof ModListReplyPacket replyPacket) { if (msg instanceof ModListReplyPacket replyPacket) {
ModInfo modInfo = new ModInfo("FML2", replyPacket.getMods().stream().map( ModInfo modInfo = new ModInfo("FML2", replyPacket.getMods().stream().map(
(v) -> new ModInfo.Mod(v,"1")).toList()); (v) -> new ModInfo.Mod(v,"1")).toList());
player.setModInfo(modInfo); player.setModInfo(modInfo);
this.clientModList = replyPacket; forgeHandshake.setModListReplyPacket(replyPacket);
if (!(server.getConnection().getType() instanceof ForgeFMLConnectionType)) { if (!(server.getConnection().getType() instanceof ForgeFMLConnectionType)) {
complete(player); complete(player);
player.getConnectionInFlight().getConnection().getChannel().config().setAutoRead(true); player.getConnectionInFlight().getConnection().getChannel().config().setAutoRead(true);
@ -165,6 +168,10 @@ public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase
} }
player.getConnectionInFlight().getConnection().write(msg); player.getConnectionInFlight().getConnection().write(msg);
player.setPhase(nextPhase());
nextPhase().forgeHandshake = this.forgeHandshake;
return true; return true;
} }
@ -181,11 +188,11 @@ public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase
if (resettable) { if (resettable) {
player.setPhase(RESETTABLE); player.setPhase(RESETTABLE);
RESETTABLE.onTransitionToNewPhase(player); RESETTABLE.onTransitionToNewPhase(player);
RESETTABLE.clientModList = clientModList; RESETTABLE.forgeHandshake = forgeHandshake;
} else { } else {
player.setPhase(COMPLETE); player.setPhase(COMPLETE);
COMPLETE.onTransitionToNewPhase(player); COMPLETE.onTransitionToNewPhase(player);
COMPLETE.clientModList = clientModList; COMPLETE.forgeHandshake = forgeHandshake;
} }
} }

View File

@ -95,5 +95,8 @@ public class ModListPacket implements IForgeLoginWrapperPacket<Context> {
return channels; return channels;
} }
public List<String> getRegistries() {
return registries;
}
} }

View File

@ -7,6 +7,7 @@ import io.netty.buffer.Unpooled;
public class RegistryPacket implements IForgeLoginWrapperPacket<Context> { public class RegistryPacket implements IForgeLoginWrapperPacket<Context> {
private final String registryName; private final String registryName;
private final byte[] snapshot; private final byte[] snapshot;
private final Context context; private final Context context;
@ -48,4 +49,8 @@ public class RegistryPacket implements IForgeLoginWrapperPacket<Context> {
public Context getContext() { public Context getContext() {
return context; return context;
} }
public byte[] getSnapshot() {
return snapshot;
}
} }