Skip to content

Commit

Permalink
Done
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowOfHeaven committed Nov 28, 2024
1 parent f51c1b5 commit 94d4d80
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -244,53 +244,8 @@ public static int getIntLE(Object buffer, int readerIndex) {
return PacketEvents.getAPI().getNettyManager().getByteBufOperator().getIntLE(buffer, readerIndex);
}

//Src: https://github.com/jonesdevelopment/sonar/blob/main/common/src/main/java/xyz/jonesdev/sonar/common/fallback/netty/FallbackVarInt21FrameDecoder.java#L69
public static int readVarInt(Object buf) {
if (readableBytes(buf) < 4) return readVarIntSmallBuffer(buf);

// take the last three bytes and check if any of them have the high bit set
int wholeOrMore = getIntLE(buf, readerIndex(buf));
int atStop = ~wholeOrMore & 0x808080;
if (atStop == 0) throw new RuntimeException("fucked up - VarInt too big");

final int bitsToKeep = Integer.numberOfTrailingZeros(atStop) + 1;
skipBytes(buf, bitsToKeep >> 3);

// https://github.com/netty/netty/pull/14050#issuecomment-2107750734
int preservedBytes = wholeOrMore & (atStop ^ (atStop - 1));

// https://github.com/netty/netty/pull/14050#discussion_r1597896639
preservedBytes = (preservedBytes & 0x007F007F) | ((preservedBytes & 0x00007F00) >> 1);
preservedBytes = (preservedBytes & 0x00003FFF) | ((preservedBytes & 0x3FFF0000) >> 2);
return preservedBytes;
}

//fallback to unrolled loop
//I'll try to optimize this in the future
private static int readVarIntSmallBuffer(Object buf) {
if (!isReadable(buf)) return 0;

int rIdx = readerIndex(buf);

byte tmp = readByte(buf);
if (tmp >= 0) return tmp;

int result = tmp & 0x7F;
if (!isReadable(buf)) {
readerIndex(buf, rIdx);
return 0;
}

if ((tmp = readByte(buf)) >= 0) return result | tmp << 7;

result |= (tmp & 0x7F) << 7;
if (!isReadable(buf)) {
readerIndex(buf, rIdx);
return 0;
}
if ((tmp = readByte(buf)) >= 0) return result | tmp << 14;

return result | (tmp & 0x7F) << 14;
return PacketEvents.getAPI().getNettyManager().getByteBufOperator().readVarInt(buf);
}

//Src: https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package com.github.retrooper.packetevents.netty.buffer;

import java.nio.charset.Charset;
import java.util.Objects;

public interface ByteBufOperator {
int capacity(Object buffer);
Expand Down Expand Up @@ -50,6 +51,7 @@ public interface ByteBufOperator {
short getUnsignedByte(Object buffer, int index);

int getIntLE(Object buffer, int readerIndex);
int readVarInt(Object buffer);

boolean isReadable(Object buffer);
Object copy(Object buffer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.netty.buffer.ByteBuf;

import java.nio.charset.Charset;
import java.util.Objects;

public class ByteBufOperatorImpl implements ByteBufOperator {
@Override
Expand Down Expand Up @@ -104,6 +105,11 @@ public int getIntLE(Object buffer, int readerIndex) {
return ((ByteBuf) buffer).getIntLE(readerIndex);
}

@Override
public int readVarInt(Object buffer) {
return FastNettyUtils.readVarInt((ByteBuf) buffer);
}

@Override
public void writeByte(Object buffer, int value) {
((ByteBuf)buffer).writeByte(value);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package io.github.retrooper.packetevents.impl.netty.buffer;

import io.netty.buffer.ByteBuf;

public final class FastNettyUtils {

//Src: https://github.com/PaperMC/Velocity/blob/9cfcfcf2ed5712e792114a3ab824670e25e23526/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java#L82
public static int readVarInt(final ByteBuf buf) {
if (buf.readableBytes() < 4)
return readVarIntSmallBuffer(buf);

// take the last three bytes and check if any of them have the high bit set
final int wholeOrMore = buf.getIntLE(buf.readerIndex());
final int atStop = ~wholeOrMore & 0x808080;
if (atStop == 0) throw new IllegalArgumentException("VarInt too big");

final int bitsToKeep = Integer.numberOfTrailingZeros(atStop) + 1;
buf.skipBytes(bitsToKeep >> 3);

// https://github.com/netty/netty/pull/14050#issuecomment-2107750734
int preservedBytes = wholeOrMore & (atStop ^ (atStop - 1));

// https://github.com/netty/netty/pull/14050#discussion_r1597896639
preservedBytes = (preservedBytes & 0x007F007F) | ((preservedBytes & 0x00007F00) >> 1);
preservedBytes = (preservedBytes & 0x00003FFF) | ((preservedBytes & 0x3FFF0000) >> 2);
return preservedBytes;
}

private static int readVarIntSmallBuffer(ByteBuf buf) {
switch (buf.readableBytes()) {
case 3:
return readVarInt3Bytes(buf);
case 2:
return readVarInt2Bytes(buf);
case 1: {
byte val = buf.readByte();
//check if it has the continuation bit set
if ((val & -128) != 0) throw new IllegalArgumentException("VarInt too big for 1 byte");
return val;
}
case 0:
return 0;//I guess 0? Or an Exception?
default:
throw new AssertionError("how");
}
}

private static int readVarInt3Bytes(final ByteBuf buf) {
// Read 3 bytes in little-endian order
final int wholeOrMore = buf.getMediumLE(buf.readerIndex()); // Reads 3 bytes as an int
final int atStop = ~wholeOrMore & 0x808080; // Check for stop bits

// If no stop bits are found, throw an exception
if (atStop == 0) throw new IllegalArgumentException("VarInt too big for 3 bytes");

// Find the position of the first stop bit
final int bitsToKeep = Integer.numberOfTrailingZeros(atStop) + 1;
buf.skipBytes(bitsToKeep >> 3); // Skip the processed bytes

// Extract and preserve the valid bytes
int preservedBytes = wholeOrMore & (atStop ^ (atStop - 1));

// Compact the 7-bit chunks
preservedBytes = (preservedBytes & 0x007F007F) | ((preservedBytes & 0x00007F00) >> 1);
preservedBytes = (preservedBytes & 0x00003FFF) | ((preservedBytes & 0x3FFF0000) >> 2);

return preservedBytes;
}

private static int readVarInt2Bytes(final ByteBuf buf) {
// Read 2 bytes in little-endian order
final int wholeOrMore = buf.getShortLE(buf.readerIndex()); // Reads 2 bytes as an integer
final int atStop = ~wholeOrMore & 0x8080; // Identify stop bits in the two bytes

// If no stop bits are found, the VarInt is too large
if (atStop == 0) throw new IllegalArgumentException("VarInt too big for 2 bytes");

// Find the first stop bit
final int bitsToKeep = Integer.numberOfTrailingZeros(atStop) + 1;
buf.skipBytes(bitsToKeep >> 3); // Skip the number of processed bytes

// Extract and preserve the relevant 7-bit chunks
int preservedBytes = wholeOrMore & (atStop ^ (atStop - 1));

// Compact the 7-bit chunks into a single integer
preservedBytes = (preservedBytes & 0x007F) | ((preservedBytes & 0x7F00) >> 1);

return preservedBytes;
}

}
Loading

0 comments on commit 94d4d80

Please sign in to comment.