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

import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.ClientTickEvent;
import dev.crucifixbeta.api.events.impl.PacketEvent;
import dev.crucifixbeta.api.events.impl.RotationEvent;
import dev.crucifixbeta.api.utils.combat.CombatUtil;
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.api.utils.world.BlockUtil;
import dev.crucifixbeta.core.impl.RotationManager;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.impl.movement.ElytraFly;
import dev.crucifixbeta.mod.modules.impl.movement.Velocity;
import dev.crucifixbeta.mod.modules.impl.player.AutoPearl;
import dev.crucifixbeta.mod.modules.impl.player.PacketMine;
import dev.crucifixbeta.mod.modules.settings.enums.Timing;
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.block.Blocks;
import net.minecraft.block.LadderBlock;
import net.minecraft.block.ScaffoldingBlock;
import net.minecraft.entity.Entity;
import net.minecraft.entity.decoration.EndCrystalEntity;
import net.minecraft.entity.decoration.ItemFrameEntity;
import net.minecraft.entity.decoration.painting.PaintingEntity;
import net.minecraft.item.Items;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket.Action;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.Full;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.PositionAndOnGround;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;

@Environment(EnvType.CLIENT)
public class Phase extends Module {
   public static Phase INSTANCE;
   private final EnumSetting<Phase.Mode> mode = this.add(new EnumSetting<>("Mode", Phase.Mode.Pearl));
   public final BooleanSetting onEnable = this.add(new BooleanSetting("OnEnable", true));
   public final BooleanSetting onlyGround = this.add(new BooleanSetting("OnlyGround", true));
   private final BooleanSetting breakBlock = this.add(new BooleanSetting("Break", true).setParent());
   private final BooleanSetting scaffolding = this.add(new BooleanSetting("Scaffolding", true, this.breakBlock::isOpen));
   private final BooleanSetting packetMine = this.add(new BooleanSetting("PacketMine", false, this.breakBlock::isOpen));
   private final BooleanSetting crystal = this.add(new BooleanSetting("Crystal", true, this.breakBlock::isOpen));
   private final BooleanSetting itemFrame = this.add(new BooleanSetting("ItemFrame", true, this.breakBlock::isOpen));
   private final BooleanSetting paint = this.add(new BooleanSetting("Paint", true, this.breakBlock::isOpen));
   private final BooleanSetting rotate = this.add(new BooleanSetting("Rotate", true, this.breakBlock::isOpen));
   public final BooleanSetting correct = this.add(new BooleanSetting("Correct", true));
   public final BooleanSetting dynamicPitch = this.add(new BooleanSetting("DynamicPitch", true, this.correct::getValue).setParent());
   private final SliderSetting factor = this.add(
      new SliderSetting("Factor", 0.5, 0.0, 1.0, 0.01, () -> this.dynamicPitch.isOpen() && this.correct.getValue())
   );
   private final BooleanSetting onlyHard = this.add(
      new BooleanSetting("OnlyHard", false, () -> this.dynamicPitch.isOpen() && this.correct.getValue())
   );
   public final SliderSetting pitch = this.add(
      new SliderSetting("Pitch", 88, 0, 90, () -> !this.dynamicPitch.getValue() || !this.correct.getValue())
   );
   private final EnumSetting<Timing> timing = this.add(new EnumSetting<>("Timing", Timing.All));
   private final BooleanSetting yawStep = this.add(new BooleanSetting("YawStep", false).setParent());
   private final BooleanSetting whenElytra = this.add(new BooleanSetting("FallFlying", true, this.yawStep::isOpen));
   private final SliderSetting steps = this.add(new SliderSetting("Steps", 0.05, 0.0, 1.0, 0.01, this.yawStep::isOpen));
   private final SliderSetting fov = this.add(new SliderSetting("Fov", 20.0, 0.0, 360.0, 0.1, this.yawStep::isOpen));
   private final SliderSetting priority = this.add(new SliderSetting("Priority", 100, 0, 100, this.yawStep::isOpen));
   private final BooleanSetting sync = this.add(new BooleanSetting("Sync", true, this.yawStep::isOpen));
   private final SliderSetting clipDelay = this.add(new SliderSetting("ClipDelay", 5, 1, 10, () -> this.mode.is(Phase.Mode.Clip)));
   private final SliderSetting clipRotationDelay = this.add(
      new SliderSetting("ClipRotationDelay", 100, 0, 500, () -> this.mode.is(Phase.Mode.NoPacket))
   );
   private final BooleanSetting clipObsidian = this.add(new BooleanSetting("ClipObsidian", false, () -> this.mode.is(Phase.Mode.NoPacket)));
   private final BooleanSetting clipMove = this.add(new BooleanSetting("ClipMove", true, () -> this.mode.is(Phase.Mode.NoPacket)));
   private final BooleanSetting clipMoveIn = this.add(
      new BooleanSetting("ClipMoveIn", true, () -> this.mode.is(Phase.Mode.NoPacket) && this.clipMove.isOpen())
   );
   private final BooleanSetting clipInvalid = this.add(new BooleanSetting("ClipInvalidPacket", true, () -> this.mode.is(Phase.Mode.NoPacket)));
   private final Timer clipTimer = new Timer();
   public Vec3d directionVec = null;
   Vec3d targetPos;
   private boolean clipCancel = true;
   private int clipPackets;
   private static final double MAGIC_OFFSET;

   public Phase() {
      super("Phase", Module.Category.Exploit);
      this.setChinese("\u73cd\u73e0\u7a7f\u5899");
      INSTANCE = this;
   }

   @Override
   public String getInfo() {
      if (this.mode.is(Phase.Mode.NoPacket)) {
         return String.valueOf(this.clipTimer.getMs());
      } else {
         return this.mode.is(Phase.Mode.Clip) ? String.valueOf(this.clipPackets) : this.mode.getValue().name();
      }
   }

   @EventListener
   public void onRotate(RotationEvent event) {
      if (this.directionVec != null) {
         event.setTarget(this.directionVec, this.steps.getValueFloat(), this.priority.getValueFloat());
      }
   }

   private boolean faceVector(Vec3d directionVec) {
      this.directionVec = directionVec;
      return CrucifixBeta.ROTATION.inFov(directionVec, this.fov.getValueFloat());
   }

   private void updatePos() {
      this.targetPos = new Vec3d(
         mc.player.getX()
            + MathHelper.clamp(
               this.roundToClosest(mc.player.getX(), Math.floor(mc.player.getX()) + 0.241, Math.floor(mc.player.getX()) + 0.759) - mc.player.getX(), -0.2, 0.2
            ),
         mc.player.getY() - 0.5,
         mc.player.getZ()
            + MathHelper.clamp(
               this.roundToClosest(mc.player.getZ(), Math.floor(mc.player.getZ()) + 0.241, Math.floor(mc.player.getZ()) + 0.759) - mc.player.getZ(), -0.2, 0.2
            )
      );
   }

   @EventListener
   public void onTick(ClientTickEvent event) {
      if (!nullCheck()) {
         if (!this.mode.is(Phase.Mode.Pearl)) {
            if (event.isPre()) {
               this.clipUpdate();
            }
         } else if ((!this.timing.is(Timing.Pre) || !event.isPost()) && (!this.timing.is(Timing.Post) || !event.isPre())) {
            if (!AutoPearl.INSTANCE.inventory.getValue() || EntityUtil.inInventory()) {
               if (!Blink.INSTANCE.isOn() || !Blink.INSTANCE.pauseModule.getValue()) {
                  if (!this.onlyGround.getValue() || mc.player.isOnGround() || BlockUtil.getBlock(mc.player.getBlockPos()) instanceof LadderBlock) {
                     if (this.breakBlock.getValue()) {
                        if (this.scaffolding.getValue()) {
                           BlockPos var2 = EntityUtil.getPlayerPos(true);
                           BlockPos var3 = var2.up();
                           if (BlockUtil.getBlock(var2) instanceof ScaffoldingBlock) {
                              this.mineBlock(var2);
                              return;
                           }

                           if (BlockUtil.getBlock(var3) instanceof ScaffoldingBlock) {
                              this.mineBlock(var3);
                              return;
                           }
                        }

                        for (Entity var6 : CrucifixBeta.THREAD.getEntities()) {
                           if (var6 instanceof EndCrystalEntity && this.crystal.getValue()) {
                              if (!(var6.getY() >= mc.player.getY()) && var6.getBoundingBox().intersects(mc.player.getBoundingBox())) {
                                 CombatUtil.attack(var6, this.rotate.getValue());
                              }
                           } else if (this.itemFrame.getValue() && var6 instanceof ItemFrameEntity) {
                              ItemFrameEntity var4 = (ItemFrameEntity)var6;
                              if (var6.getBoundingBox().intersects(new Box(mc.player.getBlockPos()))) {
                                 if (!var4.getHeldItemStack().isEmpty()) {
                                    CombatUtil.attack(var6, this.rotate.getValue());
                                 }

                                 CombatUtil.attack(var6, this.rotate.getValue());
                              }
                           } else if (this.paint.getValue()
                              && var6 instanceof PaintingEntity
                              && var6.getBoundingBox().intersects(new Box(mc.player.getBlockPos()))) {
                              CombatUtil.attack(var6, this.rotate.getValue());
                           }
                        }
                     }

                     if (!this.shouldYawStep()) {
                        if (Velocity.INSTANCE != null) {
                           Velocity.INSTANCE.pearlTimer.reset();
                        }

                        AutoPearl.INSTANCE.throwPearl(this.getYaw(), this.getPitch());
                     } else {
                        this.updatePos();
                        if (!this.faceVector(this.targetPos)) {
                           return;
                        }

                        if (Velocity.INSTANCE != null) {
                           Velocity.INSTANCE.pearlTimer.reset();
                        }

                        if (this.sync.getValue()) {
                           AutoPearl.INSTANCE.throwPearl(this.getYaw(), this.getPitch());
                        } else {
                           this.throwPearl();
                        }
                     }

                     this.disable();
                  }
               }
            }
         }
      }
   }

   @EventListener
   public void onPacket(PacketEvent.Send event) {
      if (!nullCheck() && this.mode.is(Phase.Mode.NoPacket)) {
         Packet var2;
         if (this.clipCancel && (var2 = event.getPacket()) instanceof PlayerMoveC2SPacket) {
            PlayerMoveC2SPacket var3 = (PlayerMoveC2SPacket)var2;
            if (!this.insideClipBlock()) {
               if (this.clipMove.getValue()) {
                  this.disable();
               }

               return;
            }

            if (var3.changesLook() && this.clipTimer.passedMs(this.clipRotationDelay.getValue())) {
               float var4 = var3.getYaw(0.0F);
               float var5 = var3.getPitch(0.0F);
               this.clipCancel = false;
               if (this.clipInvalid.getValue()) {
                  mc.getNetworkHandler().sendPacket(new Full(mc.player.getX(), mc.player.getY() + 1337.0, mc.player.getZ(), var4, var5, false));
                  mc.getNetworkHandler().sendPacket(new Full(mc.player.getX(), mc.player.getY() - 1337.0, mc.player.getZ(), var4, var5, false));
               } else {
                  mc.getNetworkHandler().sendPacket(new Full(mc.player.getX(), mc.player.getY() + 2.0, mc.player.getZ(), var4, var5, false));
                  mc.getNetworkHandler().sendPacket(new Full(mc.player.getX(), mc.player.getY() - 2.0, mc.player.getZ(), var4, var5, false));
               }

               this.clipCancel = true;
               this.clipTimer.reset();
            }

            event.cancel();
         }
      }
   }

   private void clipOnEnable() {
      if (this.mode.is(Phase.Mode.NoPacket) && this.clipMove.getValue()) {
         this.clipCancel = false;
         if (this.clipMoveIn.getValue()) {
            Direction var1 = mc.player.getHorizontalFacing();
            mc.player.setPosition(mc.player.getX() + (double)var1.getOffsetX() * 0.5, mc.player.getY(), mc.player.getZ() + (double)var1.getOffsetZ() * 0.5);
            mc.getNetworkHandler().sendPacket(new PositionAndOnGround(mc.player.getX(), mc.player.getY(), mc.player.getZ(), true));
         } else {
            mc.getNetworkHandler().sendPacket(new PositionAndOnGround(mc.player.getX(), mc.player.getY(), mc.player.getZ(), true));
            mc.player
               .setPosition(
                  this.roundToClosest(mc.player.getX(), Math.floor(mc.player.getX()) + 0.23, Math.floor(mc.player.getX()) + 0.77),
                  mc.player.getY(),
                  this.roundToClosest(mc.player.getZ(), Math.floor(mc.player.getZ()) + 0.23, Math.floor(mc.player.getZ()) + 0.77)
               );
            mc.getNetworkHandler()
               .sendPacket(
                  new PositionAndOnGround(
                     this.roundToClosest(mc.player.getX(), Math.floor(mc.player.getX()) + 0.23, Math.floor(mc.player.getX()) + 0.77),
                     mc.player.getY(),
                     this.roundToClosest(mc.player.getZ(), Math.floor(mc.player.getZ()) + 0.23, Math.floor(mc.player.getZ()) + 0.77),
                     true
                  )
               );
         }

         this.clipCancel = true;
      }
   }

   private void clipUpdate() {
      if (this.mode.is(Phase.Mode.NoPacket)) {
         if (!this.insideClipBlock() && this.clipMove.getValue()) {
            this.disable();
         }
      } else if (this.mode.is(Phase.Mode.Clip)) {
         if (MovementUtil.isMoving()) {
            this.clipPackets = 0;
            return;
         }

         if ((double)mc.player.age % this.clipDelay.getValue() == 0.0) {
            mc.player
               .setPosition(
                  mc.player.getX()
                     + MathHelper.clamp(
                        this.roundToClosest(mc.player.getX(), Math.floor(mc.player.getX()) + 0.241, Math.floor(mc.player.getX()) + 0.759) - mc.player.getX(),
                        -0.03,
                        0.03
                     ),
                  mc.player.getY(),
                  mc.player.getZ()
                     + MathHelper.clamp(
                        this.roundToClosest(mc.player.getZ(), Math.floor(mc.player.getZ()) + 0.241, Math.floor(mc.player.getZ()) + 0.759) - mc.player.getZ(),
                        -0.03,
                        0.03
                     )
               );
            mc.getNetworkHandler().sendPacket(new PositionAndOnGround(mc.player.getX(), mc.player.getY(), mc.player.getZ(), true));
            mc.getNetworkHandler()
               .sendPacket(
                  new PositionAndOnGround(
                     this.roundToClosest(mc.player.getX(), Math.floor(mc.player.getX()) + 0.23, Math.floor(mc.player.getX()) + 0.77),
                     mc.player.getY(),
                     this.roundToClosest(mc.player.getZ(), Math.floor(mc.player.getZ()) + 0.23, Math.floor(mc.player.getZ()) + 0.77),
                     true
                  )
               );
            this.clipPackets++;
         }
      } else if (this.mode.is(Phase.Mode.HitboxDesync)) {
         Direction var1 = mc.player.getHorizontalFacing();
         Box var2 = mc.player.getBoundingBox();
         Vec3d var3 = var2.getCenter();
         Vec3d var4 = new Vec3d(var1.getUnitVector());
         Vec3d var5 = this.merge(BlockPos.ofFloored(var3).toCenterPos().add(0.0, -0.5, 0.0).add(var4.multiply(0.20000996883537)), var1);
         mc.player.setPosition(var5.x == 0.0 ? mc.player.getX() : var5.x, mc.player.getY(), var5.z == 0.0 ? mc.player.getZ() : var5.z);
         this.disable();
      }
   }

   private Vec3d merge(Vec3d pos, Direction facing) {
      return new Vec3d(
         pos.x * (double)Math.abs(facing.getOffsetX()), pos.y * (double)Math.abs(facing.getOffsetY()), pos.z * (double)Math.abs(facing.getOffsetZ())
      );
   }

   private boolean insideClipBlock() {
      BlockPos var1 = EntityUtil.getPlayerPos(true);

      for (int var2 = -1; var2 <= 1; var2++) {
         for (int var3 = -1; var3 <= 1; var3++) {
            for (int var4 = -1; var4 <= 1; var4++) {
               BlockPos var5 = var1.add(var2, var3, var4);
               if ((
                     mc.world.getBlockState(var5).getBlock() == Blocks.BEDROCK
                        || mc.world.getBlockState(var5).getBlock() == Blocks.OBSIDIAN && this.clipObsidian.getValue()
                  )
                  && mc.player.getBoundingBox().intersects(new Box(var5))) {
                  return true;
               }
            }
         }
      }

      return false;
   }

   private boolean shouldYawStep() {
      return this.whenElytra.getValue() || !mc.player.isFallFlying() && (!ElytraFly.INSTANCE.isOn() || !ElytraFly.INSTANCE.isFallFlying())
         ? this.yawStep.getValue()
         : false;
   }

   private void mineBlock(BlockPos pos) {
      sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, pos, Direction.UP, id));
      sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.STOP_DESTROY_BLOCK, pos, Direction.UP, id));
      if (this.packetMine.getValue()) {
         PacketMine.INSTANCE.mine(pos);
      }
   }

   private Vec3d targetPos() {
      BlockPos var1 = mc.player.getBlockPos();
      Vec3d var2 = mc.player.getPos();
      Vec3d var3 = mc.player.getBlockPos().toBottomCenterPos();
      float var4 = this.factor.getValueFloat();
      Vec3d var5 = var3;
      double var6 = Double.MAX_VALUE;

      int[] var8;
      for (int var12 : var8 = new int[]{1, -1}) {
         for (int var16 : var8) {
            Vec3d var17;
            double var18;
            if ((
                  !this.onlyHard.getValue()
                        && (!mc.world.isAir(var1.add(var12, 0, 0)) || !mc.world.isAir(var1.add(0, 0, var16)) || !mc.world.isAir(var1.add(var12, 0, var16)))
                     || CrucifixBeta.HOLE.isHard(var1.add(var12, 0, 0))
                     || CrucifixBeta.HOLE.isHard(var1.add(0, 0, var16))
                     || CrucifixBeta.HOLE.isHard(var1.add(var12, 0, var16))
               )
               && (var18 = (var17 = var3.add((double)((float)var12 * var4), 0.0, (double)((float)var16 * var4))).distanceTo(var2)) < var6) {
               var6 = var18;
               var5 = var17;
            }
         }
      }

      return var5;
   }

   private float getYaw() {
      if (this.correct.getValue()) {
         Vec3d var1;
         return this.dynamicPitch.getValue() && (var1 = this.targetPos()) != null
            ? RotationManager.getRotation(var1)[0]
            : MathHelper.wrapDegrees(RotationManager.getRotation(mc.player.getBlockPos().toCenterPos())[0] - 180.0F);
      } else {
         return mc.player.getYaw();
      }
   }

   private float getPitch() {
      Vec3d var1;
      return this.correct.getValue() && this.dynamicPitch.getValue() && (var1 = this.targetPos()) != null
         ? RotationManager.getRotation(var1)[1]
         : this.pitch.getValueFloat();
   }

   public void throwPearl() {
      AutoPearl.throwing = true;
      if (mc.player.getMainHandStack().getItem() == Items.ENDER_PEARL) {
         sendSequencedPacket(
            id -> new PlayerInteractItemC2SPacket(Hand.MAIN_HAND, id, CrucifixBeta.ROTATION.getLastYaw(), CrucifixBeta.ROTATION.getLastPitch())
         );
         EntityUtil.swingHand(Hand.MAIN_HAND, AutoPearl.INSTANCE.interactSwing.getValue());
      } else {
         int var1;
         if (AutoPearl.INSTANCE.inventory.getValue() && (var1 = InventoryUtil.findItemInventorySlotFromZero(Items.ENDER_PEARL)) != -1) {
            InventoryUtil.inventorySwap(var1, mc.player.getInventory().selectedSlot);
            sendSequencedPacket(
               id -> new PlayerInteractItemC2SPacket(Hand.MAIN_HAND, id, CrucifixBeta.ROTATION.getLastYaw(), CrucifixBeta.ROTATION.getLastPitch())
            );
            EntityUtil.swingHand(Hand.MAIN_HAND, AutoPearl.INSTANCE.interactSwing.getValue());
            InventoryUtil.inventorySwap(var1, mc.player.getInventory().selectedSlot);
            EntityUtil.syncInventory();
         } else {
            var1 = InventoryUtil.findItem(Items.ENDER_PEARL);
            if (var1 != -1) {
               int var2 = mc.player.getInventory().selectedSlot;
               InventoryUtil.switchToSlot(var1);
               sendSequencedPacket(
                  id -> new PlayerInteractItemC2SPacket(Hand.MAIN_HAND, id, CrucifixBeta.ROTATION.getLastYaw(), CrucifixBeta.ROTATION.getLastPitch())
               );
               EntityUtil.swingHand(Hand.MAIN_HAND, AutoPearl.INSTANCE.interactSwing.getValue());
               InventoryUtil.switchToSlot(var2);
            }
         }
      }

      AutoPearl.throwing = false;
   }

   @Override
   public void onDisable() {
      this.clipPackets = 0;
      this.clipCancel = true;
   }

   @Override
   public void onEnable() {
      if (nullCheck()) {
         this.disable();
      } else if (!this.mode.is(Phase.Mode.Pearl)) {
         this.clipOnEnable();
      } else {
         if (AutoPearl.INSTANCE.inventory.getValue()) {
            if (InventoryUtil.findItemInventorySlotFromZero(Items.ENDER_PEARL) == -1) {
               this.disable();
               return;
            }
         } else if (InventoryUtil.findItem(Items.ENDER_PEARL) == -1) {
            this.disable();
            return;
         }

         if (this.onEnable.getValue()) {
            if (!this.onlyGround.getValue() || mc.player.isOnGround() || BlockUtil.getBlock(mc.player.getBlockPos()) instanceof LadderBlock) {
               if (this.breakBlock.getValue()) {
                  if (this.scaffolding.getValue()) {
                     BlockPos var1 = EntityUtil.getPlayerPos(true);
                     BlockPos var2 = var1.up();
                     if (BlockUtil.getBlock(var1) instanceof ScaffoldingBlock) {
                        this.mineBlock(var1);
                        return;
                     }

                     if (BlockUtil.getBlock(var2) instanceof ScaffoldingBlock) {
                        this.mineBlock(var2);
                        return;
                     }
                  }

                  for (Entity var5 : CrucifixBeta.THREAD.getEntities()) {
                     if (var5 instanceof EndCrystalEntity && this.crystal.getValue()) {
                        if (!(var5.getY() >= mc.player.getY()) && var5.getBoundingBox().intersects(mc.player.getBoundingBox())) {
                           CombatUtil.attack(var5, this.rotate.getValue());
                        }
                     } else if (this.itemFrame.getValue() && var5 instanceof ItemFrameEntity) {
                        ItemFrameEntity var3 = (ItemFrameEntity)var5;
                        if (var5.getBoundingBox().intersects(new Box(mc.player.getBlockPos()))) {
                           if (!var3.getHeldItemStack().isEmpty()) {
                              CombatUtil.attack(var5, this.rotate.getValue());
                           }

                           CombatUtil.attack(var5, this.rotate.getValue());
                        }
                     } else if (this.paint.getValue() && var5 instanceof PaintingEntity && var5.getBoundingBox().intersects(new Box(mc.player.getBlockPos()))) {
                        CombatUtil.attack(var5, this.rotate.getValue());
                     }
                  }
               }

               this.directionVec = null;
               this.updatePos();
               if (!this.shouldYawStep()) {
                  if (!AutoPearl.INSTANCE.inventory.getValue() || EntityUtil.inInventory()) {
                     if (!Blink.INSTANCE.isOn() || !Blink.INSTANCE.pauseModule.getValue()) {
                        if (Velocity.INSTANCE != null) {
                           Velocity.INSTANCE.pearlTimer.reset();
                        }

                        AutoPearl.INSTANCE.throwPearl(this.getYaw(), this.getPitch());
                        this.disable();
                     }
                  }
               }
            }
         }
      }
   }

   private double roundToClosest(double num, double low, double high) {
      double var7 = high - num;
      double var9 = num - low;
      return var7 > var9 ? low : high;
   }

   static {

      MAGIC_OFFSET = 0.20000996883537;
   }
@Environment(EnvType.CLIENT)
   private static enum Mode {
      Pearl,
      Clip,
      NoPacket,
      HitboxDesync;

}
}
