package net.minecraft.network.protocol.game;

import net.minecraft.network.protocol.Packet;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.PositionMoveRotation;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.entity.vehicle.minecart.NewMinecartBehavior.MinecartStep;

import com.bergerkiller.bukkit.common.internal.logic.ProtocolMath;

import com.bergerkiller.generated.net.minecraft.network.protocol.game.ClientboundEntityPositionSyncPacketHandle;
import com.bergerkiller.generated.net.minecraft.network.protocol.game.ClientboundMoveEntityPacketHandle;
import com.bergerkiller.generated.net.minecraft.network.protocol.game.ClientboundMoveEntityPacketHandle.PosHandle;
import com.bergerkiller.generated.net.minecraft.network.protocol.game.ClientboundMoveEntityPacketHandle.PosRotHandle;
import com.bergerkiller.generated.net.minecraft.network.protocol.game.ClientboundMoveEntityPacketHandle.RotHandle;
import com.bergerkiller.generated.net.minecraft.network.protocol.game.ClientboundRotateHeadPacketHandle;
import com.bergerkiller.generated.net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacketHandle
import com.bergerkiller.generated.net.minecraft.network.protocol.game.ClientboundMoveVehiclePacketHandle;
import com.bergerkiller.generated.net.minecraft.network.protocol.game.ServerboundMoveVehiclePacketHandle;
import com.bergerkiller.generated.net.minecraft.network.protocol.game.ClientboundMoveMinecartPacketHandle;

import com.bergerkiller.generated.net.minecraft.world.entity.vehicle.minecart.NewMinecartBehaviorHandle.MinecartStepHandle;

import com.bergerkiller.bukkit.common.wrappers.RelativeFlags;

// Only >= MC 1.9
optional class ServerboundMoveVehiclePacket extends Packet {
#if version >= 1.21.4
    public double getPosX() { return instance.position().x; }
    public double getPosY() { return instance.position().y; }
    public double getPosZ() { return instance.position().z; }
    public float getYaw:yRot();
    public float getPitch:xRot();
    public boolean isOnGround:onGround();

    public static (ServerboundMoveVehiclePacketHandle) ServerboundMoveVehiclePacket createNew(double posX, double posY, double posZ, float yaw, float pitch, boolean onGround) {
        return new ServerboundMoveVehiclePacket(new Vec3(posX, posY, posZ), yaw, pitch, onGround);
    }
#else
  #if version >= 1.17
    #require ServerboundMoveVehiclePacket private double posX:x;
    #require ServerboundMoveVehiclePacket private double posY:y;
    #require ServerboundMoveVehiclePacket private double posZ:z;
    #require ServerboundMoveVehiclePacket private float yaw:yRot;
    #require ServerboundMoveVehiclePacket private float pitch:xRot;
  #elseif version >= 1.9
    #require ServerboundMoveVehiclePacket private double posX:a;
    #require ServerboundMoveVehiclePacket private double posY:b;
    #require ServerboundMoveVehiclePacket private double posZ:c;
    #require ServerboundMoveVehiclePacket private float yaw:d;
    #require ServerboundMoveVehiclePacket private float pitch:e;
  #endif

    public double getPosX() { return instance#posX; }
    public double getPosY() { return instance#posY; }
    public double getPosZ() { return instance#posZ; }
    public float getYaw() { return instance#yaw; }
    public float getPitch() { return instance#pitch; }
    public boolean isOnGround() { return false; /* not supported */ }

    public static (ServerboundMoveVehiclePacketHandle) ServerboundMoveVehiclePacket createNew(double posX, double posY, double posZ, float yaw, float pitch, boolean onGround) {
  #if version >= 1.17
        #require ServerboundMoveVehiclePacket private ServerboundMoveVehiclePacket createVehicleMovePacket:<init>(net.minecraft.network.FriendlyByteBuf packetdataserializer);
        ServerboundMoveVehiclePacket packet = #createVehicleMovePacket(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
  #else
        ServerboundMoveVehiclePacket packet = new ServerboundMoveVehiclePacket();
  #endif
        packet#posX = posX;
        packet#posY = posY;
        packet#posZ = posZ;
        packet#yaw = yaw;
        packet#pitch = pitch;
        //onGround is ignored (doesn't exist)
        return packet;
    }
#endif
}

// Only >= MC 1.9
optional class ClientboundMoveVehiclePacket extends Packet {
#if version >= 1.21.4
    public double getPosX() { return instance.position().x; }
    public double getPosY() { return instance.position().y; }
    public double getPosZ() { return instance.position().z; }
    public float getYaw:yRot();
    public float getPitch:xRot();

    public static (ClientboundMoveVehiclePacketHandle) ClientboundMoveVehiclePacket createNew(double posX, double posY, double posZ, float yaw, float pitch) {
        return new ClientboundMoveVehiclePacket(new Vec3(posX, posY, posZ), yaw, pitch);
    }
#else
  #if version >= 1.17
    #require ClientboundMoveVehiclePacket private double posX:x;
    #require ClientboundMoveVehiclePacket private double posY:y;
    #require ClientboundMoveVehiclePacket private double posZ:z;
    #require ClientboundMoveVehiclePacket private float yaw:yRot;
    #require ClientboundMoveVehiclePacket private float pitch:xRot;
  #elseif version >= 1.9
    #require ClientboundMoveVehiclePacket private double posX:a;
    #require ClientboundMoveVehiclePacket private double posY:b;
    #require ClientboundMoveVehiclePacket private double posZ:c;
    #require ClientboundMoveVehiclePacket private float yaw:d;
    #require ClientboundMoveVehiclePacket private float pitch:e;
  #endif

    public double getPosX() { return instance#posX; }
    public double getPosY() { return instance#posY; }
    public double getPosZ() { return instance#posZ; }
    public float getYaw() { return instance#yaw; }
    public float getPitch() { return instance#pitch; }

    public static (ClientboundMoveVehiclePacketHandle) ClientboundMoveVehiclePacket createNew(double posX, double posY, double posZ, float yaw, float pitch) {
  #if version >= 1.17
        #require ClientboundMoveVehiclePacket private ClientboundMoveVehiclePacket createVehicleMovePacket:<init>(net.minecraft.network.FriendlyByteBuf packetdataserializer);
        ClientboundMoveVehiclePacket packet = #createVehicleMovePacket(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
  #else
        ClientboundMoveVehiclePacket packet = new ClientboundMoveVehiclePacket();
  #endif
        packet#posX = posX;
        packet#posY = posY;
        packet#posZ = posZ;
        packet#yaw = yaw;
        packet#pitch = pitch;
        return packet;
    }
#endif
}

class ClientboundEntityPositionSyncPacket extends Packet {
#if version >= 1.20.5
    #bootstrap com.bergerkiller.bukkit.common.internal.CommonBootstrap.initServer();
#endif

    // Reflection needed on some versions of Minecraft, and also for creating a new packet
#if version >= 1.21.2
    // Record class, no fields need to be set using reflection
#elseif version >= 1.17
    #require ClientboundEntityPositionSyncPacket private final int entityId:id;
    #require ClientboundEntityPositionSyncPacket private final double posX:x;
    #require ClientboundEntityPositionSyncPacket private final double posY:y;
    #require ClientboundEntityPositionSyncPacket private final double posZ:z;
    #require ClientboundEntityPositionSyncPacket private final byte encodedYaw:yRot;
    #require ClientboundEntityPositionSyncPacket private final byte encodedPitch:xRot;
    #require ClientboundEntityPositionSyncPacket private final boolean onGround;
#else
    #require ClientboundEntityPositionSyncPacket private int entityId:a;
  #if version >= 1.9
    #require ClientboundEntityPositionSyncPacket private double posX:b;
    #require ClientboundEntityPositionSyncPacket private double posY:c;
    #require ClientboundEntityPositionSyncPacket private double posZ:d;
  #else
    #require ClientboundEntityPositionSyncPacket private int encodedPosX:b;
    #require ClientboundEntityPositionSyncPacket private int encodedPosY:c;
    #require ClientboundEntityPositionSyncPacket private int encodedPosZ:d;
  #endif
    #require ClientboundEntityPositionSyncPacket private byte encodedYaw:e;
    #require ClientboundEntityPositionSyncPacket private byte encodedPitch:f;
    #require ClientboundEntityPositionSyncPacket private boolean onGround:g;
#endif

#if version >= 1.21.2
    public int getEntityId:id();
    public double getPosX() { return instance.values().position().x; }
    public double getPosY() { return instance.values().position().y; }
    public double getPosZ() { return instance.values().position().z; }
    public float getYaw() { return instance.values().yRot(); }
    public float getPitch() { return instance.values().xRot(); }
    public boolean isOnGround:onGround();

    // Not really used anymore, but here for completion sake
    public int getEncodedPosX() {
        return ProtocolMath.serializePosition_1_8_8(instance.values().position().x);
    }
    public int getEncodedPosY() {
        return ProtocolMath.serializePosition_1_8_8(instance.values().position().y);
    }
    public int getEncodedPosZ() {
        return ProtocolMath.serializePosition_1_8_8(instance.values().position().z);
    }
    public int getEncodedYaw() {
        return ProtocolMath.serializeRotation(instance.values().yRot());
    }
    public int getEncodedPitch() {
        return ProtocolMath.serializeRotation(instance.values().xRot());
    }
#elseif version >= 1.18
    public int getEntityId:getId();
    public double getPosX:getX();
    public double getPosY:getY();
    public double getPosZ:getZ();
    public float getYaw() {
        return ProtocolMath.deserializeRotation(instance.getyRot());
    }
    public float getPitch() {
        return ProtocolMath.deserializeRotation(instance.getxRot());
    }
    public boolean isOnGround();

    // Not really used anymore, but here for completion sake
    public int getEncodedPosX() {
        return ProtocolMath.serializePosition_1_8_8(instance.getX());
    }
    public int getEncodedPosY() {
        return ProtocolMath.serializePosition_1_8_8(instance.getY());
    }
    public int getEncodedPosZ() {
        return ProtocolMath.serializePosition_1_8_8(instance.getZ());
    }

    public int getEncodedYaw() { return (int) instance.getyRot() & 0xFF; }
    public int getEncodedPitch() { return (int) instance.getxRot() & 0xFF; }
#elseif version >= 1.17
    public int getEntityId:b();
    public double getPosX:c();
    public double getPosY:d();
    public double getPosZ:e();
    public float getYaw() {
        return ProtocolMath.deserializeRotation(instance.f());
    }
    public float getPitch() {
        return ProtocolMath.deserializeRotation(instance.g());
    }
    public boolean isOnGround:h();

    // Not really used anymore, but here for completion sake
    public int getEncodedPosX() {
        return ProtocolMath.serializePosition_1_8_8(instance.c());
    }
    public int getEncodedPosY() {
        return ProtocolMath.serializePosition_1_8_8(instance.d());
    }
    public int getEncodedPosZ() {
        return ProtocolMath.serializePosition_1_8_8(instance.e());
    }

    public int getEncodedYaw() { return (int) instance.f() & 0xFF; }
    public int getEncodedPitch() { return (int) instance.g() & 0xFF; }
#else
    // Relies on reflection to access the private fields
    public int getEntityId() { return instance#entityId; }

  #if version >= 1.9
    public double getPosX() { return instance#posX; }
    public double getPosY() { return instance#posY; }
    public double getPosZ() { return instance#posZ; }
  #else
    public double getPosX() { return ProtocolMath.deserializePosition_1_8_8( instance#encodedPosX ); }
    public double getPosY() { return ProtocolMath.deserializePosition_1_8_8( instance#encodedPosY ); }
    public double getPosZ() { return ProtocolMath.deserializePosition_1_8_8( instance#encodedPosZ ); }
  #endif

    public float getYaw() {
        return ProtocolMath.deserializeRotation( instance#encodedYaw );
    }
    public float getPitch() {
        return ProtocolMath.deserializeRotation( instance#encodedPitch );
    }

    public boolean isOnGround() { return instance#onGround; }

  #if version >= 1.9
    // Not really used anymore, but here for completion sake
    public int getEncodedPosX() {
        return ProtocolMath.serializePosition_1_8_8( instance#posX );
    }
    public int getEncodedPosY() {
        return ProtocolMath.serializePosition_1_8_8( instance#posY );
    }
    public int getEncodedPosZ() {
        return ProtocolMath.serializePosition_1_8_8( instance#posZ );
    }
  #else
    public int getEncodedPosX() { return instance#encodedPosX; }
    public int getEncodedPosY() { return instance#encodedPosY; }
    public int getEncodedPosZ() { return instance#encodedPosZ; }
  #endif

    public int getEncodedYaw() { return (int) instance#encodedYaw & 0xFF; }
    public int getEncodedPitch() { return (int) instance#encodedPitch & 0xFF; }
#endif

    public static (ClientboundEntityPositionSyncPacketHandle) ClientboundEntityPositionSyncPacket createNewForEntity((org.bukkit.entity.Entity) Entity entity) {
#if version >= 1.21.2
        PositionMoveRotation values = PositionMoveRotation.of(entity);
        return new ClientboundEntityPositionSyncPacket(entity.getId(), values, entity.onGround());
#else
        return new ClientboundEntityPositionSyncPacket(entity);
#endif
    }

    public static (ClientboundEntityPositionSyncPacketHandle) ClientboundEntityPositionSyncPacket createNew(int entityId, double posX, double posY, double posZ, float yaw, float pitch, boolean onGround) {
#if version >= 1.21.2
        PositionMoveRotation values = new PositionMoveRotation(new Vec3(posX, posY, posZ), new Vec3(0.0, 0.0, 0.0), yaw, pitch);
        return new ClientboundEntityPositionSyncPacket(entityId, values, onGround);

#elseif version >= 1.9
        // Create a new packet and use reflection to set the fields
        // Unfortunately, no nice constructor :(
  #if version >= 1.20.5
        #require net.minecraft.network.protocol.game.ClientboundEntityPositionSyncPacket private ClientboundEntityPositionSyncPacket createTeleportPacket:<init>(net.minecraft.network.FriendlyByteBuf serializer);
        ClientboundEntityPositionSyncPacket packet = #createTeleportPacket(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
  #elseif version >= 1.17
        ClientboundEntityPositionSyncPacket packet = new ClientboundEntityPositionSyncPacket(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
  #else
        ClientboundEntityPositionSyncPacket packet = new ClientboundEntityPositionSyncPacket();
  #endif

        byte encodedYaw = (byte) ProtocolMath.serializeRotation(yaw);
        byte encodedPitch = (byte) ProtocolMath.serializeRotation(pitch);

        packet#entityId = entityId;
        packet#posX = posX;
        packet#posY = posY;
        packet#posZ = posZ;
        packet#encodedYaw = encodedYaw;
        packet#encodedPitch = encodedPitch;
        packet#onGround = onGround;
        return packet;
#else
        // Constructor is available
        int encodedPosX = ProtocolMath.serializePosition_1_8_8(posX);
        int encodedPosY = ProtocolMath.serializePosition_1_8_8(posY);
        int encodedPosZ = ProtocolMath.serializePosition_1_8_8(posZ);
        byte encodedYaw = (byte) ProtocolMath.serializeRotation(yaw);
        byte encodedPitch = (byte) ProtocolMath.serializeRotation(pitch);
        return new ClientboundEntityPositionSyncPacket(entityId, encodedPosX, encodedPosY, encodedPosZ, encodedYaw, encodedPitch, onGround);
#endif
    }

    <code>
    @Override
    public com.bergerkiller.bukkit.common.protocol.PacketType getPacketType() {
        return com.bergerkiller.bukkit.common.protocol.PacketType.OUT_ENTITY_TELEPORT;
    }


    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {
        private int entityId;
        private double posX, posY, posZ;
        private float yaw, pitch;
        private boolean onGround;

        public Builder entityId(int entityId) { this.entityId = entityId; return this; }
        public Builder posX(double posX) { this.posX = posX; return this; }
        public Builder posY(double posY) { this.posY = posY; return this; }
        public Builder posZ(double posZ) { this.posZ = posZ; return this; }
        public Builder position(org.bukkit.util.Vector position) {
            return position(position.getX(), position.getY(), position.getZ());
        }
        public Builder position(double x, double y, double z) {
            this.posX = x;
            this.posY = y;
            this.posZ = z;
            return this;
        }
        public Builder yaw(float yaw) { this.yaw = yaw; return this; }
        public Builder pitch(float pitch) { this.pitch = pitch; return this; }
        public Builder rotation(float yaw, float pitch) {
            this.yaw = yaw;
            this.pitch = pitch;
            return this;
        }
        public Builder onGround(boolean onGround) { this.onGround = onGround; return this; }

        public ClientboundEntityPositionSyncPacketHandle create() {
            return ClientboundEntityPositionSyncPacketHandle.createNew(entityId, posX, posY, posZ, yaw, pitch, onGround);
        }
    }
    </code>
}

// Only >= MC 1.9
optional class ServerboundPaddleBoatPacket {
#if version >= 1.17
    private boolean leftPaddle:left;
    private boolean rightPaddle:right;
#else
    private boolean leftPaddle:a;
    private boolean rightPaddle:b;
#endif
}

class ClientboundSetEntityMotionPacket extends Packet {
#if version >= 1.17
    private int entityId:id;
#else
    private int entityId:a;
#endif

    public static (ClientboundSetEntityMotionPacketHandle) ClientboundSetEntityMotionPacket createNew(int entityId, double motX, double motY, double motZ) {
#if version >= 1.14
        return new ClientboundSetEntityMotionPacket(entityId, new Vec3(motX, motY, motZ));
#else
        return new ClientboundSetEntityMotionPacket(entityId, motX, motY, motZ);
#endif
    }

    public (ClientboundSetEntityMotionPacketHandle) ClientboundSetEntityMotionPacket((org.bukkit.entity.Entity) Entity entity);

#if version >= 26.1
    public (org.bukkit.util.Vector) Vec3 getMotVector:movement();
    public double getMotX() { return instance.movement().x; }
    public double getMotY() { return instance.movement().y; }
    public double getMotZ() { return instance.movement().z; }
#elseif version >= 1.21.9
    public (org.bukkit.util.Vector) Vec3 getMotVector:getMovement();
    public double getMotX() { return instance.getMovement().x; }
    public double getMotY() { return instance.getMovement().y; }
    public double getMotZ() { return instance.getMovement().z; }
#else
  #if version >= 1.17
    #require ClientboundSetEntityMotionPacket private int motX_raw:xa;
    #require ClientboundSetEntityMotionPacket private int motY_raw:ya;
    #require ClientboundSetEntityMotionPacket private int motZ_raw:za;
  #else
    #require ClientboundSetEntityMotionPacket private int motX_raw:b;
    #require ClientboundSetEntityMotionPacket private int motY_raw:c;
    #require ClientboundSetEntityMotionPacket private int motZ_raw:d;
  #endif

    public (org.bukkit.util.Vector) Vec3 getMotVector:getMovement() {
        int motX_raw = instance#motX_raw;
        int motY_raw = instance#motY_raw;
        int motZ_raw = instance#motZ_raw;
        return new Vec3( com.bergerkiller.bukkit.common.internal.logic.ProtocolMath.deserializeVelocity(motX_raw),
                          com.bergerkiller.bukkit.common.internal.logic.ProtocolMath.deserializeVelocity(motY_raw),
                          com.bergerkiller.bukkit.common.internal.logic.ProtocolMath.deserializeVelocity(motZ_raw) );
    }

    public double getMotX() {
        int motX_raw = instance#motX_raw;
        return com.bergerkiller.bukkit.common.internal.logic.ProtocolMath.deserializeVelocity(motX_raw);
    }

    public double getMotY() {
        int motY_raw = instance#motY_raw;
        return com.bergerkiller.bukkit.common.internal.logic.ProtocolMath.deserializeVelocity(motY_raw);
    }

    public double getMotZ() {
        int motZ_raw = instance#motZ_raw;
        return com.bergerkiller.bukkit.common.internal.logic.ProtocolMath.deserializeVelocity(motZ_raw);
    }
#endif

    <code>
    @Override
    public com.bergerkiller.bukkit.common.protocol.PacketType getPacketType() {
        return com.bergerkiller.bukkit.common.protocol.PacketType.OUT_ENTITY_VELOCITY;
    }
    </code>
}

class ClientboundMoveEntityPacket extends Packet {
#if version >= 1.17
    protected int entityId;
    protected boolean onGround;
#else
    protected int entityId:a;
    protected boolean onGround:g;
#endif

#if version >= 1.14
  #if version >= 1.17
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected short dx:xa;
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected short dy:ya;
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected short dz:za;
  #else
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected short dx:b;
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected short dy:c;
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected short dz:d;
  #endif

    public double getDeltaX() {
        return ProtocolMath.deserializePosition_1_10_2(instance#dx);
    }

    public double getDeltaY() {
        return ProtocolMath.deserializePosition_1_10_2(instance#dy);
    }

    public double getDeltaZ() {
        return ProtocolMath.deserializePosition_1_10_2(instance#dz);
    }

    public void setDeltaX(double dx) {
        instance#dx = (short) ProtocolMath.serializePosition_1_10_2(dx);
    }

    public void setDeltaY(double dy) {
        instance#dy = (short) ProtocolMath.serializePosition_1_10_2(dy);
    }

    public void setDeltaZ(double dz) {
        instance#dz = (short) ProtocolMath.serializePosition_1_10_2(dz);
    }
#elseif version >= 1.9
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected int dx:b;
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected int dy:c;
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected int dz:d;

    public double getDeltaX() {
        return ProtocolMath.deserializePosition_1_10_2(instance#dx);
    }

    public double getDeltaY() {
        return ProtocolMath.deserializePosition_1_10_2(instance#dy);
    }

    public double getDeltaZ() {
        return ProtocolMath.deserializePosition_1_10_2(instance#dz);
    }

    public void setDeltaX(double dx) {
        instance#dx = ProtocolMath.serializePosition_1_10_2(dx);
    }

    public void setDeltaY(double dy) {
        instance#dy = ProtocolMath.serializePosition_1_10_2(dy);
    }

    public void setDeltaZ(double dz) {
        instance#dz = ProtocolMath.serializePosition_1_10_2(dz);
    }
#else
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected byte dx:b;
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected byte dy:c;
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected byte dz:d;

    public double getDeltaX() {
        return ProtocolMath.deserializePosition_1_8_8(instance#dx);
    }

    public double getDeltaY() {
        return ProtocolMath.deserializePosition_1_8_8(instance#dy);
    }

    public double getDeltaZ() {
        return ProtocolMath.deserializePosition_1_8_8(instance#dz);
    }

    public void setDeltaX(double dx) {
        instance#dx = (byte) ProtocolMath.serializePosition_1_8_8(dx);
    }

    public void setDeltaY(double dy) {
        instance#dy = (byte) ProtocolMath.serializePosition_1_8_8(dy);
    }

    public void setDeltaZ(double dz) {
        instance#dz = (byte) ProtocolMath.serializePosition_1_8_8(dz);
    }
#endif

#if version >= 1.17
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected byte yaw:yRot;
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected byte pitch:xRot;
#else
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected byte yaw:e;
    #require net.minecraft.network.protocol.game.ClientboundMoveEntityPacket protected byte pitch:f;
#endif

    public float getYaw() {
        return ProtocolMath.deserializeRotation(instance#yaw);
    }

    public float getPitch() {
        return ProtocolMath.deserializeRotation(instance#pitch);
    }

    public void setYaw(float yaw) {
        instance#yaw = (byte) ProtocolMath.serializeRotation(yaw);
    }

    public void setPitch(float pitch) {
        instance#pitch = (byte) ProtocolMath.serializeRotation(pitch);
    }

    <code>
    /**
     * Deprecated: is not actually a delta, use getYaw() instead
     */
    @Deprecated
    public float getDeltaYaw() {
        return getYaw();
    }

    /**
     * Deprecated: is not actually a delta, use getPitch() instead
     */
    @Deprecated
    public float getDeltaPitch() {
        return getPitch();
    }

    /**
     * Deprecated: is not actually a delta, use setYaw(yaw) instead
     */
    @Deprecated
    public void setDeltaYaw(float deltaYaw) {
        setYaw(deltaYaw);
    }

    /**
     * Deprecated: is not actually a delta, use setPitch(pitch) instead
     */
    @Deprecated
    public void setDeltaPitch(float deltaPitch) {
        setPitch(deltaPitch);
    }
    </code>

    class ClientboundMoveEntityPacket.Rot extends ClientboundMoveEntityPacket {
        public static (ClientboundMoveEntityPacketHandle.RotHandle) ClientboundMoveEntityPacket.Rot createNew() {
#if version >= 1.20.5
            return new ClientboundMoveEntityPacket$Rot(0, (byte) 0, (byte) 0, false);
#elseif version >= 1.18
            return ClientboundMoveEntityPacket$Rot.read(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
#elseif version >= 1.17
            return ClientboundMoveEntityPacket$Rot.b(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
#else
            return new ClientboundMoveEntityPacket$Rot();
#endif
        }

        <code>
        @Override
        public com.bergerkiller.bukkit.common.protocol.PacketType getPacketType() {
            return com.bergerkiller.bukkit.common.protocol.PacketType.OUT_ENTITY_LOOK;
        }

        public static ClientboundMoveEntityPacketHandle.RotHandle createNew(int entityId, float yaw, float pitch, boolean onGround) {
            ClientboundMoveEntityPacketHandle.RotHandle handle = createNew();
            handle.setEntityId(entityId);
            handle.setYaw(yaw);
            handle.setPitch(pitch);
            handle.setOnGround(onGround);
            return handle;
        }
        </code>
    }

    class ClientboundMoveEntityPacket.Pos extends ClientboundMoveEntityPacket {
        public static (ClientboundMoveEntityPacketHandle.PosHandle) ClientboundMoveEntityPacket.Pos createNew() {
#if version >= 1.20.5
            return new ClientboundMoveEntityPacket$Pos(0, (short) 0, (short) 0, (short) 0, false);
#elseif version >= 1.18
            return ClientboundMoveEntityPacket$Pos.read(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
#elseif version >= 1.17
            return ClientboundMoveEntityPacket$Pos.b(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
#else
            return new ClientboundMoveEntityPacket$Pos();
#endif
        }

        <code>
        @Override
        public com.bergerkiller.bukkit.common.protocol.PacketType getPacketType() {
            return com.bergerkiller.bukkit.common.protocol.PacketType.OUT_ENTITY_MOVE;
        }

        public static ClientboundMoveEntityPacketHandle.PosHandle createNew(int entityId, double dx, double dy, double dz, boolean onGround) {
            ClientboundMoveEntityPacketHandle.PosHandle handle = createNew();
            handle.setEntityId(entityId);
            handle.setDeltaX(dx);
            handle.setDeltaY(dy);
            handle.setDeltaZ(dz);
            handle.setOnGround(onGround);
            return handle;
        }
        </code>
    }

    class ClientboundMoveEntityPacket.PosRot extends ClientboundMoveEntityPacket {
        public static (ClientboundMoveEntityPacketHandle.PosRotHandle) ClientboundMoveEntityPacket.PosRot createNew() {
#if version >= 1.20.5
            return new ClientboundMoveEntityPacket$PosRot(0, (short) 0, (short) 0, (short) 0, (byte) 0, (byte) 0, false);
#elseif version >= 1.18
            return ClientboundMoveEntityPacket$PosRot.read(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
#elseif version >= 1.17
            return ClientboundMoveEntityPacket$PosRot.b(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
#else
            return new ClientboundMoveEntityPacket$PosRot();
#endif
        }

        <code>
        @Override
        public com.bergerkiller.bukkit.common.protocol.PacketType getPacketType() {
            return com.bergerkiller.bukkit.common.protocol.PacketType.OUT_ENTITY_MOVE_LOOK;
        }

        public static ClientboundMoveEntityPacketHandle.PosRotHandle createNew(int entityId, double dx, double dy, double dz, float yaw, float pitch, boolean onGround) {
            ClientboundMoveEntityPacketHandle.PosRotHandle handle = createNew();
            handle.setEntityId(entityId);
            handle.setDeltaX(dx);
            handle.setDeltaY(dy);
            handle.setDeltaZ(dz);
            handle.setYaw(yaw);
            handle.setPitch(pitch);
            handle.setOnGround(onGround);
            return handle;
        }
        </code>
    }
}

class ClientboundRotateHeadPacket extends Packet {
#if version >= 1.17
    private int entityId:entityId;
#else
    private int entityId:a;
#endif

    public static optional (ClientboundRotateHeadPacketHandle) ClientboundRotateHeadPacket createNewEmpty() {
#if version >= 1.20.5
        #require net.minecraft.network.protocol.game.ClientboundRotateHeadPacket ClientboundRotateHeadPacket createHeadRotationPacket:<init>(net.minecraft.network.FriendlyByteBuf serializer);
        return #createHeadRotationPacket(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
#elseif version >= 1.17
        return new ClientboundRotateHeadPacket(com.bergerkiller.bukkit.common.internal.logic.NullPacketDataSerializer.INSTANCE);
#else
        return new ClientboundRotateHeadPacket();
#endif
    }

    <code>
    public static ClientboundRotateHeadPacketHandle createNew() {
        return T.createNewEmpty.invoke();
    }

    public static ClientboundRotateHeadPacketHandle createNew(int entityId, float headYaw) {
        ClientboundRotateHeadPacketHandle packet = createNew();
        packet.setEntityId(entityId);
        packet.setHeadYaw(headYaw);
        return packet;
    }
    </code>

    public static (ClientboundRotateHeadPacketHandle) ClientboundRotateHeadPacket createNew((org.bukkit.entity.Entity) Entity entity, float headYaw) {
        return new ClientboundRotateHeadPacket(entity, (byte) com.bergerkiller.bukkit.common.utils.MathUtil.floor(headYaw * 256.0f / 360.0f));
    }

#if version >= 1.17
    #require net.minecraft.network.protocol.game.ClientboundRotateHeadPacket private byte headYaw:yHeadRot;
#else
    #require net.minecraft.network.protocol.game.ClientboundRotateHeadPacket private byte headYaw:b;
#endif

    public float getHeadYaw() {
        return (float) instance#headYaw * 360.0f / 256.0f;   
    }

    public void setHeadYaw(float headYaw) {
        instance#headYaw = (byte) com.bergerkiller.bukkit.common.utils.MathUtil.floor(headYaw * 256.0f / 360.0f);
    }
}

class ServerboundMovePlayerPacket extends Packet {
    protected double x;
    protected double y;
    protected double z;
#if version >= 1.17
    protected float yaw:yRot;
    protected float pitch:xRot;
    protected boolean onGround;
    protected boolean hasPos;
    protected boolean hasLook:hasRot;
#else
    protected float yaw;
    protected float pitch;
    protected boolean onGround:f;
    protected boolean hasPos;
    protected boolean hasLook;
#endif
}

// Since Minecraft 1.21.2, and only used with the new minecart movement behavior feature
optional class ClientboundMoveMinecartPacket extends Packet {
    public int getEntityId:entityId();
    public (List<NewMinecartBehaviorHandle.MinecartStepHandle>) List<NewMinecartBehavior.MinecartStep> getLerpSteps:lerpSteps();

    public static (ClientboundMoveMinecartPacketHandle) ClientboundMoveMinecartPacket createNew(int entityId, (List<NewMinecartBehaviorHandle.MinecartStepHandle>) List<NewMinecartBehavior.MinecartStep> lerpSteps) {
        return new ClientboundMoveMinecartPacket(entityId, lerpSteps);
    }
}
