package dev.crucifixbeta.mod.modules.impl.movement;

import asm.accessors.IFireworkRocketEntity;
import asm.accessors.ILivingEntity;
import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.ClientTickEvent;
import dev.crucifixbeta.api.events.impl.MoveEvent;
import dev.crucifixbeta.api.events.impl.PacketEvent;
import dev.crucifixbeta.api.events.impl.PlaySoundEvent;
import dev.crucifixbeta.api.events.impl.TravelEvent;
import dev.crucifixbeta.api.events.impl.UpdateEvent;
import dev.crucifixbeta.api.events.impl.UpdateRotateEvent;
import dev.crucifixbeta.api.utils.Wrapper;
import dev.crucifixbeta.api.utils.math.MathUtil;
import dev.crucifixbeta.api.utils.math.Timer;
import dev.crucifixbeta.api.utils.player.EntityUtil;
import dev.crucifixbeta.api.utils.player.InventoryUtil;
import dev.crucifixbeta.api.utils.player.MovementUtil;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.impl.client.AntiCheat;
import dev.crucifixbeta.mod.modules.impl.combat.AutoSpear;
import dev.crucifixbeta.mod.modules.impl.combat.Criticals;
import dev.crucifixbeta.mod.modules.settings.impl.BindSetting;
import dev.crucifixbeta.mod.modules.settings.impl.BooleanSetting;
import dev.crucifixbeta.mod.modules.settings.impl.EnumSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.MovementType;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.projectile.FireworkRocketEntity;
import net.minecraft.item.ElytraItem;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket.InteractType;
import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;

@Environment(EnvType.CLIENT)
public class ElytraFly extends Module {
   public static ElytraFly INSTANCE;
   public final EnumSetting<ElytraFly.Mode> mode = this.add(new EnumSetting<>("Mode", ElytraFly.Mode.Control));
   public final BooleanSetting packet = this.add(new BooleanSetting("Packet", false).setParent());
   private final SliderSetting packetDelay = this.add(new SliderSetting("PacketDelay", 0.0, 0.0, 20.0, 1.0, this.packet::isOpen));
   private final BooleanSetting setFlag = this.add(new BooleanSetting("SetFlag", false, () -> !this.mode.is(ElytraFly.Mode.Bounce)));
   private final BooleanSetting firework = this.add(new BooleanSetting("Firework", false).setParent());
   private final EnumSetting<ElytraFly.FireworkMode> fireworkMode = this.add(
      new EnumSetting<>("FireworkMode", ElytraFly.FireworkMode.Auto, this.firework::isOpen)
   );
   private final SliderSetting fireworkInterval = this.add(
      new SliderSetting(
         "FireworkInterval", 1000.0, 0.0, 20000.0, 50.0, () -> this.firework.isOpen() && this.fireworkMode.is(ElytraFly.FireworkMode.Interval)
      )
   );
   private final SliderSetting fireworkSpeed = this.add(
      new SliderSetting(
            "FireworkSpeed", 100.0, 1.0, 300.0, 1.0, () -> this.firework.isOpen() && this.fireworkMode.is(ElytraFly.FireworkMode.Speed)
         )
         .setSuffix("km/h")
   );
   public final BindSetting fireWork = this.add(new BindSetting("FireWorkBind", -1, this.firework::isOpen));
   public final BooleanSetting packetInteract = this.add(new BooleanSetting("PacketInteract", true, this.firework::isOpen));
   public final BooleanSetting inventory = this.add(new BooleanSetting("InventorySwap", true, this.firework::isOpen));
   public final BooleanSetting onlyOne = this.add(new BooleanSetting("OnlyOne", true, this.firework::isOpen));
   private final BooleanSetting usingPause = this.add(new BooleanSetting("UsingPause", true, this.firework::isOpen));
   private final BooleanSetting silentArmorSwap = this.add(new BooleanSetting("SilentArmorSwap", true, this.firework::isOpen));
   private final BooleanSetting debug = this.add(new BooleanSetting("Debug", false));
   public final BooleanSetting maceFix = this.add(new BooleanSetting("MaceFix", true));
   public final BooleanSetting autoJump = this.add(new BooleanSetting("AutoJump", true, () -> this.mode.is(ElytraFly.Mode.Bounce)));
   public final SliderSetting upPitch = this.add(
      new SliderSetting("UpPitch", 0.0, 0.0, 90.0, () -> this.mode.getValue() == ElytraFly.Mode.Control)
   );
   public final SliderSetting upFactor = this.add(
      new SliderSetting("UpFactor", 1.0, 0.0, 10.0, () -> this.mode.getValue() == ElytraFly.Mode.Control)
   );
   public final SliderSetting downFactor = this.add(
      new SliderSetting("FallSpeed", 1.0, 0.0, 10.0, () -> this.mode.getValue() == ElytraFly.Mode.Control)
   );
   public final SliderSetting speed = this.add(
      new SliderSetting("Speed", 1.0, 0.1, 10.0, () -> this.mode.getValue() == ElytraFly.Mode.Control)
   );
   public final BooleanSetting speedLimit = this.add(new BooleanSetting("SpeedLimit", true, () -> this.mode.getValue() == ElytraFly.Mode.Control));
   public final SliderSetting maxSpeed = this.add(
      new SliderSetting("MaxSpeed", 2.5, 0.1, 10.0, () -> this.speedLimit.getValue() && this.mode.getValue() == ElytraFly.Mode.Control)
   );
   public final BooleanSetting noDrag = this.add(new BooleanSetting("NoDrag", false, () -> this.mode.getValue() == ElytraFly.Mode.Control));
   public final Timer fireworkTimer = new Timer();
   private final BooleanSetting autoStop = this.add(new BooleanSetting("AutoStop", true));
   private final BooleanSetting sprint = this.add(new BooleanSetting("Sprint", true, () -> this.mode.is(ElytraFly.Mode.Bounce)));
   private final SliderSetting pitch = this.add(
      new SliderSetting("Pitch", 88.0, -90.0, 90.0, 0.1, () -> this.mode.is(ElytraFly.Mode.Bounce))
   );
   private final BooleanSetting instantFly = this.add(new BooleanSetting("AutoStart", true, () -> !this.mode.is(ElytraFly.Mode.Bounce)));
   private final BooleanSetting checkSpeed = this.add(new BooleanSetting("CheckSpeed", false, () -> !this.mode.is(ElytraFly.Mode.Bounce)));
   public final SliderSetting minSpeed = this.add(new SliderSetting("MinSpeed", 70.0, 0.1, 200.0, () -> !this.mode.is(ElytraFly.Mode.Bounce)));
   private final SliderSetting delay = this.add(
      new SliderSetting("Delay", 1000.0, 0.0, 20000.0, 50.0, () -> !this.mode.is(ElytraFly.Mode.Bounce))
   );
   private final SliderSetting timeout = this.add(
      new SliderSetting("Timeout", 0.0, 0.1, 1.0, 0.1, () -> !this.mode.is(ElytraFly.Mode.Bounce))
   );
   private final SliderSetting sneakDownSpeed = this.add(
      new SliderSetting("DownSpeed", 1.0, 0.1, 10.0, () -> this.mode.getValue() == ElytraFly.Mode.Control)
   );
   private final SliderSetting boost = this.add(
      new SliderSetting("Boost", 1.0, 0.1, 4.0, () -> this.mode.getValue() == ElytraFly.Mode.Boost)
   );
   private final BooleanSetting freeze = this.add(new BooleanSetting("Freeze", false, () -> this.mode.is(ElytraFly.Mode.Rotation)));
   private final BooleanSetting motionStop = this.add(new BooleanSetting("MotionStop", false, () -> this.mode.is(ElytraFly.Mode.Rotation)));
   private final SliderSetting infiniteMaxSpeed = this.add(
      new SliderSetting("InfiniteMaxSpeed", 150.0, 50.0, 170.0, () -> this.mode.getValue() == ElytraFly.Mode.Pitch)
   );
   private final SliderSetting infiniteMinSpeed = this.add(
      new SliderSetting("InfiniteMinSpeed", 25.0, 10.0, 70.0, () -> this.mode.getValue() == ElytraFly.Mode.Pitch)
   );
   private final SliderSetting infiniteMaxHeight = this.add(
      new SliderSetting("InfiniteMaxHeight", 200, -50, 360, () -> this.mode.getValue() == ElytraFly.Mode.Pitch)
   );
   public final BooleanSetting releaseSneak = this.add(new BooleanSetting("ReleaseSneak", false));
   public final BooleanSetting noAnimation = this.add(new BooleanSetting("ForceStand", false));
   private final Timer instantFlyTimer = new Timer();
   boolean prev;
   float prePitch;
   private boolean hasElytra = false;
   float yaw = 0.0F;
   float rotationPitch = 0.0F;
   boolean flying = false;
   int packetDelayInt = 0;
   private boolean down;
   private float lastInfinitePitch;
   private float infinitePitch;
   private long suppressArmorSoundUntil = 0L;
   private static int maceDamagePauseDepth;
   private static int preMaceDamagePauseDepth;

   public ElytraFly() {
      super("ElytraFly", Module.Category.Movement);
      this.setChinese("\u9798\u7fc5\u98de\u884c");
      INSTANCE = this;
      CrucifixBeta.EVENT_BUS.subscribe(new ElytraFly.FireWorkTweak());
   }

   public void off() {
      if (!this.isPausedForMaceDamage()) {
         if (!this.inventory.getValue() || EntityUtil.inInventory()) {
            if (this.onlyOne.getValue()) {
               for (Entity var2 : CrucifixBeta.THREAD.getEntities()) {
                  if (var2 instanceof FireworkRocketEntity && ((IFireworkRocketEntity)var2).getShooter() == mc.player) {
                     return;
                  }
               }
            }

            INSTANCE.fireworkTimer.reset();
            AutoSpear.pauseForFirework();
            if (mc.player.getMainHandStack().getItem() == Items.FIREWORK_ROCKET) {
               if (this.packetInteract.getValue()) {
                  mc.getNetworkHandler()
                     .sendPacket(new PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, CrucifixBeta.ROTATION.getLastYaw(), CrucifixBeta.ROTATION.getLastPitch()));
               } else {
                  mc.interactionManager.interactItem(mc.player, Hand.MAIN_HAND);
               }
            } else if (this.inventory.getValue() && InventoryUtil.findItemInventorySlot(Items.FIREWORK_ROCKET) != -1) {
               int var4 = InventoryUtil.findItemInventorySlot(Items.FIREWORK_ROCKET);
               InventoryUtil.inventorySwap(var4, mc.player.getInventory().selectedSlot);
               if (this.packetInteract.getValue()) {
                  mc.getNetworkHandler()
                     .sendPacket(new PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, CrucifixBeta.ROTATION.getLastYaw(), CrucifixBeta.ROTATION.getLastPitch()));
               } else {
                  mc.interactionManager.interactItem(mc.player, Hand.MAIN_HAND);
               }

               InventoryUtil.inventorySwap(var4, mc.player.getInventory().selectedSlot);
               EntityUtil.syncInventory();
            } else {
               int var3 = InventoryUtil.findItem(Items.FIREWORK_ROCKET);
               if (var3 != -1) {
                  int var5 = mc.player.getInventory().selectedSlot;
                  InventoryUtil.switchToSlot(var3);
                  if (this.packetInteract.getValue()) {
                     mc.getNetworkHandler()
                        .sendPacket(
                           new PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, CrucifixBeta.ROTATION.getLastYaw(), CrucifixBeta.ROTATION.getLastPitch())
                        );
                  } else {
                     mc.interactionManager.interactItem(mc.player, Hand.MAIN_HAND);
                  }

                  InventoryUtil.switchToSlot(var5);
               }
            }
         }
      }
   }

   private void handlePacketMode() {
      if (!this.isPausedForMaceDamage()) {
         if (!mc.player.isOnGround()) {
            this.packetDelayInt++;
            if (!((double)this.packetDelayInt <= this.packetDelay.getValue())) {
               int var1 = InventoryUtil.findItemInventorySlot(Items.ELYTRA);
               if (var1 != -1) {
                  this.suppressArmorSwapSound();
                  mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, var1, 0, SlotActionType.PICKUP, mc.player);
                  mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, 6, 0, SlotActionType.PICKUP, mc.player);
                  this.suppressArmorSwapSound();
                  mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, var1, 0, SlotActionType.PICKUP, mc.player);
                  if (!mc.player.isFallFlying()) {
                     mc.getNetworkHandler().sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.START_FALL_FLYING));
                     if (this.setFlag.getValue()) {
                        mc.player.startFallFlying();
                     }
                  }

                  if (this.firework.getValue()
                     && this.fireworkTimer.passed(this.getFireworkDelay())
                     && this.shouldUseFirework(this.getSpeedKmh())
                     && (MovementUtil.isMoving() || mc.options.jumpKey.isPressed())
                     && (!mc.player.isUsingItem() || !this.usingPause.getValue())
                     && mc.player.isFallFlying()) {
                     this.off();
                     this.fireworkTimer.reset();
                  }

                  mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, var1, 0, SlotActionType.PICKUP, mc.player);
                  mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, 6, 0, SlotActionType.PICKUP, mc.player);
                  mc.interactionManager.clickSlot(mc.player.currentScreenHandler.syncId, var1, 0, SlotActionType.PICKUP, mc.player);
                  this.packetDelayInt = 0;
               }
            }
         }
      }
   }

   private void suppressArmorSwapSound() {
      if (this.silentArmorSwap.getValue()) {
         this.suppressArmorSoundUntil = System.currentTimeMillis() + 250L;
      }
   }

   @EventListener
   public void onPlaySound(PlaySoundEvent event) {
      if ((this.silentArmorSwap.getValue() || this.maceFix.getValue())
         && System.currentTimeMillis() <= this.suppressArmorSoundUntil
         && event.sound != null
         && this.isArmorEquipSound(event.sound.getId())) {
         event.cancel();
      }
   }

   private boolean isArmorEquipSound(Identifier id) {
      return id.equals(SoundEvents.ITEM_ARMOR_EQUIP_NETHERITE.value().getId())
         || id.equals(SoundEvents.ITEM_ARMOR_EQUIP_TURTLE.value().getId())
         || id.equals(SoundEvents.ITEM_ARMOR_EQUIP_CHAIN.value().getId())
         || id.equals(SoundEvents.ITEM_ARMOR_EQUIP_ELYTRA.value().getId())
         || id.equals(SoundEvents.ITEM_ARMOR_EQUIP_DIAMOND.value().getId())
         || id.equals(SoundEvents.ITEM_ARMOR_EQUIP_GOLD.value().getId())
         || id.equals(SoundEvents.ITEM_ARMOR_EQUIP_IRON.value().getId())
         || id.equals(SoundEvents.ITEM_ARMOR_EQUIP_LEATHER.value().getId())
         || id.equals(SoundEvents.ITEM_ARMOR_EQUIP_GENERIC.value().getId());
   }

   public static void beginMaceDamagePause() {
      if (INSTANCE != null && INSTANCE.maceFix.getValue()) {
         maceDamagePauseDepth++;
         if (INSTANCE.isOn() && mc.player != null) {
            mc.player.setPose(EntityPose.STANDING);
         }
      }
   }

   public static void endMaceDamagePause() {
      if (INSTANCE != null && maceDamagePauseDepth > 0) {
         maceDamagePauseDepth--;
      }
   }

   public static void endPreMaceDamagePause() {
      if (INSTANCE != null && preMaceDamagePauseDepth > 0) {
         preMaceDamagePauseDepth--;
      }
   }

   private boolean isPausedForMaceDamage() {
      return this.maceFix.getValue() && (maceDamagePauseDepth > 0 || preMaceDamagePauseDepth > 0);
   }

   @EventListener(
      priority = 1000
   )
   private void onMaceDamagePrePacket(PacketEvent.Send event) {
      if (this.maceFix.getValue() && !event.isCancelled()) {
         if (event.getPacket() instanceof PlayerInteractEntityC2SPacket var3) {
            if (Criticals.getInteractType(var3) == InteractType.ATTACK) {
               boolean var6 = mc.player.getMainHandStack().getItem() == Items.MACE;
               boolean var4 = InventoryUtil.findItem(Items.MACE) != -1;
               if (var6 || var4) {
                  preMaceDamagePauseDepth++;
                  if (mc.player != null && mc.player.isFallFlying()) {
                     mc.player.setPose(EntityPose.STANDING);
                     this.suppressArmorSoundUntil = System.currentTimeMillis() + 300L;
                     int var5 = mc.player.currentScreenHandler.syncId;
                     mc.interactionManager.clickSlot(var5, 6, 0, SlotActionType.PICKUP, mc.player);
                     mc.interactionManager.clickSlot(var5, 6, 0, SlotActionType.PICKUP, mc.player);
                     mc.getNetworkHandler().sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.START_FALL_FLYING));
                     if (this.setFlag.getValue()) {
                        mc.player.startFallFlying();
                     }
                  }
               }
            }
         }
      }
   }

   @EventListener(
      priority = -1000
   )
   private void onMaceDamagePostSend(PacketEvent.Sent event) {
      if (preMaceDamagePauseDepth > 0 && event.getPacket() instanceof PlayerInteractEntityC2SPacket) {
         endPreMaceDamagePause();
      }
   }

   private void forceStand() {
      if (this.noAnimation.getValue() && mc.player.isFallFlying()) {
         mc.player.setPose(EntityPose.STANDING);
      }
   }

   private boolean shouldHover() {
      return this.mode.getValue() == ElytraFly.Mode.Freeze || this.mode.getValue() == ElytraFly.Mode.Rotation;
   }

   @EventListener
   public void onUpdate(UpdateEvent event) {
      if (!this.isPausedForMaceDamage()) {
         this.forceStand();
         this.getInfinitePitch();
         this.flying = false;
         if (this.packet.getValue()) {
            this.handlePacketMode();
         } else {
            this.hasElytra = false;

            for (ItemStack var3 : mc.player.getArmorItems()) {
               if (var3.getItem() instanceof ElytraItem) {
                  this.hasElytra = true;
                  break;
               }
            }

            if (this.mode.is(ElytraFly.Mode.Bounce)) {
               ((ILivingEntity)mc.player).setLastJumpCooldown(0);
            } else {
               double var4 = this.getSpeedKmh();
               if (this.mode.getValue() == ElytraFly.Mode.Boost) {
                  this.boost();
               }

               if (this.shouldUseFirework(var4)
                  && this.firework.getValue()
                  && this.fireworkTimer.passed(this.getFireworkDelay())
                  && (MovementUtil.isMoving() || this.mode.is(ElytraFly.Mode.Rotation) && mc.options.jumpKey.isPressed())
                  && (!mc.player.isUsingItem() || !this.usingPause.getValue())
                  && this.isFallFlying()) {
                  this.off();
                  this.fireworkTimer.reset();
               }

               if (!this.isFallFlying() && this.hasElytra) {
                  this.fireworkTimer.setMs(99999999L);
                  if (!mc.player.isOnGround() && this.instantFly.getValue() && mc.player.getVelocity().getY() < 0.0) {
                     if (!this.instantFlyTimer.passed((long)(1000.0 * this.timeout.getValue()))) {
                        return;
                     }

                     this.instantFlyTimer.reset();
                     mc.getNetworkHandler().sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.START_FALL_FLYING));
                     if (this.setFlag.getValue()) {
                        mc.player.startFallFlying();
                     }
                  }
               }
            }
         }
      }
   }

   @EventListener
   public void onMove(TravelEvent event) {
      if (!this.isPausedForMaceDamage()) {
         this.forceStand();
         if (this.packet.getValue()) {
            if (this.shouldHover()) {
               boolean var11 = mc.options.forwardKey.isPressed()
                  || mc.options.backKey.isPressed()
                  || mc.options.leftKey.isPressed()
                  || mc.options.rightKey.isPressed()
                  || mc.options.jumpKey.isPressed()
                  || mc.options.sneakKey.isPressed();
               if (!var11) {
                  mc.player.setVelocity(0.0, mc.player.getVelocity().y, 0.0);
                  event.cancel();
                  return;
               }
            }
         } else if (!nullCheck() && this.hasElytra && this.isFallFlying() && !event.isPost()) {
            if ((this.mode.is(ElytraFly.Mode.Freeze) || this.mode.is(ElytraFly.Mode.Rotation) && this.freeze.getValue())
               && !MovementUtil.isMoving()
               && !mc.options.jumpKey.isPressed()
               && !mc.options.sneakKey.isPressed()) {
               event.cancel();
            } else {
               if (this.mode.getValue() == ElytraFly.Mode.Control) {
                  if (this.firework.getValue()) {
                     if (mc.options.sneakKey.isPressed() && mc.player.input.jumping) {
                        this.setY(0.0);
                     } else if (mc.options.sneakKey.isPressed()) {
                        this.setY(-this.sneakDownSpeed.getValue());
                     } else if (mc.player.input.jumping) {
                        this.setY(this.upFactor.getValue());
                     } else {
                        this.setY(-3.0E-11 * this.downFactor.getValue());
                     }

                     double[] var2 = MovementUtil.directionSpeed(this.speed.getValue());
                     this.setX(var2[0]);
                     this.setZ(var2[1]);
                  } else {
                     Vec3d var10 = this.getRotationVec(mc.getRenderTickCounter().getTickDelta(true));
                     double var3 = Math.sqrt(var10.x * var10.x + var10.z * var10.z);
                     double var5 = Math.sqrt(this.getX() * this.getX() + this.getZ() * this.getZ());
                     if (mc.player.input.sneaking) {
                        this.setY(-this.sneakDownSpeed.getValue());
                     } else if (!mc.player.input.jumping) {
                        this.setY(-3.0E-11 * this.downFactor.getValue());
                     }

                     if (mc.player.input.jumping) {
                        if (var5 > this.upFactor.getValue() / this.upFactor.getMax()) {
                           double var7 = var5 * 0.01325;
                           this.setY(this.getY() + var7 * 3.2);
                           this.setX(this.getX() - var10.x * var7 / var3);
                           this.setZ(this.getZ() - var10.z * var7 / var3);
                        } else {
                           double[] var9 = MovementUtil.directionSpeed(this.speed.getValue());
                           this.setX(var9[0]);
                           this.setZ(var9[1]);
                        }
                     }

                     if (var3 > 0.0) {
                        this.setX(this.getX() + (var10.x / var3 * var5 - this.getX()) * 0.1);
                        this.setZ(this.getZ() + (var10.z / var3 * var5 - this.getZ()) * 0.1);
                     }

                     if (!mc.player.input.jumping) {
                        double[] var13 = MovementUtil.directionSpeed(this.speed.getValue());
                        this.setX(var13[0]);
                        this.setZ(var13[1]);
                     }

                     if (!this.noDrag.getValue()) {
                        this.setY(this.getY() * 0.99F);
                        this.setX(this.getX() * 0.98F);
                        this.setZ(this.getZ() * 0.99F);
                     }

                     double var12 = Math.sqrt(this.getX() * this.getX() + this.getZ() * this.getZ());
                     if (this.speedLimit.getValue() && var12 > this.maxSpeed.getValue()) {
                        this.setX(this.getX() * this.maxSpeed.getValue() / var12);
                        this.setZ(this.getZ() * this.maxSpeed.getValue() / var12);
                     }

                     event.cancel();
                     mc.player.move(MovementType.SELF, mc.player.getVelocity());
                  }
               }
            }
         }
      }
   }

   public static boolean recastElytra(ClientPlayerEntity player) {
      if (INSTANCE != null && INSTANCE.isPausedForMaceDamage()) {
         return false;
      } else if (checkConditions(player) && ignoreGround(player)) {
         player.networkHandler.sendPacket(new ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING));
         if (INSTANCE.setFlag.getValue()) {
            mc.player.startFallFlying();
         }

         return true;
      } else {
         return false;
      }
   }

   public static boolean checkConditions(ClientPlayerEntity player) {
      ItemStack var1 = player.getEquippedStack(EquipmentSlot.CHEST);
      return !player.getAbilities().flying && !player.hasVehicle() && !player.isClimbing() && var1.isOf(Items.ELYTRA) && ElytraItem.isUsable(var1);
   }

   private static boolean ignoreGround(ClientPlayerEntity player) {
      if (!player.isTouchingWater() && !player.hasStatusEffect(StatusEffects.LEVITATION)) {
         ItemStack var1 = player.getEquippedStack(EquipmentSlot.CHEST);
         if (var1.isOf(Items.ELYTRA) && ElytraItem.isUsable(var1)) {
            player.startFallFlying();
            return true;
         } else {
            return false;
         }
      } else {
         return false;
      }
   }

   @Override
   public String getInfo() {
      return this.mode.getValue().name();
   }

   @Override
   public void onEnable() {
      if (!nullCheck()) {
         this.hasElytra = false;
         this.yaw = mc.player.getYaw();
         this.rotationPitch = mc.player.getPitch();
      }
   }

   @Override
   public void onDisable() {
      if (!nullCheck()) {
         if (this.releaseSneak.getValue()) {
            mc.getNetworkHandler().sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY));
         }
      }
   }

   private void boost() {
      if (this.hasElytra && this.isFallFlying()) {
         float var1 = (float)Math.toRadians((double)mc.player.getYaw());
         if (mc.options.forwardKey.isPressed()) {
            mc.player
               .addVelocity(
                  (double)(-MathHelper.sin(var1) * this.boost.getValueFloat() / 10.0F),
                  0.0,
                  (double)(MathHelper.cos(var1) * this.boost.getValueFloat() / 10.0F)
               );
         }
      }
   }

   @EventListener(
      priority = -9999
   )
   public void onRotation(UpdateRotateEvent event) {
      if (!nullCheck()) {
         if (!this.isPausedForMaceDamage()) {
            if (this.mode.is(ElytraFly.Mode.Rotation) && this.isFallFlying()) {
               if (MovementUtil.isMoving()) {
                  if (mc.options.jumpKey.isPressed()) {
                     this.rotationPitch = -45.0F;
                  } else if (mc.options.sneakKey.isPressed()) {
                     this.rotationPitch = 45.0F;
                  } else {
                     this.rotationPitch = -1.9F;
                     if (this.motionStop.getValue()) {
                        this.setY(0.0);
                     }
                  }
               } else if (mc.options.jumpKey.isPressed()) {
                  this.rotationPitch = -89.0F;
               } else if (mc.options.sneakKey.isPressed()) {
                  this.rotationPitch = 89.0F;
               } else if (this.motionStop.getValue()) {
                  this.setY(0.0);
               }

               if (!mc.options.forwardKey.isPressed() && !mc.options.backKey.isPressed() && !mc.options.leftKey.isPressed() && !mc.options.rightKey.isPressed()
                  )
                {
                  if (this.motionStop.getValue()) {
                     this.setX(0.0);
                     this.setZ(0.0);
                  }
               } else {
                  Float var2 = TargetFollow.INSTANCE != null ? TargetFollow.INSTANCE.getElytraFollowYaw() : null;
                  Float var3 = TargetFollow.INSTANCE != null ? TargetFollow.INSTANCE.getElytraFollowPitch() : null;
                  this.yaw = var2 != null ? var2 : Sprint.getSprintYaw(mc.player.getYaw());
                  if (var3 != null) {
                     this.rotationPitch = var3;
                  }
               }

               event.setYaw(this.yaw);
               event.setPitch(this.rotationPitch);
            } else if (this.mode.is(ElytraFly.Mode.Pitch) && this.isFallFlying()) {
               event.setPitch(this.infinitePitch);
            } else if (this.mode.is(ElytraFly.Mode.Bounce) && this.isFallFlying()) {
               event.setPitch(this.pitch.getValueFloat());
            }
         }
      }
   }

   protected final Vec3d getRotationVector(float pitch, float yaw) {
      float var3 = pitch * (float) (Math.PI / 180.0);
      float var4 = -yaw * (float) (Math.PI / 180.0);
      float var5 = MathHelper.cos(var4);
      float var6 = MathHelper.sin(var4);
      float var7 = MathHelper.cos(var3);
      float var8 = MathHelper.sin(var3);
      return new Vec3d((double)(var6 * var7), (double)(-var8), (double)(var5 * var7));
   }

   public Vec3d getRotationVec(float tickDelta) {
      return this.getRotationVector(-this.upPitch.getValueFloat(), mc.player.getYaw(tickDelta));
   }

   @EventListener
   private void onPlayerMove(MoveEvent event) {
      if (!this.isPausedForMaceDamage()) {
         if (this.autoStop.getValue() && this.isFallFlying()) {
            int var2 = (int)(mc.player.getX() / 16.0);
            int var3 = (int)(mc.player.getZ() / 16.0);
            if (!mc.world.getChunkManager().isChunkLoaded(var2, var3)) {
               event.cancel();
            }
         }
      }
   }

   @EventListener
   private void onTick(ClientTickEvent event) {
      if (!nullCheck()) {
         if (!this.isPausedForMaceDamage()) {
            if (this.mode.is(ElytraFly.Mode.Bounce) && this.hasElytra) {
               if (this.autoJump.getValue()) {
                  mc.options.jumpKey.setPressed(true);
               }

               if (event.isPost()) {
                  if (!this.isFallFlying()) {
                     mc.getNetworkHandler().sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.START_FALL_FLYING));
                  }

                  if (checkConditions(mc.player) && !this.sprint.getValue()) {
                     if (this.isFallFlying()) {
                        mc.player.setSprinting(mc.player.isOnGround());
                     } else {
                        mc.player.setSprinting(true);
                     }
                  }
               } else if (checkConditions(mc.player) && this.sprint.getValue()) {
                  mc.player.setSprinting(true);
               }
            }
         }
      }
   }

   @EventListener
   private void onPacketSend(PacketEvent.Send event) {
      if (!nullCheck()) {
         if (!this.isPausedForMaceDamage()) {
            if (this.mode.is(ElytraFly.Mode.Bounce)
               && this.hasElytra
               && event.getPacket() instanceof ClientCommandC2SPacket
               && ((ClientCommandC2SPacket)event.getPacket()).getMode().equals(ClientCommandC2SPacket.Mode.START_FALL_FLYING)
               && !this.sprint.getValue()) {
               mc.player.setSprinting(true);
            }
         }
      }
   }

   @EventListener
   private void onPacketReceive(PacketEvent.Receive event) {
      if (!nullCheck()) {
         if (!this.isPausedForMaceDamage()) {
            if (this.mode.is(ElytraFly.Mode.Bounce) && this.hasElytra && event.getPacket() instanceof PlayerPositionLookS2CPacket) {
               mc.player.stopFallFlying();
            }
         }
      }
   }

   @EventListener
   public void travel(TravelEvent event) {
      if (!nullCheck()) {
         if (!this.isPausedForMaceDamage()) {
            if (!AntiCheat.INSTANCE.movementSync()) {
               if (this.mode.is(ElytraFly.Mode.Bounce) && this.hasElytra) {
                  if (event.isPre()) {
                     this.prev = true;
                     this.prePitch = mc.player.getPitch();
                     mc.player.setPitch(this.pitch.getValueFloat());
                  } else if (this.prev) {
                     this.prev = false;
                     mc.player.setPitch(this.prePitch);
                  }
               } else if (this.mode.is(ElytraFly.Mode.Pitch) && this.isFallFlying()) {
                  if (event.isPre()) {
                     this.prev = true;
                     this.prePitch = mc.player.getPitch();
                     mc.player.setPitch(this.lastInfinitePitch);
                  } else if (this.prev) {
                     this.prev = false;
                     mc.player.setPitch(this.prePitch);
                  }
               }
            }
         }
      }
   }

   private double getX() {
      return MovementUtil.getMotionX();
   }

   private void setX(double f) {
      MovementUtil.setMotionX(f);
   }

   private double getY() {
      return MovementUtil.getMotionY();
   }

   private void setY(double f) {
      MovementUtil.setMotionY(f);
   }

   private double getZ() {
      return MovementUtil.getMotionZ();
   }

   private void setZ(double f) {
      MovementUtil.setMotionZ(f);
   }

   private void getInfinitePitch() {
      this.lastInfinitePitch = this.infinitePitch;
      double var1 = Math.hypot(mc.player.getX() - mc.player.prevX, mc.player.getZ() - mc.player.prevZ);
      if (mc.player.getY() < this.infiniteMaxHeight.getValue()) {
         if (var1 * 72.0 < this.infiniteMinSpeed.getValue() && !this.down) {
            this.down = true;
         }

         if (var1 * 72.0 > this.infiniteMaxSpeed.getValue() && this.down) {
            this.down = false;
         }
      } else {
         this.down = true;
      }

      this.infinitePitch = this.down ? (this.infinitePitch += 3.0F) : (this.infinitePitch -= 3.0F);
      this.infinitePitch = MathUtil.clamp(this.infinitePitch, -40.0F, 40.0F);
   }

   public boolean isFallFlying() {
      return this.isPausedForMaceDamage()
         ? mc.player != null && mc.player.isFallFlying()
         : mc.player.isFallFlying() || this.packet.getValue() && this.hasElytra && !mc.player.isOnGround() || this.flying;
   }

   public boolean shouldVisualSpoof() {
      return this.isOn() && this.noAnimation.getValue() && !this.isPausedForMaceDamage();
   }

   private long getFireworkDelay() {
      return (long)(this.fireworkMode.is(ElytraFly.FireworkMode.Interval) ? this.fireworkInterval.getValue() : this.delay.getValue());
   }

   private double getSpeedKmh() {
      double var1 = mc.player.getX() - mc.player.prevX;
      double var3 = mc.player.getY() - mc.player.prevY;
      double var5 = mc.player.getZ() - mc.player.prevZ;
      double var7 = Math.sqrt(var1 * var1 + var3 * var3 + var5 * var5) / 1000.0;
      double var9 = 1.388888888888889E-5;
      return var7 / var9 * (double)CrucifixBeta.TIMER.get();
   }

   private boolean shouldUseFirework(double speedKmh) {
      return this.fireworkMode.is(ElytraFly.FireworkMode.Speed)
         ? speedKmh < this.fireworkSpeed.getValue()
         : !this.checkSpeed.getValue() || speedKmh <= this.minSpeed.getValue();
   }

   static {

      maceDamagePauseDepth = 0;
      preMaceDamagePauseDepth = 0;
   }
@Environment(EnvType.CLIENT)
   public class FireWorkTweak {
      boolean press;

      @EventListener
      public void onTick(ClientTickEvent event) {
         if (!Module.nullCheck() && !event.isPost()) {
            if (!ElytraFly.this.isPausedForMaceDamage()) {
               if (!ElytraFly.this.inventory.getValue() || EntityUtil.inInventory()) {
                  if (Wrapper.mc.currentScreen == null) {
                     if (ElytraFly.this.fireWork.isPressed()) {
                        if (!this.press
                           && ElytraFly.this.fireworkTimer.passed(ElytraFly.this.getFireworkDelay())
                           && (!Wrapper.mc.player.isUsingItem() || !ElytraFly.this.usingPause.getValue())
                           && ElytraFly.this.isFallFlying()) {
                           ElytraFly.this.off();
                           ElytraFly.this.fireworkTimer.reset();
                        }

                        this.press = true;
                     } else {
                        this.press = false;
                     }
                  } else {
                     this.press = false;
                  }
               }
            }
         }
      }
   }

   @Environment(EnvType.CLIENT)
   public static enum FireworkMode {
      Auto,
      Interval,
      Speed;

}

   @Environment(EnvType.CLIENT)
   public static enum Mode {
      Control,
      Boost,
      Bounce,
      Freeze,
      None,
      Rotation,
      Pitch;

}
}
