Skip to content

Commit 94d4d80

Browse files
Done
1 parent f51c1b5 commit 94d4d80

File tree

6 files changed

+155
-90
lines changed

6 files changed

+155
-90
lines changed

api/src/main/java/com/github/retrooper/packetevents/netty/buffer/ByteBufHelper.java

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -244,53 +244,8 @@ public static int getIntLE(Object buffer, int readerIndex) {
244244
return PacketEvents.getAPI().getNettyManager().getByteBufOperator().getIntLE(buffer, readerIndex);
245245
}
246246

247-
//Src: https://github.com/jonesdevelopment/sonar/blob/main/common/src/main/java/xyz/jonesdev/sonar/common/fallback/netty/FallbackVarInt21FrameDecoder.java#L69
248247
public static int readVarInt(Object buf) {
249-
if (readableBytes(buf) < 4) return readVarIntSmallBuffer(buf);
250-
251-
// take the last three bytes and check if any of them have the high bit set
252-
int wholeOrMore = getIntLE(buf, readerIndex(buf));
253-
int atStop = ~wholeOrMore & 0x808080;
254-
if (atStop == 0) throw new RuntimeException("fucked up - VarInt too big");
255-
256-
final int bitsToKeep = Integer.numberOfTrailingZeros(atStop) + 1;
257-
skipBytes(buf, bitsToKeep >> 3);
258-
259-
// https://github.com/netty/netty/pull/14050#issuecomment-2107750734
260-
int preservedBytes = wholeOrMore & (atStop ^ (atStop - 1));
261-
262-
// https://github.com/netty/netty/pull/14050#discussion_r1597896639
263-
preservedBytes = (preservedBytes & 0x007F007F) | ((preservedBytes & 0x00007F00) >> 1);
264-
preservedBytes = (preservedBytes & 0x00003FFF) | ((preservedBytes & 0x3FFF0000) >> 2);
265-
return preservedBytes;
266-
}
267-
268-
//fallback to unrolled loop
269-
//I'll try to optimize this in the future
270-
private static int readVarIntSmallBuffer(Object buf) {
271-
if (!isReadable(buf)) return 0;
272-
273-
int rIdx = readerIndex(buf);
274-
275-
byte tmp = readByte(buf);
276-
if (tmp >= 0) return tmp;
277-
278-
int result = tmp & 0x7F;
279-
if (!isReadable(buf)) {
280-
readerIndex(buf, rIdx);
281-
return 0;
282-
}
283-
284-
if ((tmp = readByte(buf)) >= 0) return result | tmp << 7;
285-
286-
result |= (tmp & 0x7F) << 7;
287-
if (!isReadable(buf)) {
288-
readerIndex(buf, rIdx);
289-
return 0;
290-
}
291-
if ((tmp = readByte(buf)) >= 0) return result | tmp << 14;
292-
293-
return result | (tmp & 0x7F) << 14;
248+
return PacketEvents.getAPI().getNettyManager().getByteBufOperator().readVarInt(buf);
294249
}
295250

296251
//Src: https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/

api/src/main/java/com/github/retrooper/packetevents/netty/buffer/ByteBufOperator.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package com.github.retrooper.packetevents.netty.buffer;
2020

2121
import java.nio.charset.Charset;
22+
import java.util.Objects;
2223

2324
public interface ByteBufOperator {
2425
int capacity(Object buffer);
@@ -50,6 +51,7 @@ public interface ByteBufOperator {
5051
short getUnsignedByte(Object buffer, int index);
5152

5253
int getIntLE(Object buffer, int readerIndex);
54+
int readVarInt(Object buffer);
5355

5456
boolean isReadable(Object buffer);
5557
Object copy(Object buffer);

netty-common/src/main/java/io/github/retrooper/packetevents/impl/netty/buffer/ByteBufOperatorImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.netty.buffer.ByteBuf;
2323

2424
import java.nio.charset.Charset;
25+
import java.util.Objects;
2526

2627
public class ByteBufOperatorImpl implements ByteBufOperator {
2728
@Override
@@ -104,6 +105,11 @@ public int getIntLE(Object buffer, int readerIndex) {
104105
return ((ByteBuf) buffer).getIntLE(readerIndex);
105106
}
106107

108+
@Override
109+
public int readVarInt(Object buffer) {
110+
return FastNettyUtils.readVarInt((ByteBuf) buffer);
111+
}
112+
107113
@Override
108114
public void writeByte(Object buffer, int value) {
109115
((ByteBuf)buffer).writeByte(value);
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package io.github.retrooper.packetevents.impl.netty.buffer;
2+
3+
import io.netty.buffer.ByteBuf;
4+
5+
public final class FastNettyUtils {
6+
7+
//Src: https://github.com/PaperMC/Velocity/blob/9cfcfcf2ed5712e792114a3ab824670e25e23526/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java#L82
8+
public static int readVarInt(final ByteBuf buf) {
9+
if (buf.readableBytes() < 4)
10+
return readVarIntSmallBuffer(buf);
11+
12+
// take the last three bytes and check if any of them have the high bit set
13+
final int wholeOrMore = buf.getIntLE(buf.readerIndex());
14+
final int atStop = ~wholeOrMore & 0x808080;
15+
if (atStop == 0) throw new IllegalArgumentException("VarInt too big");
16+
17+
final int bitsToKeep = Integer.numberOfTrailingZeros(atStop) + 1;
18+
buf.skipBytes(bitsToKeep >> 3);
19+
20+
// https://github.com/netty/netty/pull/14050#issuecomment-2107750734
21+
int preservedBytes = wholeOrMore & (atStop ^ (atStop - 1));
22+
23+
// https://github.com/netty/netty/pull/14050#discussion_r1597896639
24+
preservedBytes = (preservedBytes & 0x007F007F) | ((preservedBytes & 0x00007F00) >> 1);
25+
preservedBytes = (preservedBytes & 0x00003FFF) | ((preservedBytes & 0x3FFF0000) >> 2);
26+
return preservedBytes;
27+
}
28+
29+
private static int readVarIntSmallBuffer(ByteBuf buf) {
30+
switch (buf.readableBytes()) {
31+
case 3:
32+
return readVarInt3Bytes(buf);
33+
case 2:
34+
return readVarInt2Bytes(buf);
35+
case 1: {
36+
byte val = buf.readByte();
37+
//check if it has the continuation bit set
38+
if ((val & -128) != 0) throw new IllegalArgumentException("VarInt too big for 1 byte");
39+
return val;
40+
}
41+
case 0:
42+
return 0;//I guess 0? Or an Exception?
43+
default:
44+
throw new AssertionError("how");
45+
}
46+
}
47+
48+
private static int readVarInt3Bytes(final ByteBuf buf) {
49+
// Read 3 bytes in little-endian order
50+
final int wholeOrMore = buf.getMediumLE(buf.readerIndex()); // Reads 3 bytes as an int
51+
final int atStop = ~wholeOrMore & 0x808080; // Check for stop bits
52+
53+
// If no stop bits are found, throw an exception
54+
if (atStop == 0) throw new IllegalArgumentException("VarInt too big for 3 bytes");
55+
56+
// Find the position of the first stop bit
57+
final int bitsToKeep = Integer.numberOfTrailingZeros(atStop) + 1;
58+
buf.skipBytes(bitsToKeep >> 3); // Skip the processed bytes
59+
60+
// Extract and preserve the valid bytes
61+
int preservedBytes = wholeOrMore & (atStop ^ (atStop - 1));
62+
63+
// Compact the 7-bit chunks
64+
preservedBytes = (preservedBytes & 0x007F007F) | ((preservedBytes & 0x00007F00) >> 1);
65+
preservedBytes = (preservedBytes & 0x00003FFF) | ((preservedBytes & 0x3FFF0000) >> 2);
66+
67+
return preservedBytes;
68+
}
69+
70+
private static int readVarInt2Bytes(final ByteBuf buf) {
71+
// Read 2 bytes in little-endian order
72+
final int wholeOrMore = buf.getShortLE(buf.readerIndex()); // Reads 2 bytes as an integer
73+
final int atStop = ~wholeOrMore & 0x8080; // Identify stop bits in the two bytes
74+
75+
// If no stop bits are found, the VarInt is too large
76+
if (atStop == 0) throw new IllegalArgumentException("VarInt too big for 2 bytes");
77+
78+
// Find the first stop bit
79+
final int bitsToKeep = Integer.numberOfTrailingZeros(atStop) + 1;
80+
buf.skipBytes(bitsToKeep >> 3); // Skip the number of processed bytes
81+
82+
// Extract and preserve the relevant 7-bit chunks
83+
int preservedBytes = wholeOrMore & (atStop ^ (atStop - 1));
84+
85+
// Compact the 7-bit chunks into a single integer
86+
preservedBytes = (preservedBytes & 0x007F) | ((preservedBytes & 0x7F00) >> 1);
87+
88+
return preservedBytes;
89+
}
90+
91+
}

0 commit comments

Comments
 (0)