diff --git a/build.gradle.kts b/build.gradle.kts index 26158af..b1e9b17 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "org.adde0109" -version = "1.2.0-beta" +version = "1.3.0-beta-rc1" repositories { mavenCentral() diff --git a/src/main/java/org/adde0109/ambassador/forge/ForgeConstants.java b/src/main/java/org/adde0109/ambassador/forge/ForgeConstants.java index e5f6e16..a74496a 100644 --- a/src/main/java/org/adde0109/ambassador/forge/ForgeConstants.java +++ b/src/main/java/org/adde0109/ambassador/forge/ForgeConstants.java @@ -8,6 +8,8 @@ public class ForgeConstants { public static final String RESET_LISTENER = "ambassador-reset-listener"; public static final String SERVER_SUCCESS_LISTENER = "ambassador-server-success-listener"; 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 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 cc06f9c..9541ce7 100644 --- a/src/main/java/org/adde0109/ambassador/forge/VelocityForgeBackendConnectionPhase.java +++ b/src/main/java/org/adde0109/ambassador/forge/VelocityForgeBackendConnectionPhase.java @@ -5,6 +5,7 @@ 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.packet.LoginPluginMessage; +import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperDecoder; public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhase { NOT_STARTED() { @@ -51,6 +52,10 @@ public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhas VelocityForgeClientConnectionPhase clientPhase = (VelocityForgeClientConnectionPhase) player.getPhase(); clientPhase.resetConnectionPhase(player); player.getConnection().write(message.retain()); + + ForgeLoginWrapperDecoder decoder = (ForgeLoginWrapperDecoder) player.getConnection() + .getChannel().pipeline().get(ForgeConstants.FORGE_HANDSHAKE_DECODER); + decoder.registerLoginWrapperID(message.getId()); } public void onLoginSuccess(VelocityServerConnection serverCon, ConnectedPlayer player) { diff --git a/src/main/java/org/adde0109/ambassador/forge/VelocityForgeClientConnectionPhase.java b/src/main/java/org/adde0109/ambassador/forge/VelocityForgeClientConnectionPhase.java index ad3965c..9f80fa6 100644 --- a/src/main/java/org/adde0109/ambassador/forge/VelocityForgeClientConnectionPhase.java +++ b/src/main/java/org/adde0109/ambassador/forge/VelocityForgeClientConnectionPhase.java @@ -1,5 +1,7 @@ package org.adde0109.ambassador.forge; +import com.velocitypowered.api.proxy.messages.ChannelIdentifier; +import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.MinecraftConnection; @@ -8,14 +10,14 @@ import com.velocitypowered.proxy.connection.client.ClientConnectionPhase; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.network.Connections; import com.velocitypowered.proxy.protocol.StateRegistry; -import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; import com.velocitypowered.proxy.protocol.packet.PluginMessage; import io.netty.buffer.Unpooled; import org.adde0109.ambassador.Ambassador; +import org.adde0109.ambassador.forge.packet.IForgeLoginWrapperPacket; +import org.adde0109.ambassador.forge.packet.ModListReplyPacket; import org.adde0109.ambassador.velocity.client.FML2CRPMResetCompleteDecoder; import org.adde0109.ambassador.velocity.client.OutboundForgeHandshakeHolder; import org.adde0109.ambassador.velocity.client.OutboundSuccessHolder; -import org.adde0109.ambassador.velocity.client.VelocityForgeHandshakeSessionHandler; import java.util.concurrent.TimeUnit; import java.util.concurrent.ScheduledFuture; @@ -50,7 +52,7 @@ public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase connection.getChannel().pipeline().addBefore(Connections.MINECRAFT_DECODER, ForgeConstants.RESET_LISTENER,new FML2CRPMResetCompleteDecoder()); connection.getChannel().pipeline().addAfter(Connections.MINECRAFT_ENCODER, ForgeConstants.FORGE_HANDSHAKE_HOLDER,new OutboundForgeHandshakeHolder()); - player.getConnection().setSessionHandler(new VelocityForgeHandshakeSessionHandler(player.getConnection().getSessionHandler(),player)); + //player.getConnection().setSessionHandler(new VelocityForgeHandshakeSessionHandler(player.getConnection().getSessionHandler(),player)); connection.write(new PluginMessage("fml:handshake", Unpooled.wrappedBuffer(ForgeHandshakeUtils.generatePluginResetPacket()))); @@ -77,8 +79,8 @@ public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase }, Ambassador.getInstance().config.getResetTimeout(), TimeUnit.MILLISECONDS); } @Override - public boolean handle(ConnectedPlayer player, LoginPluginResponse response, VelocityServerConnection server) { - if (response.getId() == 98) { + public boolean handle(ConnectedPlayer player, IForgeLoginWrapperPacket msg, VelocityServerConnection server) { + if (msg.getId() == 98) { if (scheduledFuture.cancel(false)) { player.getConnection().getChannel().pipeline().remove(ForgeConstants.RESET_LISTENER); player.getConnection().setState(StateRegistry.LOGIN); @@ -106,10 +108,14 @@ public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase public boolean vanillaMode = true; - public boolean handle(ConnectedPlayer player, LoginPluginResponse response, VelocityServerConnection server) { + public boolean handle(ConnectedPlayer player, IForgeLoginWrapperPacket msg, VelocityServerConnection server) { player.setPhase(nextPhase()); - player.getConnectionInFlight().getConnection().write(response.retain()); + if (msg instanceof ModListReplyPacket replyPacket) { + replyPacket.getChannels().put(MinecraftChannelIdentifier.from("ambassador:commands"),"1"); + } + + player.getConnectionInFlight().getConnection().write(msg.encode()); vanillaMode = false; return true; } diff --git a/src/main/java/org/adde0109/ambassador/forge/packet/GenericForgeLoginWrapperPacket.java b/src/main/java/org/adde0109/ambassador/forge/packet/GenericForgeLoginWrapperPacket.java new file mode 100644 index 0000000..53c868e --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/forge/packet/GenericForgeLoginWrapperPacket.java @@ -0,0 +1,24 @@ +package org.adde0109.ambassador.forge.packet; + +import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; +import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder; +import io.netty.buffer.ByteBuf; + +public class GenericForgeLoginWrapperPacket extends DeferredByteBufHolder implements IForgeLoginWrapperPacket { + private final int id; + + public GenericForgeLoginWrapperPacket(ByteBuf input, int id) { + super(input); + this.id = id; + } + + @Override + public LoginPluginResponse encode() { + return new LoginPluginResponse(id, true, content()); + } + + @Override + public int getId() { + return id; + } +} diff --git a/src/main/java/org/adde0109/ambassador/forge/packet/IForgeLoginWrapperPacket.java b/src/main/java/org/adde0109/ambassador/forge/packet/IForgeLoginWrapperPacket.java new file mode 100644 index 0000000..22ac150 --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/forge/packet/IForgeLoginWrapperPacket.java @@ -0,0 +1,8 @@ +package org.adde0109.ambassador.forge.packet; + +import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; + +public interface IForgeLoginWrapperPacket { + public LoginPluginResponse encode(); + public int getId(); +} diff --git a/src/main/java/org/adde0109/ambassador/forge/packet/ModListReplyPacket.java b/src/main/java/org/adde0109/ambassador/forge/packet/ModListReplyPacket.java new file mode 100644 index 0000000..9889c13 --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/forge/packet/ModListReplyPacket.java @@ -0,0 +1,94 @@ +package org.adde0109.ambassador.forge.packet; + +import com.velocitypowered.api.proxy.messages.ChannelIdentifier; +import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ModListReplyPacket implements IForgeLoginWrapperPacket { + + private List mods; + private Map channels; + private Map registries; + + private final int id; + + private ModListReplyPacket(List mods, Map channels, Map registries, int id) { + this.mods = mods; + this.channels = channels; + this.registries = registries; + this.id = id; + } + + public static ModListReplyPacket read(LoginPluginResponse msg) { + ByteBuf input = msg.content(); + + List mods = new ArrayList<>(); + int len = ProtocolUtils.readVarInt(input); + for (int x = 0; x < len; x++) + mods.add(ProtocolUtils.readString(input, 0x100)); + + Map channels = new HashMap<>(); + len = ProtocolUtils.readVarInt(input); + for (int x = 0; x < len; x++) + channels.put(MinecraftChannelIdentifier.from(ProtocolUtils.readString(input, 32767)), + ProtocolUtils.readString(input, 0x100)); + + Map registries = new HashMap<>(); + len = ProtocolUtils.readVarInt(input); + for (int x = 0; x < len; x++) + registries.put(ProtocolUtils.readString(input, 32767), ProtocolUtils.readString(input, 0x100)); + + return new ModListReplyPacket(mods, channels, registries, msg.getId()); + } + + @Override + public LoginPluginResponse encode() { + ByteBuf buf = Unpooled.buffer(); + + ProtocolUtils.writeVarInt(buf, 2); + + ProtocolUtils.writeVarInt(buf, mods.size()); + mods.forEach(m -> ProtocolUtils.writeString(buf, m)); + + ProtocolUtils.writeVarInt(buf, channels.size()); + channels.forEach((k, v) -> { + ProtocolUtils.writeString(buf,k.getId()); + ProtocolUtils.writeString(buf,v); + }); + + ProtocolUtils.writeVarInt(buf, registries.size()); + registries.forEach((k, v) -> { + ProtocolUtils.writeString(buf, k); + ProtocolUtils.writeString(buf, v); + }); + + ByteBuf output = Unpooled.buffer(); + ProtocolUtils.writeString(output, "fml:handshake"); + ProtocolUtils.writeVarInt(output, buf.readableBytes()); + output.writeBytes(buf); + + return new LoginPluginResponse(id,true,output); + } + + @Override + public int getId() { + return id; + } + + public List getMods() { + return mods; + } + + public Map getChannels() { + return channels; + } +} diff --git a/src/main/java/org/adde0109/ambassador/forge/pipeline/ForgeLoginWrapperDecoder.java b/src/main/java/org/adde0109/ambassador/forge/pipeline/ForgeLoginWrapperDecoder.java new file mode 100644 index 0000000..91d104b --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/forge/pipeline/ForgeLoginWrapperDecoder.java @@ -0,0 +1,45 @@ +package org.adde0109.ambassador.forge.pipeline; + +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageDecoder; +import org.adde0109.ambassador.forge.packet.GenericForgeLoginWrapperPacket; +import org.adde0109.ambassador.forge.packet.ModListReplyPacket; + +import java.util.ArrayList; +import java.util.List; + +public class ForgeLoginWrapperDecoder extends MessageToMessageDecoder { + + private final List loginWrapperIDs = new ArrayList<>(); + + @Override + protected void decode(ChannelHandlerContext ctx, LoginPluginResponse msg, List out) throws Exception { + ByteBuf buf = msg.content(); + if (!loginWrapperIDs.remove((Integer) msg.getId())) { + out.add(msg.retain()); + return; + } + int originalReaderIndex = msg.content().readerIndex(); + String channel = ProtocolUtils.readString(buf); + if (!channel.equals("fml:handshake")) { + buf.readerIndex(originalReaderIndex); + out.add(new GenericForgeLoginWrapperPacket(buf.retain(), msg.getId())); + return; + } + int length = ProtocolUtils.readVarInt(buf); + int packetID = ProtocolUtils.readVarInt(buf); + if (packetID == 2) { + out.add(ModListReplyPacket.read(msg)); + } else { + buf.readerIndex(originalReaderIndex); + out.add(new GenericForgeLoginWrapperPacket(buf.retain(), msg.getId())); + } + } + + public void registerLoginWrapperID(int loginWrapperID) { + this.loginWrapperIDs.add(loginWrapperID); + } +} diff --git a/src/main/java/org/adde0109/ambassador/forge/pipeline/ForgeLoginWrapperHandler.java b/src/main/java/org/adde0109/ambassador/forge/pipeline/ForgeLoginWrapperHandler.java new file mode 100644 index 0000000..655d144 --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/forge/pipeline/ForgeLoginWrapperHandler.java @@ -0,0 +1,25 @@ +package org.adde0109.ambassador.forge.pipeline; + +import com.velocitypowered.proxy.connection.client.ConnectedPlayer; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.util.ReferenceCountUtil; +import org.adde0109.ambassador.forge.packet.IForgeLoginWrapperPacket; +import org.adde0109.ambassador.forge.VelocityForgeClientConnectionPhase; + +public class ForgeLoginWrapperHandler extends SimpleChannelInboundHandler { + + private final ConnectedPlayer player; + + + public ForgeLoginWrapperHandler(ConnectedPlayer player) { + super(false); + this.player = player; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, IForgeLoginWrapperPacket msg) throws Exception { + VelocityForgeClientConnectionPhase phase = (VelocityForgeClientConnectionPhase) player.getPhase(); + phase.handle(player,msg,player.getConnectionInFlight()); + } +} diff --git a/src/main/java/org/adde0109/ambassador/velocity/VelocityEventHandler.java b/src/main/java/org/adde0109/ambassador/velocity/VelocityEventHandler.java index 254972d..4b59e4b 100644 --- a/src/main/java/org/adde0109/ambassador/velocity/VelocityEventHandler.java +++ b/src/main/java/org/adde0109/ambassador/velocity/VelocityEventHandler.java @@ -8,10 +8,13 @@ import com.velocitypowered.api.event.connection.PostLoginEvent; import com.velocitypowered.api.event.player.*; 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.StateRegistry; import org.adde0109.ambassador.Ambassador; +import org.adde0109.ambassador.forge.ForgeConstants; import org.adde0109.ambassador.forge.VelocityForgeClientConnectionPhase; -import org.adde0109.ambassador.velocity.client.VelocityForgeHandshakeSessionHandler; +import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperDecoder; +import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperHandler; public class VelocityEventHandler { @@ -25,7 +28,16 @@ public class VelocityEventHandler { public void onLoginEvent(LoginEvent event, Continuation continuation) { ConnectedPlayer player = (ConnectedPlayer) event.getPlayer(); if (player.getPhase() instanceof VelocityForgeClientConnectionPhase) { - player.getConnection().eventLoop().submit(() -> player.getConnection().setState(StateRegistry.LOGIN)); + player.getConnection().eventLoop().submit(() -> { + player.getConnection().setState(StateRegistry.LOGIN); + + player.getConnection().getChannel().pipeline().addBefore( + Connections.HANDLER, + ForgeConstants.FORGE_HANDSHAKE_DECODER, new ForgeLoginWrapperDecoder()); + player.getConnection().getChannel().pipeline().addAfter( + ForgeConstants.FORGE_HANDSHAKE_DECODER, + ForgeConstants.FORGE_HANDSHAKE_HANDLER, new ForgeLoginWrapperHandler(player)); + }); } continuation.resume(); } @@ -34,8 +46,8 @@ public class VelocityEventHandler { public void onPostLoginEvent(PostLoginEvent event, Continuation continuation) { ConnectedPlayer player = (ConnectedPlayer) event.getPlayer(); if (player.getPhase() instanceof VelocityForgeClientConnectionPhase phase) { - VelocityForgeHandshakeSessionHandler sessionHandler = new VelocityForgeHandshakeSessionHandler(player.getConnection().getSessionHandler(), player); - player.getConnection().eventLoop().submit(() -> player.getConnection().setSessionHandler(sessionHandler)); + //VelocityForgeHandshakeSessionHandler sessionHandler = new VelocityForgeHandshakeSessionHandler(player.getConnection().getSessionHandler(), player); + //player.getConnection().eventLoop().submit(() -> player.getConnection().setSessionHandler(sessionHandler)); } continuation.resume(); } 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 b224536..50acd49 100644 --- a/src/main/java/org/adde0109/ambassador/velocity/backend/ForgeLoginSessionHandler.java +++ b/src/main/java/org/adde0109/ambassador/velocity/backend/ForgeLoginSessionHandler.java @@ -76,7 +76,8 @@ public class ForgeLoginSessionHandler implements MinecraftSessionHandler { @Override public void disconnected() { - if (!serverConnection.getPlayer().getPhase().consideredComplete()) { + //TODO:Change this + if (!serverConnection.getPhase().consideredComplete()) { serverConnection.getPlayer().handleConnectionException(serverConnection.getServer(), Disconnect.create(Component.text("Probably mismatched mods"), serverConnection.getPlayer().getProtocolVersion()),false); diff --git a/src/main/java/org/adde0109/ambassador/velocity/client/VelocityForgeHandshakeSessionHandler.java b/src/main/java/org/adde0109/ambassador/velocity/client/VelocityForgeHandshakeSessionHandler.java index 458fb2b..4b5b2d8 100644 --- a/src/main/java/org/adde0109/ambassador/velocity/client/VelocityForgeHandshakeSessionHandler.java +++ b/src/main/java/org/adde0109/ambassador/velocity/client/VelocityForgeHandshakeSessionHandler.java @@ -7,7 +7,7 @@ import io.netty.buffer.ByteBuf; import org.adde0109.ambassador.forge.VelocityForgeClientConnectionPhase; public class VelocityForgeHandshakeSessionHandler implements MinecraftSessionHandler { - private final MinecraftSessionHandler original; + /*private final MinecraftSessionHandler original; private final ConnectedPlayer player; public VelocityForgeHandshakeSessionHandler(MinecraftSessionHandler original, ConnectedPlayer player) { @@ -37,4 +37,5 @@ public class VelocityForgeHandshakeSessionHandler implements MinecraftSessionHan public MinecraftSessionHandler getOriginal() { return this.original; } + */ } \ No newline at end of file