Using the Set Compression packet in the PLAY protocol ( http://wiki.vg/Pre-release_protocol#Set_Compression ) causes the client to disconnect with "go cannot be cast to gp" which seems to be the client trying to cast the inflater decoder to the deflator encoder.
Even though this packet isn't used in vanilla it was added to help out modded/custom implementations
Linked issues
is duplicated by 1
Attachments
Comments 12
MonsieurApple, there was a miscommunication, we don't have a set of rules. However we generally resolve tickets that are issues with non vanilla environments as invalid.
Found the reason for this bug in 1.8 based on MC-69481 (decompiled using MCP):
Error message without fix
[19:13:43] [Server thread/INFO]: Player493 lost connection: TranslatableComponent{key='disconnect.genericReason', args=[Internal Exception: java.lang.ClassCastException: net.minecraft.network.NettyCompressionDecoder cannot be cast to net.minecraft.network.NettyCompressionEncoder], siblings=[], style=Style{hasParent=false, color=null, bold=null, italic=null, underlined=null, obfuscated=null, clickEvent=null, hoverEvent=null, insertion=null}}
The problem is in the net.minecraft.network.NetworkManager
class in both server and client.
Possible fix (1.8, MCP)
public void setCompressionTreshold(int treshold)
{
if (treshold >= 0)
{
if (this.channel.pipeline().get("decompress") instanceof NettyCompressionDecoder)
{
((NettyCompressionDecoder)this.channel.pipeline().get("decompress")).setCompressionTreshold(treshold);
}
else
{
this.channel.pipeline().addBefore("decoder", "decompress", new NettyCompressionDecoder(treshold));
}
if (this.channel.pipeline().get("compress") instanceof NettyCompressionEncoder)
{
// TODO DEBUG
// ((NettyCompressionEncoder)this.channel.pipeline().get("decompress")).setCompressionTreshold(treshold);
((NettyCompressionEncoder)this.channel.pipeline().get("compress")).setCompressionTreshold(treshold);
}
else
{
this.channel.pipeline().addBefore("encoder", "compress", new NettyCompressionEncoder(treshold));
}
}
else
{
if (this.channel.pipeline().get("decompress") instanceof NettyCompressionDecoder)
{
this.channel.pipeline().remove("decompress");
}
if (this.channel.pipeline().get("compress") instanceof NettyCompressionEncoder)
{
this.channel.pipeline().remove("compress");
}
}
}
However after applying the fix there is another error:
Error message after fix
[19:33:00] [Server thread/INFO]: Player431 lost connection: TranslatableComponent{key='disconnect.genericReason', args=[Internal Exception: io.netty.handler.codec.DecoderException: Badly compressed packet - size of 2 is below server threshold of 512], siblings=[], style=Style{hasParent=false, color=null, bold=null, italic=null, underlined=null, obfuscated=null, clickEvent=null, hoverEvent=null, insertion=null}}
Compression is two way, changing the threshold causes both the client and the server to start using it. The issue comes in when this case happens:
Set compression (sent by server) -> 150 ms delay due to lag. The client can send a lot of packets (movement, interacts etc) during that window and they'll be sent with the old compression threshold until the client gets the packet. The server has no way of knowing when the client has started to use the new threshold.
Found the reason for the second bug, please add the following fix and the fix mentioned before to the description.
The second bug is caused by the net.minecraft.network.play.server.S46PacketSetCompressionLevel
(1.8 MCP name) in both server and client. This packet contains a attribute called field_179761_a
(which is the compressionLevel) however when a S46PacketSetCompressionLevel
packet is created the compressionLevel
(int) is never set and so defaults to 0 causing all following packets to get the wrong size.
A possible fix would be to add a constructor that sets for the compressionLevel
the current compression level of the server:
Possible fix for Server and Client (1.8, MCP)
/**
* TODO DEBUG Experimental constructor of this packet
*/
public S46PacketSetCompressionLevel() {
compressionLevel = MinecraftServer.getServer().getNetworkCompressionTreshold();
}
Please include both fixes and @unknowns race condition warning:
That's up to @unknown - it's his ticket and he's much more knowledgeable on this topic than either of us.
Another issue with the packet from IRC:
<Drainedsoul> I don't understand how the play version is useful
<Drainedsoul> given that there's – as far as I know – no acknowledgement, how can you prevent race conditions?
<Drainedsoul> adjusting the compression on the fly could make in flight, valid compressed/decompressed packets suddenly erroneous when received