package us.myles.ViaVersion.handlers;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.transformers.IncomingTransformer;
import us.myles.ViaVersion.util.PacketUtil;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

public class ViaDecodeHandler extends ByteToMessageDecoder {

    private final IncomingTransformer incomingTransformer;
    private final ByteToMessageDecoder minecraftDecoder;
    private final ConnectionInfo info;

    public ViaDecodeHandler(ConnectionInfo info, ByteToMessageDecoder minecraftDecoder) {
        this.info = info;
        this.minecraftDecoder = minecraftDecoder;
        this.incomingTransformer = new IncomingTransformer(info);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
        // use transformers
        if (bytebuf.readableBytes() > 0) {
            if (info.isActive()) {
                int id = PacketUtil.readVarInt(bytebuf);
                // Transform
                ByteBuf newPacket = ctx.alloc().buffer();
                try {
                    incomingTransformer.transform(id, bytebuf, newPacket);
                    bytebuf.clear();
                    bytebuf = newPacket;
                } catch (Exception e) {
                    bytebuf.clear();
                    throw e;
                }
            }
            // call minecraft decoder
            try {
                list.addAll(PacketUtil.callDecode(this.minecraftDecoder, ctx, bytebuf));
            } catch (InvocationTargetException e) {
                if (e.getCause() instanceof Exception) {
                    throw (Exception) e.getCause();
                }
            } finally {
                if (info.isActive()) {
                    bytebuf.release();
                }
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (PacketUtil.containsCause(cause, CancelException.class)) return;
        super.exceptionCaught(ctx, cause);
    }
}

@@ -1381,33 +1381,113 @@
      bytebuf
-.clear();
+ = newPacket;%0A                %7D catch (Exception e) %7B%0A                    // Clear Buffer
 %0A           
@@ -1498,36 +1498,32 @@
      bytebuf
- = newPacket
+.clear()
 ;%0A          
@@ -1528,39 +1528,47 @@
         
-%7D catch (Exception e) %7B
+    // Release Packet, be free!
 %0A       
@@ -1576,37 +1576,41 @@
             
-bytebuf.clear
+newPacket.release
 ();%0A        

Fix chance of another leak happening...