// Path: src/main/java/com/md_5/fondue/protocol/PacketHandler.java
// public abstract class PacketHandler {
// 
//     /**
//      * Method to determine whether this is a server handler, client handler or
//      * other.
//      *
//      * @return the type of method interface this handler should accept
//      */
//     public abstract Class<? extends Annotation> getType();
// 
//     @Server
//     public void handle(Packet0KeepAlive packet) {
//     }
// 
//     @ServerLogin
//     public void handle(Packet2Handshake packet) {
//     }
// 
//     @Server
//     public void handle(Packet3ChatMessage packet) {
//     }
// 
//     @Server
//     public void handle(Packet7UseEntity packet) {
//     }
// 
//     @Server
//     public void handle(PacketAFlying packet) {
//     }
// 
//     @Server
//     public void handle(PacketEDig packet) {
//     }
//     // @Server
//     // public  void handle(PacketFPlace packet){}
// 
//     @Server
//     public void handle(Packet10HeldItem packet) {
//     }
// 
//     @Server
//     public void handle(Packet12Animation packet) {
//     }
// 
//     @Server
//     public void handle(Packet13EntityAction packet) {
//     }
//     // @Server
//     // public  void handle(Packet66WindowClick packet){}
// 
//     @Server
//     public void handle(Packet6AConfirmTransaction packet) {
//     }
// 
//     @Server
//     public void handle(Packet6CEnchantItem packet) {
//     }
// 
//     @Server
//     public void handle(Packet82UpdateSign packet) {
//     }
// 
//     // @Server
//     // public  void handle(Packet6BSlot);
//     @Server
//     public void handle(PacketCAPlayerAbilities packet) {
//     }
// 
//     @Server
//     public void handle(PacketCBTabComplete packet) {
//     }
// 
//     @Server
//     public void handle(PacketCCClientInfo packet) {
//     }
// 
//     @Server
//     @ServerLogin
//     public void handle(PacketCDClientStatus packet) {
//     }
// 
//     @Server
//     public void handle(PacketFAPluginMessage packet) {
//     }
// 
//     @ServerLogin
//     public void handle(PacketFCKeyResponse packet) {
//     }
// 
//     @ServerLogin
//     public void handle(PacketFEServerPing packet) {
//     }
// 
//     @Server
//     public void handle(PacketFFDisconnect packet) {
//     }
// 
//     /**
//      * Methods denoted by this annotation should be handled by a server
//      * implementation of this class
//      */
//     @Target(ElementType.METHOD)
//     @Retention(RetentionPolicy.RUNTIME)
//     protected @interface Server {
//     }
// 
//     /**
//      * Methods denoted by this annotation should be handled by the initial
//      * server implementation of this class.
//      */
//     @Target(ElementType.METHOD)
//     @Retention(RetentionPolicy.RUNTIME)
//     protected @interface ServerLogin {
//     }
// 
//     /**
//      * Methods denoted by this method annotation be handled by a client
//      * implementation of this class
//      */
//     @Target(ElementType.METHOD)
//     @Retention(RetentionPolicy.RUNTIME)
//     protected @interface Client {
//     }
// }


import com.md_5.fondue.protocol.PacketHandler;
import gnu.trove.map.hash.TObjectIntHashMap;
import io.netty.buffer.ByteBuf;
import org.apache.commons.lang3.Validate;
package com.md_5.fondue.protocol.packet;


public abstract class Packet {

    private static final Class[] byId = new Class[256];
    private static final TObjectIntHashMap<Class<? extends Packet>> byClass = new TObjectIntHashMap<Class<? extends Packet>>();
    private int id = -1;

    /**
     * Adds a new packet class to the known packet collections
     *
     * @param id of the packet to add
     * @param clazz of the packet
     */
    private static void addMapping(int id, Class<? extends Packet> clazz) {
        Validate.isTrue(byId[id] == null, "Packet with id 0x" + Integer.toHexString(id) + " already registered");
        Validate.isTrue(!byClass.containsKey(clazz), "Class " + clazz.getName() + " already registered");

        byId[id] = clazz;
        byClass.put(clazz, id);
    }

    /**
     * Constructs a new, empty packet based on the supplied id.
     *
     * @param id of the packet to construct
     * @return the constructed packet or null if unable to construct one
     */
    public static Packet newInstance(int id) {
        try {
            Class clazz = byId[id];
            return clazz == null ? null : (Packet) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception ex) {
            ex.printStackTrace();
            System.err.println("Skipping packet with id 0x" + Integer.toHexString(id));
            return null;
        }
    }

    /**
     * @return this packet's id
     */
    public final int getId() {
        return (id == -1) ? id = byClass.get(id) : id;
    }

    /**
     * Populates the fields in this packet by reading them from the specified
     * {@link ByteBuf}
     *
     * @param in the ByteBuf to read from
     */
    public abstract void read(ByteBuf in);

    /**
     * Writes the fields in this packet to the specified {@link ByteBuf}.
     *
     * @param out the ByteBuf to write into
     */
    public abstract void write(ByteBuf out);

    /**
     * Handle this method with a given handler. This is a must for performance
     * reasons.
     *
     * @param handler the handler to handle this packet
     */
// Path: src/main/java/com/md_5/fondue/protocol/PacketHandler.java
// public abstract class PacketHandler {
// 
//     /**
//      * Method to determine whether this is a server handler, client handler or
//      * other.
//      *
//      * @return the type of method interface this handler should accept
//      */
//     public abstract Class<? extends Annotation> getType();
// 
//     @Server
//     public void handle(Packet0KeepAlive packet) {
//     }
// 
//     @ServerLogin
//     public void handle(Packet2Handshake packet) {
//     }
// 
//     @Server
//     public void handle(Packet3ChatMessage packet) {
//     }
// 
//     @Server
//     public void handle(Packet7UseEntity packet) {
//     }
// 
//     @Server
//     public void handle(PacketAFlying packet) {
//     }
// 
//     @Server
//     public void handle(PacketEDig packet) {
//     }
//     // @Server
//     // public  void handle(PacketFPlace packet){}
// 
//     @Server
//     public void handle(Packet10HeldItem packet) {
//     }
// 
//     @Server
//     public void handle(Packet12Animation packet) {
//     }
// 
//     @Server
//     public void handle(Packet13EntityAction packet) {
//     }
//     // @Server
//     // public  void handle(Packet66WindowClick packet){}
// 
//     @Server
//     public void handle(Packet6AConfirmTransaction packet) {
//     }
// 
//     @Server
//     public void handle(Packet6CEnchantItem packet) {
//     }
// 
//     @Server
//     public void handle(Packet82UpdateSign packet) {
//     }
// 
//     // @Server
//     // public  void handle(Packet6BSlot);
//     @Server
//     public void handle(PacketCAPlayerAbilities packet) {
//     }
// 
//     @Server
//     public void handle(PacketCBTabComplete packet) {
//     }
// 
//     @Server
//     public void handle(PacketCCClientInfo packet) {
//     }
// 
//     @Server
//     @ServerLogin
//     public void handle(PacketCDClientStatus packet) {
//     }
// 
//     @Server
//     public void handle(PacketFAPluginMessage packet) {
//     }
// 
//     @ServerLogin
//     public void handle(PacketFCKeyResponse packet) {
//     }
// 
//     @ServerLogin
//     public void handle(PacketFEServerPing packet) {
//     }
// 
//     @Server
//     public void handle(PacketFFDisconnect packet) {
//     }
// 
//     /**
//      * Methods denoted by this annotation should be handled by a server
//      * implementation of this class
//      */
//     @Target(ElementType.METHOD)
//     @Retention(RetentionPolicy.RUNTIME)
//     protected @interface Server {
//     }
// 
//     /**
//      * Methods denoted by this annotation should be handled by the initial
//      * server implementation of this class.
//      */
//     @Target(ElementType.METHOD)
//     @Retention(RetentionPolicy.RUNTIME)
//     protected @interface ServerLogin {
//     }
// 
//     /**
//      * Methods denoted by this method annotation be handled by a client
//      * implementation of this class
//      */
//     @Target(ElementType.METHOD)
//     @Retention(RetentionPolicy.RUNTIME)
//     protected @interface Client {
//     }
// }


// Path: src/main/java/com/md_5/fondue/protocol/packet/Packet.java
import com.md_5.fondue.protocol.PacketHandler;
import gnu.trove.map.hash.TObjectIntHashMap;
import io.netty.buffer.ByteBuf;
import org.apache.commons.lang3.Validate;

package com.md_5.fondue.protocol.packet;


public abstract class Packet {

    private static final Class[] byId = new Class[256];
    private static final TObjectIntHashMap<Class<? extends Packet>> byClass = new TObjectIntHashMap<Class<? extends Packet>>();
    private int id = -1;

    /**
     * Adds a new packet class to the known packet collections
     *
     * @param id of the packet to add
     * @param clazz of the packet
     */
    private static void addMapping(int id, Class<? extends Packet> clazz) {
        Validate.isTrue(byId[id] == null, "Packet with id 0x" + Integer.toHexString(id) + " already registered");
        Validate.isTrue(!byClass.containsKey(clazz), "Class " + clazz.getName() + " already registered");

        byId[id] = clazz;
        byClass.put(clazz, id);
    }

    /**
     * Constructs a new, empty packet based on the supplied id.
     *
     * @param id of the packet to construct
     * @return the constructed packet or null if unable to construct one
     */
    public static Packet newInstance(int id) {
        try {
            Class clazz = byId[id];
            return clazz == null ? null : (Packet) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception ex) {
            ex.printStackTrace();
            System.err.println("Skipping packet with id 0x" + Integer.toHexString(id));
            return null;
        }
    }

    /**
     * @return this packet's id
     */
    public final int getId() {
        return (id == -1) ? id = byClass.get(id) : id;
    }

    /**
     * Populates the fields in this packet by reading them from the specified
     * {@link ByteBuf}
     *
     * @param in the ByteBuf to read from
     */
    public abstract void read(ByteBuf in);

    /**
     * Writes the fields in this packet to the specified {@link ByteBuf}.
     *
     * @param out the ByteBuf to write into
     */
    public abstract void write(ByteBuf out);

    /**
     * Handle this method with a given handler. This is a must for performance
     * reasons.
     *
     * @param handler the handler to handle this packet
     */
    public abstract void handle(PacketHandler handler);