用Netty做传奇2服务器-代理服务器

传奇2的源码, 估计被改了N手了, 封包格式那是相当的乱, 大部分时间都浪费在找正确的封包格式上了; 就比如 Ability的Struct, 在C#和Delphi就能找到一个TAbility和一个TOAbility, 然后你发现用的是C#里的TOAbility. 完了吧, 到StdItem这个, 又发现Delphi版本里的TStdItem是对的.

索性, 写个代理服务器将真服务器和真客户端的封包打印出来看看. 省的用MockClient 太麻烦了;

当前Netty服务器的封包流程, 也就是在Pipeline的流向:

[服务器原封包] -> 6BitDecoder -> [解密后的明文封包] -> PacketDecoder -> [ClientPacket对象] -> Handler处理

Handler发出去的是 ServerPacket, 所以流程是:

[ServerPacket] -> PacketEncode -> [明文封包] -> 6BitEncode -> [加密封包] -> 客户端

代理服务器实际上做这么两个准备:

然后, 就是做这么两件事:

那么传奇服务器的封包通过代理服务器走到客户端的流程就是:

-------------------- 服务器连接Channel的Pipeline ----------------------------------------------
[服务器原封包] -> 6BitDecoder -> [解密后的明文封包] -> PacketDecoder -> [ClientPacket对象]   ↘   |
---------------------------------------------------------------------------------------------
                                                                                -------------------
                                                                                | 代理服务器Handler |
                                                                                -------------------
 ------------------- 客户端连接Channel的Pipeline -----------------------------------------------
 [还原的加密封包] <- 6BitEncoder <- 还原的明文 <- ClientPacketEncoder <- [ClientPacket对象]  ↙    |
 ---------------------------------------------------------------------------------------------

客户端发给传奇服务器的流程就是反过来

所以, 两端的pipeline分别就是:


// 服务器连接端的
ch.pipeline().addLast(
		
		//这里是服务器的连接端
		//来自服务器的封包, 解码成Packet
		new DelimiterBasedFrameDecoder(2048, false, Unpooled.wrappedBuffer(new byte[]{'!'})),
		new PacketBit6Decoder(),
		new PacketDecoder(ServerPackets.class.getCanonicalName()),

		//来自客户端的封包, 发给
		new ClientPacketBit6Encoder(),
		new PacketEncoder(),

		new ChannelHandlerAdapter() {
			@Override
			public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
				// 来自服务器的封包, 通过 client 连接端 发给客户端
				clientChannel.writeAndFlush(packet);
			}
		},
		new ExceptionHandler()
);

// 客户端连接端的
ch.pipeline().addLast(
		//这里是客户端的连接端

		//客户端发来的封包, 解码成 Packet
		new DelimiterBasedFrameDecoder(2048, false, Unpooled.wrappedBuffer(new byte[]{'!'})),
		new ClientPacketBit6Decoder(),
		new ClientPacketDecoder(ClientPackets.class.getCanonicalName()),

		//发给客户端的封包, 从Packet还原成加密封包
		new PacketBit6Encoder(),
		new PacketEncoder(),
		new ChannelHandlerAdapter() {
			@Override
			public void channelActive(ChannelHandlerContext ctx) throws Exception {
				super.channelActive(ctx);
				clientChannel = ctx;
			}

			@Override
			public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
				serverChannel.writeAndFlush(msg);
			}
		}
);