/*
 * Decompiled with CFR 0.152.
 * 
 * Could not load the following classes:
 *  meteordevelopment.orbit.EventHandler
 *  net.minecraft.class_1109
 *  net.minecraft.class_1113
 *  net.minecraft.class_1799
 *  net.minecraft.class_1802
 *  net.minecraft.class_1923
 *  net.minecraft.class_1935
 *  net.minecraft.class_2246
 *  net.minecraft.class_2248
 *  net.minecraft.class_2338
 *  net.minecraft.class_2338$class_2339
 *  net.minecraft.class_2350
 *  net.minecraft.class_2350$class_2351
 *  net.minecraft.class_238
 *  net.minecraft.class_2382
 *  net.minecraft.class_2561
 *  net.minecraft.class_2680
 *  net.minecraft.class_2741
 *  net.minecraft.class_2769
 *  net.minecraft.class_2791
 *  net.minecraft.class_2818
 *  net.minecraft.class_2826
 *  net.minecraft.class_327
 *  net.minecraft.class_332
 *  net.minecraft.class_3414
 *  net.minecraft.class_3417
 *  net.minecraft.class_368
 */
package meteordevelopment.meteorclient.systems.modules.donut;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import meteordevelopment.meteorclient.events.render.Render3DEvent;
import meteordevelopment.meteorclient.events.world.BlockUpdateEvent;
import meteordevelopment.meteorclient.events.world.ChunkDataEvent;
import meteordevelopment.meteorclient.events.world.TickEvent;
import meteordevelopment.meteorclient.renderer.ShapeMode;
import meteordevelopment.meteorclient.settings.BoolSetting;
import meteordevelopment.meteorclient.settings.ColorSetting;
import meteordevelopment.meteorclient.settings.DoubleSetting;
import meteordevelopment.meteorclient.settings.EnumSetting;
import meteordevelopment.meteorclient.settings.IntSetting;
import meteordevelopment.meteorclient.settings.Setting;
import meteordevelopment.meteorclient.settings.SettingGroup;
import meteordevelopment.meteorclient.systems.modules.Categories;
import meteordevelopment.meteorclient.systems.modules.Module;
import meteordevelopment.meteorclient.utils.Utils;
import meteordevelopment.meteorclient.utils.render.MeteorToast;
import meteordevelopment.meteorclient.utils.render.color.Color;
import meteordevelopment.meteorclient.utils.render.color.SettingColor;
import meteordevelopment.orbit.EventHandler;
import net.minecraft.class_1109;
import net.minecraft.class_1113;
import net.minecraft.class_1799;
import net.minecraft.class_1802;
import net.minecraft.class_1923;
import net.minecraft.class_1935;
import net.minecraft.class_2246;
import net.minecraft.class_2248;
import net.minecraft.class_2338;
import net.minecraft.class_2350;
import net.minecraft.class_238;
import net.minecraft.class_2382;
import net.minecraft.class_2561;
import net.minecraft.class_2680;
import net.minecraft.class_2741;
import net.minecraft.class_2769;
import net.minecraft.class_2791;
import net.minecraft.class_2818;
import net.minecraft.class_2826;
import net.minecraft.class_327;
import net.minecraft.class_332;
import net.minecraft.class_3414;
import net.minecraft.class_3417;
import net.minecraft.class_368;

public class ChunkFinder
extends Module {
    private final SettingGroup sgDetection;
    private final SettingGroup sgYLevels;
    private final SettingGroup sgRender;
    private final SettingGroup sgBlockHighlight;
    private final SettingGroup sgPerformance;
    private final SettingGroup sgNotifications;
    private final Setting<Boolean> detectNormalDeepslate;
    private final Setting<Boolean> detectCobbledDeepslate;
    private final Setting<Boolean> detectRotatedDeepslate;
    private final Setting<Boolean> detectCobblestoneLines;
    private final Setting<Boolean> detectTuffLines;
    private final Setting<Boolean> detectAndesiteLines;
    private final Setting<Boolean> detectDioriteLines;
    private final Setting<Boolean> detectObsidianLines;
    private final Setting<Boolean> ignoreExposed;
    private final Setting<Boolean> ignoreExposedLines;
    private final Setting<Boolean> ignoreTrialChambers;
    private final Setting<Integer> trialChamberThreshold;
    private final Setting<Integer> normalDeepslateThreshold;
    private final Setting<Integer> cobbledDeepslateThreshold;
    private final Setting<Integer> rotatedDeepslateThreshold;
    private final Setting<Integer> cobblestoneLineThreshold;
    private final Setting<Integer> tuffLineThreshold;
    private final Setting<Integer> andesiteLineThreshold;
    private final Setting<Integer> dioriteLineThreshold;
    private final Setting<Integer> obsidianLineThreshold;
    private final Setting<Integer> cobblestoneIsolationRadius;
    private final Setting<Integer> tuffIsolationRadius;
    private final Setting<Integer> andesiteIsolationRadius;
    private final Setting<Integer> dioriteIsolationRadius;
    private final Setting<Integer> obsidianIsolationRadius;
    private final Setting<Integer> cobblestoneLineCountThreshold;
    private final Setting<Integer> tuffLineCountThreshold;
    private final Setting<Integer> andesiteLineCountThreshold;
    private final Setting<Integer> dioriteLineCountThreshold;
    private final Setting<Integer> obsidianLineCountThreshold;
    private final Setting<Integer> minY;
    private final Setting<Integer> maxY;
    private final Setting<Integer> deepslateMinY;
    private final Setting<Integer> deepslateMaxY;
    private final Setting<Double> renderY;
    private final Setting<ShapeMode> renderMode;
    private final Setting<SettingColor> chunkColor;
    private final Setting<Double> thickness;
    private final Setting<Boolean> highlightBlocks;
    private final Setting<Integer> maxBlocksToRender;
    private final Setting<ShapeMode> blockRenderMode;
    private final Setting<SettingColor> cobbledDeepslateBlockColor;
    private final Setting<SettingColor> rotatedDeepslateBlockColor;
    private final Setting<SettingColor> normalDeepslateBlockColor;
    private final Setting<SettingColor> cobblestoneLineBlockColor;
    private final Setting<SettingColor> tuffLineBlockColor;
    private final Setting<SettingColor> andesiteLineBlockColor;
    private final Setting<SettingColor> dioriteLineBlockColor;
    private final Setting<SettingColor> obsidianLineBlockColor;
    private final Setting<Boolean> useMultiThreading;
    private final Setting<Integer> threadCount;
    private final Setting<Integer> scanInterval;
    private final Setting<Integer> maxConcurrentScans;
    private final Setting<Integer> cleanupInterval;
    private final Setting<Mode> notificationMode;
    private final Setting<Boolean> chatFeedback;
    private final Setting<Boolean> playSound;
    private final Setting<Integer> maxAlerts;
    private final Set<class_1923> flaggedChunks;
    private final ConcurrentHashMap<class_1923, ChunkAnalysis> chunkData;
    private final Set<class_1923> scannedChunks;
    private final ConcurrentHashMap<class_1923, Long> notificationTimes;
    private final ConcurrentLinkedQueue<Long> recentAlerts;
    private final AtomicLong activeScanCount;
    private final Map<class_2338, SuspiciousBlock> suspiciousBlocks;
    private final Set<class_1923> trialChamberChunks;
    private final Set<CobblestoneLine> detectedCobblestoneLines;
    private final Set<TuffLine> detectedTuffLines;
    private final Set<AndesiteLine> detectedAndesiteLines;
    private final Set<DioriteLine> detectedDioriteLines;
    private final Set<ObsidianLine> detectedObsidianLines;
    private ExecutorService scannerPool;
    private volatile boolean shouldScan;
    private long lastCleanup;

    public ChunkFinder() {
        super(Categories.Donut, "chunk-finder", "Detects suspicious chunks using multiple algorithms.");
        this.sgDetection = this.settings.createGroup("Detection");
        this.sgYLevels = this.settings.createGroup("Y Levels");
        this.sgRender = this.settings.createGroup("Render");
        this.sgBlockHighlight = this.settings.createGroup("Block Highlighting");
        this.sgPerformance = this.settings.createGroup("Performance");
        this.sgNotifications = this.settings.createGroup("Notifications");
        this.detectNormalDeepslate = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("detect-normal-deepslate")).description("Find regular Deepslate blocks (not cobbled/rotated)")).defaultValue(true)).build());
        this.detectCobbledDeepslate = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("detect-cobbled-deepslate")).description("Find cobbled deepslate blocks")).defaultValue(true)).build());
        this.detectRotatedDeepslate = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("detect-rotated-deepslate")).description("Find rotated deepslate blocks")).defaultValue(true)).build());
        this.detectCobblestoneLines = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("detect-cobblestone-lines")).description("Detect vertical cobblestone lines (>10 blocks)")).defaultValue(true)).build());
        this.detectTuffLines = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("detect-tuff-lines")).description("Detect vertical tuff lines (>10 blocks) with no other tuff nearby")).defaultValue(true)).build());
        this.detectAndesiteLines = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("detect-andesite-lines")).description("Detect vertical andesite lines (>10 blocks) with no other andesite nearby")).defaultValue(true)).build());
        this.detectDioriteLines = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("detect-diorite-lines")).description("Detect vertical diorite lines (>10 blocks) with no other diorite nearby")).defaultValue(true)).build());
        this.detectObsidianLines = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("detect-obsidian-lines")).description("Detect vertical obsidian lines (>5 blocks) with no other obsidian nearby")).defaultValue(true)).build());
        this.ignoreExposed = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("ignore-exposed")).description("Ignore blocks exposed to air or fluid")).defaultValue(true)).build());
        this.ignoreExposedLines = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("ignore-exposed-lines")).description("Ignore line blocks exposed to air or fluid (for line detection only)")).defaultValue(true)).visible(() -> this.detectCobblestoneLines.get() != false || this.detectTuffLines.get() != false || this.detectAndesiteLines.get() != false || this.detectDioriteLines.get() != false || this.detectObsidianLines.get() != false)).build());
        this.ignoreTrialChambers = this.sgDetection.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("ignore-trial-chambers")).description("Completely ignore trial chambers (no highlight, no detection)")).defaultValue(true)).build());
        this.trialChamberThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("trial-chamber-threshold")).description("Min trial chamber blocks to ignore chunk")).defaultValue(40)).range(10, 200).sliderRange(10, 100).visible(this.ignoreTrialChambers::get)).build());
        this.normalDeepslateThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("normal-deepslate-threshold")).description("Min normal deepslate to flag chunk")).defaultValue(3)).range(1, 30).sliderRange(1, 30).visible(this.detectNormalDeepslate::get)).build());
        this.cobbledDeepslateThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("cobbled-deepslate-threshold")).description("Min cobbled deepslate to flag")).defaultValue(1)).range(1, 15).sliderRange(1, 15).visible(this.detectCobbledDeepslate::get)).build());
        this.rotatedDeepslateThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("rotated-threshold")).description("Min rotated deepslate to flag")).defaultValue(2)).range(1, 20).sliderRange(1, 20).visible(this.detectRotatedDeepslate::get)).build());
        this.cobblestoneLineThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("cobblestone-line-threshold")).description("Minimum length of cobblestone line to detect (in blocks)")).defaultValue(10)).range(5, 30).sliderRange(5, 30).visible(this.detectCobblestoneLines::get)).build());
        this.tuffLineThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("tuff-line-threshold")).description("Minimum length of tuff line to detect (in blocks)")).defaultValue(10)).range(5, 30).sliderRange(5, 30).visible(this.detectTuffLines::get)).build());
        this.andesiteLineThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("andesite-line-threshold")).description("Minimum length of andesite line to detect (in blocks)")).defaultValue(10)).range(5, 30).sliderRange(5, 30).visible(this.detectAndesiteLines::get)).build());
        this.dioriteLineThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("diorite-line-threshold")).description("Minimum length of diorite line to detect (in blocks)")).defaultValue(10)).range(5, 30).sliderRange(5, 30).visible(this.detectDioriteLines::get)).build());
        this.obsidianLineThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("obsidian-line-threshold")).description("Minimum length of obsidian line to detect (in blocks)")).defaultValue(5)).range(3, 20).sliderRange(3, 20).visible(this.detectObsidianLines::get)).build());
        this.cobblestoneIsolationRadius = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("cobblestone-isolation-radius")).description("Radius to check for other cobblestone blocks (excluding the line itself)")).defaultValue(8)).range(3, 20).sliderRange(3, 20).visible(this.detectCobblestoneLines::get)).build());
        this.tuffIsolationRadius = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("tuff-isolation-radius")).description("Radius to check for other tuff blocks (excluding the line itself)")).defaultValue(8)).range(3, 20).sliderRange(3, 20).visible(this.detectTuffLines::get)).build());
        this.andesiteIsolationRadius = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("andesite-isolation-radius")).description("Radius to check for other andesite blocks (excluding the line itself)")).defaultValue(8)).range(3, 20).sliderRange(3, 20).visible(this.detectAndesiteLines::get)).build());
        this.dioriteIsolationRadius = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("diorite-isolation-radius")).description("Radius to check for other diorite blocks (excluding the line itself)")).defaultValue(8)).range(3, 20).sliderRange(3, 20).visible(this.detectDioriteLines::get)).build());
        this.obsidianIsolationRadius = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("obsidian-isolation-radius")).description("Radius to check for other obsidian blocks (excluding the line itself)")).defaultValue(12)).range(3, 20).sliderRange(3, 20).visible(this.detectObsidianLines::get)).build());
        this.cobblestoneLineCountThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("cobblestone-line-count-threshold")).description("Minimum number of isolated cobblestone lines to flag chunk")).defaultValue(1)).range(1, 10).sliderRange(1, 5).visible(this.detectCobblestoneLines::get)).build());
        this.tuffLineCountThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("tuff-line-count-threshold")).description("Minimum number of isolated tuff lines to flag chunk")).defaultValue(1)).range(1, 10).sliderRange(1, 5).visible(this.detectTuffLines::get)).build());
        this.andesiteLineCountThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("andesite-line-count-threshold")).description("Minimum number of isolated andesite lines to flag chunk")).defaultValue(1)).range(1, 10).sliderRange(1, 5).visible(this.detectAndesiteLines::get)).build());
        this.dioriteLineCountThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("diorite-line-count-threshold")).description("Minimum number of isolated diorite lines to flag chunk")).defaultValue(1)).range(1, 10).sliderRange(1, 5).visible(this.detectDioriteLines::get)).build());
        this.obsidianLineCountThreshold = this.sgDetection.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("obsidian-line-count-threshold")).description("Minimum number of isolated obsidian lines to flag chunk")).defaultValue(1)).range(1, 10).sliderRange(1, 5).visible(this.detectObsidianLines::get)).build());
        this.minY = this.sgYLevels.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("general-min-y")).description("Minimum Y for Cobbled & Rotated Deepslate")).defaultValue(-64)).range(-64, 320).sliderRange(-64, 300).build());
        this.maxY = this.sgYLevels.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("max-y")).description("Maximum Y level to scan")).defaultValue(300)).range(-64, 320).sliderRange(-64, 300).build());
        this.deepslateMinY = this.sgYLevels.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("deepslate-min-y")).description("Minimum Y for NORMAL Deepslate only")).defaultValue(16)).range(16, 320).sliderRange(16, 320).visible(this.detectNormalDeepslate::get)).build());
        this.deepslateMaxY = this.sgYLevels.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("deepslate-max-y")).description("Maximum Y for normal Deepslate")).defaultValue(320)).range(16, 320).sliderRange(16, 320).visible(this.detectNormalDeepslate::get)).build());
        this.renderY = this.sgRender.add(((DoubleSetting.Builder)((DoubleSetting.Builder)new DoubleSetting.Builder().name("render-height")).description("Height to render chunk highlights")).defaultValue(64.0).range(-64.0, 320.0).sliderRange(-64.0, 320.0).build());
        this.renderMode = this.sgRender.add(((EnumSetting.Builder)((EnumSetting.Builder)((EnumSetting.Builder)new EnumSetting.Builder().name("render-mode")).description("How to render highlighted chunks")).defaultValue(ShapeMode.Both)).build());
        this.chunkColor = this.sgRender.add(((ColorSetting.Builder)((ColorSetting.Builder)new ColorSetting.Builder().name("chunk-color")).description("Color for suspicious chunks")).defaultValue(new SettingColor(255, 215, 0, 120)).build());
        this.thickness = this.sgRender.add(((DoubleSetting.Builder)((DoubleSetting.Builder)new DoubleSetting.Builder().name("thickness")).description("Thickness of highlight box")).defaultValue(0.3).range(0.1, 2.0).sliderRange(0.1, 2.0).build());
        this.highlightBlocks = this.sgBlockHighlight.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("highlight-blocks")).description("Highlight individual suspicious blocks")).defaultValue(true)).build());
        this.maxBlocksToRender = this.sgBlockHighlight.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("max-blocks-render")).description("Max blocks to highlight")).defaultValue(200)).range(50, 1000).sliderRange(50, 1000).visible(this.highlightBlocks::get)).build());
        this.blockRenderMode = this.sgBlockHighlight.add(((EnumSetting.Builder)((EnumSetting.Builder)((EnumSetting.Builder)((EnumSetting.Builder)new EnumSetting.Builder().name("block-render-mode")).description("How to render blocks")).defaultValue(ShapeMode.Lines)).visible(this.highlightBlocks::get)).build());
        this.cobbledDeepslateBlockColor = this.sgBlockHighlight.add(((ColorSetting.Builder)((ColorSetting.Builder)new ColorSetting.Builder().name("cobbled-deepslate-color")).defaultValue(new SettingColor(80, 80, 80, 200)).visible(this.highlightBlocks::get)).build());
        this.rotatedDeepslateBlockColor = this.sgBlockHighlight.add(((ColorSetting.Builder)((ColorSetting.Builder)new ColorSetting.Builder().name("rotated-deepslate-color")).defaultValue(new SettingColor(120, 0, 120, 200)).visible(this.highlightBlocks::get)).build());
        this.normalDeepslateBlockColor = this.sgBlockHighlight.add(((ColorSetting.Builder)((ColorSetting.Builder)((ColorSetting.Builder)new ColorSetting.Builder().name("normal-deepslate-color")).description("Color for normal deepslate blocks")).defaultValue(new SettingColor(50, 50, 70, 220)).visible(() -> this.highlightBlocks.get() != false && this.detectNormalDeepslate.get() != false)).build());
        this.cobblestoneLineBlockColor = this.sgBlockHighlight.add(((ColorSetting.Builder)((ColorSetting.Builder)((ColorSetting.Builder)new ColorSetting.Builder().name("cobblestone-line-color")).description("Color for cobblestone line blocks")).defaultValue(new SettingColor(140, 140, 140, 210)).visible(() -> this.highlightBlocks.get() != false && this.detectCobblestoneLines.get() != false)).build());
        this.tuffLineBlockColor = this.sgBlockHighlight.add(((ColorSetting.Builder)((ColorSetting.Builder)((ColorSetting.Builder)new ColorSetting.Builder().name("tuff-line-color")).description("Color for tuff line blocks")).defaultValue(new SettingColor(100, 80, 60, 200)).visible(() -> this.highlightBlocks.get() != false && this.detectTuffLines.get() != false)).build());
        this.andesiteLineBlockColor = this.sgBlockHighlight.add(((ColorSetting.Builder)((ColorSetting.Builder)((ColorSetting.Builder)new ColorSetting.Builder().name("andesite-line-color")).description("Color for andesite line blocks")).defaultValue(new SettingColor(140, 140, 140, 200)).visible(() -> this.highlightBlocks.get() != false && this.detectAndesiteLines.get() != false)).build());
        this.dioriteLineBlockColor = this.sgBlockHighlight.add(((ColorSetting.Builder)((ColorSetting.Builder)((ColorSetting.Builder)new ColorSetting.Builder().name("diorite-line-color")).description("Color for diorite line blocks")).defaultValue(new SettingColor(220, 220, 220, 200)).visible(() -> this.highlightBlocks.get() != false && this.detectDioriteLines.get() != false)).build());
        this.obsidianLineBlockColor = this.sgBlockHighlight.add(((ColorSetting.Builder)((ColorSetting.Builder)((ColorSetting.Builder)new ColorSetting.Builder().name("obsidian-line-color")).description("Color for obsidian line blocks")).defaultValue(new SettingColor(30, 15, 50, 200)).visible(() -> this.highlightBlocks.get() != false && this.detectObsidianLines.get() != false)).build());
        this.useMultiThreading = this.sgPerformance.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("threading")).description("Use background threads")).defaultValue(true)).build());
        this.threadCount = this.sgPerformance.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("thread-count")).defaultValue(Math.max(1, Runtime.getRuntime().availableProcessors() / 2))).range(1, 4).sliderRange(1, 4).visible(this.useMultiThreading::get)).build());
        this.scanInterval = this.sgPerformance.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("scan-delay")).description("Delay between scans (ms)")).defaultValue(100)).range(50, 2000).sliderRange(50, 2000).build());
        this.maxConcurrentScans = this.sgPerformance.add(((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("max-concurrent-scans")).defaultValue(3)).range(1, 8).sliderRange(1, 8).build());
        this.cleanupInterval = this.sgPerformance.add(((IntSetting.Builder)((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("cleanup-interval")).description("Cleanup distant chunks every X seconds")).defaultValue(30)).range(15, 300).sliderRange(15, 300).build());
        this.notificationMode = this.sgNotifications.add(((EnumSetting.Builder)((EnumSetting.Builder)new EnumSetting.Builder().name("notification-mode")).defaultValue(Mode.Both)).build());
        this.chatFeedback = this.sgNotifications.add(((BoolSetting.Builder)((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("chat-feedback")).description("Show chat message when suspicious chunk is found")).defaultValue(true)).build());
        this.playSound = this.sgNotifications.add(((BoolSetting.Builder)((BoolSetting.Builder)new BoolSetting.Builder().name("sound-alerts")).defaultValue(true)).build());
        this.maxAlerts = this.sgNotifications.add(((IntSetting.Builder)((IntSetting.Builder)new IntSetting.Builder().name("max-alerts")).defaultValue(5)).range(1, 20).sliderRange(1, 20).build());
        this.flaggedChunks = ConcurrentHashMap.newKeySet();
        this.chunkData = new ConcurrentHashMap();
        this.scannedChunks = ConcurrentHashMap.newKeySet();
        this.notificationTimes = new ConcurrentHashMap();
        this.recentAlerts = new ConcurrentLinkedQueue();
        this.activeScanCount = new AtomicLong(0L);
        this.suspiciousBlocks = new ConcurrentHashMap<class_2338, SuspiciousBlock>();
        this.trialChamberChunks = ConcurrentHashMap.newKeySet();
        this.detectedCobblestoneLines = ConcurrentHashMap.newKeySet();
        this.detectedTuffLines = ConcurrentHashMap.newKeySet();
        this.detectedAndesiteLines = ConcurrentHashMap.newKeySet();
        this.detectedDioriteLines = ConcurrentHashMap.newKeySet();
        this.detectedObsidianLines = ConcurrentHashMap.newKeySet();
    }

    @Override
    public void onActivate() {
        if (this.mc.field_1687 != null && this.mc.field_1724 != null) {
            this.clearAll();
            this.shouldScan = true;
            this.lastCleanup = System.currentTimeMillis();
            if (this.useMultiThreading.get().booleanValue()) {
                this.createScannerPool();
            }
            this.startInitialScan();
            this.info("ChunkFinder activated", new Object[0]);
        }
    }

    @Override
    public void onDeactivate() {
        this.shouldScan = false;
        this.shutdownScannerPool();
        this.clearAll();
    }

    private void createScannerPool() {
        if (this.scannerPool == null || this.scannerPool.isShutdown()) {
            this.scannerPool = Executors.newFixedThreadPool(this.threadCount.get(), r -> {
                Thread t = new Thread(r, "ChunkFinder-Worker");
                t.setDaemon(true);
                t.setPriority(4);
                return t;
            });
        }
    }

    private void shutdownScannerPool() {
        if (this.scannerPool != null) {
            this.scannerPool.shutdownNow();
            this.scannerPool = null;
        }
    }

    private void clearAll() {
        this.flaggedChunks.clear();
        this.chunkData.clear();
        this.scannedChunks.clear();
        this.notificationTimes.clear();
        this.recentAlerts.clear();
        this.suspiciousBlocks.clear();
        this.trialChamberChunks.clear();
        this.detectedCobblestoneLines.clear();
        this.detectedTuffLines.clear();
        this.detectedAndesiteLines.clear();
        this.detectedDioriteLines.clear();
        this.detectedObsidianLines.clear();
        this.activeScanCount.set(0L);
    }

    @EventHandler
    private void onTick(TickEvent.Pre event) {
        if (this.mc.field_1687 != null && this.mc.field_1724 != null) {
            long now = System.currentTimeMillis();
            while (!this.recentAlerts.isEmpty() && now - this.recentAlerts.peek() > 60000L) {
                this.recentAlerts.poll();
            }
            if (now - this.lastCleanup > (long)this.cleanupInterval.get().intValue() * 1000L) {
                this.performCleanup();
                this.lastCleanup = now;
            }
        }
    }

    @EventHandler
    private void onChunkLoad(ChunkDataEvent event) {
        class_1923 pos;
        if (this.shouldScan && this.activeScanCount.get() < (long)this.maxConcurrentScans.get().intValue() && !this.scannedChunks.contains(pos = event.chunk().method_12004())) {
            this.scheduleChunkScan((class_2791)event.chunk());
        }
    }

    @EventHandler
    private void onBlockUpdate(BlockUpdateEvent event) {
        if (this.shouldScan) {
            class_2338 blockPos = event.pos;
            if (this.isRelevantBlock(event.newState) || event.newState.method_26215()) {
                class_1923 chunkPos = new class_1923(blockPos);
                class_2818 chunk = this.mc.field_1687.method_8497(chunkPos.field_9181, chunkPos.field_9180);
                this.scheduleChunkScan((class_2791)chunk);
            }
        }
    }

    private boolean isRelevantBlock(class_2680 state) {
        class_2248 b = state.method_26204();
        return b == class_2246.field_29031 || b == class_2246.field_28888 || b == class_2246.field_10445 || b == class_2246.field_27165 || b == class_2246.field_10115 || b == class_2246.field_10508 || b == class_2246.field_10540 || this.isTrialChamberBlock(state);
    }

    private void startInitialScan() {
        Runnable task = () -> {
            try {
                for (class_2791 chunk : Utils.chunks()) {
                    if (this.shouldScan) {
                        if (chunk instanceof class_2818) {
                            class_2818 worldChunk = (class_2818)chunk;
                            if (this.activeScanCount.get() < (long)this.maxConcurrentScans.get().intValue()) {
                                if (this.useMultiThreading.get().booleanValue() && this.scannerPool != null) {
                                    this.scannerPool.submit(() -> this.analyzeChunk(worldChunk));
                                } else {
                                    this.analyzeChunk(worldChunk);
                                }
                            }
                        }
                        Thread.sleep(this.scanInterval.get().intValue());
                        continue;
                    }
                    break;
                }
            }
            catch (InterruptedException interruptedException) {
                // empty catch block
            }
        };
        if (this.useMultiThreading.get().booleanValue() && this.scannerPool != null) {
            this.scannerPool.submit(task);
        } else {
            new Thread(task, "ChunkFinder-Initial").start();
        }
    }

    private void scheduleChunkScan(class_2791 chunk) {
        if (chunk instanceof class_2818) {
            class_2818 worldChunk = (class_2818)chunk;
            if (this.activeScanCount.get() < (long)this.maxConcurrentScans.get().intValue()) {
                Runnable task = () -> {
                    try {
                        Thread.sleep((long)this.scanInterval.get().intValue() / 2L);
                        if (this.shouldScan) {
                            this.analyzeChunk(worldChunk);
                        }
                    }
                    catch (InterruptedException interruptedException) {
                        // empty catch block
                    }
                };
                if (this.useMultiThreading.get().booleanValue() && this.scannerPool != null) {
                    this.scannerPool.submit(task);
                } else {
                    new Thread(task, "ChunkFinder-Scan").start();
                }
            }
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void analyzeChunk(class_2818 chunk) {
        class_1923 pos;
        if (this.shouldScan && chunk != null && !this.scannedChunks.contains(pos = chunk.method_12004())) {
            this.activeScanCount.incrementAndGet();
            try {
                this.scannedChunks.add(pos);
                ChunkAnalysis analysis = new ChunkAnalysis();
                this.scanChunkSections(chunk, analysis);
                if (this.detectCobblestoneLines.get().booleanValue()) {
                    this.scanForCobblestoneLines(chunk, analysis);
                }
                if (this.detectTuffLines.get().booleanValue()) {
                    this.scanForTuffLines(chunk, analysis);
                }
                if (this.detectAndesiteLines.get().booleanValue()) {
                    this.scanForAndesiteLines(chunk, analysis);
                }
                if (this.detectDioriteLines.get().booleanValue()) {
                    this.scanForDioriteLines(chunk, analysis);
                }
                if (this.detectObsidianLines.get().booleanValue()) {
                    this.scanForObsidianLines(chunk, analysis);
                }
                this.chunkData.put(pos, analysis);
                this.evaluateChunk(pos, analysis);
            }
            finally {
                this.activeScanCount.decrementAndGet();
            }
        }
    }

    private void scanChunkSections(class_2818 chunk, ChunkAnalysis analysis) {
        class_2826[] sections = chunk.method_12006();
        for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) {
            int endY;
            if (!this.shouldScan) {
                return;
            }
            class_2826 section = sections[sectionIndex];
            if (section == null || section.method_38292()) continue;
            int sectionY = chunk.method_31607() + sectionIndex * 16;
            int startY = Math.max(this.minY.get(), sectionY);
            if (startY > (endY = Math.min(this.maxY.get(), sectionY + 15))) continue;
            for (int x = 0; x < 16; ++x) {
                for (int z = 0; z < 16; ++z) {
                    for (int y = startY - sectionY; y <= endY - sectionY; ++y) {
                        if (y < 0 || y > 15) continue;
                        class_2680 state = section.method_12254(x, y, z);
                        int worldY = sectionY + y;
                        class_2338 blockPos = new class_2338(chunk.method_12004().method_8326() + x, worldY, chunk.method_12004().method_8328() + z);
                        this.analyzeBlock(blockPos, state, worldY, analysis);
                    }
                }
            }
        }
    }

    private void analyzeBlock(class_2338 blockPos, class_2680 state, int worldY, ChunkAnalysis analysis) {
        class_1923 chunkPos = new class_1923(blockPos);
        if (!this.ignoreTrialChambers.get().booleanValue() || !this.trialChamberChunks.contains(chunkPos)) {
            if (this.ignoreTrialChambers.get().booleanValue() && this.isTrialChamberBlock(state)) {
                ++analysis.trialChamberCount;
            }
            if (!this.ignoreExposed.get().booleanValue() || !this.isExposedToAirOrFluid(blockPos)) {
                SuspiciousBlockType blockType = null;
                if (this.detectRotatedDeepslate.get().booleanValue() && worldY >= this.minY.get() && worldY <= this.maxY.get() && this.isRotatedDeepslateBlock(state)) {
                    ++analysis.rotatedDeepslateCount;
                    blockType = SuspiciousBlockType.ROTATED_DEEPSLATE;
                }
                if (this.detectCobbledDeepslate.get().booleanValue() && worldY >= this.minY.get() && worldY <= this.maxY.get() && state.method_27852(class_2246.field_29031)) {
                    ++analysis.cobbledDeepslateCount;
                    if (blockType == null) {
                        blockType = SuspiciousBlockType.COBBLED_DEEPSLATE;
                    }
                }
                if (this.detectNormalDeepslate.get().booleanValue() && worldY >= this.deepslateMinY.get() && worldY <= this.deepslateMaxY.get() && state.method_27852(class_2246.field_28888)) {
                    boolean isVerticalOrNoAxis;
                    boolean bl = isVerticalOrNoAxis = !state.method_28498((class_2769)class_2741.field_12496) || state.method_11654((class_2769)class_2741.field_12496) == class_2350.class_2351.field_11052;
                    if (isVerticalOrNoAxis) {
                        ++analysis.normalDeepslateCount;
                        if (blockType == null) {
                            blockType = SuspiciousBlockType.NORMAL_DEEPSLATE;
                        }
                    }
                }
                if (blockType != null && this.highlightBlocks.get().booleanValue()) {
                    this.suspiciousBlocks.put(blockPos.method_10062(), new SuspiciousBlock(blockType, System.currentTimeMillis()));
                }
            }
        }
    }

    private void scanForCobblestoneLines(class_2818 chunk, ChunkAnalysis analysis) {
        class_2826[] sections = chunk.method_12006();
        int minChunkY = chunk.method_31607();
        for (int x = 0; x < 16; ++x) {
            for (int z = 0; z < 16; ++z) {
                int currentLineLength = 0;
                class_2338 lineStartPos = null;
                for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) {
                    class_2826 section = sections[sectionIndex];
                    if (section == null || section.method_38292()) continue;
                    int sectionY = minChunkY + sectionIndex * 16;
                    for (int y = 0; y < 16; ++y) {
                        int worldY = sectionY + y;
                        if (worldY < this.minY.get() || worldY > this.maxY.get()) continue;
                        class_2338 pos = new class_2338(chunk.method_12004().method_8326() + x, worldY, chunk.method_12004().method_8328() + z);
                        class_2680 state = section.method_12254(x, y, z);
                        if (state.method_27852(class_2246.field_10445)) {
                            if (this.ignoreExposedLines.get().booleanValue() && this.isExposedToAirOrFluid(pos)) {
                                if (currentLineLength >= this.cobblestoneLineThreshold.get()) {
                                    this.checkAndRecordCobblestoneLine(lineStartPos, currentLineLength, analysis);
                                }
                                currentLineLength = 0;
                                lineStartPos = null;
                                continue;
                            }
                            if (currentLineLength == 0) {
                                lineStartPos = pos;
                            }
                            ++currentLineLength;
                            continue;
                        }
                        if (currentLineLength >= this.cobblestoneLineThreshold.get()) {
                            this.checkAndRecordCobblestoneLine(lineStartPos, currentLineLength, analysis);
                        }
                        currentLineLength = 0;
                        lineStartPos = null;
                    }
                }
                if (currentLineLength < this.cobblestoneLineThreshold.get()) continue;
                this.checkAndRecordCobblestoneLine(lineStartPos, currentLineLength, analysis);
            }
        }
    }

    private void scanForTuffLines(class_2818 chunk, ChunkAnalysis analysis) {
        class_2826[] sections = chunk.method_12006();
        int minChunkY = chunk.method_31607();
        for (int x = 0; x < 16; ++x) {
            for (int z = 0; z < 16; ++z) {
                int currentLineLength = 0;
                class_2338 lineStartPos = null;
                for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) {
                    class_2826 section = sections[sectionIndex];
                    if (section == null || section.method_38292()) continue;
                    int sectionY = minChunkY + sectionIndex * 16;
                    for (int y = 0; y < 16; ++y) {
                        int worldY = sectionY + y;
                        if (worldY < this.minY.get() || worldY > this.maxY.get()) continue;
                        class_2338 pos = new class_2338(chunk.method_12004().method_8326() + x, worldY, chunk.method_12004().method_8328() + z);
                        class_2680 state = section.method_12254(x, y, z);
                        if (state.method_27852(class_2246.field_27165)) {
                            if (this.ignoreExposedLines.get().booleanValue() && this.isExposedToAirOrFluid(pos)) {
                                if (currentLineLength >= this.tuffLineThreshold.get()) {
                                    this.checkAndRecordTuffLine(lineStartPos, currentLineLength, analysis);
                                }
                                currentLineLength = 0;
                                lineStartPos = null;
                                continue;
                            }
                            if (currentLineLength == 0) {
                                lineStartPos = pos;
                            }
                            ++currentLineLength;
                            continue;
                        }
                        if (currentLineLength >= this.tuffLineThreshold.get()) {
                            this.checkAndRecordTuffLine(lineStartPos, currentLineLength, analysis);
                        }
                        currentLineLength = 0;
                        lineStartPos = null;
                    }
                }
                if (currentLineLength < this.tuffLineThreshold.get()) continue;
                this.checkAndRecordTuffLine(lineStartPos, currentLineLength, analysis);
            }
        }
    }

    private void scanForAndesiteLines(class_2818 chunk, ChunkAnalysis analysis) {
        class_2826[] sections = chunk.method_12006();
        int minChunkY = chunk.method_31607();
        for (int x = 0; x < 16; ++x) {
            for (int z = 0; z < 16; ++z) {
                int currentLineLength = 0;
                class_2338 lineStartPos = null;
                for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) {
                    class_2826 section = sections[sectionIndex];
                    if (section == null || section.method_38292()) continue;
                    int sectionY = minChunkY + sectionIndex * 16;
                    for (int y = 0; y < 16; ++y) {
                        int worldY = sectionY + y;
                        if (worldY < this.minY.get() || worldY > this.maxY.get()) continue;
                        class_2338 pos = new class_2338(chunk.method_12004().method_8326() + x, worldY, chunk.method_12004().method_8328() + z);
                        class_2680 state = section.method_12254(x, y, z);
                        if (state.method_27852(class_2246.field_10115)) {
                            if (this.ignoreExposedLines.get().booleanValue() && this.isExposedToAirOrFluid(pos)) {
                                if (currentLineLength >= this.andesiteLineThreshold.get()) {
                                    this.checkAndRecordAndesiteLine(lineStartPos, currentLineLength, analysis);
                                }
                                currentLineLength = 0;
                                lineStartPos = null;
                                continue;
                            }
                            if (currentLineLength == 0) {
                                lineStartPos = pos;
                            }
                            ++currentLineLength;
                            continue;
                        }
                        if (currentLineLength >= this.andesiteLineThreshold.get()) {
                            this.checkAndRecordAndesiteLine(lineStartPos, currentLineLength, analysis);
                        }
                        currentLineLength = 0;
                        lineStartPos = null;
                    }
                }
                if (currentLineLength < this.andesiteLineThreshold.get()) continue;
                this.checkAndRecordAndesiteLine(lineStartPos, currentLineLength, analysis);
            }
        }
    }

    private void scanForDioriteLines(class_2818 chunk, ChunkAnalysis analysis) {
        class_2826[] sections = chunk.method_12006();
        int minChunkY = chunk.method_31607();
        for (int x = 0; x < 16; ++x) {
            for (int z = 0; z < 16; ++z) {
                int currentLineLength = 0;
                class_2338 lineStartPos = null;
                for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) {
                    class_2826 section = sections[sectionIndex];
                    if (section == null || section.method_38292()) continue;
                    int sectionY = minChunkY + sectionIndex * 16;
                    for (int y = 0; y < 16; ++y) {
                        int worldY = sectionY + y;
                        if (worldY < this.minY.get() || worldY > this.maxY.get()) continue;
                        class_2338 pos = new class_2338(chunk.method_12004().method_8326() + x, worldY, chunk.method_12004().method_8328() + z);
                        class_2680 state = section.method_12254(x, y, z);
                        if (state.method_27852(class_2246.field_10508)) {
                            if (this.ignoreExposedLines.get().booleanValue() && this.isExposedToAirOrFluid(pos)) {
                                if (currentLineLength >= this.dioriteLineThreshold.get()) {
                                    this.checkAndRecordDioriteLine(lineStartPos, currentLineLength, analysis);
                                }
                                currentLineLength = 0;
                                lineStartPos = null;
                                continue;
                            }
                            if (currentLineLength == 0) {
                                lineStartPos = pos;
                            }
                            ++currentLineLength;
                            continue;
                        }
                        if (currentLineLength >= this.dioriteLineThreshold.get()) {
                            this.checkAndRecordDioriteLine(lineStartPos, currentLineLength, analysis);
                        }
                        currentLineLength = 0;
                        lineStartPos = null;
                    }
                }
                if (currentLineLength < this.dioriteLineThreshold.get()) continue;
                this.checkAndRecordDioriteLine(lineStartPos, currentLineLength, analysis);
            }
        }
    }

    private void scanForObsidianLines(class_2818 chunk, ChunkAnalysis analysis) {
        class_2826[] sections = chunk.method_12006();
        int minChunkY = chunk.method_31607();
        for (int x = 0; x < 16; ++x) {
            for (int z = 0; z < 16; ++z) {
                int currentLineLength = 0;
                class_2338 lineStartPos = null;
                for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) {
                    class_2826 section = sections[sectionIndex];
                    if (section == null || section.method_38292()) continue;
                    int sectionY = minChunkY + sectionIndex * 16;
                    for (int y = 0; y < 16; ++y) {
                        int worldY = sectionY + y;
                        if (worldY < this.minY.get() || worldY > this.maxY.get()) continue;
                        class_2338 pos = new class_2338(chunk.method_12004().method_8326() + x, worldY, chunk.method_12004().method_8328() + z);
                        class_2680 state = section.method_12254(x, y, z);
                        if (state.method_27852(class_2246.field_10540)) {
                            if (this.ignoreExposedLines.get().booleanValue() && this.isExposedToAirOrFluid(pos)) {
                                if (currentLineLength >= this.obsidianLineThreshold.get()) {
                                    this.checkAndRecordObsidianLine(lineStartPos, currentLineLength, analysis);
                                }
                                currentLineLength = 0;
                                lineStartPos = null;
                                continue;
                            }
                            if (currentLineLength == 0) {
                                lineStartPos = pos;
                            }
                            ++currentLineLength;
                            continue;
                        }
                        if (currentLineLength >= this.obsidianLineThreshold.get()) {
                            this.checkAndRecordObsidianLine(lineStartPos, currentLineLength, analysis);
                        }
                        currentLineLength = 0;
                        lineStartPos = null;
                    }
                }
                if (currentLineLength < this.obsidianLineThreshold.get()) continue;
                this.checkAndRecordObsidianLine(lineStartPos, currentLineLength, analysis);
            }
        }
    }

    private void checkAndRecordCobblestoneLine(class_2338 startPos, int length, ChunkAnalysis analysis) {
        if (startPos != null && length >= this.cobblestoneLineThreshold.get() && this.isCobblestoneLineIsolated(startPos, length)) {
            ++analysis.cobblestoneLineCount;
            this.detectedCobblestoneLines.add(new CobblestoneLine(startPos, length, System.currentTimeMillis()));
            if (this.highlightBlocks.get().booleanValue()) {
                for (int yOffset = 0; yOffset < length; ++yOffset) {
                    this.suspiciousBlocks.put(startPos.method_10086(yOffset).method_10062(), new SuspiciousBlock(SuspiciousBlockType.COBBLESTONE_LINE, System.currentTimeMillis()));
                }
            }
        }
    }

    private void checkAndRecordTuffLine(class_2338 startPos, int length, ChunkAnalysis analysis) {
        if (startPos != null && length >= this.tuffLineThreshold.get() && this.isTuffLineIsolated(startPos, length)) {
            ++analysis.tuffLineCount;
            this.detectedTuffLines.add(new TuffLine(startPos, length, System.currentTimeMillis()));
            if (this.highlightBlocks.get().booleanValue()) {
                for (int yOffset = 0; yOffset < length; ++yOffset) {
                    this.suspiciousBlocks.put(startPos.method_10086(yOffset).method_10062(), new SuspiciousBlock(SuspiciousBlockType.TUFF_LINE, System.currentTimeMillis()));
                }
            }
        }
    }

    private void checkAndRecordAndesiteLine(class_2338 startPos, int length, ChunkAnalysis analysis) {
        if (startPos != null && length >= this.andesiteLineThreshold.get() && this.isAndesiteLineIsolated(startPos, length)) {
            ++analysis.andesiteLineCount;
            this.detectedAndesiteLines.add(new AndesiteLine(startPos, length, System.currentTimeMillis()));
            if (this.highlightBlocks.get().booleanValue()) {
                for (int yOffset = 0; yOffset < length; ++yOffset) {
                    this.suspiciousBlocks.put(startPos.method_10086(yOffset).method_10062(), new SuspiciousBlock(SuspiciousBlockType.ANDESITE_LINE, System.currentTimeMillis()));
                }
            }
        }
    }

    private void checkAndRecordDioriteLine(class_2338 startPos, int length, ChunkAnalysis analysis) {
        if (startPos != null && length >= this.dioriteLineThreshold.get() && this.isDioriteLineIsolated(startPos, length)) {
            ++analysis.dioriteLineCount;
            this.detectedDioriteLines.add(new DioriteLine(startPos, length, System.currentTimeMillis()));
            if (this.highlightBlocks.get().booleanValue()) {
                for (int yOffset = 0; yOffset < length; ++yOffset) {
                    this.suspiciousBlocks.put(startPos.method_10086(yOffset).method_10062(), new SuspiciousBlock(SuspiciousBlockType.DIORITE_LINE, System.currentTimeMillis()));
                }
            }
        }
    }

    private void checkAndRecordObsidianLine(class_2338 startPos, int length, ChunkAnalysis analysis) {
        if (startPos != null && length >= this.obsidianLineThreshold.get() && this.isObsidianLineIsolated(startPos, length)) {
            ++analysis.obsidianLineCount;
            this.detectedObsidianLines.add(new ObsidianLine(startPos, length, System.currentTimeMillis()));
            if (this.highlightBlocks.get().booleanValue()) {
                for (int yOffset = 0; yOffset < length; ++yOffset) {
                    this.suspiciousBlocks.put(startPos.method_10086(yOffset).method_10062(), new SuspiciousBlock(SuspiciousBlockType.OBSIDIAN_LINE, System.currentTimeMillis()));
                }
            }
        }
    }

    private boolean isCobblestoneLineIsolated(class_2338 startPos, int length) {
        int radius = this.cobblestoneIsolationRadius.get();
        class_2338.class_2339 m = new class_2338.class_2339();
        for (int x = -radius; x <= radius; ++x) {
            for (int z = -radius; z <= radius; ++z) {
                for (int y = -radius; y <= length + radius - 1; ++y) {
                    if (x == 0 && z == 0 && y >= 0 && y < length) continue;
                    m.method_10103(startPos.method_10263() + x, startPos.method_10264() + y, startPos.method_10260() + z);
                    if (!this.mc.field_1687.method_8393(m.method_10263() >> 4, m.method_10260() >> 4) || !this.mc.field_1687.method_8320((class_2338)m).method_27852(class_2246.field_10445)) continue;
                    return false;
                }
            }
        }
        return true;
    }

    private boolean isTuffLineIsolated(class_2338 startPos, int length) {
        int radius = this.tuffIsolationRadius.get();
        class_2338.class_2339 m = new class_2338.class_2339();
        for (int x = -radius; x <= radius; ++x) {
            for (int z = -radius; z <= radius; ++z) {
                for (int y = -radius; y <= length + radius - 1; ++y) {
                    if (x == 0 && z == 0 && y >= 0 && y < length) continue;
                    m.method_10103(startPos.method_10263() + x, startPos.method_10264() + y, startPos.method_10260() + z);
                    if (!this.mc.field_1687.method_8393(m.method_10263() >> 4, m.method_10260() >> 4) || !this.mc.field_1687.method_8320((class_2338)m).method_27852(class_2246.field_27165)) continue;
                    return false;
                }
            }
        }
        return true;
    }

    private boolean isAndesiteLineIsolated(class_2338 startPos, int length) {
        int radius = this.andesiteIsolationRadius.get();
        class_2338.class_2339 m = new class_2338.class_2339();
        for (int x = -radius; x <= radius; ++x) {
            for (int z = -radius; z <= radius; ++z) {
                for (int y = -radius; y <= length + radius - 1; ++y) {
                    if (x == 0 && z == 0 && y >= 0 && y < length) continue;
                    m.method_10103(startPos.method_10263() + x, startPos.method_10264() + y, startPos.method_10260() + z);
                    if (!this.mc.field_1687.method_8393(m.method_10263() >> 4, m.method_10260() >> 4) || !this.mc.field_1687.method_8320((class_2338)m).method_27852(class_2246.field_10115)) continue;
                    return false;
                }
            }
        }
        return true;
    }

    private boolean isDioriteLineIsolated(class_2338 startPos, int length) {
        int radius = this.dioriteIsolationRadius.get();
        class_2338.class_2339 m = new class_2338.class_2339();
        for (int x = -radius; x <= radius; ++x) {
            for (int z = -radius; z <= radius; ++z) {
                for (int y = -radius; y <= length + radius - 1; ++y) {
                    if (x == 0 && z == 0 && y >= 0 && y < length) continue;
                    m.method_10103(startPos.method_10263() + x, startPos.method_10264() + y, startPos.method_10260() + z);
                    if (!this.mc.field_1687.method_8393(m.method_10263() >> 4, m.method_10260() >> 4) || !this.mc.field_1687.method_8320((class_2338)m).method_27852(class_2246.field_10508)) continue;
                    return false;
                }
            }
        }
        return true;
    }

    private boolean isObsidianLineIsolated(class_2338 startPos, int length) {
        int radius = this.obsidianIsolationRadius.get();
        class_2338.class_2339 m = new class_2338.class_2339();
        for (int x = -radius; x <= radius; ++x) {
            for (int z = -radius; z <= radius; ++z) {
                for (int y = -radius; y <= length + radius - 1; ++y) {
                    if (x == 0 && z == 0 && y >= 0 && y < length) continue;
                    m.method_10103(startPos.method_10263() + x, startPos.method_10264() + y, startPos.method_10260() + z);
                    if (!this.mc.field_1687.method_8393(m.method_10263() >> 4, m.method_10260() >> 4) || !this.mc.field_1687.method_8320((class_2338)m).method_27852(class_2246.field_10540)) continue;
                    return false;
                }
            }
        }
        return true;
    }

    private boolean isExposedToAirOrFluid(class_2338 pos) {
        for (class_2350 dir : class_2350.values()) {
            class_2680 adjacent = this.mc.field_1687.method_8320(pos.method_10093(dir));
            if (!adjacent.method_26215() && adjacent.method_26227().method_15769()) continue;
            return true;
        }
        return false;
    }

    private void evaluateChunk(class_1923 pos, ChunkAnalysis analysis) {
        if (this.ignoreTrialChambers.get().booleanValue() && analysis.trialChamberCount >= this.trialChamberThreshold.get()) {
            this.trialChamberChunks.add(pos);
            this.flaggedChunks.remove(pos);
            this.notificationTimes.remove(pos);
        } else {
            this.trialChamberChunks.remove(pos);
            boolean suspicious = false;
            StringBuilder reasons = new StringBuilder();
            if (this.detectNormalDeepslate.get().booleanValue() && analysis.normalDeepslateCount >= this.normalDeepslateThreshold.get()) {
                suspicious = true;
                reasons.append("Deepslate[").append(analysis.normalDeepslateCount).append("] ");
            }
            if (this.detectCobbledDeepslate.get().booleanValue() && analysis.cobbledDeepslateCount >= this.cobbledDeepslateThreshold.get()) {
                suspicious = true;
                reasons.append("Cobbled[").append(analysis.cobbledDeepslateCount).append("] ");
            }
            if (this.detectRotatedDeepslate.get().booleanValue() && analysis.rotatedDeepslateCount >= this.rotatedDeepslateThreshold.get()) {
                suspicious = true;
                reasons.append("Rotated[").append(analysis.rotatedDeepslateCount).append("] ");
            }
            if (this.detectCobblestoneLines.get().booleanValue() && analysis.cobblestoneLineCount >= this.cobblestoneLineCountThreshold.get()) {
                suspicious = true;
                reasons.append("CobblestoneLine[").append(analysis.cobblestoneLineCount).append("] ");
            }
            if (this.detectTuffLines.get().booleanValue() && analysis.tuffLineCount >= this.tuffLineCountThreshold.get()) {
                suspicious = true;
                reasons.append("TuffLine[").append(analysis.tuffLineCount).append("] ");
            }
            if (this.detectAndesiteLines.get().booleanValue() && analysis.andesiteLineCount >= this.andesiteLineCountThreshold.get()) {
                suspicious = true;
                reasons.append("AndesiteLine[").append(analysis.andesiteLineCount).append("] ");
            }
            if (this.detectDioriteLines.get().booleanValue() && analysis.dioriteLineCount >= this.dioriteLineCountThreshold.get()) {
                suspicious = true;
                reasons.append("DioriteLine[").append(analysis.dioriteLineCount).append("] ");
            }
            if (this.detectObsidianLines.get().booleanValue() && analysis.obsidianLineCount >= this.obsidianLineCountThreshold.get()) {
                suspicious = true;
                reasons.append("ObsidianLine[").append(analysis.obsidianLineCount).append("] ");
            }
            if (suspicious) {
                if (this.flaggedChunks.add(pos)) {
                    this.notifyChunkFound(pos, reasons.toString().trim());
                }
            } else {
                this.flaggedChunks.remove(pos);
                this.notificationTimes.remove(pos);
            }
        }
    }

    private boolean isRotatedDeepslateBlock(class_2680 state) {
        return state.method_27852(class_2246.field_28888) && state.method_28498((class_2769)class_2741.field_12496) && state.method_11654((class_2769)class_2741.field_12496) != class_2350.class_2351.field_11052;
    }

    private boolean isTrialChamberBlock(class_2680 state) {
        class_2248 b = state.method_26204();
        return b == class_2246.field_47035 || b == class_2246.field_47039 || b == class_2246.field_47030 || b == class_2246.field_47072 || b == class_2246.field_27165 || b == class_2246.field_47336 || b == class_2246.field_48851 || b == class_2246.field_47057;
    }

    private void notifyChunkFound(class_1923 pos, String details) {
        Long last;
        long now = System.currentTimeMillis();
        if (this.recentAlerts.size() < this.maxAlerts.get() && ((last = this.notificationTimes.get(pos)) == null || now - last >= 45000L)) {
            String coordinates = String.format("[%d, %d]", pos.field_9181 * 16, pos.field_9180 * 16);
            String formattedDetails = this.formatDetectionDetails(details);
            this.mc.execute(() -> {
                switch (this.notificationMode.get().ordinal()) {
                    case 0: {
                        if (!this.chatFeedback.get().booleanValue() || this.mc.field_1724 == null) break;
                        this.sendChatMessage(coordinates, formattedDetails);
                        break;
                    }
                    case 1: {
                        this.mc.method_1566().method_1999((class_368)new ChunkToast(new class_1799((class_1935)class_1802.field_8449), (class_2561)class_2561.method_43470((String)"ChunkFinder"), (class_2561)class_2561.method_43470((String)coordinates)));
                        break;
                    }
                    case 2: {
                        if (this.chatFeedback.get().booleanValue() && this.mc.field_1724 != null) {
                            this.sendChatMessage(coordinates, formattedDetails);
                        }
                        this.mc.method_1566().method_1999((class_368)new ChunkToast(new class_1799((class_1935)class_1802.field_8449), (class_2561)class_2561.method_43470((String)"ChunkFinder"), (class_2561)class_2561.method_43470((String)coordinates)));
                    }
                }
                if (this.playSound.get().booleanValue()) {
                    this.mc.method_1483().method_4873((class_1113)class_1109.method_4757((class_3414)((class_3414)class_3417.field_14725.comp_349()), (float)1.5f, (float)1.0f));
                }
                this.recentAlerts.offer(now);
                this.notificationTimes.put(pos, now);
            });
        }
    }

    private String formatDetectionDetails(String details) {
        String[] parts;
        if (details.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (String part : parts = details.split(" ")) {
            if (part.contains("[")) {
                String type = part.substring(0, part.indexOf("["));
                String count = part.substring(part.indexOf("[") + 1, part.indexOf("]"));
                switch (type) {
                    case "Deepslate": {
                        sb.append("\u00a79").append(type).append("\u00a77[\u00a7b").append(count).append("\u00a77] ");
                        break;
                    }
                    case "Cobbled": {
                        sb.append("\u00a78").append(type).append("\u00a77[\u00a77").append(count).append("\u00a77] ");
                        break;
                    }
                    case "Rotated": {
                        sb.append("\u00a75").append(type).append("\u00a77[\u00a7d").append(count).append("\u00a77] ");
                        break;
                    }
                    case "CobblestoneLine": {
                        sb.append("\u00a77Cobble\u00a77[\u00a7f").append(count).append("\u00a77] ");
                        break;
                    }
                    case "TuffLine": {
                        sb.append("\u00a76Tuff\u00a77[\u00a7e").append(count).append("\u00a77] ");
                        break;
                    }
                    case "AndesiteLine": {
                        sb.append("\u00a77Andesite\u00a77[\u00a7f").append(count).append("\u00a77] ");
                        break;
                    }
                    case "DioriteLine": {
                        sb.append("\u00a7fDiorite\u00a77[\u00a7f").append(count).append("\u00a77] ");
                        break;
                    }
                    case "ObsidianLine": {
                        sb.append("\u00a75Obsidian\u00a77[\u00a7d").append(count).append("\u00a77] ");
                        break;
                    }
                    default: {
                        sb.append("\u00a7f").append(part).append(" ");
                        break;
                    }
                }
                continue;
            }
            sb.append("\u00a7f").append(part).append(" ");
        }
        return sb.toString().trim();
    }

    private void sendChatMessage(String coordinates, String details) {
        String message = String.format("\u00a76[\u00a7eChunkFinder\u00a76] \u00a7fFound suspicious chunk at \u00a7e%s \u00a7f- %s", coordinates, details);
        this.mc.field_1724.method_7353((class_2561)class_2561.method_43470((String)message), false);
    }

    private void performCleanup() {
        if (this.mc.field_1724 == null) {
            return;
        }
        int viewDist = (Integer)this.mc.field_1690.method_42503().method_41753();
        int playerChunkX = this.mc.field_1724.method_31476().field_9181;
        int playerChunkZ = this.mc.field_1724.method_31476().field_9180;
        this.flaggedChunks.removeIf(pos -> {
            boolean tooFar;
            boolean bl = tooFar = Math.abs(pos.field_9181 - playerChunkX) > viewDist + 5 || Math.abs(pos.field_9180 - playerChunkZ) > viewDist + 5;
            if (tooFar) {
                this.chunkData.remove(pos);
                this.notificationTimes.remove(pos);
            }
            return tooFar;
        });
        this.trialChamberChunks.removeIf(pos -> Math.abs(pos.field_9181 - playerChunkX) > viewDist + 10 || Math.abs(pos.field_9180 - playerChunkZ) > viewDist + 10);
        this.scannedChunks.removeIf(pos -> Math.abs(pos.field_9181 - playerChunkX) > viewDist + 3 || Math.abs(pos.field_9180 - playerChunkZ) > viewDist + 3);
        this.suspiciousBlocks.entrySet().removeIf(e -> this.mc.field_1724.method_24515().method_10262((class_2382)e.getKey()) > Math.pow(viewDist * 16 + 80, 2.0));
        this.detectedCobblestoneLines.removeIf(line -> Math.abs(line.startPos.method_10263() / 16 - playerChunkX) > viewDist + 5 || Math.abs(line.startPos.method_10260() / 16 - playerChunkZ) > viewDist + 5 || System.currentTimeMillis() - line.detectedTime > 300000L);
        this.detectedTuffLines.removeIf(line -> Math.abs(line.startPos.method_10263() / 16 - playerChunkX) > viewDist + 5 || Math.abs(line.startPos.method_10260() / 16 - playerChunkZ) > viewDist + 5 || System.currentTimeMillis() - line.detectedTime > 300000L);
        this.detectedAndesiteLines.removeIf(line -> Math.abs(line.startPos.method_10263() / 16 - playerChunkX) > viewDist + 5 || Math.abs(line.startPos.method_10260() / 16 - playerChunkZ) > viewDist + 5 || System.currentTimeMillis() - line.detectedTime > 300000L);
        this.detectedDioriteLines.removeIf(line -> Math.abs(line.startPos.method_10263() / 16 - playerChunkX) > viewDist + 5 || Math.abs(line.startPos.method_10260() / 16 - playerChunkZ) > viewDist + 5 || System.currentTimeMillis() - line.detectedTime > 300000L);
        this.detectedObsidianLines.removeIf(line -> Math.abs(line.startPos.method_10263() / 16 - playerChunkX) > viewDist + 5 || Math.abs(line.startPos.method_10260() / 16 - playerChunkZ) > viewDist + 5 || System.currentTimeMillis() - line.detectedTime > 300000L);
    }

    @EventHandler
    private void onRender3D(Render3DEvent event) {
        if (this.mc.field_1724 == null) {
            return;
        }
        if (!this.flaggedChunks.isEmpty()) {
            Color color = this.chunkColor.get();
            int rendered = 0;
            for (class_1923 pos : this.flaggedChunks) {
                if (rendered++ > 50) break;
                class_238 box = new class_238((double)pos.method_8326(), this.renderY.get().doubleValue(), (double)pos.method_8328(), (double)(pos.method_8326() + 16), this.renderY.get() + this.thickness.get(), (double)(pos.method_8328() + 16));
                event.renderer.box(box, color, color, this.renderMode.get(), 0);
            }
        }
        if (this.highlightBlocks.get().booleanValue()) {
            Color color;
            int rendered = 0;
            for (Map.Entry<class_2338, SuspiciousBlock> entry : this.suspiciousBlocks.entrySet()) {
                Color color2;
                class_1923 pos;
                if (rendered >= this.maxBlocksToRender.get()) break;
                pos = entry.getKey();
                if (!this.flaggedChunks.contains(new class_1923((class_2338)pos)) || !(this.mc.field_1724.method_24515().method_10262((class_2382)pos) <= Math.pow((Integer)this.mc.field_1690.method_42503().method_41753() * 16, 2.0)) || (color2 = this.getColorForBlockType(entry.getValue().type)) == null) continue;
                event.renderer.box(new class_238((class_2338)pos), color2, color2, this.blockRenderMode.get(), 0);
                ++rendered;
            }
            if (this.detectCobblestoneLines.get().booleanValue()) {
                for (CobblestoneLine cobblestoneLine : this.detectedCobblestoneLines) {
                    if (rendered >= this.maxBlocksToRender.get()) break;
                    if (this.mc.field_1724.method_24515().method_10262((class_2382)cobblestoneLine.startPos) > Math.pow((Integer)this.mc.field_1690.method_42503().method_41753() * 16, 2.0)) continue;
                    color = this.cobblestoneLineBlockColor.get();
                    for (int i = 0; i < cobblestoneLine.length && rendered < this.maxBlocksToRender.get(); ++rendered, ++i) {
                        event.renderer.box(new class_238(cobblestoneLine.startPos.method_10086(i)), color, color, this.blockRenderMode.get(), 0);
                    }
                }
            }
            if (this.detectTuffLines.get().booleanValue()) {
                for (TuffLine tuffLine : this.detectedTuffLines) {
                    if (rendered >= this.maxBlocksToRender.get()) break;
                    if (this.mc.field_1724.method_24515().method_10262((class_2382)tuffLine.startPos) > Math.pow((Integer)this.mc.field_1690.method_42503().method_41753() * 16, 2.0)) continue;
                    color = this.tuffLineBlockColor.get();
                    for (int i = 0; i < tuffLine.length && rendered < this.maxBlocksToRender.get(); ++rendered, ++i) {
                        event.renderer.box(new class_238(tuffLine.startPos.method_10086(i)), color, color, this.blockRenderMode.get(), 0);
                    }
                }
            }
            if (this.detectAndesiteLines.get().booleanValue()) {
                for (AndesiteLine andesiteLine : this.detectedAndesiteLines) {
                    if (rendered >= this.maxBlocksToRender.get()) break;
                    if (this.mc.field_1724.method_24515().method_10262((class_2382)andesiteLine.startPos) > Math.pow((Integer)this.mc.field_1690.method_42503().method_41753() * 16, 2.0)) continue;
                    color = this.andesiteLineBlockColor.get();
                    for (int i = 0; i < andesiteLine.length && rendered < this.maxBlocksToRender.get(); ++rendered, ++i) {
                        event.renderer.box(new class_238(andesiteLine.startPos.method_10086(i)), color, color, this.blockRenderMode.get(), 0);
                    }
                }
            }
            if (this.detectDioriteLines.get().booleanValue()) {
                for (DioriteLine dioriteLine : this.detectedDioriteLines) {
                    if (rendered >= this.maxBlocksToRender.get()) break;
                    if (this.mc.field_1724.method_24515().method_10262((class_2382)dioriteLine.startPos) > Math.pow((Integer)this.mc.field_1690.method_42503().method_41753() * 16, 2.0)) continue;
                    color = this.dioriteLineBlockColor.get();
                    for (int i = 0; i < dioriteLine.length && rendered < this.maxBlocksToRender.get(); ++rendered, ++i) {
                        event.renderer.box(new class_238(dioriteLine.startPos.method_10086(i)), color, color, this.blockRenderMode.get(), 0);
                    }
                }
            }
            if (this.detectObsidianLines.get().booleanValue()) {
                for (ObsidianLine obsidianLine : this.detectedObsidianLines) {
                    if (rendered >= this.maxBlocksToRender.get()) break;
                    if (this.mc.field_1724.method_24515().method_10262((class_2382)obsidianLine.startPos) > Math.pow((Integer)this.mc.field_1690.method_42503().method_41753() * 16, 2.0)) continue;
                    color = this.obsidianLineBlockColor.get();
                    for (int i = 0; i < obsidianLine.length && rendered < this.maxBlocksToRender.get(); ++rendered, ++i) {
                        event.renderer.box(new class_238(obsidianLine.startPos.method_10086(i)), color, color, this.blockRenderMode.get(), 0);
                    }
                }
            }
        }
    }

    private Color getColorForBlockType(SuspiciousBlockType type) {
        return switch (type.ordinal()) {
            default -> throw new MatchException(null, null);
            case 0 -> this.cobbledDeepslateBlockColor.get();
            case 1 -> this.rotatedDeepslateBlockColor.get();
            case 2 -> this.normalDeepslateBlockColor.get();
            case 3 -> this.cobblestoneLineBlockColor.get();
            case 4 -> this.tuffLineBlockColor.get();
            case 5 -> this.andesiteLineBlockColor.get();
            case 6 -> this.dioriteLineBlockColor.get();
            case 7 -> this.obsidianLineBlockColor.get();
        };
    }

    @Override
    public String getInfoString() {
        if (!this.flaggedChunks.isEmpty()) {
            class_1923 first = this.flaggedChunks.iterator().next();
            return String.format("%d, %d", first.field_9181 * 16, first.field_9180 * 16);
        }
        return "None";
    }

    public static enum Mode {
        Chat,
        Toast,
        Both;

    }

    private static class ChunkAnalysis {
        int cobbledDeepslateCount = 0;
        int rotatedDeepslateCount = 0;
        int normalDeepslateCount = 0;
        int trialChamberCount = 0;
        int cobblestoneLineCount = 0;
        int tuffLineCount = 0;
        int andesiteLineCount = 0;
        int dioriteLineCount = 0;
        int obsidianLineCount = 0;

        private ChunkAnalysis() {
        }
    }

    public static enum SuspiciousBlockType {
        COBBLED_DEEPSLATE,
        ROTATED_DEEPSLATE,
        NORMAL_DEEPSLATE,
        COBBLESTONE_LINE,
        TUFF_LINE,
        ANDESITE_LINE,
        DIORITE_LINE,
        OBSIDIAN_LINE;

    }

    private static class SuspiciousBlock {
        final SuspiciousBlockType type;
        final long detectedTime;

        SuspiciousBlock(SuspiciousBlockType type, long time) {
            this.type = type;
            this.detectedTime = time;
        }
    }

    private record CobblestoneLine(class_2338 startPos, int length, long detectedTime) {
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || this.getClass() != o.getClass()) {
                return false;
            }
            CobblestoneLine that = (CobblestoneLine)o;
            return this.startPos.equals((Object)that.startPos);
        }

        @Override
        public int hashCode() {
            return this.startPos.hashCode();
        }
    }

    private record TuffLine(class_2338 startPos, int length, long detectedTime) {
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || this.getClass() != o.getClass()) {
                return false;
            }
            TuffLine that = (TuffLine)o;
            return this.startPos.equals((Object)that.startPos);
        }

        @Override
        public int hashCode() {
            return this.startPos.hashCode();
        }
    }

    private record AndesiteLine(class_2338 startPos, int length, long detectedTime) {
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || this.getClass() != o.getClass()) {
                return false;
            }
            AndesiteLine that = (AndesiteLine)o;
            return this.startPos.equals((Object)that.startPos);
        }

        @Override
        public int hashCode() {
            return this.startPos.hashCode();
        }
    }

    private record DioriteLine(class_2338 startPos, int length, long detectedTime) {
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || this.getClass() != o.getClass()) {
                return false;
            }
            DioriteLine that = (DioriteLine)o;
            return this.startPos.equals((Object)that.startPos);
        }

        @Override
        public int hashCode() {
            return this.startPos.hashCode();
        }
    }

    private record ObsidianLine(class_2338 startPos, int length, long detectedTime) {
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || this.getClass() != o.getClass()) {
                return false;
            }
            ObsidianLine that = (ObsidianLine)o;
            return this.startPos.equals((Object)that.startPos);
        }

        @Override
        public int hashCode() {
            return this.startPos.hashCode();
        }
    }

    private static class ChunkToast
    extends MeteorToast {
        private final class_1799 icon;
        private final class_2561 title;
        private final class_2561 description;

        public ChunkToast(class_1799 icon, class_2561 title, class_2561 description) {
            super(new MeteorToast.Builder(title.getString()).icon(icon.method_7909()).text(description.getString()));
            this.icon = icon;
            this.title = title;
            this.description = description;
        }

        @Override
        public void method_1986(class_332 context, class_327 textRenderer, long startTime) {
            context.method_25294(0, 0, 160, 32, -1442840576);
            int yellow = -256;
            context.method_25294(0, 0, 160, 1, yellow);
            context.method_25294(0, 31, 160, 32, yellow);
            context.method_25294(0, 1, 1, 31, yellow);
            context.method_25294(159, 1, 160, 31, yellow);
            if (this.icon != null && !this.icon.method_7960()) {
                context.method_51427(this.icon, 8, 8);
            }
            if (this.title != null) {
                context.method_51439(textRenderer, this.title, 32, 7, 0xFFFFFF, false);
            }
            if (this.description != null) {
                context.method_51439(textRenderer, this.description, 32, 18, 0xFFFF00, false);
            }
        }
    }
}

