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

import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.ClickBlockEvent;
import dev.crucifixbeta.api.events.impl.ClientTickEvent;
import dev.crucifixbeta.api.events.impl.PacketEvent;
import dev.crucifixbeta.api.utils.Wrapper;
import dev.crucifixbeta.api.utils.math.Easing;
import dev.crucifixbeta.api.utils.math.FadeUtils;
import dev.crucifixbeta.api.utils.math.Timer;
import dev.crucifixbeta.api.utils.player.InventoryUtil;
import dev.crucifixbeta.api.utils.render.Render3DUtil;
import dev.crucifixbeta.api.utils.world.BlockUtil;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.settings.impl.BooleanSetting;
import dev.crucifixbeta.mod.modules.settings.impl.ColorSetting;
import dev.crucifixbeta.mod.modules.settings.impl.EnumSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import java.awt.Color;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.TimerTask;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.item.ItemStack;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket.Action;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.Full;
import net.minecraft.registry.Registries;
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.Vec3d;

@Environment(EnvType.CLIENT)
public class SpeedMine2 extends Module {
   public static SpeedMine2 INSTANCE;
   public static BlockPos secondPos;
   public static BlockPos targetPos;
   public static double progress;
   public static int publicProgress;
   public static int secondPublicProgress;
   public static boolean completed;
   public static int maxBreaksCount;
   public static BlockPos selfClickPos;
   private static BlockPos lastInstantPos;
   private static BlockPos lastDonePos;
   private final FadeUtils animationTime = new FadeUtils(1000L);
   private final FadeUtils secondAnim = new FadeUtils(1000L);
   private final DecimalFormat df = new DecimalFormat("0.0");
   private long lastBreakTime = 0L;
   private final EnumSetting<SpeedMine2.Page> page = this.add(new EnumSetting<>("Page", SpeedMine2.Page.General));
   private final BooleanSetting usingPause = this.add(new BooleanSetting("UsingPause", true, () -> this.page.is(SpeedMine2.Page.General)));
   private final BooleanSetting onlyMain = this.add(
      new BooleanSetting("OnlyMain", true, () -> this.page.is(SpeedMine2.Page.General) && this.usingPause.getValue())
   );
   private final EnumSetting<SpeedMine2.SwitchMode> autoSwitch = this.add(
      new EnumSetting<>("AutoSwitch", SpeedMine2.SwitchMode.Silent, () -> this.page.is(SpeedMine2.Page.General))
   );
   private final SliderSetting range = this.add(new SliderSetting("Range", 6.0, 0.0, 12.0, 0.1, () -> this.page.is(SpeedMine2.Page.General)));
   private final SliderSetting maxBreaks = this.add(
      new SliderSetting("TryBreakTime", 6.0, 0.0, 10.0, 1.0, () -> this.page.is(SpeedMine2.Page.General))
   );
   private final BooleanSetting farCancel = this.add(new BooleanSetting("FarCancel", true, () -> this.page.is(SpeedMine2.Page.General)));
   private final BooleanSetting swing = this.add(new BooleanSetting("SwingHand", true, () -> this.page.is(SpeedMine2.Page.General)));
   private final BooleanSetting instantMine = this.add(new BooleanSetting("InstantMine", true, () -> this.page.is(SpeedMine2.Page.General)));
   private final SliderSetting instantDelay = this.add(
      new SliderSetting("InstantDelay", 10.0, 0.0, 1000.0, 1.0, () -> this.page.is(SpeedMine2.Page.General) && this.instantMine.getValue())
   );
   private final BooleanSetting fastBypass = this.add(new BooleanSetting("FastBypass", true, () -> this.page.is(SpeedMine2.Page.General)));
   private final BooleanSetting doubleBreak = this.add(new BooleanSetting("DoubleBreak", false, () -> this.page.is(SpeedMine2.Page.General)))
      .setParent();
   private final BooleanSetting checkGround = this.add(new BooleanSetting("CheckGround", true, () -> this.page.is(SpeedMine2.Page.General)));
   private final BooleanSetting bypassGround = this.add(new BooleanSetting("BypassGround", false, () -> this.page.is(SpeedMine2.Page.General)));
   private final SliderSetting switchDamage = this.add(
      new SliderSetting("SwitchDamage", 95.0, 0.0, 100.0, 1.0, () -> this.page.is(SpeedMine2.Page.General) && this.doubleBreak.isOpen())
   );
   private final SliderSetting switchTime = this.add(
      new SliderSetting("SwitchTime", 100.0, 0.0, 1000.0, 1.0, () -> this.page.is(SpeedMine2.Page.General) && this.doubleBreak.isOpen())
   );
   private final SliderSetting mineDelay = this.add(
      new SliderSetting("MineDelay", 300.0, 0.0, 1000.0, 1.0, () -> this.page.is(SpeedMine2.Page.General))
   );
   private final SliderSetting packetDelay = this.add(
      new SliderSetting("PacketDelay", 200.0, 0.0, 1000.0, 1.0, () -> this.page.is(SpeedMine2.Page.General))
   );
   private final SliderSetting damage = this.add(
      new SliderSetting("Damage", 0.8, 0.0, 2.0, 0.01, () -> this.page.is(SpeedMine2.Page.General))
   );
   private final SliderSetting priority = this.add(new SliderSetting("Priority", 50, 0, 100, () -> this.page.is(SpeedMine2.Page.General)));
   private final BooleanSetting glassDelay = this.add(
      new BooleanSetting("GlassDelay", true, () -> this.page.is(SpeedMine2.Page.General) && this.instantMine.getValue())
   );
   private final SliderSetting glassDelayTime = this.add(
      new SliderSetting(
         "GlassDelayTime",
         500.0,
         100.0,
         2000.0,
         50.0,
         () -> this.page.is(SpeedMine2.Page.General) && this.instantMine.getValue() && this.glassDelay.getValue()
      )
   );
   private final EnumSetting<Easing> ease = this.add(
      new EnumSetting<>("Ease", Easing.CubicInOut, () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final EnumSetting<Easing> fadeEase = this.add(
      new EnumSetting<>("FadeEase", Easing.CubicInOut, () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final EnumSetting<SpeedMine2.Animation> animation = this.add(
      new EnumSetting<>("Animation", SpeedMine2.Animation.Up, () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final SliderSetting expandLine = this.add(new SliderSetting("ExpandLine", 0.0, 0.0, 1.0, () -> this.page.is(SpeedMine2.Page.Render)));
   private final BooleanSetting renderProgress = this.add(new BooleanSetting("RenderProgress", true, () -> this.page.is(SpeedMine2.Page.Render)));
   private final BooleanSetting renderBox = this.add(new BooleanSetting("RenderBox", true, () -> this.page.is(SpeedMine2.Page.Render)));
   private final BooleanSetting renderFill = this.add(new BooleanSetting("RenderFill", true, () -> this.page.is(SpeedMine2.Page.Render)));
   private final BooleanSetting renderOutline = this.add(new BooleanSetting("RenderOutline", true, () -> this.page.is(SpeedMine2.Page.Render)));
   private final SliderSetting lineWidth = this.add(
      new SliderSetting("LineWidth", 2.0, 0.5, 5.0, 0.5, () -> this.page.is(SpeedMine2.Page.Render) && this.renderOutline.getValue())
   );
   private final SliderSetting fillAlpha = this.add(
      new SliderSetting("FillAlpha", 50.0, 0.0, 255.0, 1.0, () -> this.page.is(SpeedMine2.Page.Render) && this.renderFill.getValue())
   );
   private final ColorSetting targetColor = this.add(
      new ColorSetting("TargetColor", new Color(255, 255, 255, 255), () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final ColorSetting secondColor = this.add(
      new ColorSetting("SecondColor", new Color(255, 100, 100, 255), () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final ColorSetting startColor = this.add(
      new ColorSetting("StartFill", new Color(255, 255, 255, 0), () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final ColorSetting startOutlineColor = this.add(
      new ColorSetting("StartOutline", new Color(255, 255, 255, 255), () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final ColorSetting endColor = this.add(
      new ColorSetting("EndFill", new Color(255, 255, 255, 50), () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final ColorSetting endOutlineColor = this.add(
      new ColorSetting("EndOutline", new Color(255, 255, 255, 255), () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final ColorSetting secondSideStartColor = this.add(
      new ColorSetting("SecondSideStart", new Color(255, 100, 100, 0), () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final ColorSetting secondSideEndColor = this.add(
      new ColorSetting("SecondSideEnd", new Color(255, 100, 100, 50), () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final ColorSetting secondLineStartColor = this.add(
      new ColorSetting("SecondLineStart", new Color(255, 100, 100, 0), () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final ColorSetting secondLineEndColor = this.add(
      new ColorSetting("SecondLineEnd", new Color(255, 100, 100, 255), () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final EnumSetting<SpeedMine2.VisualMode> visualMode = this.add(
      new EnumSetting<>("VisualMode", SpeedMine2.VisualMode.Quantum, () -> this.page.is(SpeedMine2.Page.Render))
   );
   private final BooleanSetting enableRipple = this.add(
      new BooleanSetting(
         "RippleEffect", true, () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic
      )
   );
   private final SliderSetting rippleCount = this.add(
      new SliderSetting(
         "RippleCount",
         3.0,
         1.0,
         8.0,
         1.0,
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableRipple.getValue()
      )
   );
   private final SliderSetting rippleSpeed = this.add(
      new SliderSetting(
         "RippleSpeed",
         2.0,
         0.5,
         5.0,
         0.1,
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableRipple.getValue()
      )
   );
   private final ColorSetting rippleColor = this.add(
      new ColorSetting(
         "RippleColor",
         new Color(0, 200, 255, 180),
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableRipple.getValue()
      )
   );
   private final BooleanSetting enableParticles = this.add(
      new BooleanSetting(
         "Particles", true, () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic
      )
   );
   private final SliderSetting particleCount = this.add(
      new SliderSetting(
         "ParticleCount",
         12.0,
         4.0,
         24.0,
         1.0,
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableParticles.getValue()
      )
   );
   private final SliderSetting particleSpeed = this.add(
      new SliderSetting(
         "ParticleSpeed",
         1.0,
         0.2,
         3.0,
         0.1,
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableParticles.getValue()
      )
   );
   private final ColorSetting particleColor = this.add(
      new ColorSetting(
         "ParticleColor",
         new Color(255, 100, 255, 220),
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableParticles.getValue()
      )
   );
   private final BooleanSetting enableHologram = this.add(
      new BooleanSetting(
         "Hologram", true, () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic
      )
   );
   private final SliderSetting hologramDensity = this.add(
      new SliderSetting(
         "GridDensity",
         4.0,
         2.0,
         10.0,
         1.0,
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableHologram.getValue()
      )
   );
   private final ColorSetting hologramColor = this.add(
      new ColorSetting(
         "GridColor",
         new Color(0, 255, 200, 120),
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableHologram.getValue()
      )
   );
   private final BooleanSetting enableScanLine = this.add(
      new BooleanSetting(
         "ScanLine", true, () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic
      )
   );
   private final SliderSetting scanSpeed = this.add(
      new SliderSetting(
         "ScanSpeed",
         1.5,
         0.5,
         4.0,
         0.1,
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableScanLine.getValue()
      )
   );
   private final ColorSetting scanLineColor = this.add(
      new ColorSetting(
         "ScanLineColor",
         new Color(255, 50, 50, 200),
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableScanLine.getValue()
      )
   );
   private final BooleanSetting enableShatter = this.add(
      new BooleanSetting(
         "ShatterEffect", true, () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic
      )
   );
   private final SliderSetting shatterDuration = this.add(
      new SliderSetting(
         "ShatterTime",
         800.0,
         300.0,
         2000.0,
         50.0,
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableShatter.getValue()
      )
   );
   private final ColorSetting shatterColor = this.add(
      new ColorSetting(
         "ShatterColor",
         new Color(255, 200, 0, 230),
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableShatter.getValue()
      )
   );
   private final BooleanSetting enableGlow = this.add(
      new BooleanSetting(
         "GlowEffect", true, () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic
      )
   );
   private final SliderSetting glowIntensity = this.add(
      new SliderSetting(
         "GlowIntensity",
         1.5,
         0.5,
         3.0,
         0.1,
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableGlow.getValue()
      )
   );
   private final ColorSetting glowColor = this.add(
      new ColorSetting(
         "GlowColor",
         new Color(100, 200, 255, 100),
         () -> this.page.is(SpeedMine2.Page.Render) && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic && this.enableGlow.getValue()
      )
   );
   private final BooleanSetting renderInstantMine = this.add(new BooleanSetting("RenderInstant", true, () -> this.page.is(SpeedMine2.Page.Render)));
   private final ColorSetting instantMineColor = this.add(
      new ColorSetting(
         "InstantColor", new Color(255, 215, 0, 255), () -> this.page.is(SpeedMine2.Page.Render) && this.renderInstantMine.getValue()
      )
   );
   private final SliderSetting instantFlashSpeed = this.add(
      new SliderSetting("FlashSpeed", 3.0, 1.0, 10.0, 0.5, () -> this.page.is(SpeedMine2.Page.Render) && this.renderInstantMine.getValue())
   );
   private final BooleanSetting instantPulse = this.add(
      new BooleanSetting("PulseEffect", true, () -> this.page.is(SpeedMine2.Page.Render) && this.renderInstantMine.getValue())
   );
   private final SliderSetting pulseAmplitude = this.add(
      new SliderSetting(
         "PulseAmp",
         0.3,
         0.1,
         1.0,
         0.1,
         () -> this.page.is(SpeedMine2.Page.Render) && this.renderInstantMine.getValue() && this.instantPulse.getValue()
      )
   );
   private final BooleanSetting renderAfterBreak = this.add(new BooleanSetting("RenderAfterBreak", true, () -> this.page.is(SpeedMine2.Page.Render)));
   private final SliderSetting afterBreakDuration = this.add(
      new SliderSetting(
         "AfterBreakTime", 2000.0, 500.0, 10000.0, 100.0, () -> this.page.is(SpeedMine2.Page.Render) && this.renderAfterBreak.getValue()
      )
   );
   private final ColorSetting afterBreakColor = this.add(
      new ColorSetting(
         "AfterBreakColor", new Color(0, 255, 150, 200), () -> this.page.is(SpeedMine2.Page.Render) && this.renderAfterBreak.getValue()
      )
   );
   private final SliderSetting afterBreakAlpha = this.add(
      new SliderSetting("AfterBreakAlpha", 80.0, 0.0, 255.0, 1.0, () -> this.page.is(SpeedMine2.Page.Render) && this.renderAfterBreak.getValue())
   );
   private final SliderSetting afterBreakLineWidth = this.add(
      new SliderSetting("AfterBreakLine", 2.0, 0.5, 5.0, 0.5, () -> this.page.is(SpeedMine2.Page.Render) && this.renderAfterBreak.getValue())
   );
   private final Timer mineTimer = new Timer();
   private final Timer timer = new Timer();
   private final Timer secondTimer = new Timer();
   private final Timer instantTimer = new Timer();
   private final Timer bypassTimer = new Timer();
   private final Timer glassDelayTimer = new Timer();
   private final Timer keepAliveTimer = new Timer();
   private int oldSlot = -1;
   private boolean hasSwitch = false;
   private boolean secondHasSwitch = false;
   private boolean started = false;
   private boolean secondStarted = false;
   private double secondProgress = 0.0;
   private long lastTime;
   private long secondLastTime;
   private double render = 1.0;
   private double secondRender = 1.0;
   private final List<SpeedMine2.ShardParticle> shatterParticles = new ArrayList<>();
   private final Random random = new Random();
   private long shatterStartTime = 0L;
   private boolean isShattering = false;

   public SpeedMine2() {
      super("SpeedMine2", Module.Category.Player);
      this.setChinese("SpeedMine2");
      INSTANCE = this;
      this.initChineseTranslations();
   }

   private void initChineseTranslations() {
      this.page.setChinese("\u9875\u9762");
      this.usingPause.setChinese("\u4f7f\u7528\u65f6\u6682\u505c");
      this.onlyMain.setChinese("\u4ec5\u4e3b\u624b");
      this.autoSwitch.setChinese("\u81ea\u52a8\u5207\u6362");
      this.range.setChinese("\u6316\u6398\u8303\u56f4");
      this.maxBreaks.setChinese("\u6700\u5927\u5c1d\u8bd5\u6b21\u6570");
      this.farCancel.setChinese("\u8fdc\u8ddd\u79bb\u53d6\u6d88");
      this.swing.setChinese("\u6325\u52a8\u624b\u81c2");
      this.instantMine.setChinese("\u5373\u65f6\u6316\u6398");
      this.instantDelay.setChinese("\u5373\u65f6\u5ef6\u8fdf");
      this.fastBypass.setChinese("\u5feb\u901f\u7ed5\u8fc7");
      this.doubleBreak.setChinese("\u53cc\u91cd\u7834\u574f");
      this.doubleBreak.setParent();
      this.checkGround.setChinese("\u68c0\u67e5\u5730\u9762");
      this.bypassGround.setChinese("\u7ed5\u8fc7\u5730\u9762");
      this.switchDamage.setChinese("\u5207\u6362\u4f24\u5bb3\u9608\u503c");
      this.switchTime.setChinese("\u5207\u6362\u65f6\u95f4");
      this.mineDelay.setChinese("\u6316\u6398\u5ef6\u8fdf");
      this.packetDelay.setChinese("\u6570\u636e\u5305\u5ef6\u8fdf");
      this.damage.setChinese("\u6316\u6398\u4f24\u5bb3");
      this.priority.setChinese("\u4f18\u5148\u7ea7");
      this.glassDelay.setChinese("\u73bb\u7483\u5ef6\u8fdf");
      this.glassDelayTime.setChinese("\u73bb\u7483\u5ef6\u8fdf\u65f6\u95f4");
      this.ease.setChinese("\u7f13\u52a8\u6548\u679c");
      this.fadeEase.setChinese("\u6de1\u51fa\u7f13\u52a8");
      this.animation.setChinese("\u52a8\u753b\u7c7b\u578b");
      this.expandLine.setChinese("\u7ebf\u6761\u6269\u5c55");
      this.renderProgress.setChinese("\u663e\u793a\u8fdb\u5ea6");
      this.renderBox.setChinese("\u6e32\u67d3\u65b9\u6846");
      this.renderFill.setChinese("\u6e32\u67d3\u586b\u5145");
      this.renderOutline.setChinese("\u6e32\u67d3\u8f6e\u5ed3");
      this.lineWidth.setChinese("\u7ebf\u5bbd");
      this.fillAlpha.setChinese("\u586b\u5145\u900f\u660e\u5ea6");
      this.targetColor.setChinese("\u76ee\u6807\u989c\u8272");
      this.secondColor.setChinese("\u6b21\u8981\u989c\u8272");
      this.startColor.setChinese("\u8d77\u59cb\u586b\u5145\u989c\u8272");
      this.startOutlineColor.setChinese("\u8d77\u59cb\u8f6e\u5ed3\u989c\u8272");
      this.endColor.setChinese("\u7ed3\u675f\u586b\u5145\u989c\u8272");
      this.endOutlineColor.setChinese("\u7ed3\u675f\u8f6e\u5ed3\u989c\u8272");
      this.secondSideStartColor.setChinese("\u6b21\u8981\u4fa7\u9762\u8d77\u59cb\u989c\u8272");
      this.secondSideEndColor.setChinese("\u6b21\u8981\u4fa7\u9762\u7ed3\u675f\u989c\u8272");
      this.secondLineStartColor.setChinese("\u6b21\u8981\u7ebf\u6761\u8d77\u59cb\u989c\u8272");
      this.secondLineEndColor.setChinese("\u6b21\u8981\u7ebf\u6761\u7ed3\u675f\u989c\u8272");
      this.visualMode.setChinese("\u89c6\u89c9\u6a21\u5f0f");
      this.enableRipple.setChinese("\u542f\u7528\u6d9f\u6f2a\u6548\u679c");
      this.rippleCount.setChinese("\u6d9f\u6f2a\u6570\u91cf");
      this.rippleSpeed.setChinese("\u6d9f\u6f2a\u901f\u5ea6");
      this.rippleColor.setChinese("\u6d9f\u6f2a\u989c\u8272");
      this.enableParticles.setChinese("\u542f\u7528\u7c92\u5b50\u6548\u679c");
      this.particleCount.setChinese("\u7c92\u5b50\u6570\u91cf");
      this.particleSpeed.setChinese("\u7c92\u5b50\u901f\u5ea6");
      this.particleColor.setChinese("\u7c92\u5b50\u989c\u8272");
      this.enableHologram.setChinese("\u542f\u7528\u5168\u606f\u6548\u679c");
      this.hologramDensity.setChinese("\u7f51\u683c\u5bc6\u5ea6");
      this.hologramColor.setChinese("\u7f51\u683c\u989c\u8272");
      this.enableScanLine.setChinese("\u542f\u7528\u626b\u63cf\u7ebf");
      this.scanSpeed.setChinese("\u626b\u63cf\u901f\u5ea6");
      this.scanLineColor.setChinese("\u626b\u63cf\u7ebf\u989c\u8272");
      this.enableShatter.setChinese("\u542f\u7528\u7834\u788e\u6548\u679c");
      this.shatterDuration.setChinese("\u7834\u788e\u6301\u7eed\u65f6\u95f4");
      this.shatterColor.setChinese("\u7834\u788e\u989c\u8272");
      this.enableGlow.setChinese("\u542f\u7528\u53d1\u5149\u6548\u679c");
      this.glowIntensity.setChinese("\u53d1\u5149\u5f3a\u5ea6");
      this.glowColor.setChinese("\u53d1\u5149\u989c\u8272");
      this.renderInstantMine.setChinese("\u6e32\u67d3\u5373\u65f6\u6316\u6398");
      this.instantMineColor.setChinese("\u5373\u65f6\u6316\u6398\u989c\u8272");
      this.instantFlashSpeed.setChinese("\u95ea\u70c1\u901f\u5ea6");
      this.instantPulse.setChinese("\u8109\u51b2\u6548\u679c");
      this.pulseAmplitude.setChinese("\u8109\u51b2\u632f\u5e45");
      this.renderAfterBreak.setChinese("\u7834\u574f\u540e\u6e32\u67d3");
      this.afterBreakDuration.setChinese("\u7834\u574f\u540e\u6301\u7eed\u65f6\u95f4");
      this.afterBreakColor.setChinese("\u7834\u574f\u540e\u989c\u8272");
      this.afterBreakAlpha.setChinese("\u7834\u574f\u540e\u900f\u660e\u5ea6");
      this.afterBreakLineWidth.setChinese("\u7834\u574f\u540e\u7ebf\u5bbd");
   }

   @Override
   public String getInfo() {
      if (targetPos == null) {
         return null;
      } else {
         double var1 = (double)this.getMineTicks(this.getTool(targetPos));
         return progress >= var1 * this.damage.getValue() ? "Done" : publicProgress + "%";
      }
   }

   @Override
   public void onEnable() {
      maxBreaksCount = 0;
      this.hasSwitch = false;
      this.secondHasSwitch = false;
      this.bypassTimer.setMs(999999L);
      this.mineTimer.setMs(999999L);
      this.instantTimer.setMs(999999L);
      this.timer.setMs(999999L);
      this.secondTimer.setMs(999999L);
      this.keepAliveTimer.setMs(999999L);
      targetPos = null;
      secondPos = null;
      this.started = false;
      this.secondStarted = false;
      publicProgress = 0;
      secondPublicProgress = 0;
      progress = 0.0;
      this.secondProgress = 0.0;
      this.lastTime = System.currentTimeMillis();
      this.secondLastTime = System.currentTimeMillis();
      this.render = 1.0;
      this.lastBreakTime = 0L;
      this.shatterParticles.clear();
      this.isShattering = false;
   }

   @Override
   public void onDisable() {
      if (this.hasSwitch) {
         InventoryUtil.switchToSlot(this.oldSlot);
         this.hasSwitch = false;
      }

      if (this.secondHasSwitch) {
         InventoryUtil.switchToSlot(this.oldSlot);
         this.secondHasSwitch = false;
      }

      targetPos = null;
      secondPos = null;
      completed = false;
      this.started = false;
      this.secondStarted = false;
      progress = 0.0;
      this.secondProgress = 0.0;
      publicProgress = 0;
      secondPublicProgress = 0;
      lastInstantPos = null;
      lastDonePos = null;
      this.lastBreakTime = 0L;
      this.shatterParticles.clear();
      this.isShattering = false;
   }

   @EventListener
   public void onTick(ClientTickEvent event) {
      if (!nullCheck()) {
         boolean var2 = mc.player.isUsingItem();
         if (publicProgress >= 100) {
            selfClickPos = null;
            if (targetPos != null) {
               lastDonePos = targetPos;
            }

            if (!this.instantMine.getValue()) {
               targetPos = null;
            }
         }

         if (secondPublicProgress >= 100) {
            selfClickPos = null;
            secondPos = null;
         }

         if (this.timer.passedMs((double)((long)this.switchTime.getValue())) && this.hasSwitch && this.autoSwitch.getValue() != SpeedMine2.SwitchMode.None) {
            if (this.autoSwitch.getValue() == SpeedMine2.SwitchMode.Delay) {
               InventoryUtil.switchToSlot(this.oldSlot);
            } else if (this.autoSwitch.getValue() == SpeedMine2.SwitchMode.Silent) {
               this.sendPacket(new UpdateSelectedSlotC2SPacket(this.oldSlot));
            }

            this.hasSwitch = false;
         }

         if ((double)maxBreaksCount >= this.maxBreaks.getValue() * 10.0) {
            maxBreaksCount = 0;
            targetPos = null;
         }

         if (secondPos != null && this.doubleBreak.getValue()) {
            if (this.farCancel.getValue() && Math.sqrt(mc.player.getEyePos().squaredDistanceTo(secondPos.toCenterPos())) > this.range.getValue()) {
               secondPos = null;
               return;
            }

            double var3 = (double)this.getMineTicks2(this.getTool(secondPos));
            double var5 = (double)(System.currentTimeMillis() - this.secondLastTime) / 1000.0;
            double var7 = var3 * this.damage.getValue();
            secondPublicProgress = (int)Math.max(0.0, Math.min(100.0, this.secondProgress / var7 * 100.0));
            this.secondLastTime = System.currentTimeMillis();
            if (!this.secondStarted) {
               this.secondStarted = true;
               this.secondProgress = 0.0;
               return;
            }

            if (this.checkGround.getValue() && !mc.player.isOnGround()) {
               if (this.checkGround.getValue() && !mc.player.isOnGround() && !var2) {
                  this.secondProgress += var5 * 4.0;
               }
            } else if (!var2) {
               this.secondProgress += var5 * 20.0;
            }

            this.secondProgress = Math.max(0.0, Math.min(this.secondProgress, var3 * this.damage.getValue() * 1.5));
            if (this.secondProgress >= var3 * this.damage.getValue()) {
               this.sendStopSecond();
            }
         }

         if (this.doubleBreak.getValue()
            && (!this.usingPause.getValue() || !this.checkPause(this.onlyMain.getValue()))
            && ((double)secondPublicProgress >= this.switchDamage.getValue() || (double)publicProgress >= this.switchDamage.getValue())
            && !this.hasSwitch
            && secondPos != null) {
            int var9 = this.getTool(secondPos);
            if (!this.hasSwitch) {
               this.oldSlot = mc.player.getInventory().selectedSlot;
            }

            if (this.autoSwitch.getValue() != SpeedMine2.SwitchMode.None && var9 != -1) {
               if (this.autoSwitch.getValue() == SpeedMine2.SwitchMode.Delay) {
                  InventoryUtil.switchToSlot(var9);
               } else if (this.autoSwitch.getValue() == SpeedMine2.SwitchMode.Silent) {
                  this.sendPacket(new UpdateSelectedSlotC2SPacket(var9));
               }

               this.timer.reset();
               this.hasSwitch = true;
            }
         }

         if (targetPos != null) {
            if (this.farCancel.getValue() && Math.sqrt(mc.player.getEyePos().squaredDistanceTo(targetPos.toCenterPos())) > this.range.getValue()) {
               targetPos = null;
               return;
            }

            double var12 = (double)this.getMineTicks(this.getTool(targetPos));
            double var13 = var12 * this.damage.getValue();
            publicProgress = (int)Math.max(0.0, Math.min(100.0, progress / var13 * 100.0));
            if (progress >= var12 * this.damage.getValue() && completed) {
               if (this.isAir(targetPos) || mc.world.getBlockState(targetPos).isReplaceable()) {
                  maxBreaksCount = 0;
               }

               if (!this.isAir(targetPos)
                  && !mc.world.getBlockState(targetPos).isReplaceable()
                  && (!this.usingPause.getValue() || !this.checkPause(this.onlyMain.getValue()))) {
                  maxBreaksCount++;
               }
            }

            if (this.instantMine.getValue() && completed) {
               if (!mc.world.isAir(targetPos)
                  && !mc.world.getBlockState(targetPos).isReplaceable()
                  && this.instantTimer.passedMs((double)((long)this.instantDelay.getValue()))) {
                  if (this.glassDelay.getValue()) {
                     BlockState var10 = mc.world.getBlockState(targetPos);
                     boolean var11 = var10.getBlock() == Blocks.GLASS
                        || var10.getBlock().toString().toLowerCase().contains("glass")
                        || Registries.BLOCK.getId(var10.getBlock()).toString().contains("glass");
                     if (var11 && !this.glassDelayTimer.passedMs((double)((long)this.glassDelayTime.getValue()))) {
                        return;
                     }

                     if (var11) {
                        this.glassDelayTimer.reset();
                     }
                  }

                  this.sendStop();
                  this.instantTimer.reset();
               }

               return;
            }

            double var14 = (double)(System.currentTimeMillis() - this.lastTime) / 1000.0;
            this.lastTime = System.currentTimeMillis();
            if (!this.started) {
               this.sendStart(targetPos);
               return;
            }

            if (this.checkGround.getValue() && !mc.player.isOnGround()) {
               if (this.checkGround.getValue() && !mc.player.isOnGround() && !var2) {
                  progress += var14 * 4.0;
               }
            } else if (!var2) {
               progress += var14 * 20.0;
            }

            progress = Math.max(0.0, Math.min(progress, var12 * this.damage.getValue() * 1.5));
            if (progress >= var12 * this.damage.getValue()) {
               this.sendStop();
               completed = true;
               if (targetPos != null) {
                  lastDonePos = targetPos;
               }

               if (this.instantMine.getValue()) {
                  lastInstantPos = targetPos;
               }

               if (!this.instantMine.getValue() && secondPos == null) {
                  targetPos = null;
               }
            }
         }
      }

      this.updateShatterParticles();
   }

   @EventListener
   public void onAttackBlock(ClickBlockEvent event) {
      if (!nullCheck() && !mc.player.isCreative()) {
         event.cancel();
         BlockPos var2 = event.getPos();
         if (!this.mineTimer.passedMs((double)((long)this.mineDelay.getValue()))) {
            return;
         }

         selfClickPos = var2;
         this.mine(var2);
      }
   }

   @EventListener
   public void onPacketSend(PacketEvent.Send event) {
      if (nullCheck()) {
         if (mc.world != null && targetPos != null && this.started) {
            if (event.getPacket() instanceof PlayerActionC2SPacket var3) {
               Action var4 = var3.getAction();
               BlockPos var5 = var3.getPos();
               if (var4 == Action.ABORT_DESTROY_BLOCK && (var5.equals(targetPos) || secondPos != null && var5.equals(secondPos))) {
                  event.cancel();
                  return;
               }

               if (var4 == Action.START_DESTROY_BLOCK || var4 == Action.STOP_DESTROY_BLOCK || var4 == Action.ABORT_DESTROY_BLOCK) {
                  return;
               }
            }

            if (this.keepAliveTimer.passedMs(10.0)) {
               this.refreshMiningState();
            }
         }
      }
   }

   private void refreshMiningState() {
      if (targetPos != null && this.started && mc.world != null) {
         Direction var1 = BlockUtil.getClickSide(targetPos);
         if (var1 == null) {
            var1 = Direction.UP;
         }

         this.sendPacket(new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, targetPos, var1));
         this.keepAliveTimer.reset();
      }
   }

   @Override
   public void onRender3D(MatrixStack matrixStack) {
      if (this.visualMode.getValue() == SpeedMine2.VisualMode.Classic) {
         this.renderClassicMode(matrixStack);
      } else {
         this.renderAdvancedMode(matrixStack);
      }
   }

   private void renderClassicMode(MatrixStack matrixStack) {
      if (targetPos != null && this.renderBox.getValue()) {
         this.renderTargetBlock(
            matrixStack,
            targetPos,
            progress,
            publicProgress,
            completed,
            this.startColor.getValue(),
            this.endColor.getValue(),
            this.startOutlineColor.getValue(),
            this.endOutlineColor.getValue(),
            this.targetColor.getValue(),
            true
         );
      }

      if (secondPos != null && this.doubleBreak.getValue() && this.renderBox.getValue()) {
         this.renderTargetBlock(
            matrixStack,
            secondPos,
            this.secondProgress,
            secondPublicProgress,
            false,
            this.secondSideStartColor.getValue(),
            this.secondSideEndColor.getValue(),
            this.secondLineStartColor.getValue(),
            this.secondLineEndColor.getValue(),
            this.secondColor.getValue(),
            false
         );
      }

      if (this.renderInstantMine.getValue() && this.instantMine.getValue()) {
         if (targetPos != null && completed) {
            this.renderQuantumInstant(matrixStack, targetPos);
         } else if (lastInstantPos != null) {
            this.renderQuantumInstant(matrixStack, lastInstantPos);
         }
      }

      if (lastDonePos != null && this.renderAfterBreak.getValue() && this.lastBreakTime > 0L) {
         this.renderAfterBreakEffect(matrixStack, lastDonePos);
      }

      if (lastDonePos != null && this.renderProgress.getValue() && (targetPos == null || !completed)) {
         Render3DUtil.drawText3D("Done", lastDonePos.toCenterPos(), this.targetColor.getValue());
      }
   }

   private void renderAdvancedMode(MatrixStack matrixStack) {
      if (targetPos != null && this.renderBox.getValue()) {
         this.renderQuantumBlock(matrixStack, targetPos, progress, publicProgress, completed);
      }

      if (secondPos != null && this.doubleBreak.getValue() && this.renderBox.getValue()) {
         this.renderQuantumBlock(matrixStack, secondPos, this.secondProgress, secondPublicProgress, false);
      }

      if (this.enableShatter.getValue() && this.isShattering) {
         this.renderShatterEffect(matrixStack);
      }

      if (this.renderInstantMine.getValue() && this.instantMine.getValue()) {
         if (targetPos != null && completed) {
            this.renderQuantumInstant(matrixStack, targetPos);
         } else if (lastInstantPos != null) {
            this.renderQuantumInstant(matrixStack, lastInstantPos);
         }
      }

      if (lastDonePos != null && this.renderAfterBreak.getValue() && this.lastBreakTime > 0L) {
         this.renderQuantumAfterBreak(matrixStack, lastDonePos);
      }
   }

   private void renderQuantumBlock(MatrixStack matrixStack, BlockPos pos, double currentProgress, int displayProgress, boolean isCompleted) {
      if (!this.isAir(pos)) {
         double var7 = (double)this.getMineTicks(this.getTool(pos));
         double var9 = Math.min(1.0, Math.max(0.0, currentProgress / (var7 * this.damage.getValue())));
         long var11 = System.currentTimeMillis();
         Vec3d var13 = pos.toCenterPos();
         if (this.enableGlow.getValue()) {
            this.renderGlowEffect(matrixStack, var13, var9, var11);
         }

         if (this.enableHologram.getValue()) {
            this.renderHolographicGrid(matrixStack, pos, var9, var11);
         }

         if (this.enableRipple.getValue()) {
            this.renderEnergyRipples(matrixStack, var13, var9, var11);
         }

         if (this.enableParticles.getValue()) {
            this.renderOrbitingParticles(matrixStack, var13, var9, var11);
         }

         if (this.enableScanLine.getValue()) {
            this.renderScanLine(matrixStack, pos, var11);
         }

         Box var14 = this.getFillBox(pos, var9);
         Box var15 = this.getOutlineBox(pos, var9);
         if (this.renderFill.getValue()) {
            Color var16 = this.getQuantumFillColor(var9, var11);
            Render3DUtil.drawFill(matrixStack, var14, var16);
         }

         if (this.renderOutline.getValue()) {
            Color var20 = this.getQuantumOutlineColor(var9, var11);
            float var17 = (float)this.lineWidth.getValue();
            Render3DUtil.drawBox(matrixStack, var15, var20, var17);
         }

         if (this.renderProgress.getValue()) {
            String var21 = isCompleted ? "\u2713 DONE" : displayProgress + "%";
            Color var22 = this.getQuantumTextColor(var9, var11);
            Render3DUtil.drawText3D(var21, var13.add(0.0, 0.6, 0.0), var22);
            String var18 = "[" + this.visualMode.getValue().name() + "]";
            Color var19 = new Color(
               this.particleColor.getValue().getRed(), this.particleColor.getValue().getGreen(), this.particleColor.getValue().getBlue(), 180
            );
            Render3DUtil.drawText3D(var18, var13.add(0.0, -0.4, 0.0), var19);
         }
      }
   }

   private void renderAfterBreakEffect(MatrixStack matrixStack, BlockPos pos) {
      if (pos != null && this.lastBreakTime > 0L) {
         long var3 = System.currentTimeMillis();
         long var5 = var3 - this.lastBreakTime;
         long var7 = (long)this.afterBreakDuration.getValue();
         if (var5 > var7) {
            lastDonePos = null;
            this.lastBreakTime = 0L;
         } else {
            double var9 = 1.0 - (double)var5 / (double)var7;
            double var11 = Easing.CubicOut.ease(var9);
            Box var13 = new Box(
               (double)pos.getX(), (double)pos.getY(), (double)pos.getZ(), (double)pos.getX() + 1.0, (double)pos.getY() + 1.0, (double)pos.getZ() + 1.0
            );
            Color var14 = this.afterBreakColor.getValue();
            int var15 = (int)(this.afterBreakAlpha.getValue() * var11);
            Color var16 = new Color(var14.getRed(), var14.getGreen(), var14.getBlue(), var15);
            Render3DUtil.drawFill(matrixStack, var13, var16);
            int var17 = (int)((double)var14.getAlpha() * var11);
            Color var18 = new Color(var14.getRed(), var14.getGreen(), var14.getBlue(), var17);
            float var19 = (float)this.afterBreakLineWidth.getValue();
            Render3DUtil.drawBox(matrixStack, var13, var18, var19);
            if (this.renderProgress.getValue()) {
               int var20 = (int)(255.0 * var11);
               Color var21 = new Color(255, 255, 255, var20);
               String var22 = String.format("%.1fs", (double)(var7 - var5) / 1000.0);
               Render3DUtil.drawText3D("✓ " + var22, pos.toCenterPos().add(0.0, 0.5, 0.0), var21);
            }
         }
      }
   }

   private void renderGlowEffect(MatrixStack matrixStack, Vec3d center, double progressRatio, long time) {
      double var7 = (double)(time % 2000L) / 2000.0 * Math.PI * 2.0;
      double var9 = this.glowIntensity.getValue() * (0.7 + Math.sin(var7) * 0.3);
      double var11 = 0.8 + progressRatio * 0.4;
      double var13 = var11 * var9;
      Color var15 = this.glowColor.getValue();

      for (int var16 = 3; var16 >= 0; var16--) {
         double var17 = var13 + (double)var16 * 0.15;
         int var19 = (int)((double)var15.getAlpha() * (1.0 - (double)var16 * 0.25) * progressRatio);
         Color var20 = new Color(var15.getRed(), var15.getGreen(), var15.getBlue(), var19);
         Box var21 = new Box(center.x - var17, center.y - var17, center.z - var17, center.x + var17, center.y + var17, center.z + var17);
         Render3DUtil.drawFill(matrixStack, var21, var20);
      }
   }

   private void renderHolographicGrid(MatrixStack matrixStack, BlockPos pos, double progressRatio, long time) {
      Color var7 = this.hologramColor.getValue();
      int var8 = (int)this.hologramDensity.getValue();
      double var9 = 1.0 / (double)var8;
      float var11 = 0.5F;
      double var12 = (double)(time % 3000L) / 3000.0 * Math.PI * 4.0;

      for (int var14 = 0; var14 <= var8; var14++) {
         double var15 = (double)var14 * var9;
         double var17 = Math.sin(var12 + var15 * Math.PI * 2.0) * 0.02;
         int var19 = (int)((double)var7.getAlpha() * (0.4 + progressRatio * 0.6));
         Color var20 = new Color(var7.getRed(), var7.getGreen(), var7.getBlue(), var19);
         double var21 = (double)pos.getX() + var15 + var17;
         Vec3d var23 = new Vec3d(var21, (double)pos.getY(), (double)pos.getZ());
         Vec3d var24 = new Vec3d(var21, (double)(pos.getY() + 1), (double)(pos.getZ() + 1));
         Render3DUtil.drawLine(var23, var24, var20);
         Vec3d var25 = new Vec3d((double)pos.getX(), (double)pos.getY() + var15 + var17, (double)pos.getZ());
         Vec3d var26 = new Vec3d((double)(pos.getX() + 1), (double)pos.getY() + var15 + var17, (double)(pos.getZ() + 1));
         Render3DUtil.drawLine(var25, var26, var20);
         Vec3d var27 = new Vec3d((double)pos.getX(), (double)pos.getY(), (double)pos.getZ() + var15 + var17);
         Vec3d var28 = new Vec3d((double)(pos.getX() + 1), (double)(pos.getY() + 1), (double)pos.getZ() + var15 + var17);
         Render3DUtil.drawLine(var27, var28, var20);
      }
   }

   private void renderEnergyRipples(MatrixStack matrixStack, Vec3d center, double progressRatio, long time) {
      Color var7 = this.rippleColor.getValue();
      int var8 = (int)this.rippleCount.getValue();
      double var9 = this.rippleSpeed.getValue();

      for (int var11 = 0; var11 < var8; var11++) {
         double var12 = ((double)time * var9 * 0.001 + (double)var11 / (double)var8) % 1.0;
         double var14 = var12 * 1.2 * progressRatio;
         int var16 = (int)((double)var7.getAlpha() * (1.0 - var12) * progressRatio);
         Color var17 = new Color(var7.getRed(), var7.getGreen(), var7.getBlue(), var16);
         this.renderCircleRing(matrixStack, center, var14, var17, 32);
      }
   }

   private void renderCircleRing(MatrixStack matrixStack, Vec3d center, double radius, Color color, int segments) {
      float var7 = 1.5F;

      for (int var8 = 0; var8 < segments; var8++) {
         double var9 = (double)var8 / (double)segments * Math.PI * 2.0;
         double var11 = (double)(var8 + 1) / (double)segments * Math.PI * 2.0;
         Vec3d var13 = new Vec3d(center.x + Math.cos(var9) * radius, center.y, center.z + Math.sin(var9) * radius);
         Vec3d var14 = new Vec3d(center.x + Math.cos(var11) * radius, center.y, center.z + Math.sin(var11) * radius);
         Render3DUtil.drawLine(var13, var14, color);
      }
   }

   private void renderOrbitingParticles(MatrixStack matrixStack, Vec3d center, double progressRatio, long time) {
      Color var7 = this.particleColor.getValue();
      int var8 = (int)this.particleCount.getValue();
      double var9 = this.particleSpeed.getValue();

      for (int var11 = 0; var11 < var8; var11++) {
         double var12 = (double)time * var9 * 0.002 + (double)var11 / (double)var8 * Math.PI * 2.0;
         double var14 = Math.sin((double)time * 0.003 + (double)var11 * 0.5) * 0.3;
         double var16 = 0.6 + Math.sin((double)time * 0.002 + (double)var11) * 0.15;
         double var18 = (double)(var11 % 3) * (Math.PI * 2.0 / 3.0);
         double var20 = center.x + Math.cos(var12) * var16;
         double var22 = center.y + var14 + Math.cos(var18) * 0.25;
         double var24 = center.z + Math.sin(var12) * var16;
         int var26 = (int)((double)var7.getAlpha() * (0.6 + Math.sin((double)time * 0.005 + (double)var11 * 0.3) * 0.4));
         Color var27 = new Color(var7.getRed(), var7.getGreen(), var7.getBlue(), var26);
         double var28 = 0.04 + Math.abs(Math.sin((double)time * 0.004 + (double)var11 * 0.7)) * 0.03;
         Box var30 = new Box(var20 - var28, var22 - var28, var24 - var28, var20 + var28, var22 + var28, var24 + var28);
         Render3DUtil.drawFill(matrixStack, var30, var27);
         if (var11 % 3 == 0) {
            Color var31 = new Color(var7.getRed(), var7.getGreen(), var7.getBlue(), var26 / 2);
            Vec3d var32 = new Vec3d(center.x + Math.cos(var12 - 0.3) * var16 * 1.2, center.y + var14, center.z + Math.sin(var12 - 0.3) * var16 * 1.2);
            Render3DUtil.drawLine(new Vec3d(var20, var22, var24), var32, var31);
         }
      }
   }

   private void renderScanLine(MatrixStack matrixStack, BlockPos pos, long time) {
      Color var5 = this.scanLineColor.getValue();
      double var6 = this.scanSpeed.getValue();
      double var8 = (double)time * var6 * 0.001 % 2.0 - 1.0;
      double var10 = (double)pos.getY() + 0.5 + var8 * 0.8;
      if (var10 >= (double)pos.getY() && var10 <= (double)(pos.getY() + 1)) {
         int var12 = var5.getAlpha();
         Color var13 = new Color(var5.getRed(), var5.getGreen(), var5.getBlue(), var12);
         float var14 = 3.0F;
         Vec3d var15 = new Vec3d((double)pos.getX() - 0.05, var10, (double)pos.getZ() - 0.05);
         Vec3d var16 = new Vec3d((double)pos.getX() + 1.05, var10, (double)pos.getZ() + 1.05);
         Render3DUtil.drawLine(var15, var16, var13);
         Vec3d var17 = new Vec3d((double)pos.getX() + 1.05, var10, (double)pos.getZ() - 0.05);
         Vec3d var18 = new Vec3d((double)pos.getX() - 0.05, var10, (double)pos.getZ() + 1.05);
         Render3DUtil.drawLine(var17, var18, var13);
      }
   }

   private Color getQuantumFillColor(double progressRatio, long time) {
      Color var5 = this.startColor.getValue();
      Color var6 = this.endColor.getValue();
      double var7 = (double)(time % 5000L) / 5000.0;
      int var9 = this.interpolateColor(var5.getRed(), var6.getRed(), progressRatio);
      int var10 = this.interpolateColor(var5.getGreen(), var6.getGreen(), progressRatio);
      int var11 = this.interpolateColor(var5.getBlue(), var6.getBlue(), progressRatio);
      var9 = (int)Math.min(255.0, (double)var9 + Math.sin(var7 * Math.PI * 2.0) * 30.0);
      var10 = (int)Math.min(255.0, (double)var10 + Math.sin(var7 * Math.PI * 2.0 + 2.0) * 30.0);
      var11 = (int)Math.min(255.0, (double)var11 + Math.sin(var7 * Math.PI * 2.0 + 4.0) * 30.0);
      int var12 = (int)(((double)var5.getAlpha() + (double)(var6.getAlpha() - var5.getAlpha()) * progressRatio) * (this.fillAlpha.getValue() / 255.0));
      return new Color(var9, var10, var11, var12);
   }

   private Color getQuantumOutlineColor(double progressRatio, long time) {
      Color var5 = this.startOutlineColor.getValue();
      Color var6 = this.endOutlineColor.getValue();
      double var7 = (Math.sin((double)time * 0.005) + 1.0) / 2.0;
      int var9 = this.interpolateColor(var5.getRed(), var6.getRed(), progressRatio);
      int var10 = this.interpolateColor(var5.getGreen(), var6.getGreen(), progressRatio);
      int var11 = this.interpolateColor(var5.getBlue(), var6.getBlue(), progressRatio);
      var9 = (int)Math.min(255.0, (double)var9 * (0.8 + var7 * 0.2));
      var10 = (int)Math.min(255.0, (double)var10 * (0.8 + var7 * 0.2));
      var11 = (int)Math.min(255.0, (double)var11 * (0.8 + var7 * 0.2));
      int var12 = this.interpolateColor(var5.getAlpha(), var6.getAlpha(), progressRatio);
      return new Color(var9, var10, var11, var12);
   }

   private Color getQuantumTextColor(double progressRatio, long time) {
      Color var5 = this.targetColor.getValue();
      double var6 = (Math.sin((double)time * 0.008) + 1.0) / 2.0;
      int var8 = (int)((double)var5.getAlpha() * (0.85 + var6 * 0.15));
      return new Color(var5.getRed(), var5.getGreen(), var5.getBlue(), var8);
   }

   private void renderQuantumInstant(MatrixStack matrixStack, BlockPos pos) {
      if (!this.isAir(pos)) {
         long var3 = System.currentTimeMillis();
         double var5 = (double)(var3 % 1000L) / 1000.0 * this.instantFlashSpeed.getValue() * Math.PI * 2.0;
         double var7 = (Math.sin(var5) + 1.0) / 2.0;
         Color var9 = this.instantMineColor.getValue();
         int var10 = var9.getRed();
         int var11 = var9.getGreen();
         int var12 = var9.getBlue();
         double var13 = 1.0;
         if (this.instantPulse.getValue()) {
            double var15 = (double)(var3 % 2000L) / 2000.0 * Math.PI * 2.0;
            var13 = 1.0 + Math.sin(var15) * this.pulseAmplitude.getValue();
         }

         double var48 = (1.0 - var13) * 0.5;
         Box var17 = new Box(
            (double)pos.getX() - var48,
            (double)pos.getY() - var48,
            (double)pos.getZ() - var48,
            (double)(pos.getX() + 1) + var48,
            (double)(pos.getY() + 1) + var48,
            (double)(pos.getZ() + 1) + var48
         );
         if (this.enableGlow.getValue()) {
            for (int var18 = 2; var18 >= 0; var18--) {
               double var19 = var48 + (double)var18 * 0.1;
               Box var21 = new Box(
                  (double)pos.getX() - var19,
                  (double)pos.getY() - var19,
                  (double)pos.getZ() - var19,
                  (double)(pos.getX() + 1) + var19,
                  (double)(pos.getY() + 1) + var19,
                  (double)(pos.getZ() + 1) + var19
               );
               int var22 = (int)(100.0 * var7 * (1.0 - (double)var18 * 0.3));
               Color var23 = new Color(var10, var11, var12, var22);
               Render3DUtil.drawFill(matrixStack, var21, var23);
            }
         }

         int var49 = (int)(150.0 * var7);
         Color var24 = new Color(var10, var11, var12, var49);
         Render3DUtil.drawFill(matrixStack, var17, var24);
         int var25 = (int)(255.0 * var7);
         Color var50 = new Color(var10, var11, var12, var25);
         float var51 = (float)this.lineWidth.getValue();
         Render3DUtil.drawBox(matrixStack, var17, var50, var51);
         if (this.enableRipple.getValue()) {
            for (int var52 = 0; var52 < 3; var52++) {
               double var26 = ((double)var3 * 0.003 + (double)var52 * 0.33) % 1.0;
               double var28 = var26 * 1.5;
               int var30 = (int)((double)var25 * (1.0 - var26) * 0.6);
               Color var31 = new Color(var10, var11, var12, var30);
               this.renderCircleRing(matrixStack, pos.toCenterPos(), var28, var31, 24);
            }
         }

         String var53 = "\u26a1 INSTANT";
         Color var32 = new Color(var10, var11, var12, var25);
         Vec3d var33 = pos.toCenterPos().add(0.0, var13 * 0.5, 0.0);
         Render3DUtil.drawText3D(var53, var33, var32);
         if (this.enableParticles.getValue()) {
            for (int var34 = 0; var34 < 8; var34++) {
               double var35 = (double)var3 / 400.0 + (double)var34 * Math.PI / 4.0;
               double var37 = 0.7 + Math.sin((double)var3 / 250.0 + (double)var34) * 0.25;
               double var39 = (double)pos.getX() + 0.5 + Math.cos(var35) * var37;
               double var41 = (double)pos.getY() + 0.5 + Math.sin(var35 * 2.0) * 0.3;
               double var43 = (double)pos.getZ() + 0.5 + Math.sin(var35) * var37;
               int var45 = (int)(220.0 * var7);
               Color var46 = new Color(255, 255, 255, var45);
               Vec3d var47 = new Vec3d(var39, var41, var43);
               Render3DUtil.drawText3D("\u2726", var47, var46);
            }
         }
      }
   }

   private void renderQuantumAfterBreak(MatrixStack matrixStack, BlockPos pos) {
      if (pos != null && this.lastBreakTime > 0L) {
         long var3 = System.currentTimeMillis();
         long var5 = var3 - this.lastBreakTime;
         long var7 = (long)this.afterBreakDuration.getValue();
         if (var5 > var7) {
            lastDonePos = null;
            this.lastBreakTime = 0L;
         } else {
            double var9 = 1.0 - (double)var5 / (double)var7;
            double var11 = Easing.CubicOut.ease(var9);
            Box var13 = new Box(
               (double)pos.getX(), (double)pos.getY(), (double)pos.getZ(), (double)pos.getX() + 1.0, (double)pos.getY() + 1.0, (double)pos.getZ() + 1.0
            );
            Color var14 = this.afterBreakColor.getValue();
            if (this.enableGlow.getValue()) {
               for (int var15 = 2; var15 >= 0; var15--) {
                  double var16 = 0.1 + (double)var15 * 0.08;
                  Box var18 = new Box(
                     (double)pos.getX() - var16,
                     (double)pos.getY() - var16,
                     (double)pos.getZ() - var16,
                     (double)(pos.getX() + 1) + var16,
                     (double)(pos.getY() + 1) + var16,
                     (double)(pos.getZ() + 1) + var16
                  );
                  int var19 = (int)(this.afterBreakAlpha.getValue() * var11 * (1.0 - (double)var15 * 0.3) * 0.5);
                  Color var20 = new Color(var14.getRed(), var14.getGreen(), var14.getBlue(), var19);
                  Render3DUtil.drawFill(matrixStack, var18, var20);
               }
            }

            int var31 = (int)(this.afterBreakAlpha.getValue() * var11);
            Color var21 = new Color(var14.getRed(), var14.getGreen(), var14.getBlue(), var31);
            Render3DUtil.drawFill(matrixStack, var13, var21);
            int var22 = (int)((double)var14.getAlpha() * var11);
            Color var32 = new Color(var14.getRed(), var14.getGreen(), var14.getBlue(), var22);
            float var33 = (float)this.afterBreakLineWidth.getValue();
            Render3DUtil.drawBox(matrixStack, var13, var32, var33);
            if (this.enableRipple.getValue()) {
               double var23 = (double)var5 % 1000.0 / 1000.0;
               double var25 = var23 * 1.0;
               int var27 = (int)((double)var22 * (1.0 - var23) * 0.7);
               Color var28 = new Color(var14.getRed(), var14.getGreen(), var14.getBlue(), var27);
               this.renderCircleRing(matrixStack, pos.toCenterPos(), var25, var28, 20);
            }

            if (this.renderProgress.getValue()) {
               int var34 = (int)(255.0 * var11);
               Color var29 = new Color(255, 255, 255, var34);
               String var30 = String.format("%.1fs", (double)(var7 - var5) / 1000.0);
               Render3DUtil.drawText3D("✓ " + var30, pos.toCenterPos().add(0.0, 0.5, 0.0), var29);
            }
         }
      }
   }

   private void triggerShatter(BlockPos pos) {
      this.shatterParticles.clear();
      int var2 = 20 + this.random.nextInt(15);

      for (int var3 = 0; var3 < var2; var3++) {
         double var4 = this.random.nextDouble() * Math.PI * 2.0;
         double var6 = (this.random.nextDouble() - 0.5) * Math.PI;
         double var8 = 0.5 + this.random.nextDouble() * 1.5;
         Vec3d var10 = new Vec3d(Math.cos(var4) * Math.cos(var6) * var8, Math.sin(var6) * var8 + 0.5, Math.sin(var4) * Math.cos(var6) * var8);
         Vec3d var11 = pos.toCenterPos()
            .add((this.random.nextDouble() - 0.5) * 0.8, (this.random.nextDouble() - 0.5) * 0.8, (this.random.nextDouble() - 0.5) * 0.8);
         double var12 = 0.03 + this.random.nextDouble() * 0.06;
         this.shatterParticles.add(new SpeedMine2.ShardParticle(var11, var10, var12));
      }

      this.shatterStartTime = System.currentTimeMillis();
      this.isShattering = true;
   }

   private void updateShatterParticles() {
      if (this.isShattering) {
         long var1 = System.currentTimeMillis() - this.shatterStartTime;
         if ((double)var1 > this.shatterDuration.getValue()) {
            this.shatterParticles.clear();
            this.isShattering = false;
         } else {
            double var3 = 0.016;

            for (SpeedMine2.ShardParticle var6 : this.shatterParticles) {
               var6.velocity = var6.velocity.add(0.0, -0.02, 0.0);
               var6.position = var6.position.add(var6.velocity.x * var3, var6.velocity.y * var3, var6.velocity.z * var3);
            }
         }
      }
   }

   private void renderShatterEffect(MatrixStack matrixStack) {
      if (this.isShattering && !this.shatterParticles.isEmpty()) {
         long var2 = System.currentTimeMillis() - this.shatterStartTime;
         double var4 = Math.min(1.0, (double)var2 / this.shatterDuration.getValue());
         double var6 = 1.0 - var4;
         Color var8 = this.shatterColor.getValue();

         for (SpeedMine2.ShardParticle var10 : this.shatterParticles) {
            int var11 = (int)((double)var8.getAlpha() * var6);
            Color var12 = new Color(var8.getRed(), var8.getGreen(), var8.getBlue(), var11);
            double var13 = var10.size * (1.0 - var4 * 0.5);
            Box var15 = new Box(
               var10.position.x - var13,
               var10.position.y - var13,
               var10.position.z - var13,
               var10.position.x + var13,
               var10.position.y + var13,
               var10.position.z + var13
            );
            Render3DUtil.drawFill(matrixStack, var15, var12);
            Color var16 = new Color(255, 255, 255, (int)((double)var11 * 0.6));
            Render3DUtil.drawBox(matrixStack, var15, var16, 0.5F);
         }
      }
   }

   private void renderTargetBlock(
      MatrixStack matrixStack,
      BlockPos pos,
      double currentProgress,
      int displayProgress,
      boolean isCompleted,
      Color startFillColor,
      Color endFillColor,
      Color startLineColor,
      Color endLineColor,
      Color textColor,
      boolean isPrimary
   ) {
      if (!this.isAir(pos)) {
         double var13 = (double)this.getMineTicks(this.getTool(pos));
         double var15 = Math.min(1.0, Math.max(0.0, currentProgress / (var13 * this.damage.getValue())));
         double var17 = this.ease.getValue().ease(var15);
         double var19 = this.fadeEase.getValue().ease(var15);
         Box var21 = this.getFillBox(pos, var17);
         Box var22 = this.getOutlineBox(pos, var17);
         Object var23 = null;
         if (this.renderOutline.getValue()) {
            var23 = new Color(
               this.interpolateColor(startLineColor.getRed(), endLineColor.getRed(), var19),
               this.interpolateColor(startLineColor.getGreen(), endLineColor.getGreen(), var19),
               this.interpolateColor(startLineColor.getBlue(), endLineColor.getBlue(), var19),
               this.interpolateColor(startLineColor.getAlpha(), endLineColor.getAlpha(), var19)
            );
            float var24 = (float)this.lineWidth.getValue();
            Render3DUtil.drawBox(matrixStack, var22, (Color)var23, var24);
         }

         int var27 = 0;
         if (this.renderFill.getValue()) {
            var27 = (int)(
               ((double)startFillColor.getAlpha() + (double)(endFillColor.getAlpha() - startFillColor.getAlpha()) * var19)
                  * (this.fillAlpha.getValue() / 255.0)
            );
            Color var25 = new Color(
               this.interpolateColor(startFillColor.getRed(), endFillColor.getRed(), var19),
               this.interpolateColor(startFillColor.getGreen(), endFillColor.getGreen(), var19),
               this.interpolateColor(startFillColor.getBlue(), endFillColor.getBlue(), var19),
               var27
            );
            Render3DUtil.drawFill(matrixStack, var21, var25);
         }

         if (this.renderProgress.getValue()) {
            String var29 = isCompleted ? "Done" : displayProgress + "%";
            Render3DUtil.drawText3D(var29, pos.toCenterPos(), textColor);
         }
      }
   }

   private Box getFillBox(BlockPos pos, double ease) {
      switch ((SpeedMine2.Animation)this.animation.getValue()) {
         case Center:
            ease = (1.0 - ease) / 2.0;
            return new Box(pos).shrink(ease, ease, ease).shrink(-ease, -ease, -ease);
         case Grow:
            ease = (1.0 - ease) / 2.0;
            return new Box(pos).shrink(ease, 0.0, ease).shrink(-ease, 0.0, -ease);
         case Up:
            return new Box(
               (double)pos.getX(), (double)pos.getY(), (double)pos.getZ(), (double)(pos.getX() + 1), (double)pos.getY() + ease, (double)(pos.getZ() + 1)
            );
         case Down:
            return new Box(
               (double)pos.getX(),
               (double)(pos.getY() + 1) - ease,
               (double)pos.getZ(),
               (double)(pos.getX() + 1),
               (double)(pos.getY() + 1),
               (double)(pos.getZ() + 1)
            );
         case Oscillation:
            return new Box(pos).shrink(ease, ease, ease).shrink(-ease, -ease, -ease);
         default:
            return new Box(pos);
      }
   }

   private Box getOutlineBox(BlockPos pos, double ease) {
      ease = Math.min(ease + this.expandLine.getValue(), 1.0);
      switch ((SpeedMine2.Animation)this.animation.getValue()) {
         case Center:
            ease = (1.0 - ease) / 2.0;
            return new Box(pos).shrink(ease, ease, ease).shrink(-ease, -ease, -ease);
         case Grow:
            ease = (1.0 - ease) / 2.0;
            return new Box(pos).shrink(ease, 0.0, ease).shrink(-ease, 0.0, -ease);
         case Up:
            return new Box(
               (double)pos.getX(), (double)pos.getY(), (double)pos.getZ(), (double)(pos.getX() + 1), (double)pos.getY() + ease, (double)(pos.getZ() + 1)
            );
         case Down:
            return new Box(
               (double)pos.getX(),
               (double)(pos.getY() + 1) - ease,
               (double)pos.getZ(),
               (double)(pos.getX() + 1),
               (double)(pos.getY() + 1),
               (double)(pos.getZ() + 1)
            );
         case Oscillation:
            return new Box(pos).shrink(ease, ease, ease).shrink(-ease, -ease, -ease);
         default:
            return new Box(pos);
      }
   }

   private int interpolateColor(int start, int end, double progress) {
      return (int)((float)start + (float)(end - start) * (float)progress);
   }

   private void sendStart(BlockPos pos) {
      if (secondPos != null) {
         this.sendPacket(new PlayerActionC2SPacket(Action.STOP_DESTROY_BLOCK, secondPos, BlockUtil.getClickSide(secondPos)));
         long var2 = (long)this.packetDelay.getValue();
         final java.util.Timer var4 = new java.util.Timer();
         var4.schedule(new TimerTask() {
            @Override
            public void run() {
               Wrapper.mc.execute(() -> {
                  SpeedMine2.this.sendPacket(new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, pos, BlockUtil.getClickSide(pos)));
                  if (SpeedMine2.this.fastBypass.getValue()) {
                     BlockPos var2 = SpeedMine2.this.getSafeBypassPos();
                     Module.sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var2, Direction.DOWN, id));
                     Module.sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var2, Direction.DOWN, id));
                     Module.sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var2, Direction.DOWN, id));
                     Module.sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var2, Direction.DOWN, id));
                     Module.sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var2, Direction.DOWN, id));
                  }
               });
               var4.cancel();
            }
         }, var2);
      } else {
         this.sendPacket(new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, pos, BlockUtil.getClickSide(pos)));
         if (this.fastBypass.getValue()) {
            BlockPos var5 = this.getSafeBypassPos();
            sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var5, Direction.DOWN, id));
            sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var5, Direction.DOWN, id));
            sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var5, Direction.DOWN, id));
            sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var5, Direction.DOWN, id));
            sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var5, Direction.DOWN, id));
         }
      }

      this.sendPacket(new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, pos, BlockUtil.getClickSide(pos)));
      if (this.fastBypass.getValue()) {
         BlockPos var6 = this.getSafeBypassPos();
         sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var6, Direction.DOWN, id));
         sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var6, Direction.DOWN, id));
         sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var6, Direction.DOWN, id));
         sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var6, Direction.DOWN, id));
         sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.START_DESTROY_BLOCK, var6, Direction.DOWN, id));
      }

      mc.player.swingHand(Hand.MAIN_HAND);
      if (pos.equals(targetPos)) {
         this.started = true;
         progress = 0.0;
      } else {
         this.secondStarted = true;
         this.secondProgress = 0.0;
      }
   }

   private BlockPos getSafeBypassPos() {
      int var1 = mc.player.getBlockY();
      short var2 = 319;
      if (var1 > 200) {
         return mc.player.getBlockPos().down(7891);
      } else if (var1 + 7891 > var2) {
         int var3 = Math.max(1, var2 - var1 - 10);
         return mc.player.getBlockPos().up(var3);
      } else {
         return mc.player.getBlockPos().up(7891);
      }
   }

   private void sendStop() {
      if (!this.usingPause.getValue() || !this.checkPause(this.onlyMain.getValue())) {
         if (!this.doubleBreak.getValue() || secondPos == null) {
            int var1 = this.getTool(targetPos);
            if (!this.hasSwitch) {
               this.oldSlot = mc.player.getInventory().selectedSlot;
            }

            if (this.autoSwitch.getValue() != SpeedMine2.SwitchMode.None && var1 != -1) {
               if (this.autoSwitch.getValue() == SpeedMine2.SwitchMode.Delay) {
                  InventoryUtil.switchToSlot(var1);
               } else if (this.autoSwitch.getValue() == SpeedMine2.SwitchMode.Silent) {
                  this.sendPacket(new UpdateSelectedSlotC2SPacket(var1));
               }

               this.timer.reset();
               this.hasSwitch = true;
            }
         }

         if (this.bypassGround.getValue() && !mc.player.isFallFlying() && targetPos != null && !this.isAir(targetPos) && !mc.player.isOnGround()) {
            mc.getNetworkHandler()
               .sendPacket(new Full(mc.player.getX(), mc.player.getY() + 1.0E-9, mc.player.getZ(), mc.player.getYaw(), mc.player.getPitch(), true));
            mc.player.onLanding();
         }

         if (this.swing.getValue()) {
            mc.player.swingHand(Hand.MAIN_HAND);
         }

         sendSequencedPacket(id -> new PlayerActionC2SPacket(Action.STOP_DESTROY_BLOCK, targetPos, BlockUtil.getClickSide(targetPos), id));
         if (this.renderAfterBreak.getValue() && targetPos != null) {
            lastDonePos = targetPos.toImmutable();
            this.lastBreakTime = System.currentTimeMillis();
            if (this.enableShatter.getValue() && this.visualMode.getValue() != SpeedMine2.VisualMode.Classic) {
               this.triggerShatter(targetPos);
            }
         }
      }
   }

   private void sendStopSecond() {
      if (this.bypassGround.getValue() && !mc.player.isFallFlying() && secondPos != null && !this.isAir(secondPos) && !mc.player.isOnGround()) {
         mc.getNetworkHandler()
            .sendPacket(new Full(mc.player.getX(), mc.player.getY() + 1.0E-9, mc.player.getZ(), mc.player.getYaw(), mc.player.getPitch(), true));
         mc.player.onLanding();
      }

      if (this.swing.getValue()) {
         mc.player.swingHand(Hand.MAIN_HAND);
      }
   }

   public void mine(BlockPos pos) {
      this.mineTimer.reset();
      maxBreaksCount = 0;
      lastInstantPos = null;
      lastDonePos = null;
      if (this.doubleBreak.getValue()) {
         if (targetPos != null && secondPos == null && !targetPos.equals(pos)) {
            if (completed) {
               this.setTarget(pos);
            } else {
               secondPos = targetPos;
               this.setTarget(pos);
            }
         } else if (targetPos == null || !targetPos.equals(pos) && (secondPos == null || !secondPos.equals(pos))) {
            this.setTarget(pos);
         }
      } else if (!pos.equals(targetPos)) {
         this.setTarget(pos);
      }
   }

   private void resetTarget() {
      this.mineTimer.reset();
      targetPos = null;
      publicProgress = 0;
      this.started = false;
      progress = 0.0;
      completed = false;
   }

   private void setTarget(BlockPos pos) {
      targetPos = pos;
      progress = 0.0;
      publicProgress = 0;
      this.started = false;
      completed = false;
      this.lastTime = System.currentTimeMillis();
      this.secondStarted = false;
      this.secondProgress = 0.0;
      secondPublicProgress = 0;
   }

   private boolean isAir(BlockPos breakPos) {
      return mc.world.isAir(breakPos) || BlockUtil.getBlock(breakPos) == Blocks.FIRE && BlockUtil.hasCrystal(breakPos);
   }

   private float getMineTicks(int slot) {
      return this.calcMineTicks(targetPos, slot);
   }

   private float getMineTicks2(int slot) {
      return this.calcMineTicks(secondPos, slot);
   }

   private float calcMineTicks(BlockPos pos, int slot) {
      if (pos != null && mc.world != null && mc.player != null) {
         BlockState var3 = mc.world.getBlockState(pos);
         float var4 = var3.getHardness(mc.world, pos);
         if (var4 < 0.0F) {
            return Float.MAX_VALUE;
         } else if (var4 == 0.0F) {
            return 1.0F;
         } else {
            ItemStack var5 = slot == -1 ? ItemStack.EMPTY : mc.player.getInventory().getStack(slot);
            boolean var6 = var5.isSuitableFor(var3);
            float var7 = var5.getMiningSpeedMultiplier(var3);
            int var8 = EnchantmentHelper.getLevel(
               mc.world.getRegistryManager().getWrapperOrThrow(Enchantments.EFFICIENCY.getRegistryRef()).getOptional(Enchantments.EFFICIENCY).get(), var5
            );
            if (var8 > 0 && var7 > 1.0F) {
               var7 += (float)(var8 * var8 + 1);
            }

            if (mc.player.hasStatusEffect(StatusEffects.HASTE)) {
               int var9 = mc.player.getStatusEffect(StatusEffects.HASTE).getAmplifier();
               var7 *= 1.0F + (float)(var9 + 1) * 0.2F;
            }

            if (mc.player.hasStatusEffect(StatusEffects.MINING_FATIGUE)) {
               int var10 = mc.player.getStatusEffect(StatusEffects.MINING_FATIGUE).getAmplifier();

               var7 *= switch (var10) {
                  case 0 -> 0.3F;
                  case 1 -> 0.09F;
                  case 2 -> 0.0027F;
                  default -> 8.1E-4F;
               };
            }

            float var11 = var7 / var4 / (var6 ? 30.0F : 100.0F);
            return var11 <= 0.0F ? Float.MAX_VALUE : 1.0F / var11;
         }
      } else {
         return 20.0F;
      }
   }

   private int getTool(BlockPos pos) {
      int var2 = -1;
      float var3 = 1.0F;

      for (int var4 = 0; var4 < 9; var4++) {
         ItemStack var5 = mc.player.getInventory().getStack(var4);
         if (var5 != ItemStack.EMPTY) {
            float var6 = (float)EnchantmentHelper.getLevel(
               mc.world.getRegistryManager().getWrapperOrThrow(Enchantments.EFFICIENCY.getRegistryRef()).getOptional(Enchantments.EFFICIENCY).get(), var5
            );
            float var7 = var5.getMiningSpeedMultiplier(mc.world.getBlockState(pos));
            if (var6 + var7 > var3) {
               var3 = var6 + var7;
               var2 = var4;
            }
         }
      }

      return var2;
   }

   public boolean checkPause(boolean onlyMain) {
      return mc.options.useKey.isPressed() && (!onlyMain || mc.player.getActiveHand() == Hand.MAIN_HAND);
   }

   private void sendPacket(Packet<?> packet) {
      if (mc.getNetworkHandler() != null) {
         mc.getNetworkHandler().sendPacket(packet);
      }
   }

   static {

      progress = 0.0;
      publicProgress = 0;
      secondPublicProgress = 0;
      completed = false;
      maxBreaksCount = 0;
      selfClickPos = null;
      lastInstantPos = null;
      lastDonePos = null;
   }
@Environment(EnvType.CLIENT)
   public static enum Animation {
      Center,
      Grow,
      Up,
      Down,
      Oscillation;

}

   @Environment(EnvType.CLIENT)
   public static enum Page {
      General,
      Render;

}

   @Environment(EnvType.CLIENT)
   private class ShardParticle {
      Vec3d position;
      Vec3d velocity;
      double size;

      ShardParticle(Vec3d position, Vec3d velocity, double size) {
         this.position = position;
         this.velocity = velocity;
         this.size = size;
      }
   }

   @Environment(EnvType.CLIENT)
   public static enum SwitchMode {
      None,
      Delay,
      Silent;

}

   @Environment(EnvType.CLIENT)
   public static enum VisualMode {
      Classic,
      Quantum,
      Cyberpunk,
      Neon;

}
}
