// Path: src/main/java/net/techcable/spudcompat/ProtocolVersion.java
// @RequiredArgsConstructor
// public enum ProtocolVersion {
//     v1_7_10(5),
//     v1_8(47);
// 
//     public boolean isBefore(ProtocolVersion other) {
//         return this.getId() < other.getId();
//     }
// 
//     private final int versionNumber;
// 
//     public int getId() {
//         return versionNumber;
//     }
// 
//     public static final int MAX_ID;
//     private static final ProtocolVersion[] BY_ID;
// 
//     static {
//         int maxId = 0;
//         for (ProtocolVersion version : values()) {
//             if (version.getId() > maxId) {
//                 maxId = version.getId();
//             }
//         }
//         MAX_ID = maxId;
//         BY_ID = new ProtocolVersion[MAX_ID + 1];
//         for (ProtocolVersion version : values()) {
//             int id = version.getId();
//             if (BY_ID[id] != null) throw new AssertionError("Already a version with id: " + id);
//             BY_ID[id] = version;
//         }
//     }
// 
//     public static ProtocolVersion getById(int id) {
//         if (id < 0) {
//             throw new IllegalArgumentException("Negative id: " + id);
//         } else if (id < BY_ID.length) {
//             return BY_ID[id];
//         } else {
//             return null;
//         }
//     }
// }
// 
// Path: src/main/java/net/techcable/spudcompat/protocol/injector/RawPacket.java
// @Getter
// public class RawPacket extends AbstractReferenceCounted {
//     private final ByteBuf allData;
//     private final ByteBuf packetData;
//     private final int id;
//     private final ProtocolState protocolState;
//     private final ProtocolDirection direction;
//     private final PacketType type;
// 
//     private RawPacket(ByteBuf allData, ByteBuf packetData, int id, ProtocolState protocolState, ProtocolDirection direction) {
//         this.allData = allData.retain();
//         this.packetData = packetData.retain();
//         this.id = id;
//         this.protocolState = checkNotNull(protocolState, "Null state");
//         this.direction = checkNotNull(direction, "Null direction");
//         this.type = PacketType.getById(id, protocolState, direction);
//     }
// 
//     public ByteBuf getAllData() {
//         assertValid();
//         return allData;
//     }
// 
//     public ByteBuf getPacketData() {
//         assertValid();
//         return packetData;
//     }
// 
// 
//     public boolean isKnownType() {
//         return getType() != null;
//     }
// 
//     public static RawPacket fromWrapper(PacketWrapper wrapper, ProtocolState protocolState, ProtocolDirection direction) {
//         return fromBuffer(checkNotNull(wrapper, "Null wrapper").buf, protocolState, direction);
//     }
// 
//     public static RawPacket fromBuffer(ByteBuf buf, ProtocolState protocolState, ProtocolDirection direction) {
//         checkNotNull(buf, "Null buffer");
//         checkNotNull(protocolState, "Null state");
//         checkNotNull(direction, "Null direction");
//         buf = Unpooled.unmodifiableBuffer(buf.duplicate()); // Read-only
//         ByteBuf allData = buf.duplicate();
//         int id = DefinedPacket.readVarInt(buf);
//         return new RawPacket(allData, buf.slice(), id, protocolState, direction);
//     }
// 
//     @Override
//     protected void deallocate() {
//         allData.release();
//         packetData.release();
//     }
// 
//     private void assertValid() {
//         if (refCnt() <= 0) throw new IllegalReferenceCountException("Packet deallocated");
//     }
// }


import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import net.md_5.bungee.api.connection.Connection;
import net.techcable.spudcompat.ProtocolVersion;
import net.techcable.spudcompat.protocol.injector.RawPacket;
package net.techcable.spudcompat.protocol;



public interface Packet {
    public PacketType getType();

    public void write(ByteBuf buf, ProtocolVersion version, ProtocolState state, ProtocolDirection direction);

    public default RawPacket toRaw(ByteBufAllocator allocator, ProtocolVersion version, ProtocolState state, ProtocolDirection direction) {
        ByteBuf buf = allocator.buffer();
        write(buf, version, state, direction);
// Path: src/main/java/net/techcable/spudcompat/ProtocolVersion.java
// @RequiredArgsConstructor
// public enum ProtocolVersion {
//     v1_7_10(5),
//     v1_8(47);
// 
//     public boolean isBefore(ProtocolVersion other) {
//         return this.getId() < other.getId();
//     }
// 
//     private final int versionNumber;
// 
//     public int getId() {
//         return versionNumber;
//     }
// 
//     public static final int MAX_ID;
//     private static final ProtocolVersion[] BY_ID;
// 
//     static {
//         int maxId = 0;
//         for (ProtocolVersion version : values()) {
//             if (version.getId() > maxId) {
//                 maxId = version.getId();
//             }
//         }
//         MAX_ID = maxId;
//         BY_ID = new ProtocolVersion[MAX_ID + 1];
//         for (ProtocolVersion version : values()) {
//             int id = version.getId();
//             if (BY_ID[id] != null) throw new AssertionError("Already a version with id: " + id);
//             BY_ID[id] = version;
//         }
//     }
// 
//     public static ProtocolVersion getById(int id) {
//         if (id < 0) {
//             throw new IllegalArgumentException("Negative id: " + id);
//         } else if (id < BY_ID.length) {
//             return BY_ID[id];
//         } else {
//             return null;
//         }
//     }
// }
// 
// Path: src/main/java/net/techcable/spudcompat/protocol/injector/RawPacket.java
// @Getter
// public class RawPacket extends AbstractReferenceCounted {
//     private final ByteBuf allData;
//     private final ByteBuf packetData;
//     private final int id;
//     private final ProtocolState protocolState;
//     private final ProtocolDirection direction;
//     private final PacketType type;
// 
//     private RawPacket(ByteBuf allData, ByteBuf packetData, int id, ProtocolState protocolState, ProtocolDirection direction) {
//         this.allData = allData.retain();
//         this.packetData = packetData.retain();
//         this.id = id;
//         this.protocolState = checkNotNull(protocolState, "Null state");
//         this.direction = checkNotNull(direction, "Null direction");
//         this.type = PacketType.getById(id, protocolState, direction);
//     }
// 
//     public ByteBuf getAllData() {
//         assertValid();
//         return allData;
//     }
// 
//     public ByteBuf getPacketData() {
//         assertValid();
//         return packetData;
//     }
// 
// 
//     public boolean isKnownType() {
//         return getType() != null;
//     }
// 
//     public static RawPacket fromWrapper(PacketWrapper wrapper, ProtocolState protocolState, ProtocolDirection direction) {
//         return fromBuffer(checkNotNull(wrapper, "Null wrapper").buf, protocolState, direction);
//     }
// 
//     public static RawPacket fromBuffer(ByteBuf buf, ProtocolState protocolState, ProtocolDirection direction) {
//         checkNotNull(buf, "Null buffer");
//         checkNotNull(protocolState, "Null state");
//         checkNotNull(direction, "Null direction");
//         buf = Unpooled.unmodifiableBuffer(buf.duplicate()); // Read-only
//         ByteBuf allData = buf.duplicate();
//         int id = DefinedPacket.readVarInt(buf);
//         return new RawPacket(allData, buf.slice(), id, protocolState, direction);
//     }
// 
//     @Override
//     protected void deallocate() {
//         allData.release();
//         packetData.release();
//     }
// 
//     private void assertValid() {
//         if (refCnt() <= 0) throw new IllegalReferenceCountException("Packet deallocated");
//     }
// }


// Path: src/main/java/net/techcable/spudcompat/protocol/Packet.java
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import net.md_5.bungee.api.connection.Connection;
import net.techcable.spudcompat.ProtocolVersion;
import net.techcable.spudcompat.protocol.injector.RawPacket;

package net.techcable.spudcompat.protocol;



public interface Packet {
    public PacketType getType();

    public void write(ByteBuf buf, ProtocolVersion version, ProtocolState state, ProtocolDirection direction);

    public default RawPacket toRaw(ByteBufAllocator allocator, ProtocolVersion version, ProtocolState state, ProtocolDirection direction) {
        ByteBuf buf = allocator.buffer();
        write(buf, version, state, direction);
        RawPacket raw = RawPacket.fromBuffer(buf, state, direction);