Skip to content

Commit 72223ec

Browse files
committed
Add support for WDPE 2.0.2-Snapshot
1 parent 0ded00d commit 72223ec

10 files changed

+234
-173
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
<dependency>
4040
<groupId>dev.waterdog.waterdogpe</groupId>
4141
<artifactId>waterdog</artifactId>
42-
<version>2.0.1-SNAPSHOT</version>
42+
<version>2.0.2-SNAPSHOT</version>
4343
<scope>provided</scope>
4444
</dependency>
4545
</dependencies>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.nethergames.proxytransport.compression;
2+
3+
import io.netty.buffer.ByteBuf;
4+
import io.netty.channel.ChannelHandlerContext;
5+
import io.netty.handler.codec.MessageToMessageCodec;
6+
import org.cloudburstmc.protocol.bedrock.netty.BedrockBatchWrapper;
7+
8+
import java.util.List;
9+
10+
public class FrameIdCodec extends MessageToMessageCodec<ByteBuf, BedrockBatchWrapper> {
11+
public static final String NAME = "frame-id-codec";
12+
13+
@Override
14+
protected void encode(ChannelHandlerContext ctx, BedrockBatchWrapper msg, List<Object> out) throws Exception {
15+
out.add(msg.getCompressed().retain());
16+
}
17+
18+
@Override
19+
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
20+
out.add(BedrockBatchWrapper.newInstance(msg.readRetainedSlice(msg.readableBytes()), null));
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.nethergames.proxytransport.compression;
2+
3+
import org.cloudburstmc.protocol.bedrock.data.CompressionAlgorithm;
4+
5+
public enum ProxyTransportAlgorithm implements CompressionAlgorithm {
6+
ZSTD;
7+
8+
private ProxyTransportAlgorithm() {
9+
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package org.nethergames.proxytransport.compression;
2+
3+
import dev.waterdog.waterdogpe.network.connection.codec.compression.ProxiedCompressionCodec;
4+
import io.netty.buffer.ByteBuf;
5+
import io.netty.buffer.CompositeByteBuf;
6+
import io.netty.channel.ChannelHandlerContext;
7+
import org.cloudburstmc.protocol.bedrock.data.CompressionAlgorithm;
8+
import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm;
9+
import org.cloudburstmc.protocol.bedrock.netty.BedrockBatchWrapper;
10+
import org.cloudburstmc.protocol.bedrock.netty.codec.compression.BatchCompression;
11+
import org.cloudburstmc.protocol.bedrock.netty.codec.compression.CompressionStrategy;
12+
13+
import java.util.List;
14+
15+
public class ProxyTransportCompressionCodec extends ProxiedCompressionCodec {
16+
private final boolean prefixed;
17+
private final ZstdCompression zstdCompression = new ZstdCompression();
18+
19+
public ProxyTransportCompressionCodec(CompressionStrategy strategy, boolean prefixed) {
20+
super(strategy, prefixed);
21+
this.prefixed = prefixed;
22+
}
23+
24+
protected void encode(ChannelHandlerContext ctx, BedrockBatchWrapper msg, List<Object> out) throws Exception {
25+
if (msg.getCompressed() == null && msg.getUncompressed() == null) {
26+
throw new IllegalStateException("Batch was not encoded before");
27+
} else if (msg.getCompressed() != null && !msg.isModified()) { // already compressed
28+
if (!this.prefixed) { // we need to prefix the compressed data
29+
CompositeByteBuf buf = ctx.alloc().compositeDirectBuffer(2);
30+
buf.addComponent(true, ctx.alloc().ioBuffer(1).writeByte(getCompressionHeader(msg.getAlgorithm())));
31+
buf.addComponent(true, msg.getCompressed().retainedSlice());
32+
msg.setCompressed(buf, msg.getAlgorithm());
33+
}
34+
35+
this.onPassedThrough(ctx, msg);
36+
out.add(msg.retain());
37+
} else {
38+
BatchCompression compression = this.getStrategy().getCompression(msg);
39+
if (!compression.getAlgorithm().equals(PacketCompressionAlgorithm.NONE)) {
40+
compression = this.zstdCompression;
41+
}
42+
43+
ByteBuf compressed = compression.encode(ctx, msg.getUncompressed());
44+
45+
try {
46+
ByteBuf outBuf;
47+
48+
outBuf = ctx.alloc().ioBuffer(1 + compressed.readableBytes());
49+
outBuf.writeByte(this.getCompressionHeader(compression.getAlgorithm()));
50+
outBuf.writeBytes(compressed);
51+
52+
msg.setCompressed(outBuf, compression.getAlgorithm());
53+
} finally {
54+
compressed.release();
55+
}
56+
57+
this.onCompressed(ctx, msg);
58+
out.add(msg.retain());
59+
}
60+
}
61+
62+
protected byte getCompressionHeader0(CompressionAlgorithm algorithm) {
63+
if (algorithm instanceof ProxyTransportAlgorithm) {
64+
return -2;
65+
}
66+
67+
return super.getCompressionHeader0(algorithm);
68+
}
69+
70+
protected CompressionAlgorithm getCompressionAlgorithm0(byte header) {
71+
if (header == -2) {
72+
return ProxyTransportAlgorithm.ZSTD;
73+
}
74+
75+
return super.getCompressionAlgorithm0(header);
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.nethergames.proxytransport.compression;
2+
3+
import com.github.luben.zstd.Zstd;
4+
import io.netty.buffer.ByteBuf;
5+
import io.netty.buffer.CompositeByteBuf;
6+
import io.netty.channel.ChannelHandlerContext;
7+
import io.netty.util.ReferenceCountUtil;
8+
import org.cloudburstmc.protocol.bedrock.data.CompressionAlgorithm;
9+
import org.cloudburstmc.protocol.bedrock.netty.codec.compression.BatchCompression;
10+
11+
import java.nio.ByteBuffer;
12+
13+
public class ZstdCompression implements BatchCompression {
14+
private int level = -1;
15+
16+
public ByteBuf encode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
17+
ByteBuf direct;
18+
if (!msg.isDirect() || msg instanceof CompositeByteBuf) {
19+
direct = ctx.alloc().ioBuffer(msg.readableBytes());
20+
direct.writeBytes(msg);
21+
} else {
22+
direct = msg;
23+
}
24+
25+
ByteBuf output = ctx.alloc().directBuffer();
26+
try {
27+
int uncompressedLength = direct.readableBytes();
28+
int maxLength = (int) Zstd.compressBound(uncompressedLength);
29+
30+
output.ensureWritable(maxLength);
31+
32+
int compressedLength;
33+
if (direct.hasMemoryAddress()) {
34+
compressedLength = (int) Zstd.compressUnsafe(output.memoryAddress(), maxLength, direct.memoryAddress() + direct.readerIndex(), uncompressedLength, this.level);
35+
} else {
36+
ByteBuffer sourceNio = direct.nioBuffer(direct.readerIndex(), direct.readableBytes());
37+
ByteBuffer targetNio = output.nioBuffer(0, maxLength);
38+
39+
compressedLength = Zstd.compress(targetNio, sourceNio, this.level);
40+
}
41+
42+
output.writerIndex(compressedLength);
43+
return output.retain();
44+
} finally {
45+
ReferenceCountUtil.release(output);
46+
if (direct != msg) {
47+
ReferenceCountUtil.release(direct);
48+
}
49+
}
50+
}
51+
52+
public ByteBuf decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
53+
throw new UnsupportedOperationException("Zstd is not supported");
54+
}
55+
56+
public CompressionAlgorithm getAlgorithm() {
57+
return ProxyTransportAlgorithm.ZSTD;
58+
}
59+
60+
public void setLevel(int level) {
61+
this.level = level;
62+
}
63+
64+
public int getLevel() {
65+
return level;
66+
}
67+
}

src/main/java/org/nethergames/proxytransport/compression/ZstdCompressionCodec.java

-136
This file was deleted.

src/main/java/org/nethergames/proxytransport/impl/TransportChannelInitializer.java

+11-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import dev.waterdog.waterdogpe.network.connection.client.ClientConnection;
66
import dev.waterdog.waterdogpe.network.connection.codec.batch.BedrockBatchDecoder;
77
import dev.waterdog.waterdogpe.network.connection.codec.batch.BedrockBatchEncoder;
8+
import dev.waterdog.waterdogpe.network.connection.codec.client.ClientPacketQueue;
9+
import dev.waterdog.waterdogpe.network.connection.codec.compression.CompressionType;
810
import dev.waterdog.waterdogpe.network.connection.codec.packet.BedrockPacketCodec;
911
import dev.waterdog.waterdogpe.network.serverinfo.ServerInfo;
1012
import dev.waterdog.waterdogpe.player.ProxiedPlayer;
@@ -16,13 +18,14 @@
1618
import org.cloudburstmc.netty.channel.raknet.RakChannel;
1719
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
1820
import org.cloudburstmc.netty.channel.raknet.config.RakMetrics;
19-
import org.nethergames.proxytransport.compression.ZstdCompressionCodec;
21+
import org.cloudburstmc.protocol.bedrock.netty.codec.compression.CompressionCodec;
22+
import org.nethergames.proxytransport.compression.FrameIdCodec;
23+
import org.nethergames.proxytransport.compression.ProxyTransportCompressionCodec;
2024
import org.nethergames.proxytransport.integration.CustomClientEventHandler;
2125

2226
import static dev.waterdog.waterdogpe.network.connection.codec.initializer.ProxiedSessionInitializer.*;
2327

2428
public class TransportChannelInitializer extends ChannelInitializer<Channel> {
25-
private static final int ZSTD_COMPRESSION_LEVEL = 3;
2629

2730
private final ProxiedPlayer player;
2831
private final ServerInfo serverInfo;
@@ -39,6 +42,7 @@ public TransportChannelInitializer(ProxiedPlayer player, ServerInfo serverInfo,
3942
@Override
4043
protected void initChannel(Channel channel) {
4144
int rakVersion = this.player.getProtocol().getRaknetVersion();
45+
CompressionType compression = this.player.getProxy().getConfiguration().getCompression();
4246

4347
channel.attr(PacketDirection.ATTRIBUTE).set(PacketDirection.FROM_SERVER);
4448

@@ -55,14 +59,15 @@ protected void initChannel(Channel channel) {
5559
.addLast(FRAME_DECODER, new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4))
5660
.addLast(FRAME_ENCODER, new LengthFieldPrepender(4));
5761

58-
59-
ClientConnection connection = this.createConnection(channel);
6062
channel.pipeline()
61-
.addLast(ZstdCompressionCodec.NAME, new ZstdCompressionCodec(ZSTD_COMPRESSION_LEVEL, connection))
63+
.addLast(FrameIdCodec.NAME, new FrameIdCodec())
64+
.addLast(CompressionCodec.NAME, new ProxyTransportCompressionCodec(getCompressionStrategy(compression, rakVersion, true), false))
6265
.addLast(BedrockBatchDecoder.NAME, BATCH_DECODER)
6366
.addLast(BedrockBatchEncoder.NAME, new BedrockBatchEncoder())
64-
.addLast(BedrockPacketCodec.NAME, getPacketCodec(rakVersion));
67+
.addLast(BedrockPacketCodec.NAME, getPacketCodec(rakVersion))
68+
.addLast(ClientPacketQueue.NAME, new ClientPacketQueue());
6569

70+
ClientConnection connection = this.createConnection(channel);
6671
if (connection instanceof ChannelHandler handler) { // For reference: This will take care of the packets received being handled.
6772
channel.pipeline().addLast(ClientConnection.NAME, handler);
6873
}

0 commit comments

Comments
 (0)