Write entire compressed packet at once (#236)

This commit is contained in:
Richard Grover
2023-03-31 19:57:16 -06:00
committed by GitHub
parent 6bbfeec2c7
commit a8f9c4bee5
2 changed files with 52 additions and 88 deletions

View File

@ -63,103 +63,53 @@ func (p *Packet) packWithoutCompression(w io.Writer) error {
VarInt(p.ID).WriteTo(buffer)
buffer.Write(p.Data)
payloadLen := uint32(buffer.Len() - 3)
// Write length at front
payloadLen := VarInt(buffer.Len() - 3)
varIntOffset := 3 - payloadLen.Len()
payloadLen.WriteToBytes(buffer.Bytes()[varIntOffset:])
// Determine where to start writing the header based on the payload size
var headerStart int
if payloadLen <= 0xFF>>1 {
headerStart = 2
} else if payloadLen <= 0xFFFF>>2 {
headerStart = 1
} else if payloadLen <= 0xFFFFFF>>3 {
headerStart = 0
} else {
panic(fmt.Errorf("packet length %d is too large", payloadLen))
}
// Write the packet length at the beginning of the packet
for i := headerStart; payloadLen != 0; i++ {
b := byte(payloadLen & 0b01111111)
payloadLen >>= 7
if payloadLen != 0 {
b |= 0b10000000
}
buffer.Bytes()[i] = b
}
_, err := w.Write(buffer.Bytes()[headerStart:])
_, err := w.Write(buffer.Bytes()[varIntOffset:])
return err
}
func (p *Packet) packWithCompression(w io.Writer, threshold int) error {
buff := bufPool.Get().(*bytes.Buffer)
defer bufPool.Put(buff)
// Allocate room for the 'packet length' and 'data length' fields. Each can take up to 3 bytes
buff.Reset()
buff.Write([]byte{0, 0, 0, 0, 0, 0})
var writeStart int
if len(p.Data) < threshold {
_, err := VarInt(0).WriteTo(buff)
if err != nil {
return err
}
_, err = VarInt(p.ID).WriteTo(buff)
if err != nil {
return err
}
_, err = buff.Write(p.Data)
if err != nil {
return err
}
// Packet Length
_, err = VarInt(buff.Len()).WriteTo(w)
if err != nil {
return err
}
// Data Length + Packet ID + Data
_, err = buff.WriteTo(w)
if err != nil {
return err
}
VarInt(p.ID).WriteTo(buff)
buff.Write(p.Data)
// Packet is below compression threshold so 'data length' is 0
// Front of the packet is already initialized to 0, so just decrement the offset
writeStart = 5
} else {
zw := zlib.NewWriter(buff)
n1, err := VarInt(p.ID).WriteTo(zw)
if err != nil {
return err
}
n2, err := zw.Write(p.Data)
if err != nil {
return err
}
err = zw.Close()
varIntLen, _ := VarInt(p.ID).WriteTo(zw)
zw.Write(p.Data)
err := zw.Close()
if err != nil {
return err
}
dataLength := bufPool.Get().(*bytes.Buffer)
defer bufPool.Put(dataLength)
dataLength.Reset()
n3, err := VarInt(int(n1) + n2).WriteTo(dataLength)
if err != nil {
return err
}
// Packet Length
_, err = VarInt(int(n3) + buff.Len()).WriteTo(w)
if err != nil {
return err
}
// Data Length
_, err = dataLength.WriteTo(w)
if err != nil {
return err
}
// PacketID + Data
_, err = buff.WriteTo(w)
if err != nil {
return err
}
// Write 'data length' before ID + payload
uncompressedLen := VarInt(varIntLen + int64(len(p.Data)))
writeStart = 6 - uncompressedLen.Len()
uncompressedLen.WriteToBytes(buff.Bytes()[writeStart:])
}
return nil
// Write 'packet length' before all other fields
packetLen := VarInt(buff.Len() - writeStart)
start := writeStart - packetLen.Len()
VarInt(packetLen).WriteToBytes(buff.Bytes()[start:])
_, err := w.Write(buff.Bytes()[start:])
return err
}
// UnPack in-place decompression a packet