mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-31 21:48:08 +01:00
Use velocity native compression
This commit is contained in:
parent
85d01e5009
commit
1e817ee4b5
@ -39,6 +39,9 @@ allprojects {
|
||||
name 'sponge'
|
||||
url 'https://repo.spongepowered.org/maven'
|
||||
}
|
||||
maven {
|
||||
url "https://repo.velocitypowered.com/snapshots/"
|
||||
}
|
||||
}
|
||||
javadoc {
|
||||
options {
|
||||
@ -148,6 +151,9 @@ dependencies {
|
||||
api "org.ow2.asm:asm-commons:${asmVersion}"
|
||||
api "org.spongepowered:mixin:${mixinVersion}"
|
||||
|
||||
// Compression
|
||||
implementation "com.velocitypowered:velocity-native:1.1.0-SNAPSHOT"
|
||||
|
||||
// Path finding
|
||||
api 'com.github.MadMartian:hydrazine-path-finding:1.5.4'
|
||||
|
||||
|
@ -16,8 +16,10 @@
|
||||
|
||||
package net.minestom.server.network.netty.codec;
|
||||
|
||||
import com.velocitypowered.natives.compression.VelocityCompressor;
|
||||
import com.velocitypowered.natives.util.MoreByteBufUtils;
|
||||
import com.velocitypowered.natives.util.Natives;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageCodec;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
@ -25,8 +27,6 @@ import net.minestom.server.utils.PacketUtils;
|
||||
import net.minestom.server.utils.Utils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
||||
|
||||
@ -34,8 +34,7 @@ public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
||||
|
||||
private final int threshold;
|
||||
|
||||
private final Deflater deflater = new Deflater();
|
||||
private final Inflater inflater = new Inflater();
|
||||
private final VelocityCompressor compressor = Natives.compress.get().create(4);
|
||||
|
||||
public PacketCompressor(int threshold) {
|
||||
this.threshold = threshold;
|
||||
@ -43,36 +42,38 @@ public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf from, ByteBuf to) {
|
||||
PacketUtils.compressBuffer(deflater, from, to);
|
||||
PacketUtils.compressBuffer(compressor, from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
|
||||
if (buf.readableBytes() != 0) {
|
||||
final int i = Utils.readVarInt(buf);
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
if (in.readableBytes() != 0) {
|
||||
final int claimedUncompressedSize = Utils.readVarInt(in);
|
||||
|
||||
if (i == 0) {
|
||||
out.add(buf.readRetainedSlice(buf.readableBytes()));
|
||||
if (claimedUncompressedSize == 0) {
|
||||
out.add(in.readRetainedSlice(in.readableBytes()));
|
||||
} else {
|
||||
if (i < this.threshold) {
|
||||
throw new DecoderException("Badly compressed packet - size of " + i + " is below server threshold of " + this.threshold);
|
||||
if (claimedUncompressedSize < this.threshold) {
|
||||
throw new DecoderException("Badly compressed packet - size of " + claimedUncompressedSize + " is below server threshold of " + this.threshold);
|
||||
}
|
||||
|
||||
if (i > MAX_SIZE) {
|
||||
throw new DecoderException("Badly compressed packet - size of " + i + " is larger than protocol maximum of " + MAX_SIZE);
|
||||
if (claimedUncompressedSize > MAX_SIZE) {
|
||||
throw new DecoderException("Badly compressed packet - size of " + claimedUncompressedSize + " is larger than protocol maximum of " + MAX_SIZE);
|
||||
}
|
||||
|
||||
// TODO optimize to do not initialize arrays each time
|
||||
|
||||
byte[] input = new byte[buf.readableBytes()];
|
||||
buf.readBytes(input);
|
||||
|
||||
inflater.setInput(input);
|
||||
byte[] output = new byte[i];
|
||||
inflater.inflate(output);
|
||||
inflater.reset();
|
||||
|
||||
out.add(Unpooled.wrappedBuffer(output));
|
||||
ByteBuf compatibleIn = MoreByteBufUtils.ensureCompatible(ctx.alloc(), compressor, in);
|
||||
ByteBuf uncompressed = MoreByteBufUtils.preferredBuffer(ctx.alloc(), compressor, claimedUncompressedSize);
|
||||
try {
|
||||
compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize);
|
||||
out.add(uncompressed);
|
||||
in.clear();
|
||||
} catch (Exception e) {
|
||||
uncompressed.release();
|
||||
throw e;
|
||||
} finally {
|
||||
compatibleIn.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package net.minestom.server.utils;
|
||||
|
||||
import com.velocitypowered.natives.compression.VelocityCompressor;
|
||||
import com.velocitypowered.natives.util.Natives;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
@ -16,9 +18,8 @@ import net.minestom.server.utils.callback.validator.PlayerValidator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
/**
|
||||
* Utils class for packets. Including writing a {@link ServerPacket} into a {@link ByteBuf}
|
||||
@ -27,7 +28,7 @@ import java.util.zip.Deflater;
|
||||
public final class PacketUtils {
|
||||
|
||||
private static final PacketListenerManager PACKET_LISTENER_MANAGER = MinecraftServer.getPacketListenerManager();
|
||||
private static final ThreadLocal<Deflater> DEFLATER = ThreadLocal.withInitial(Deflater::new);
|
||||
private static final ThreadLocal<VelocityCompressor> COMPRESSOR = ThreadLocal.withInitial(() -> Natives.compress.get().create(4));
|
||||
|
||||
private PacketUtils() {
|
||||
|
||||
@ -162,35 +163,27 @@ public final class PacketUtils {
|
||||
* <p>
|
||||
* {@code packetBuffer} needs to be the packet content without any header (if you want to use it to write a Minecraft packet).
|
||||
*
|
||||
* @param deflater the deflater for zlib compression
|
||||
* @param compressor the deflater for zlib compression
|
||||
* @param packetBuffer the buffer containing all the packet fields
|
||||
* @param compressionTarget the buffer which will receive the compressed version of {@code packetBuffer}
|
||||
*/
|
||||
public static void compressBuffer(@NotNull Deflater deflater, @NotNull ByteBuf packetBuffer, @NotNull ByteBuf compressionTarget) {
|
||||
public static void compressBuffer(@NotNull VelocityCompressor compressor, @NotNull ByteBuf packetBuffer, @NotNull ByteBuf compressionTarget) {
|
||||
final int packetLength = packetBuffer.readableBytes();
|
||||
final boolean compression = packetLength > MinecraftServer.getCompressionThreshold();
|
||||
Utils.writeVarIntBuf(compressionTarget, compression ? packetLength : 0);
|
||||
if (compression) {
|
||||
compress(deflater, packetBuffer, compressionTarget);
|
||||
compress(compressor, packetBuffer, compressionTarget);
|
||||
} else {
|
||||
compressionTarget.writeBytes(packetBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
private static void compress(@NotNull Deflater deflater, @NotNull ByteBuf uncompressed, @NotNull ByteBuf compressed) {
|
||||
deflater.setInput(uncompressed.nioBuffer());
|
||||
deflater.finish();
|
||||
|
||||
while (!deflater.finished()) {
|
||||
ByteBuffer nioBuffer = compressed.nioBuffer(compressed.writerIndex(), compressed.writableBytes());
|
||||
compressed.writerIndex(deflater.deflate(nioBuffer) + compressed.writerIndex());
|
||||
|
||||
if (compressed.writableBytes() == 0) {
|
||||
compressed.ensureWritable(8192);
|
||||
}
|
||||
private static void compress(@NotNull VelocityCompressor compressor, @NotNull ByteBuf uncompressed, @NotNull ByteBuf compressed) {
|
||||
try {
|
||||
compressor.deflate(uncompressed, compressed);
|
||||
} catch (DataFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
deflater.reset();
|
||||
}
|
||||
|
||||
public static void writeFramedPacket(@NotNull ByteBuf buffer,
|
||||
@ -212,11 +205,11 @@ public final class PacketUtils {
|
||||
if (packetSize >= compressionThreshold) {
|
||||
// Packet large enough
|
||||
|
||||
final Deflater deflater = DEFLATER.get();
|
||||
final VelocityCompressor compressor = COMPRESSOR.get();
|
||||
// Compress id + payload
|
||||
ByteBuf uncompressedCopy = buffer.copy(contentIndex, packetSize);
|
||||
buffer.writerIndex(contentIndex);
|
||||
compress(deflater, uncompressedCopy, buffer);
|
||||
compress(compressor, uncompressedCopy, buffer);
|
||||
uncompressedCopy.release();
|
||||
|
||||
final int totalPacketLength = buffer.writerIndex() - contentIndex + Utils.VARINT_HEADER_SIZE;
|
||||
|
@ -92,10 +92,8 @@ public class BinaryReader extends InputStream {
|
||||
public String readSizedString(int maxLength) {
|
||||
final int length = readVarInt();
|
||||
Check.stateCondition(length > maxLength,
|
||||
"String length (" + length + ") was higher than the max length of " + maxLength);
|
||||
|
||||
final byte[] bytes = readBytes(length);
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
"String length ({0}) was higher than the max length of {1}", length, maxLength);
|
||||
return buffer.readCharSequence(length, StandardCharsets.UTF_8).toString();
|
||||
}
|
||||
|
||||
public byte[] readBytes(int length) {
|
||||
|
@ -44,4 +44,11 @@ public final class Check {
|
||||
}
|
||||
}
|
||||
|
||||
@Contract("true, _, _ -> fail")
|
||||
public static void stateCondition(boolean condition, @NotNull String reason, Object... arguments) {
|
||||
if (condition) {
|
||||
throw new IllegalStateException(MessageFormat.format(reason, arguments));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user