diff --git a/src/main/java/org/adde0109/ambassador/forge/ForgeConstants.java b/src/main/java/org/adde0109/ambassador/forge/ForgeConstants.java index a74496a..117f3cb 100644 --- a/src/main/java/org/adde0109/ambassador/forge/ForgeConstants.java +++ b/src/main/java/org/adde0109/ambassador/forge/ForgeConstants.java @@ -10,6 +10,7 @@ public class ForgeConstants { public static final String FORGE_HANDSHAKE_HOLDER = "ambassador-forge-handshake-holder"; public static final String FORGE_HANDSHAKE_DECODER = "ambassador-forge-decoder"; public static final String FORGE_HANDSHAKE_HANDLER = "ambassador-forge-handler"; + public static final String COMMAND_ERROR_CATCHER = "ambassador-command-catcher"; public static final String FML2Marker = "\0FML2\0"; public static final String FML3Marker = "\0FML3\0"; diff --git a/src/main/java/org/adde0109/ambassador/forge/VelocityForgeBackendConnectionPhase.java b/src/main/java/org/adde0109/ambassador/forge/VelocityForgeBackendConnectionPhase.java index 301b5d0..0c1c7f5 100644 --- a/src/main/java/org/adde0109/ambassador/forge/VelocityForgeBackendConnectionPhase.java +++ b/src/main/java/org/adde0109/ambassador/forge/VelocityForgeBackendConnectionPhase.java @@ -4,11 +4,12 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.backend.BackendConnectionPhase; import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; -import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.network.Connections; 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.pipeline.CommandDecoderErrorCatcher; import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperDecoder; public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhase { @@ -22,6 +23,10 @@ public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhas @Override public void onLoginSuccess(VelocityServerConnection serverCon, ConnectedPlayer player) { serverCon.setConnectionPhase(VelocityForgeBackendConnectionPhase.COMPLETE); + + serverCon.getConnection().getChannel().pipeline().addBefore(Connections.MINECRAFT_DECODER, + ForgeConstants.COMMAND_ERROR_CATCHER, + new CommandDecoderErrorCatcher(serverCon.getConnection().getProtocolVersion(),player)); } @Override diff --git a/src/main/java/org/adde0109/ambassador/forge/pipeline/CommandDecoderErrorCatcher.java b/src/main/java/org/adde0109/ambassador/forge/pipeline/CommandDecoderErrorCatcher.java new file mode 100644 index 0000000..2e57f23 --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/forge/pipeline/CommandDecoderErrorCatcher.java @@ -0,0 +1,61 @@ +package org.adde0109.ambassador.forge.pipeline; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.api.proxy.server.RegisteredServer; +import com.velocitypowered.proxy.connection.client.ConnectedPlayer; +import com.velocitypowered.proxy.network.Connections; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; +import com.velocitypowered.proxy.protocol.packet.AvailableCommands; +import com.velocitypowered.proxy.protocol.packet.Disconnect; +import com.velocitypowered.proxy.util.except.QuietRuntimeException; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.codec.CorruptedFrameException; +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; + +public class CommandDecoderErrorCatcher extends ChannelInboundHandlerAdapter { + + private final StateRegistry.PacketRegistry.ProtocolRegistry registry; + + private final ConnectedPlayer player; + + public CommandDecoderErrorCatcher(ProtocolVersion protocolVersion, ConnectedPlayer player) { + this.registry = StateRegistry.PLAY.getProtocolRegistry(ProtocolUtils.Direction.CLIENTBOUND, protocolVersion); + this.player = player; + } + + @Override + public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) throws Exception { + if (msg instanceof ByteBuf buf) { + if (!ctx.channel().isActive() || !buf.isReadable()) { + buf.release(); + return; + } + + int originalReaderIndex = buf.readerIndex(); + int packetId = ProtocolUtils.readVarInt(buf); + MinecraftPacket packet = registry.createPacket(packetId); + buf.readerIndex(originalReaderIndex); + if (packet instanceof AvailableCommands) { + try { + ((MinecraftDecoder) ctx.pipeline().get(Connections.MINECRAFT_DECODER)).channelRead(ctx, msg); + } catch (QuietRuntimeException | CorruptedFrameException e) { + RegisteredServer server = player.getConnectedServer().getServer(); + player.handleConnectionException(server, + Disconnect.create(Component.text("Ambassador: Unsupported command argument type detected! " + + "Please install Proxy-Compatible-Forge mod on this backend server."), + player.getProtocolVersion()),true); + } + + } else { + ctx.fireChannelRead(msg); + } + + } + } +} diff --git a/src/main/java/org/adde0109/ambassador/velocity/backend/ForgeLoginSessionHandler.java b/src/main/java/org/adde0109/ambassador/velocity/backend/ForgeLoginSessionHandler.java index 02fbcf3..aff31ae 100644 --- a/src/main/java/org/adde0109/ambassador/velocity/backend/ForgeLoginSessionHandler.java +++ b/src/main/java/org/adde0109/ambassador/velocity/backend/ForgeLoginSessionHandler.java @@ -80,7 +80,7 @@ public class ForgeLoginSessionHandler implements MinecraftSessionHandler { public void disconnected() { if (!serverConnection.getPhase().consideredComplete()) { serverConnection.getPlayer().handleConnectionException(serverConnection.getServer(), - Disconnect.create(Component.text("Backend server disconnected during handshake could be: " + + Disconnect.create(Component.text("Ambassador: Backend server disconnected during handshake could be: " + "mismatched mods OR bad player-forwarding config"), serverConnection.getPlayer().getProtocolVersion()),false); return;