13
0
geforkt von Mirrors/Velocity

Add highly-optimized VarInt writing method

Dieser Commit ist enthalten in:
Andrew Steinborn 2021-05-08 23:26:43 -04:00
Ursprung 6369a95ec9
Commit 150fd9a9cf
3 geänderte Dateien mit 16 neuen und 20 gelöschten Zeilen

Datei anzeigen

@ -120,7 +120,7 @@ public enum ProtocolUtils {
* @param value the integer to write * @param value the integer to write
*/ */
public static void writeVarInt(ByteBuf buf, int value) { public static void writeVarInt(ByteBuf buf, int value) {
// Optimization: focus on 1-3 byte VarInts as they are the most common // See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
if ((value & (0xFFFFFFFF << 7)) == 0) { if ((value & (0xFFFFFFFF << 7)) == 0) {
buf.writeByte(value); buf.writeByte(value);
} else if ((value & (0xFFFFFFFF << 14)) == 0) { } else if ((value & (0xFFFFFFFF << 14)) == 0) {
@ -129,30 +129,26 @@ public enum ProtocolUtils {
} else if ((value & (0xFFFFFFFF << 21)) == 0) { } else if ((value & (0xFFFFFFFF << 21)) == 0) {
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14); int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
buf.writeMedium(w); buf.writeMedium(w);
} else if ((value & (0xFFFFFFFF << 28)) == 0) {
int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16)
| ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21);
buf.writeInt(w);
} else { } else {
// 4 and 5 byte VarInts aren't common so split those cases off int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16
writeVarIntUncommon(buf, value); | ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80);
} buf.writeInt(w);
} buf.writeByte(value >>> 28);
private static void writeVarIntUncommon(ByteBuf buf, int value) {
while (true) {
if ((value & 0xFFFFFF80) == 0) {
buf.writeByte(value);
return;
}
buf.writeByte(value & 0x7F | 0x80);
value >>>= 7;
} }
} }
/** /**
* Writes all integers as 3 bytes Minecraft-style VarInt to the specified {@code buf}. * Writes the specified {@code value} as a 21-bit Minecraft VarInt to the specified {@code buf}.
* The upper 11 bits will be discarded.
* @param buf the buffer to read from * @param buf the buffer to read from
* @param value the integer to write * @param value the integer to write
*/ */
public static void writeVarIntAs3Bytes(ByteBuf buf, int value) { public static void write21BitVarInt(ByteBuf buf, int value) {
// See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14); int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
buf.writeMedium(w); buf.writeMedium(w);
} }

Datei anzeigen

@ -61,7 +61,7 @@ public class MinecraftCompressorAndLengthEncoder extends MessageToByteEncoder<By
throws DataFormatException { throws DataFormatException {
int uncompressed = msg.readableBytes(); int uncompressed = msg.readableBytes();
ProtocolUtils.writeVarIntAs3Bytes(out, 0); // Dummy packet length ProtocolUtils.write21BitVarInt(out, 0); // Dummy packet length
ProtocolUtils.writeVarInt(out, uncompressed); ProtocolUtils.writeVarInt(out, uncompressed);
ByteBuf compatibleIn = MoreByteBufUtils.ensureCompatible(ctx.alloc(), compressor, msg); ByteBuf compatibleIn = MoreByteBufUtils.ensureCompatible(ctx.alloc(), compressor, msg);
@ -81,7 +81,7 @@ public class MinecraftCompressorAndLengthEncoder extends MessageToByteEncoder<By
int writerIndex = out.writerIndex(); int writerIndex = out.writerIndex();
int packetLength = out.readableBytes() - 3; int packetLength = out.readableBytes() - 3;
out.writerIndex(0); out.writerIndex(0);
ProtocolUtils.writeVarIntAs3Bytes(out, packetLength); // Rewrite packet length ProtocolUtils.write21BitVarInt(out, packetLength); // Rewrite packet length
out.writerIndex(writerIndex); out.writerIndex(writerIndex);
} }

Datei anzeigen

@ -81,7 +81,7 @@ public class ProtocolUtilsTest {
private void writeReadTest3Bytes(ByteBuf buf, int test) { private void writeReadTest3Bytes(ByteBuf buf, int test) {
buf.clear(); buf.clear();
ProtocolUtils.writeVarIntAs3Bytes(buf, test); ProtocolUtils.write21BitVarInt(buf, test);
assertEquals(test, ProtocolUtils.readVarInt(buf)); assertEquals(test, ProtocolUtils.readVarInt(buf));
} }