geforkt von Mirrors/Paper
1044c32a54
When sending chunks to a player we use their writer thread to do chunk compression to avoid blocking the main thread with this work. However, after a teleport or respawn there are a large number of chunk packets to process. This causes the thread to spend a long period handling compression while we continue dumping more chunk packets on it to handle. The result of this is a noticable delay in getting responses to commands and chat immediately after teleporting. Switching to a lower compression level reduces this load and makes our behavior more like vanilla. We do, however, still give this thread more work to do so there will likely still be some delay when comparing to vanilla. The only way to avoid this would be to put chunk compression back on the main thread and give everyone on the server a poorer experience instead.
168 Zeilen
5.0 KiB
Java
168 Zeilen
5.0 KiB
Java
package net.minecraft.server;
|
|
|
|
import java.io.DataInputStream;
|
|
import java.io.DataOutputStream;
|
|
import java.io.IOException;
|
|
import java.util.List;
|
|
import java.util.zip.DataFormatException;
|
|
import java.util.zip.Deflater;
|
|
import java.util.zip.Inflater;
|
|
|
|
public class Packet56MapChunkBulk extends Packet {
|
|
|
|
private int[] c;
|
|
private int[] d;
|
|
public int[] a;
|
|
public int[] b;
|
|
private byte[] buffer;
|
|
private byte[][] inflatedBuffers;
|
|
private int size;
|
|
private byte[] buildBuffer = new byte[0]; // CraftBukkit - remove static
|
|
// CraftBukkit start
|
|
static final ThreadLocal<Deflater> localDeflater = new ThreadLocal<Deflater>() {
|
|
@Override
|
|
protected Deflater initialValue() {
|
|
// Don't use higher compression level, slows things down too much
|
|
return new Deflater(6);
|
|
}
|
|
};
|
|
// CraftBukkit end
|
|
|
|
public Packet56MapChunkBulk() {}
|
|
|
|
public Packet56MapChunkBulk(List list) {
|
|
int i = list.size();
|
|
|
|
this.c = new int[i];
|
|
this.d = new int[i];
|
|
this.a = new int[i];
|
|
this.b = new int[i];
|
|
this.inflatedBuffers = new byte[i][];
|
|
int j = 0;
|
|
|
|
for (int k = 0; k < i; ++k) {
|
|
Chunk chunk = (Chunk) list.get(k);
|
|
ChunkMap chunkmap = Packet51MapChunk.a(chunk, true, '\uffff');
|
|
|
|
if (buildBuffer.length < j + chunkmap.a.length) {
|
|
byte[] abyte = new byte[j + chunkmap.a.length];
|
|
|
|
System.arraycopy(buildBuffer, 0, abyte, 0, buildBuffer.length);
|
|
buildBuffer = abyte;
|
|
}
|
|
|
|
System.arraycopy(chunkmap.a, 0, buildBuffer, j, chunkmap.a.length);
|
|
j += chunkmap.a.length;
|
|
this.c[k] = chunk.x;
|
|
this.d[k] = chunk.z;
|
|
this.a[k] = chunkmap.b;
|
|
this.b[k] = chunkmap.c;
|
|
this.inflatedBuffers[k] = chunkmap.a;
|
|
}
|
|
|
|
/* CraftBukkit start - moved to compress()
|
|
Deflater deflater = new Deflater(-1);
|
|
|
|
try {
|
|
deflater.setInput(buildBuffer, 0, j);
|
|
deflater.finish();
|
|
this.buffer = new byte[j];
|
|
this.size = deflater.deflate(this.buffer);
|
|
} finally {
|
|
deflater.end();
|
|
}
|
|
*/
|
|
}
|
|
|
|
// Add compression method
|
|
public void compress() {
|
|
if (this.buffer != null) {
|
|
return;
|
|
}
|
|
|
|
Deflater deflater = localDeflater.get();
|
|
deflater.reset();
|
|
deflater.setInput(this.buildBuffer);
|
|
deflater.finish();
|
|
|
|
this.buffer = new byte[this.buildBuffer.length + 100];
|
|
this.size = deflater.deflate(this.buffer);
|
|
}
|
|
// CraftBukkit end
|
|
|
|
public void a(DataInputStream datainputstream) throws IOException { // CraftBukkit - throws IOException
|
|
short short1 = datainputstream.readShort();
|
|
|
|
this.size = datainputstream.readInt();
|
|
this.c = new int[short1];
|
|
this.d = new int[short1];
|
|
this.a = new int[short1];
|
|
this.b = new int[short1];
|
|
this.inflatedBuffers = new byte[short1][];
|
|
if (buildBuffer.length < this.size) {
|
|
buildBuffer = new byte[this.size];
|
|
}
|
|
|
|
datainputstream.readFully(buildBuffer, 0, this.size);
|
|
byte[] abyte = new byte[196864 * short1];
|
|
Inflater inflater = new Inflater();
|
|
|
|
inflater.setInput(buildBuffer, 0, this.size);
|
|
|
|
try {
|
|
inflater.inflate(abyte);
|
|
} catch (DataFormatException dataformatexception) {
|
|
throw new IOException("Bad compressed data format");
|
|
} finally {
|
|
inflater.end();
|
|
}
|
|
|
|
int i = 0;
|
|
|
|
for (int j = 0; j < short1; ++j) {
|
|
this.c[j] = datainputstream.readInt();
|
|
this.d[j] = datainputstream.readInt();
|
|
this.a[j] = datainputstream.readShort();
|
|
this.b[j] = datainputstream.readShort();
|
|
int k = 0;
|
|
|
|
int l;
|
|
|
|
for (l = 0; l < 16; ++l) {
|
|
k += this.a[j] >> l & 1;
|
|
}
|
|
|
|
l = 2048 * 5 * k + 256;
|
|
this.inflatedBuffers[j] = new byte[l];
|
|
System.arraycopy(abyte, i, this.inflatedBuffers[j], 0, l);
|
|
i += l;
|
|
}
|
|
}
|
|
|
|
public void a(DataOutputStream dataoutputstream) throws IOException { // CraftBukkit - throws IOException
|
|
compress(); // CraftBukkit
|
|
dataoutputstream.writeShort(this.c.length);
|
|
dataoutputstream.writeInt(this.size);
|
|
dataoutputstream.write(this.buffer, 0, this.size);
|
|
|
|
for (int i = 0; i < this.c.length; ++i) {
|
|
dataoutputstream.writeInt(this.c[i]);
|
|
dataoutputstream.writeInt(this.d[i]);
|
|
dataoutputstream.writeShort((short) (this.a[i] & '\uffff'));
|
|
dataoutputstream.writeShort((short) (this.b[i] & '\uffff'));
|
|
}
|
|
}
|
|
|
|
public void handle(NetHandler nethandler) {
|
|
nethandler.a(this);
|
|
}
|
|
|
|
public int a() {
|
|
return 6 + this.size + 12 * this.d();
|
|
}
|
|
|
|
public int d() {
|
|
return this.c.length;
|
|
}
|
|
}
|