WIP: Almost done
This commit is contained in:
parent
2ab257ffe7
commit
007ff8511a
|
|
@ -4,7 +4,7 @@ plugins {
|
|||
}
|
||||
|
||||
group 'org.adde0109'
|
||||
version '1.0.0-alpha'
|
||||
version '1.0.2-alpha'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import org.adde0109.ambassador.forge.ForgeConnection;
|
|||
import org.adde0109.ambassador.forge.ForgeHandshakeHandler;
|
||||
import org.adde0109.ambassador.forge.ForgeHandshakeUtils;
|
||||
import org.adde0109.ambassador.forge.ForgeServerSwitchHandler;
|
||||
import org.adde0109.ambassador.velocity.VelocityBackendChannelInitializer;
|
||||
import org.adde0109.ambassador.velocity.VelocityServerChannelInitializer;
|
||||
import org.adde0109.ambassador.velocity.VelocityEventHandler;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
|
|
@ -28,7 +29,7 @@ import org.slf4j.Logger;
|
|||
|
||||
import java.nio.file.Path;
|
||||
|
||||
@Plugin(id = "ambassador", name = "Ambassador", version = "1.0.0-alpha", authors = {"adde0109"})
|
||||
@Plugin(id = "ambassador", name = "Ambassador", version = "1.0.2-alpha", authors = {"adde0109"})
|
||||
public class Ambassador {
|
||||
|
||||
public ProxyServer server;
|
||||
|
|
@ -72,11 +73,12 @@ public class Ambassador {
|
|||
private void inject() throws ReflectiveOperationException {
|
||||
Field cmField = VelocityServer.class.getDeclaredField("cm");
|
||||
cmField.setAccessible(true);
|
||||
Field endpointMap = ConnectionManager.class.getDeclaredField("endpoints");
|
||||
endpointMap.setAccessible(true);
|
||||
|
||||
ChannelInitializer<?> original = ((ConnectionManager) cmField.get(server)).serverChannelInitializer.get();
|
||||
((ConnectionManager) cmField.get(server)).serverChannelInitializer.set(new VelocityServerChannelInitializer(original));
|
||||
|
||||
ChannelInitializer<?> originalBackend = ((ConnectionManager) cmField.get(server)).backendChannelInitializer.get();
|
||||
((ConnectionManager) cmField.get(server)).backendChannelInitializer.set(new VelocityBackendChannelInitializer(originalBackend,(VelocityServer) server));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ package org.adde0109.ambassador.forge;
|
|||
|
||||
public class ForgeConstants {
|
||||
public static final String HANDLER = "Modern Forge handler";
|
||||
public static final ForgeFML2ConnectionType ForgeFML2 = new ForgeFML2ConnectionType();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,13 +25,12 @@ import org.checkerframework.checker.units.qual.A;
|
|||
import org.checkerframework.checker.units.qual.C;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class ForgeFML2ClientConnectionPhase implements VelocityForgeClientConnectionPhase {
|
||||
private boolean isResettable;
|
||||
|
|
@ -40,24 +39,30 @@ public class ForgeFML2ClientConnectionPhase implements VelocityForgeClientConnec
|
|||
public byte[] modListData;
|
||||
|
||||
private final ArrayList<Integer> listenerList = new ArrayList();
|
||||
public ArrayList<MinecraftPacket> packagesToSendAfterReset = new ArrayList<>();
|
||||
private Runnable whenComplete;
|
||||
public boolean isReady = false;
|
||||
public ClientPhase clientPhase = ClientPhase.HANDSHAKE;
|
||||
@Override
|
||||
public void handleLogin(ConnectedPlayer player,ForgeHandshakeUtils.CachedServerHandshake handshake, Continuation continuation) {
|
||||
this.whenComplete = continuation::resume;
|
||||
final MinecraftConnection connection = player.getConnection();
|
||||
VelocityForgeHandshakeSessionHandler sessionHandler = new VelocityForgeHandshakeSessionHandler(connection.getSessionHandler(),player);
|
||||
if(handshake == null) {
|
||||
connection.delayedWrite(new LoginPluginMessage(0,"fml:loginwrapper", Unpooled.wrappedBuffer(ForgeHandshakeUtils.emptyModlist)));
|
||||
listenerList.add(0);
|
||||
VelocityForgeHandshakeSessionHandler sessionHandler = new VelocityForgeHandshakeSessionHandler(connection.getSessionHandler(), player);
|
||||
if (handshake == null) {
|
||||
connection.delayedWrite(new LoginPluginMessage(98, "fml:loginwrapper", Unpooled.wrappedBuffer(ForgeHandshakeUtils.generateResetPacket())));
|
||||
listenerList.add(98);
|
||||
this.whenComplete = () -> {
|
||||
this.clientPhase = ClientPhase.VANILLA;
|
||||
continuation.resume();
|
||||
};
|
||||
} else {
|
||||
connection.delayedWrite(new LoginPluginMessage(0,"fml:loginwrapper", Unpooled.wrappedBuffer(handshake.modListPacket)));
|
||||
connection.delayedWrite(new LoginPluginMessage(0, "fml:loginwrapper", Unpooled.wrappedBuffer(handshake.modListPacket)));
|
||||
listenerList.add(0);
|
||||
for (int i = 0;i<handshake.otherPackets.size();i++) {
|
||||
connection.delayedWrite(new LoginPluginMessage(i+1,"fml:loginwrapper", Unpooled.wrappedBuffer(handshake.otherPackets.get(i))));
|
||||
listenerList.add(i+1);
|
||||
for (int i = 0; i < handshake.otherPackets.size(); i++) {
|
||||
connection.delayedWrite(new LoginPluginMessage(i + 1, "fml:loginwrapper", Unpooled.wrappedBuffer(handshake.otherPackets.get(i))));
|
||||
listenerList.add(i + 1);
|
||||
}
|
||||
this.whenComplete = () -> {
|
||||
this.clientPhase = ClientPhase.MODDED;
|
||||
continuation.resume();
|
||||
};
|
||||
}
|
||||
connection.setSessionHandler(sessionHandler);
|
||||
connection.flush();
|
||||
|
|
@ -65,40 +70,35 @@ public class ForgeFML2ClientConnectionPhase implements VelocityForgeClientConnec
|
|||
|
||||
@Override
|
||||
public boolean handle(ConnectedPlayer player, LoginPluginResponse packet) {
|
||||
if (packet.getId() == 98) {
|
||||
this.clientPhase = ClientPhase.HANDSHAKE;
|
||||
this.isResettable = packet.isSuccess();
|
||||
} else if (packet.getId() == 0) {
|
||||
this.clientPhase = ClientPhase.MODLIST;
|
||||
}
|
||||
if (!listenerList.removeIf(id -> id.equals(packet.getId()))) {
|
||||
player.getConnectionInFlight().getConnection().write(packet.retain());
|
||||
return true;
|
||||
}
|
||||
if (packet.getId() == 98) {
|
||||
isReady = true;
|
||||
for (MinecraftPacket packet1 : packagesToSendAfterReset) {
|
||||
player.getConnection().delayedWrite(packet1);
|
||||
}
|
||||
packagesToSendAfterReset = new ArrayList<>();
|
||||
player.getConnection().flush();
|
||||
} else if (packet.getId() == 0) {
|
||||
if (!packet.isSuccess()) {
|
||||
//TODO: Write disconnect message to end user
|
||||
player.getConnection().close();
|
||||
return true;
|
||||
}
|
||||
modListData = ByteBufUtil.getBytes(packet.content());
|
||||
}
|
||||
if (listenerList.isEmpty() && whenComplete != null) {
|
||||
} else if (listenerList.isEmpty() && whenComplete != null) {
|
||||
whenComplete.run();
|
||||
whenComplete = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public void reset(ConnectedPlayer player,MinecraftConnection connection) {
|
||||
isReady = false;
|
||||
public void reset(ConnectedPlayer player, Runnable whenComplete) {
|
||||
this.whenComplete = whenComplete;
|
||||
if (player.getConnectedServer() != null) {
|
||||
player.getConnectedServer().disconnect();
|
||||
}
|
||||
MinecraftConnection connection = player.getConnection();
|
||||
connection.setSessionHandler(new VelocityForgeHandshakeSessionHandler(connection.getSessionHandler(),player));
|
||||
connection.write(new PluginMessage("fml:handshake",Unpooled.wrappedBuffer(ForgeHandshakeUtils.generatePluginResetPacket())));
|
||||
if (connection.getState() == StateRegistry.LOGIN) {
|
||||
connection.write(new LoginPluginMessage(98,"fml:loginwrapper", Unpooled.wrappedBuffer(ForgeHandshakeUtils.generateResetPacket())));
|
||||
} else {
|
||||
connection.write(new PluginMessage("fml:handshake",Unpooled.wrappedBuffer(ForgeHandshakeUtils.generatePluginResetPacket())));
|
||||
connection.setState(StateRegistry.LOGIN);
|
||||
}
|
||||
listenerList.add(98);
|
||||
connection.setState(StateRegistry.LOGIN);
|
||||
this.clientPhase = null;
|
||||
}
|
||||
public void complete(VelocityServer server, ConnectedPlayer player, MinecraftConnection connection) {
|
||||
VelocityConfiguration configuration = (VelocityConfiguration) server.getConfiguration();
|
||||
|
|
@ -109,16 +109,21 @@ public class ForgeFML2ClientConnectionPhase implements VelocityForgeClientConnec
|
|||
ServerLoginSuccess success = new ServerLoginSuccess();
|
||||
success.setUsername(player.getUsername());
|
||||
success.setUuid(playerUniqueId);
|
||||
send(player,success);
|
||||
connection.write(success);
|
||||
|
||||
this.clientPhase = this.clientPhase == ClientPhase.MODLIST ? ClientPhase.MODDED : ClientPhase.VANILLA;
|
||||
|
||||
connection.setState(StateRegistry.PLAY);
|
||||
connection.setSessionHandler(((VelocityForgeHandshakeSessionHandler) connection.getSessionHandler()).getOriginal());
|
||||
}
|
||||
public void send(ConnectedPlayer player, MinecraftPacket message) {
|
||||
if (isReady) {
|
||||
player.getConnection().write(message);
|
||||
} else {
|
||||
packagesToSendAfterReset.add(message);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ClientPhase {
|
||||
VANILLA,
|
||||
HANDSHAKE,
|
||||
MODLIST,
|
||||
MODDED
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class ForgeFML2ConnectionType implements ConnectionType {
|
|||
|
||||
@Override
|
||||
public BackendConnectionPhase getInitialBackendPhase() {
|
||||
return BackendConnectionPhases.UNKNOWN;
|
||||
return new VelocityForgeBackendConnectionPhase();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
package org.adde0109.ambassador.velocity;
|
||||
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import org.adde0109.ambassador.forge.ForgeConstants;
|
||||
import org.adde0109.ambassador.forge.ForgeFML2ClientConnectionPhase;
|
||||
import org.adde0109.ambassador.forge.ForgeFML2ConnectionType;
|
||||
import org.adde0109.ambassador.velocity.backend.VelocityForgeBackendHandshakeHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
|
@ -36,20 +31,8 @@ public class VelocityBackendChannelInitializer extends ChannelInitializer<Channe
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(@NotNull Channel ch) throws Exception {
|
||||
INIT_CHANNEL.invoke(original);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||
if (ctx.handler() instanceof MinecraftConnection connection) {
|
||||
if (connection.getAssociation() instanceof VelocityServerConnection serverConnection) {
|
||||
if (serverConnection.getPlayer().getPhase() instanceof ForgeFML2ClientConnectionPhase) {
|
||||
connection.setType(new ForgeFML2ConnectionType());
|
||||
ctx.pipeline().addBefore(ctx.name(), ForgeConstants.HANDLER, new VelocityForgeBackendHandshakeHandler(connection, serverConnection, server));
|
||||
}
|
||||
}
|
||||
}
|
||||
super.handlerAdded(ctx);
|
||||
protected void initChannel(Channel ch) throws Exception {
|
||||
INIT_CHANNEL.invoke(original,ch);
|
||||
ch.pipeline().addLast(ForgeConstants.HANDLER, new VelocityForgeBackendHandshakeHandler(server));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
|||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
import com.velocitypowered.proxy.protocol.packet.Handshake;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.adde0109.ambassador.forge.ForgeFML2ConnectionType;
|
||||
import org.adde0109.ambassador.forge.ForgeConstants;
|
||||
|
||||
public class VelocityHandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
private final HandshakeSessionHandler original;
|
||||
|
|
@ -24,7 +24,7 @@ public class VelocityHandshakeSessionHandler implements MinecraftSessionHandler
|
|||
handshake.handle(original);
|
||||
if (connection.getType() == ConnectionTypes.VANILLA && connection.getState() == StateRegistry.LOGIN) {
|
||||
if (handshake.getServerAddress().split("\0")[1].equals("FML2")) {
|
||||
connection.setType(new ForgeFML2ConnectionType());
|
||||
connection.setType(ForgeConstants.ForgeFML2);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,45 +1,46 @@
|
|||
package org.adde0109.ambassador.velocity.backend;
|
||||
|
||||
import com.velocitypowered.proxy.Velocity;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
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.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
|
||||
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.adde0109.ambassador.Ambassador;
|
||||
import org.adde0109.ambassador.forge.ForgeFML2ClientConnectionPhase;
|
||||
import org.adde0109.ambassador.forge.ForgeHandshakeUtils;
|
||||
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class VelocityForgeBackendConnectionPhase implements BackendConnectionPhase {
|
||||
|
||||
private final Ambassador ambassador;
|
||||
private boolean vanilla = true;
|
||||
private final List<LoginPluginMessage> queuedHandshakePackets = new ArrayList<>();
|
||||
|
||||
public VelocityForgeBackendConnectionPhase(Ambassador ambassador) {
|
||||
this.ambassador = ambassador;
|
||||
public VelocityForgeBackendConnectionPhase() {
|
||||
}
|
||||
|
||||
public void handleSuccess(VelocityServerConnection serverCon, VelocityServer server) {
|
||||
ForgeFML2ClientConnectionPhase clientPhase = ((ForgeFML2ClientConnectionPhase) serverCon.getPlayer().getPhase());
|
||||
if (vanilla) {
|
||||
clientPhase.reset(serverCon.getPlayer(),serverCon.getPlayer().getConnection());
|
||||
if (clientPhase.clientPhase == ForgeFML2ClientConnectionPhase.ClientPhase.HANDSHAKE || clientPhase.clientPhase == ForgeFML2ClientConnectionPhase.ClientPhase.MODLIST) {
|
||||
clientPhase.complete((VelocityServer) server,serverCon.getPlayer(),serverCon.getPlayer().getConnection());
|
||||
}
|
||||
clientPhase.complete((VelocityServer) ambassador.server,serverCon.getPlayer(),serverCon.getPlayer().getConnection());
|
||||
}
|
||||
|
||||
public boolean handle(VelocityServerConnection server, ConnectedPlayer player, LoginPluginMessage message) {
|
||||
vanilla = false;
|
||||
public boolean handle(VelocityServerConnection server, ConnectedPlayer player, LoginPluginMessage message) throws Exception {
|
||||
ForgeFML2ClientConnectionPhase clientPhase = ((ForgeFML2ClientConnectionPhase) player.getPhase());
|
||||
message.retain();
|
||||
((ForgeFML2ClientConnectionPhase) player.getPhase()).send(player,message);
|
||||
if (clientPhase.clientPhase == ForgeFML2ClientConnectionPhase.ClientPhase.VANILLA) {
|
||||
clientPhase.reset(player, () -> {
|
||||
for (LoginPluginMessage msg: queuedHandshakePackets) {
|
||||
player.getConnection().delayedWrite(msg);
|
||||
}
|
||||
player.getConnection().flush();
|
||||
});
|
||||
queuedHandshakePackets.add(message);
|
||||
} else if (clientPhase.clientPhase != null) {
|
||||
player.getConnection().write(message);
|
||||
} else {
|
||||
queuedHandshakePackets.add(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,34 +3,73 @@ package org.adde0109.ambassador.velocity.backend;
|
|||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||
import com.velocitypowered.proxy.network.Connections;
|
||||
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
|
||||
import com.velocitypowered.proxy.protocol.packet.ServerLogin;
|
||||
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import org.adde0109.ambassador.forge.ForgeConstants;
|
||||
import org.adde0109.ambassador.forge.ForgeFML2ClientConnectionPhase;
|
||||
|
||||
public class VelocityForgeBackendHandshakeHandler extends ChannelInboundHandlerAdapter {
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
private final MinecraftConnection connection;
|
||||
private final VelocityServerConnection serverConnection;
|
||||
public class VelocityForgeBackendHandshakeHandler extends ChannelDuplexHandler {
|
||||
|
||||
private VelocityServerConnection serverConnection;
|
||||
private final VelocityServer server;
|
||||
|
||||
public VelocityForgeBackendHandshakeHandler(MinecraftConnection connection, VelocityServerConnection serverConnection, VelocityServer server) {
|
||||
this.connection = connection;
|
||||
this.serverConnection = serverConnection;
|
||||
public VelocityForgeBackendHandshakeHandler(VelocityServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
if ((msg instanceof ServerLogin)) {
|
||||
ChannelHandler handler = ctx.pipeline().get(Connections.HANDLER);
|
||||
if (handler instanceof MinecraftConnection connection) {
|
||||
if (connection.getAssociation() instanceof VelocityServerConnection serverConnection) {
|
||||
if (serverConnection.getPlayer().getPhase() instanceof ForgeFML2ClientConnectionPhase phase) {
|
||||
init(connection,serverConnection);
|
||||
if (phase.clientPhase == ForgeFML2ClientConnectionPhase.ClientPhase.MODDED) {
|
||||
phase.reset(serverConnection.getPlayer(), () -> {
|
||||
ctx.write(msg, promise);
|
||||
ctx.flush();
|
||||
});
|
||||
} else {
|
||||
ctx.write(msg,promise);
|
||||
}
|
||||
} else {
|
||||
ctx.pipeline().remove(this);
|
||||
ctx.write(msg,promise);
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Connection not associated with a server connection");
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Default minecraft packet handler not found");
|
||||
}
|
||||
} else {
|
||||
ctx.write(msg,promise);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
if (msg instanceof LoginPluginMessage message && message.getChannel().equals("fml:loginwrapper")) {
|
||||
((VelocityForgeBackendConnectionPhase) serverConnection.getPhase()).handle(serverConnection, serverConnection.getPlayer(), message);
|
||||
ReferenceCountUtil.release(msg);
|
||||
} else if (msg instanceof ServerLoginSuccess) {
|
||||
((VelocityForgeBackendConnectionPhase) serverConnection.getPhase()).handleSuccess(serverConnection,server);
|
||||
ReferenceCountUtil.release(msg);
|
||||
ctx.fireChannelRead(msg);
|
||||
} else {
|
||||
ctx.fireChannelRead(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void init(MinecraftConnection connection, VelocityServerConnection serverConnection) {
|
||||
this.serverConnection = serverConnection;
|
||||
connection.setType(ForgeConstants.ForgeFML2);
|
||||
serverConnection.setConnectionPhase(connection.getType().getInitialBackendPhase());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user