Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Часть функционала AutoMiner FT

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
12 Янв 2025
Сообщения
24
Реакции
1
Выберите загрузчик игры
  1. OptiFine
Всем привет, моя вторая тема в кратце ходит по анкам добывает на шахтe что выберешь. !нужен баритон!
Java:
Expand Collapse Copy
import beame.components.baritone.api.BaritoneAPI;
import beame.components.baritone.api.IBaritone;
import beame.components.baritone.api.process.IMineProcess;
import beame.module.Category;
import beame.module.Module;
import beame.setting.SettingList.BooleanSetting;
import beame.setting.SettingList.EnumSetting;
import events.Event;
import events.impl.player.EventUpdate;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.item.PickaxeItem;
import net.minecraft.util.math.BlockPos;
import beame.util.math.TimerUtil;
import beame.components.baritone.api.pathing.goals.GoalXZ;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.inventory.container.ClickType;
import beame.components.baritone.api.pathing.path.IPathExecutor;
import beame.components.baritone.api.pathing.movement.IMovement;
import beame.components.baritone.pathing.movement.movements.MovementPillar;
import beame.util.math.RaytraceUtility;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.lang.reflect.Field;

public class AutoMiner extends Module {
    // Выбор руд для добычи
    private final EnumSetting ores = new EnumSetting("Добывать",
            new BooleanSetting("Алмазная руда", true),
            new BooleanSetting("Железная руда", false),
            new BooleanSetting("Золотая руда", false),
            new BooleanSetting("Угольная руда", false)
    );

    private IMineProcess mineProcess;
    private static final int DEFAULT_RADIUS = 30;
    private static final int EAT_THRESHOLD = 18;
    private boolean isEating = false;
    private int previousSlot = -1;
    // Sequence after finishing mining
    private final String[] AN_COMMANDS = new String[]{
            "/an217", "/an218", "/an216", "/an313", "/an312", "/an308", "/an309",
            "/an211", "/an115", "/an602", "/an505", "/an311", "/an312", "/an104",
            "/an212", "/an213", "/an503", "/an504", "/an507", "/an506"
    };
    private int anIndex = 0;
    private boolean chainInProgress = false;
    private int chainStage = 0; // 0 idle, 1 wait 5s after /an, 2 wait 12s after /warp, 3 moving forward
    private final TimerUtil chainTimer = new TimerUtil();
    private boolean prevMineActive = false;
    private static final double PICKAXE_MIN_PCT = 0.20; // 20%
    private boolean haltedFromHub = false;
    private boolean isUnstucking = false;
    private BlockPos unstuckBreakingPos = null;
    private final TimerUtil unstuckTimer = new TimerUtil();
    // Save and override Baritone render settings to hide path/boxes while AutoMiner works
    private Boolean prevRenderPath = null;
    // ===== ЗАСТРЕВАНИЕ ПО КООРДИНАТАМ (5 сек на одном месте) =====
    private BlockPos lastStuckCheckPos = null;
    private final TimerUtil stuckTimer = new TimerUtil();


    public AutoMiner() {
        super("FTNuker", Category.Misc, true, "Автоматически ходит и добывает выбранные руды");
        addSettings(ores);
    }

    @Override
    protected boolean onEnable() {
        IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
        if (baritone == null) return false;
        mineProcess = baritone.getMineProcess();
        haltedFromHub = false;
        prevMineActive = false;

        // Hide Baritone path/goal/selection boxes while AutoMiner is active
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath == null) prevRenderPath = settings.renderPath.value;
            settings.renderPath.value = false;
        } catch (Throwable ignored) {}

        

        List<Block> targets = new ArrayList<>();
        if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
        if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
        if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
        if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

        if (targets.isEmpty()) {
            // Нет выбранных блоков — не запускаем майнинг, модуль остаётся включён
            return true;
        }

        // Запуск майнинга выбранных блоков, без ограничения по количеству
        mineProcess.mine(targets.toArray(new Block[0]));
        // Сразу ограничим цели радиусом, чтобы старт происходил в рамках DEFAULT_RADIUS
        filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
        return true;
    }

    @Override
    protected void onDisable() {
        if (mineProcess != null) {
            mineProcess.cancel();
        }
        // Restore Baritone rendering settings
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath != null) {
                settings.renderPath.value = prevRenderPath;
                prevRenderPath = null;
            }
        } catch (Throwable ignored) {}
        
        // Сброс клика атаки на случай, если держим для разлома блока
        try {
            mc.gameSettings.keyBindAttack.setPressed(false);
            if (isUnstucking) {
                mc.playerController.resetBlockRemoving();
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
        } catch (Throwable ignored) {}
    }

    // Возвращает true, если выполнили действие (заменили кирку или ушли на /hub)
    private boolean ensurePickaxeDurabilityOrHub() {
        ItemStack main = mc.player.getHeldItemMainhand();
        boolean hasPickaxeInHand = main != null && main.getItem() instanceof PickaxeItem;
        if (hasPickaxeInHand) {
            double pct = remainingPct(main);
            if (pct <= PICKAXE_MIN_PCT) {
                // Найти лучшую кирку с >20%
                int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
                if (best != -1) {
                    switchToSlot(best);
                    return true; // заменили
                } else {
                    // Все кирки <=20% (или нет кирок) — уходим в /hub и стоп
                    mc.player.sendChatMessage("/hub");
                    haltedFromHub = true;
                    return true;
                }
            }
        } else {
            // В руке не кирка: попробуем взять подходящую кирку >20%, если есть
            int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
            if (best != -1) {
                switchToSlot(best);
                return true;
            }
            // Нет подходящей кирки >20% — уходим в /hub и стоп
            mc.player.sendChatMessage("/hub");
            haltedFromHub = true;
            return true;
        }
        return false;
    }

    private int findBestPickaxeSlotAboveThreshold(double minPct) {
        int bestSlot = -1;
        double bestPct = -1.0;
        // Проверяем хотбар 0..8 и инвентарь 9..35
        for (int i = 0; i < 36; i++) {
            ItemStack s = mc.player.inventory.getStackInSlot(i);
            if (s == null || s.isEmpty() || !(s.getItem() instanceof PickaxeItem)) continue;
            double pct = remainingPct(s);
            if (pct > minPct && pct > bestPct) {
                bestPct = pct;
                bestSlot = i;
            }
        }
        return bestSlot;
    }

    private double remainingPct(ItemStack stack) {
        int max = stack.getMaxDamage();
        if (max <= 0) return 1.0; // небьющийся предмет
        int used = stack.getDamage();
        int remaining = Math.max(0, max - used);
        return (double) remaining / (double) max;
    }

    private void switchToSlot(int invIndex) {
        if (invIndex < 0 || invIndex >= 36) return;
        int currentHotbar = mc.player.inventory.currentItem; // 0..8
        if (invIndex <= 8) {
            // Уже в хотбаре
            if (currentHotbar != invIndex) {
                mc.player.inventory.currentItem = invIndex;
            }
        } else {
            // В инвентаре: свапаем с текущим хотбар слотом
            int containerSlot = invIndex; // 9..35
            int windowId = mc.player.openContainer.windowId;
            mc.playerController.windowClick(windowId, containerSlot, currentHotbar, ClickType.SWAP, mc.player);
        }
    }

    @Override
    public void event(Event event) {
        if (event instanceof EventUpdate) {
            IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
            if (baritone == null || mc.player == null) return;
            if (haltedFromHub) return;

            // 1) Если голоден — остановиться, поесть, затем продолжить
            boolean hungry = mc.player.getFoodStats().getFoodLevel() < EAT_THRESHOLD;
            if (hungry) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                // Важно: не запускать /an после отмены майнинга из-за еды
                // Сбросим prevMineActive, чтобы не сработало условие prevMineActive && !currentMineActive
                prevMineActive = false;
                if (!isEating) {
                    int foodSlot = findFoodHotbarSlot();
                    if (foodSlot != -1 || hasFoodInHands()) {
                        startEating(foodSlot);
                    }
                } else {
                    continueEating();
                }
                return;
            } else if (isEating) {
                stopEating();
            }

            // 1b) Проверка прочности кирки и замена / выход в /hub
            if (ensurePickaxeDurabilityOrHub()) {
                // либо заменили кирку, либо ушли на /hub и остановились
                if (haltedFromHub) {
                    if (mineProcess != null && mineProcess.isActive()) mineProcess.cancel();
                    chainInProgress = false;
                    return;
                }
                // если была замена инструмента, продолжаем дальше
            }

            // 1c) Если застряли/душимся в блоках — ломаем блок перед собой и ничего больше не делаем в этот тик
            if (handleSuffocationUnstuck()) {
                prevMineActive = mineProcess != null && mineProcess.isActive();
                return;
            }

            // 2) Если есть выбранные руды — майним, иначе стоим
            List<Block> targets = new ArrayList<>();
            if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
            if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
            if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
            if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

            boolean currentMineActive = mineProcess != null && mineProcess.isActive();

            // 2a-Застревание: если 5 секунд на одних координатах во время майнинга — делаем /warp mine и идём вперёд
            {
                BlockPos cur = mc.player.getPosition();
                if (lastStuckCheckPos == null || !lastStuckCheckPos.equals(cur)) {
                    lastStuckCheckPos = cur;
                    stuckTimer.reset();
                } else if (currentMineActive && !chainInProgress && !isEating) {
                    if (stuckTimer.finished(5000)) {
                        if (mineProcess != null && mineProcess.isActive()) {
                            mineProcess.cancel();
                        }
                        mc.player.sendChatMessage("/warp mine");
                        chainInProgress = true;
                        chainStage = 21; // ждать ~10с, затем идти вперёд на 9 блоков
                        chainTimer.reset();
                        prevMineActive = currentMineActive;
                        return;
                    }
                }
            }

            // 2a0) Если баритон пытается строиться вверх (пиллар) к руде — вместо этого выполняем warp-сценарий
            if (!chainInProgress && !isEating) {
                try {
                    IPathExecutor exec = baritone.getPathingBehavior().getCurrent();
                    if (exec != null && exec.getPath() != null && exec.getPath().movements() != null && !exec.getPath().movements().isEmpty()) {
                        int idx = Math.min(Math.max(exec.getPosition(), 0), exec.getPath().movements().size() - 1);
                        IMovement mv = exec.getPath().movements().get(idx);
                        if (mv instanceof MovementPillar) {
                            if (mineProcess != null && mineProcess.isActive()) {
                                mineProcess.cancel();
                            }
                            mc.player.sendChatMessage("/warp mine");
                            chainInProgress = true;
                            chainStage = 21; // ждать 10 секунд, затем идти вперёд на 9 блоков
                            chainTimer.reset();
                            prevMineActive = currentMineActive;
                            return;
                        }
                    }
                } catch (Throwable ignored) {}
            }

            // 2a) Обработка последовательности после завершения майнинга И/ИЛИ warp-сценариев
            if (chainInProgress) {
                // Выполняем этапы: 1) ждать 5с => /warp mine; 2) ждать 12с => пройти вперёд 5 блоков; 3) дождаться завершения движения
                switch (chainStage) {
                    case 1 -> {
                        if (chainTimer.finished(5000)) {
                            mc.player.sendChatMessage("/warp mine");
                            chainStage = 2;
                            chainTimer.reset();
                        }
                    }
                    case 2 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 3;
                        }
                    }
                    case 3 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            // Движение завершено, завершаем цепочку, далее общий код перезапустит майнинг
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                    case 21 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 22;
                        }
                    }
                    case 22 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                }
                // Поддерживаем ограничение радиуса, даже пока идёт цепочка
                filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
                prevMineActive = currentMineActive;
                return; // Не перезапускаем майнинг, пока идёт цепочка
            }

            if (targets.isEmpty()) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                prevMineActive = currentMineActive;
                return;
            }

            // 2b) Детектируем окончание майнинга и запускаем цепочку команд
            if (prevMineActive && !currentMineActive && !isEating) {
                // Завершён майнинг: отправляем следующий /an и запускаем таймер на 5 секунд
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1;
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // 2c) Если процесс не активен и нет цепочки — перезапускаем майнинг
            if (mineProcess != null && !currentMineActive && !chainInProgress) {
                mineProcess.mine(targets.toArray(new Block[0]));
            }

            // 3) Ограничение целей радиусом
            filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);

            // 3a) Если в радиусе нет выбранной руды — запустить цепочку /an -> /warp mine -> идти вперёд
            if (!chainInProgress && !isEating && currentMineActive && noTargetsInRadius(baritone)) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1; // ждать 5 секунд, затем /warp mine
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // Обновляем предыдущее состояние активности майнинга
            prevMineActive = currentMineActive;
        }
    }

    private void filterTargetsWithinRadius(IBaritone baritone, int radius) {
        if (baritone == null || mc.player == null) return;
        if (mineProcess == null) return;
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            if (locs == null || locs.isEmpty()) return;

            BlockPos playerPos = mc.player.getPosition();
            double maxSq = (double) radius * (double) radius;
            List<BlockPos> filtered = locs.stream()
                    .filter(p -> p != null && playerPos.distanceSq(p) <= maxSq)
                    .collect(Collectors.toCollection(ArrayList::new));

            // Replace with a new list to avoid concurrent modification
            fKnown.set(impl, filtered);
        } catch (Throwable ignored) {
            // fail silently to avoid crashing if internals change
        }
    }

    private boolean noTargetsInRadius(IBaritone baritone) {
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return true;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            return locs == null || locs.isEmpty();
        } catch (Throwable ignored) {
            return false;
        }
    }

    // ===== ЕДА =====
    private boolean hasFoodInHands() {
        if (mc.player == null) return false;
        ItemStack main = mc.player.getHeldItemMainhand();
        ItemStack off = mc.player.getHeldItemOffhand();
        return (!main.isEmpty() && main.getItem().isFood()) || (!off.isEmpty() && off.getItem().isFood());
    }

    private int findFoodHotbarSlot() {
        if (mc.player == null) return -1;
        for (int i = 0; i < 9; i++) {
            ItemStack stack = mc.player.inventory.getStackInSlot(i);
            if (!stack.isEmpty() && stack.getItem().isFood()) {
                return i;
            }
        }
        return -1;
    }

    private void startEating(int foodSlot) {
        isEating = true;
        if (!hasFoodInHands()) {
            if (foodSlot == -1) {
                isEating = false;
                return;
            }
            previousSlot = mc.player.inventory.currentItem;
            mc.player.inventory.currentItem = foodSlot;
        }
        continueEating();
    }

    private void continueEating() {
        if (mc.currentScreen == null) {
            mc.gameSettings.keyBindUseItem.setPressed(true);
        }
        if (mc.player.getFoodStats().getFoodLevel() >= EAT_THRESHOLD || !hasFoodInHands()) {
            stopEating();
        }
    }

    private void stopEating() {
        mc.gameSettings.keyBindUseItem.setPressed(false);
        isEating = false;
        if (previousSlot != -1 && mc.player != null) {
            mc.player.inventory.currentItem = previousSlot;
            previousSlot = -1;
        }
    }

    // ===== АНТИ-ЗАСТРЕВАНИЕ (ломаем блок перед собой при удушье) =====
    private boolean handleSuffocationUnstuck() {
        if (mc.player == null || mc.world == null) return false;
        boolean inside = mc.player.isEntityInsideOpaqueBlock();
        if (!inside) {
            // Не душимся — сброс состояния
            if (isUnstucking) {
                try {
                    mc.gameSettings.keyBindAttack.setPressed(false);
                    mc.playerController.resetBlockRemoving();
                } catch (Throwable ignored) {}
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
            return false;
        }

        // Отменяем майнинг, чтобы не мешал разлому
        if (mineProcess != null && mineProcess.isActive()) {
            mineProcess.cancel();
        }

        // Находим блок перед взглядом игрока (до 2 блока)
        RayTraceResult rt = RaytraceUtility.rayTrace(2.5, mc.player.rotationYaw, mc.player.rotationPitch, mc.player);
        net.minecraft.util.math.BlockPos targetPos = null;
        Direction face = Direction.UP;
        if (rt != null && rt.getType() == RayTraceResult.Type.BLOCK && rt instanceof BlockRayTraceResult brt) {
            targetPos = brt.getPos();
            face = brt.getFace();
        }
        if (targetPos == null) {
            // fallback: блок на уровне глаз
            targetPos = new net.minecraft.util.math.BlockPos(mc.player.getEyePosition(1.0f));
            face = Direction.UP;
        }

        if (mc.world.isAirBlock(targetPos)) {
            // если перед нами воздух, пробуем блок в ногах
            targetPos = mc.player.getPosition();
        }

        if (!mc.world.isAirBlock(targetPos)) {
            try {
                // Начинаем ломать и продолжаем до разрушения
                if (unstuckBreakingPos == null || !unstuckBreakingPos.equals(targetPos)) {
                    mc.playerController.syncCurrentPlayItem();
                    mc.playerController.clickBlock(targetPos, face);
                    unstuckBreakingPos = targetPos;
                }
                mc.playerController.onPlayerDamageBlock(targetPos, face);
                mc.player.swingArm(Hand.MAIN_HAND);
                mc.gameSettings.keyBindAttack.setPressed(true);
                isUnstucking = true;
            } catch (Throwable ignored) {}
        }
        return true;
    }
}

жду сообщение "cursor", ps это другая нейронка
 
Всем привет, моя вторая тема в кратце ходит по анкам добывает на шахтe что выберешь. !нужен баритон!
Java:
Expand Collapse Copy
import beame.components.baritone.api.BaritoneAPI;
import beame.components.baritone.api.IBaritone;
import beame.components.baritone.api.process.IMineProcess;
import beame.module.Category;
import beame.module.Module;
import beame.setting.SettingList.BooleanSetting;
import beame.setting.SettingList.EnumSetting;
import events.Event;
import events.impl.player.EventUpdate;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.item.PickaxeItem;
import net.minecraft.util.math.BlockPos;
import beame.util.math.TimerUtil;
import beame.components.baritone.api.pathing.goals.GoalXZ;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.inventory.container.ClickType;
import beame.components.baritone.api.pathing.path.IPathExecutor;
import beame.components.baritone.api.pathing.movement.IMovement;
import beame.components.baritone.pathing.movement.movements.MovementPillar;
import beame.util.math.RaytraceUtility;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.lang.reflect.Field;

public class AutoMiner extends Module {
    // Выбор руд для добычи
    private final EnumSetting ores = new EnumSetting("Добывать",
            new BooleanSetting("Алмазная руда", true),
            new BooleanSetting("Железная руда", false),
            new BooleanSetting("Золотая руда", false),
            new BooleanSetting("Угольная руда", false)
    );

    private IMineProcess mineProcess;
    private static final int DEFAULT_RADIUS = 30;
    private static final int EAT_THRESHOLD = 18;
    private boolean isEating = false;
    private int previousSlot = -1;
    // Sequence after finishing mining
    private final String[] AN_COMMANDS = new String[]{
            "/an217", "/an218", "/an216", "/an313", "/an312", "/an308", "/an309",
            "/an211", "/an115", "/an602", "/an505", "/an311", "/an312", "/an104",
            "/an212", "/an213", "/an503", "/an504", "/an507", "/an506"
    };
    private int anIndex = 0;
    private boolean chainInProgress = false;
    private int chainStage = 0; // 0 idle, 1 wait 5s after /an, 2 wait 12s after /warp, 3 moving forward
    private final TimerUtil chainTimer = new TimerUtil();
    private boolean prevMineActive = false;
    private static final double PICKAXE_MIN_PCT = 0.20; // 20%
    private boolean haltedFromHub = false;
    private boolean isUnstucking = false;
    private BlockPos unstuckBreakingPos = null;
    private final TimerUtil unstuckTimer = new TimerUtil();
    // Save and override Baritone render settings to hide path/boxes while AutoMiner works
    private Boolean prevRenderPath = null;
    // ===== ЗАСТРЕВАНИЕ ПО КООРДИНАТАМ (5 сек на одном месте) =====
    private BlockPos lastStuckCheckPos = null;
    private final TimerUtil stuckTimer = new TimerUtil();


    public AutoMiner() {
        super("FTNuker", Category.Misc, true, "Автоматически ходит и добывает выбранные руды");
        addSettings(ores);
    }

    @Override
    protected boolean onEnable() {
        IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
        if (baritone == null) return false;
        mineProcess = baritone.getMineProcess();
        haltedFromHub = false;
        prevMineActive = false;

        // Hide Baritone path/goal/selection boxes while AutoMiner is active
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath == null) prevRenderPath = settings.renderPath.value;
            settings.renderPath.value = false;
        } catch (Throwable ignored) {}

       

        List<Block> targets = new ArrayList<>();
        if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
        if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
        if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
        if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

        if (targets.isEmpty()) {
            // Нет выбранных блоков — не запускаем майнинг, модуль остаётся включён
            return true;
        }

        // Запуск майнинга выбранных блоков, без ограничения по количеству
        mineProcess.mine(targets.toArray(new Block[0]));
        // Сразу ограничим цели радиусом, чтобы старт происходил в рамках DEFAULT_RADIUS
        filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
        return true;
    }

    @Override
    protected void onDisable() {
        if (mineProcess != null) {
            mineProcess.cancel();
        }
        // Restore Baritone rendering settings
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath != null) {
                settings.renderPath.value = prevRenderPath;
                prevRenderPath = null;
            }
        } catch (Throwable ignored) {}
       
        // Сброс клика атаки на случай, если держим для разлома блока
        try {
            mc.gameSettings.keyBindAttack.setPressed(false);
            if (isUnstucking) {
                mc.playerController.resetBlockRemoving();
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
        } catch (Throwable ignored) {}
    }

    // Возвращает true, если выполнили действие (заменили кирку или ушли на /hub)
    private boolean ensurePickaxeDurabilityOrHub() {
        ItemStack main = mc.player.getHeldItemMainhand();
        boolean hasPickaxeInHand = main != null && main.getItem() instanceof PickaxeItem;
        if (hasPickaxeInHand) {
            double pct = remainingPct(main);
            if (pct <= PICKAXE_MIN_PCT) {
                // Найти лучшую кирку с >20%
                int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
                if (best != -1) {
                    switchToSlot(best);
                    return true; // заменили
                } else {
                    // Все кирки <=20% (или нет кирок) — уходим в /hub и стоп
                    mc.player.sendChatMessage("/hub");
                    haltedFromHub = true;
                    return true;
                }
            }
        } else {
            // В руке не кирка: попробуем взять подходящую кирку >20%, если есть
            int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
            if (best != -1) {
                switchToSlot(best);
                return true;
            }
            // Нет подходящей кирки >20% — уходим в /hub и стоп
            mc.player.sendChatMessage("/hub");
            haltedFromHub = true;
            return true;
        }
        return false;
    }

    private int findBestPickaxeSlotAboveThreshold(double minPct) {
        int bestSlot = -1;
        double bestPct = -1.0;
        // Проверяем хотбар 0..8 и инвентарь 9..35
        for (int i = 0; i < 36; i++) {
            ItemStack s = mc.player.inventory.getStackInSlot(i);
            if (s == null || s.isEmpty() || !(s.getItem() instanceof PickaxeItem)) continue;
            double pct = remainingPct(s);
            if (pct > minPct && pct > bestPct) {
                bestPct = pct;
                bestSlot = i;
            }
        }
        return bestSlot;
    }

    private double remainingPct(ItemStack stack) {
        int max = stack.getMaxDamage();
        if (max <= 0) return 1.0; // небьющийся предмет
        int used = stack.getDamage();
        int remaining = Math.max(0, max - used);
        return (double) remaining / (double) max;
    }

    private void switchToSlot(int invIndex) {
        if (invIndex < 0 || invIndex >= 36) return;
        int currentHotbar = mc.player.inventory.currentItem; // 0..8
        if (invIndex <= 8) {
            // Уже в хотбаре
            if (currentHotbar != invIndex) {
                mc.player.inventory.currentItem = invIndex;
            }
        } else {
            // В инвентаре: свапаем с текущим хотбар слотом
            int containerSlot = invIndex; // 9..35
            int windowId = mc.player.openContainer.windowId;
            mc.playerController.windowClick(windowId, containerSlot, currentHotbar, ClickType.SWAP, mc.player);
        }
    }

    @Override
    public void event(Event event) {
        if (event instanceof EventUpdate) {
            IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
            if (baritone == null || mc.player == null) return;
            if (haltedFromHub) return;

            // 1) Если голоден — остановиться, поесть, затем продолжить
            boolean hungry = mc.player.getFoodStats().getFoodLevel() < EAT_THRESHOLD;
            if (hungry) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                // Важно: не запускать /an после отмены майнинга из-за еды
                // Сбросим prevMineActive, чтобы не сработало условие prevMineActive && !currentMineActive
                prevMineActive = false;
                if (!isEating) {
                    int foodSlot = findFoodHotbarSlot();
                    if (foodSlot != -1 || hasFoodInHands()) {
                        startEating(foodSlot);
                    }
                } else {
                    continueEating();
                }
                return;
            } else if (isEating) {
                stopEating();
            }

            // 1b) Проверка прочности кирки и замена / выход в /hub
            if (ensurePickaxeDurabilityOrHub()) {
                // либо заменили кирку, либо ушли на /hub и остановились
                if (haltedFromHub) {
                    if (mineProcess != null && mineProcess.isActive()) mineProcess.cancel();
                    chainInProgress = false;
                    return;
                }
                // если была замена инструмента, продолжаем дальше
            }

            // 1c) Если застряли/душимся в блоках — ломаем блок перед собой и ничего больше не делаем в этот тик
            if (handleSuffocationUnstuck()) {
                prevMineActive = mineProcess != null && mineProcess.isActive();
                return;
            }

            // 2) Если есть выбранные руды — майним, иначе стоим
            List<Block> targets = new ArrayList<>();
            if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
            if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
            if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
            if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

            boolean currentMineActive = mineProcess != null && mineProcess.isActive();

            // 2a-Застревание: если 5 секунд на одних координатах во время майнинга — делаем /warp mine и идём вперёд
            {
                BlockPos cur = mc.player.getPosition();
                if (lastStuckCheckPos == null || !lastStuckCheckPos.equals(cur)) {
                    lastStuckCheckPos = cur;
                    stuckTimer.reset();
                } else if (currentMineActive && !chainInProgress && !isEating) {
                    if (stuckTimer.finished(5000)) {
                        if (mineProcess != null && mineProcess.isActive()) {
                            mineProcess.cancel();
                        }
                        mc.player.sendChatMessage("/warp mine");
                        chainInProgress = true;
                        chainStage = 21; // ждать ~10с, затем идти вперёд на 9 блоков
                        chainTimer.reset();
                        prevMineActive = currentMineActive;
                        return;
                    }
                }
            }

            // 2a0) Если баритон пытается строиться вверх (пиллар) к руде — вместо этого выполняем warp-сценарий
            if (!chainInProgress && !isEating) {
                try {
                    IPathExecutor exec = baritone.getPathingBehavior().getCurrent();
                    if (exec != null && exec.getPath() != null && exec.getPath().movements() != null && !exec.getPath().movements().isEmpty()) {
                        int idx = Math.min(Math.max(exec.getPosition(), 0), exec.getPath().movements().size() - 1);
                        IMovement mv = exec.getPath().movements().get(idx);
                        if (mv instanceof MovementPillar) {
                            if (mineProcess != null && mineProcess.isActive()) {
                                mineProcess.cancel();
                            }
                            mc.player.sendChatMessage("/warp mine");
                            chainInProgress = true;
                            chainStage = 21; // ждать 10 секунд, затем идти вперёд на 9 блоков
                            chainTimer.reset();
                            prevMineActive = currentMineActive;
                            return;
                        }
                    }
                } catch (Throwable ignored) {}
            }

            // 2a) Обработка последовательности после завершения майнинга И/ИЛИ warp-сценариев
            if (chainInProgress) {
                // Выполняем этапы: 1) ждать 5с => /warp mine; 2) ждать 12с => пройти вперёд 5 блоков; 3) дождаться завершения движения
                switch (chainStage) {
                    case 1 -> {
                        if (chainTimer.finished(5000)) {
                            mc.player.sendChatMessage("/warp mine");
                            chainStage = 2;
                            chainTimer.reset();
                        }
                    }
                    case 2 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 3;
                        }
                    }
                    case 3 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            // Движение завершено, завершаем цепочку, далее общий код перезапустит майнинг
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                    case 21 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 22;
                        }
                    }
                    case 22 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                }
                // Поддерживаем ограничение радиуса, даже пока идёт цепочка
                filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
                prevMineActive = currentMineActive;
                return; // Не перезапускаем майнинг, пока идёт цепочка
            }

            if (targets.isEmpty()) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                prevMineActive = currentMineActive;
                return;
            }

            // 2b) Детектируем окончание майнинга и запускаем цепочку команд
            if (prevMineActive && !currentMineActive && !isEating) {
                // Завершён майнинг: отправляем следующий /an и запускаем таймер на 5 секунд
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1;
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // 2c) Если процесс не активен и нет цепочки — перезапускаем майнинг
            if (mineProcess != null && !currentMineActive && !chainInProgress) {
                mineProcess.mine(targets.toArray(new Block[0]));
            }

            // 3) Ограничение целей радиусом
            filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);

            // 3a) Если в радиусе нет выбранной руды — запустить цепочку /an -> /warp mine -> идти вперёд
            if (!chainInProgress && !isEating && currentMineActive && noTargetsInRadius(baritone)) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1; // ждать 5 секунд, затем /warp mine
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // Обновляем предыдущее состояние активности майнинга
            prevMineActive = currentMineActive;
        }
    }

    private void filterTargetsWithinRadius(IBaritone baritone, int radius) {
        if (baritone == null || mc.player == null) return;
        if (mineProcess == null) return;
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            if (locs == null || locs.isEmpty()) return;

            BlockPos playerPos = mc.player.getPosition();
            double maxSq = (double) radius * (double) radius;
            List<BlockPos> filtered = locs.stream()
                    .filter(p -> p != null && playerPos.distanceSq(p) <= maxSq)
                    .collect(Collectors.toCollection(ArrayList::new));

            // Replace with a new list to avoid concurrent modification
            fKnown.set(impl, filtered);
        } catch (Throwable ignored) {
            // fail silently to avoid crashing if internals change
        }
    }

    private boolean noTargetsInRadius(IBaritone baritone) {
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return true;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            return locs == null || locs.isEmpty();
        } catch (Throwable ignored) {
            return false;
        }
    }

    // ===== ЕДА =====
    private boolean hasFoodInHands() {
        if (mc.player == null) return false;
        ItemStack main = mc.player.getHeldItemMainhand();
        ItemStack off = mc.player.getHeldItemOffhand();
        return (!main.isEmpty() && main.getItem().isFood()) || (!off.isEmpty() && off.getItem().isFood());
    }

    private int findFoodHotbarSlot() {
        if (mc.player == null) return -1;
        for (int i = 0; i < 9; i++) {
            ItemStack stack = mc.player.inventory.getStackInSlot(i);
            if (!stack.isEmpty() && stack.getItem().isFood()) {
                return i;
            }
        }
        return -1;
    }

    private void startEating(int foodSlot) {
        isEating = true;
        if (!hasFoodInHands()) {
            if (foodSlot == -1) {
                isEating = false;
                return;
            }
            previousSlot = mc.player.inventory.currentItem;
            mc.player.inventory.currentItem = foodSlot;
        }
        continueEating();
    }

    private void continueEating() {
        if (mc.currentScreen == null) {
            mc.gameSettings.keyBindUseItem.setPressed(true);
        }
        if (mc.player.getFoodStats().getFoodLevel() >= EAT_THRESHOLD || !hasFoodInHands()) {
            stopEating();
        }
    }

    private void stopEating() {
        mc.gameSettings.keyBindUseItem.setPressed(false);
        isEating = false;
        if (previousSlot != -1 && mc.player != null) {
            mc.player.inventory.currentItem = previousSlot;
            previousSlot = -1;
        }
    }

    // ===== АНТИ-ЗАСТРЕВАНИЕ (ломаем блок перед собой при удушье) =====
    private boolean handleSuffocationUnstuck() {
        if (mc.player == null || mc.world == null) return false;
        boolean inside = mc.player.isEntityInsideOpaqueBlock();
        if (!inside) {
            // Не душимся — сброс состояния
            if (isUnstucking) {
                try {
                    mc.gameSettings.keyBindAttack.setPressed(false);
                    mc.playerController.resetBlockRemoving();
                } catch (Throwable ignored) {}
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
            return false;
        }

        // Отменяем майнинг, чтобы не мешал разлому
        if (mineProcess != null && mineProcess.isActive()) {
            mineProcess.cancel();
        }

        // Находим блок перед взглядом игрока (до 2 блока)
        RayTraceResult rt = RaytraceUtility.rayTrace(2.5, mc.player.rotationYaw, mc.player.rotationPitch, mc.player);
        net.minecraft.util.math.BlockPos targetPos = null;
        Direction face = Direction.UP;
        if (rt != null && rt.getType() == RayTraceResult.Type.BLOCK && rt instanceof BlockRayTraceResult brt) {
            targetPos = brt.getPos();
            face = brt.getFace();
        }
        if (targetPos == null) {
            // fallback: блок на уровне глаз
            targetPos = new net.minecraft.util.math.BlockPos(mc.player.getEyePosition(1.0f));
            face = Direction.UP;
        }

        if (mc.world.isAirBlock(targetPos)) {
            // если перед нами воздух, пробуем блок в ногах
            targetPos = mc.player.getPosition();
        }

        if (!mc.world.isAirBlock(targetPos)) {
            try {
                // Начинаем ломать и продолжаем до разрушения
                if (unstuckBreakingPos == null || !unstuckBreakingPos.equals(targetPos)) {
                    mc.playerController.syncCurrentPlayItem();
                    mc.playerController.clickBlock(targetPos, face);
                    unstuckBreakingPos = targetPos;
                }
                mc.playerController.onPlayerDamageBlock(targetPos, face);
                mc.player.swingArm(Hand.MAIN_HAND);
                mc.gameSettings.keyBindAttack.setPressed(true);
                isUnstucking = true;
            } catch (Throwable ignored) {}
        }
        return true;
    }
}

жду сообщение "cursor", ps это другая нейронка
да что блять приисходит когда югейм стал полезным?
  • Теги #essence
  • ну зенит рекод мейби?
 
Всем привет, моя вторая тема в кратце ходит по анкам добывает на шахтe что выберешь. !нужен баритон!
Java:
Expand Collapse Copy
import beame.components.baritone.api.BaritoneAPI;
import beame.components.baritone.api.IBaritone;
import beame.components.baritone.api.process.IMineProcess;
import beame.module.Category;
import beame.module.Module;
import beame.setting.SettingList.BooleanSetting;
import beame.setting.SettingList.EnumSetting;
import events.Event;
import events.impl.player.EventUpdate;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.item.PickaxeItem;
import net.minecraft.util.math.BlockPos;
import beame.util.math.TimerUtil;
import beame.components.baritone.api.pathing.goals.GoalXZ;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.inventory.container.ClickType;
import beame.components.baritone.api.pathing.path.IPathExecutor;
import beame.components.baritone.api.pathing.movement.IMovement;
import beame.components.baritone.pathing.movement.movements.MovementPillar;
import beame.util.math.RaytraceUtility;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.lang.reflect.Field;

public class AutoMiner extends Module {
    // Выбор руд для добычи
    private final EnumSetting ores = new EnumSetting("Добывать",
            new BooleanSetting("Алмазная руда", true),
            new BooleanSetting("Железная руда", false),
            new BooleanSetting("Золотая руда", false),
            new BooleanSetting("Угольная руда", false)
    );

    private IMineProcess mineProcess;
    private static final int DEFAULT_RADIUS = 30;
    private static final int EAT_THRESHOLD = 18;
    private boolean isEating = false;
    private int previousSlot = -1;
    // Sequence after finishing mining
    private final String[] AN_COMMANDS = new String[]{
            "/an217", "/an218", "/an216", "/an313", "/an312", "/an308", "/an309",
            "/an211", "/an115", "/an602", "/an505", "/an311", "/an312", "/an104",
            "/an212", "/an213", "/an503", "/an504", "/an507", "/an506"
    };
    private int anIndex = 0;
    private boolean chainInProgress = false;
    private int chainStage = 0; // 0 idle, 1 wait 5s after /an, 2 wait 12s after /warp, 3 moving forward
    private final TimerUtil chainTimer = new TimerUtil();
    private boolean prevMineActive = false;
    private static final double PICKAXE_MIN_PCT = 0.20; // 20%
    private boolean haltedFromHub = false;
    private boolean isUnstucking = false;
    private BlockPos unstuckBreakingPos = null;
    private final TimerUtil unstuckTimer = new TimerUtil();
    // Save and override Baritone render settings to hide path/boxes while AutoMiner works
    private Boolean prevRenderPath = null;
    // ===== ЗАСТРЕВАНИЕ ПО КООРДИНАТАМ (5 сек на одном месте) =====
    private BlockPos lastStuckCheckPos = null;
    private final TimerUtil stuckTimer = new TimerUtil();


    public AutoMiner() {
        super("FTNuker", Category.Misc, true, "Автоматически ходит и добывает выбранные руды");
        addSettings(ores);
    }

    @Override
    protected boolean onEnable() {
        IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
        if (baritone == null) return false;
        mineProcess = baritone.getMineProcess();
        haltedFromHub = false;
        prevMineActive = false;

        // Hide Baritone path/goal/selection boxes while AutoMiner is active
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath == null) prevRenderPath = settings.renderPath.value;
            settings.renderPath.value = false;
        } catch (Throwable ignored) {}

       

        List<Block> targets = new ArrayList<>();
        if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
        if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
        if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
        if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

        if (targets.isEmpty()) {
            // Нет выбранных блоков — не запускаем майнинг, модуль остаётся включён
            return true;
        }

        // Запуск майнинга выбранных блоков, без ограничения по количеству
        mineProcess.mine(targets.toArray(new Block[0]));
        // Сразу ограничим цели радиусом, чтобы старт происходил в рамках DEFAULT_RADIUS
        filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
        return true;
    }

    @Override
    protected void onDisable() {
        if (mineProcess != null) {
            mineProcess.cancel();
        }
        // Restore Baritone rendering settings
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath != null) {
                settings.renderPath.value = prevRenderPath;
                prevRenderPath = null;
            }
        } catch (Throwable ignored) {}
       
        // Сброс клика атаки на случай, если держим для разлома блока
        try {
            mc.gameSettings.keyBindAttack.setPressed(false);
            if (isUnstucking) {
                mc.playerController.resetBlockRemoving();
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
        } catch (Throwable ignored) {}
    }

    // Возвращает true, если выполнили действие (заменили кирку или ушли на /hub)
    private boolean ensurePickaxeDurabilityOrHub() {
        ItemStack main = mc.player.getHeldItemMainhand();
        boolean hasPickaxeInHand = main != null && main.getItem() instanceof PickaxeItem;
        if (hasPickaxeInHand) {
            double pct = remainingPct(main);
            if (pct <= PICKAXE_MIN_PCT) {
                // Найти лучшую кирку с >20%
                int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
                if (best != -1) {
                    switchToSlot(best);
                    return true; // заменили
                } else {
                    // Все кирки <=20% (или нет кирок) — уходим в /hub и стоп
                    mc.player.sendChatMessage("/hub");
                    haltedFromHub = true;
                    return true;
                }
            }
        } else {
            // В руке не кирка: попробуем взять подходящую кирку >20%, если есть
            int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
            if (best != -1) {
                switchToSlot(best);
                return true;
            }
            // Нет подходящей кирки >20% — уходим в /hub и стоп
            mc.player.sendChatMessage("/hub");
            haltedFromHub = true;
            return true;
        }
        return false;
    }

    private int findBestPickaxeSlotAboveThreshold(double minPct) {
        int bestSlot = -1;
        double bestPct = -1.0;
        // Проверяем хотбар 0..8 и инвентарь 9..35
        for (int i = 0; i < 36; i++) {
            ItemStack s = mc.player.inventory.getStackInSlot(i);
            if (s == null || s.isEmpty() || !(s.getItem() instanceof PickaxeItem)) continue;
            double pct = remainingPct(s);
            if (pct > minPct && pct > bestPct) {
                bestPct = pct;
                bestSlot = i;
            }
        }
        return bestSlot;
    }

    private double remainingPct(ItemStack stack) {
        int max = stack.getMaxDamage();
        if (max <= 0) return 1.0; // небьющийся предмет
        int used = stack.getDamage();
        int remaining = Math.max(0, max - used);
        return (double) remaining / (double) max;
    }

    private void switchToSlot(int invIndex) {
        if (invIndex < 0 || invIndex >= 36) return;
        int currentHotbar = mc.player.inventory.currentItem; // 0..8
        if (invIndex <= 8) {
            // Уже в хотбаре
            if (currentHotbar != invIndex) {
                mc.player.inventory.currentItem = invIndex;
            }
        } else {
            // В инвентаре: свапаем с текущим хотбар слотом
            int containerSlot = invIndex; // 9..35
            int windowId = mc.player.openContainer.windowId;
            mc.playerController.windowClick(windowId, containerSlot, currentHotbar, ClickType.SWAP, mc.player);
        }
    }

    @Override
    public void event(Event event) {
        if (event instanceof EventUpdate) {
            IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
            if (baritone == null || mc.player == null) return;
            if (haltedFromHub) return;

            // 1) Если голоден — остановиться, поесть, затем продолжить
            boolean hungry = mc.player.getFoodStats().getFoodLevel() < EAT_THRESHOLD;
            if (hungry) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                // Важно: не запускать /an после отмены майнинга из-за еды
                // Сбросим prevMineActive, чтобы не сработало условие prevMineActive && !currentMineActive
                prevMineActive = false;
                if (!isEating) {
                    int foodSlot = findFoodHotbarSlot();
                    if (foodSlot != -1 || hasFoodInHands()) {
                        startEating(foodSlot);
                    }
                } else {
                    continueEating();
                }
                return;
            } else if (isEating) {
                stopEating();
            }

            // 1b) Проверка прочности кирки и замена / выход в /hub
            if (ensurePickaxeDurabilityOrHub()) {
                // либо заменили кирку, либо ушли на /hub и остановились
                if (haltedFromHub) {
                    if (mineProcess != null && mineProcess.isActive()) mineProcess.cancel();
                    chainInProgress = false;
                    return;
                }
                // если была замена инструмента, продолжаем дальше
            }

            // 1c) Если застряли/душимся в блоках — ломаем блок перед собой и ничего больше не делаем в этот тик
            if (handleSuffocationUnstuck()) {
                prevMineActive = mineProcess != null && mineProcess.isActive();
                return;
            }

            // 2) Если есть выбранные руды — майним, иначе стоим
            List<Block> targets = new ArrayList<>();
            if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
            if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
            if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
            if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

            boolean currentMineActive = mineProcess != null && mineProcess.isActive();

            // 2a-Застревание: если 5 секунд на одних координатах во время майнинга — делаем /warp mine и идём вперёд
            {
                BlockPos cur = mc.player.getPosition();
                if (lastStuckCheckPos == null || !lastStuckCheckPos.equals(cur)) {
                    lastStuckCheckPos = cur;
                    stuckTimer.reset();
                } else if (currentMineActive && !chainInProgress && !isEating) {
                    if (stuckTimer.finished(5000)) {
                        if (mineProcess != null && mineProcess.isActive()) {
                            mineProcess.cancel();
                        }
                        mc.player.sendChatMessage("/warp mine");
                        chainInProgress = true;
                        chainStage = 21; // ждать ~10с, затем идти вперёд на 9 блоков
                        chainTimer.reset();
                        prevMineActive = currentMineActive;
                        return;
                    }
                }
            }

            // 2a0) Если баритон пытается строиться вверх (пиллар) к руде — вместо этого выполняем warp-сценарий
            if (!chainInProgress && !isEating) {
                try {
                    IPathExecutor exec = baritone.getPathingBehavior().getCurrent();
                    if (exec != null && exec.getPath() != null && exec.getPath().movements() != null && !exec.getPath().movements().isEmpty()) {
                        int idx = Math.min(Math.max(exec.getPosition(), 0), exec.getPath().movements().size() - 1);
                        IMovement mv = exec.getPath().movements().get(idx);
                        if (mv instanceof MovementPillar) {
                            if (mineProcess != null && mineProcess.isActive()) {
                                mineProcess.cancel();
                            }
                            mc.player.sendChatMessage("/warp mine");
                            chainInProgress = true;
                            chainStage = 21; // ждать 10 секунд, затем идти вперёд на 9 блоков
                            chainTimer.reset();
                            prevMineActive = currentMineActive;
                            return;
                        }
                    }
                } catch (Throwable ignored) {}
            }

            // 2a) Обработка последовательности после завершения майнинга И/ИЛИ warp-сценариев
            if (chainInProgress) {
                // Выполняем этапы: 1) ждать 5с => /warp mine; 2) ждать 12с => пройти вперёд 5 блоков; 3) дождаться завершения движения
                switch (chainStage) {
                    case 1 -> {
                        if (chainTimer.finished(5000)) {
                            mc.player.sendChatMessage("/warp mine");
                            chainStage = 2;
                            chainTimer.reset();
                        }
                    }
                    case 2 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 3;
                        }
                    }
                    case 3 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            // Движение завершено, завершаем цепочку, далее общий код перезапустит майнинг
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                    case 21 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 22;
                        }
                    }
                    case 22 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                }
                // Поддерживаем ограничение радиуса, даже пока идёт цепочка
                filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
                prevMineActive = currentMineActive;
                return; // Не перезапускаем майнинг, пока идёт цепочка
            }

            if (targets.isEmpty()) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                prevMineActive = currentMineActive;
                return;
            }

            // 2b) Детектируем окончание майнинга и запускаем цепочку команд
            if (prevMineActive && !currentMineActive && !isEating) {
                // Завершён майнинг: отправляем следующий /an и запускаем таймер на 5 секунд
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1;
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // 2c) Если процесс не активен и нет цепочки — перезапускаем майнинг
            if (mineProcess != null && !currentMineActive && !chainInProgress) {
                mineProcess.mine(targets.toArray(new Block[0]));
            }

            // 3) Ограничение целей радиусом
            filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);

            // 3a) Если в радиусе нет выбранной руды — запустить цепочку /an -> /warp mine -> идти вперёд
            if (!chainInProgress && !isEating && currentMineActive && noTargetsInRadius(baritone)) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1; // ждать 5 секунд, затем /warp mine
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // Обновляем предыдущее состояние активности майнинга
            prevMineActive = currentMineActive;
        }
    }

    private void filterTargetsWithinRadius(IBaritone baritone, int radius) {
        if (baritone == null || mc.player == null) return;
        if (mineProcess == null) return;
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            if (locs == null || locs.isEmpty()) return;

            BlockPos playerPos = mc.player.getPosition();
            double maxSq = (double) radius * (double) radius;
            List<BlockPos> filtered = locs.stream()
                    .filter(p -> p != null && playerPos.distanceSq(p) <= maxSq)
                    .collect(Collectors.toCollection(ArrayList::new));

            // Replace with a new list to avoid concurrent modification
            fKnown.set(impl, filtered);
        } catch (Throwable ignored) {
            // fail silently to avoid crashing if internals change
        }
    }

    private boolean noTargetsInRadius(IBaritone baritone) {
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return true;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            return locs == null || locs.isEmpty();
        } catch (Throwable ignored) {
            return false;
        }
    }

    // ===== ЕДА =====
    private boolean hasFoodInHands() {
        if (mc.player == null) return false;
        ItemStack main = mc.player.getHeldItemMainhand();
        ItemStack off = mc.player.getHeldItemOffhand();
        return (!main.isEmpty() && main.getItem().isFood()) || (!off.isEmpty() && off.getItem().isFood());
    }

    private int findFoodHotbarSlot() {
        if (mc.player == null) return -1;
        for (int i = 0; i < 9; i++) {
            ItemStack stack = mc.player.inventory.getStackInSlot(i);
            if (!stack.isEmpty() && stack.getItem().isFood()) {
                return i;
            }
        }
        return -1;
    }

    private void startEating(int foodSlot) {
        isEating = true;
        if (!hasFoodInHands()) {
            if (foodSlot == -1) {
                isEating = false;
                return;
            }
            previousSlot = mc.player.inventory.currentItem;
            mc.player.inventory.currentItem = foodSlot;
        }
        continueEating();
    }

    private void continueEating() {
        if (mc.currentScreen == null) {
            mc.gameSettings.keyBindUseItem.setPressed(true);
        }
        if (mc.player.getFoodStats().getFoodLevel() >= EAT_THRESHOLD || !hasFoodInHands()) {
            stopEating();
        }
    }

    private void stopEating() {
        mc.gameSettings.keyBindUseItem.setPressed(false);
        isEating = false;
        if (previousSlot != -1 && mc.player != null) {
            mc.player.inventory.currentItem = previousSlot;
            previousSlot = -1;
        }
    }

    // ===== АНТИ-ЗАСТРЕВАНИЕ (ломаем блок перед собой при удушье) =====
    private boolean handleSuffocationUnstuck() {
        if (mc.player == null || mc.world == null) return false;
        boolean inside = mc.player.isEntityInsideOpaqueBlock();
        if (!inside) {
            // Не душимся — сброс состояния
            if (isUnstucking) {
                try {
                    mc.gameSettings.keyBindAttack.setPressed(false);
                    mc.playerController.resetBlockRemoving();
                } catch (Throwable ignored) {}
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
            return false;
        }

        // Отменяем майнинг, чтобы не мешал разлому
        if (mineProcess != null && mineProcess.isActive()) {
            mineProcess.cancel();
        }

        // Находим блок перед взглядом игрока (до 2 блока)
        RayTraceResult rt = RaytraceUtility.rayTrace(2.5, mc.player.rotationYaw, mc.player.rotationPitch, mc.player);
        net.minecraft.util.math.BlockPos targetPos = null;
        Direction face = Direction.UP;
        if (rt != null && rt.getType() == RayTraceResult.Type.BLOCK && rt instanceof BlockRayTraceResult brt) {
            targetPos = brt.getPos();
            face = brt.getFace();
        }
        if (targetPos == null) {
            // fallback: блок на уровне глаз
            targetPos = new net.minecraft.util.math.BlockPos(mc.player.getEyePosition(1.0f));
            face = Direction.UP;
        }

        if (mc.world.isAirBlock(targetPos)) {
            // если перед нами воздух, пробуем блок в ногах
            targetPos = mc.player.getPosition();
        }

        if (!mc.world.isAirBlock(targetPos)) {
            try {
                // Начинаем ломать и продолжаем до разрушения
                if (unstuckBreakingPos == null || !unstuckBreakingPos.equals(targetPos)) {
                    mc.playerController.syncCurrentPlayItem();
                    mc.playerController.clickBlock(targetPos, face);
                    unstuckBreakingPos = targetPos;
                }
                mc.playerController.onPlayerDamageBlock(targetPos, face);
                mc.player.swingArm(Hand.MAIN_HAND);
                mc.gameSettings.keyBindAttack.setPressed(true);
                isUnstucking = true;
            } catch (Throwable ignored) {}
        }
        return true;
    }
}

жду сообщение "cursor", ps это другая нейронка
и нахуй это, фулл гпт работа где даже "разраб" не удосужелся коменты убрать, 500 строк вайбкода
 
а что ты полезного сделал и выложил?
а что ты сделал такого? я хотябы даю ответ, и бо данный автор этого треда не смог нормально иишке описать че да как, да и сам посмотри на данную гптшную залупу) А ты меня спрашиваешь еще "А что ты полезного сделал и выложил?" Чувак, тебе какое дело?) Если тебе нравится как в данный тред заливают мусор сгенерированной хуйней. То ладно:roflanEbalo:
 
Всем привет, моя вторая тема в кратце ходит по анкам добывает на шахтe что выберешь. !нужен баритон!
Java:
Expand Collapse Copy
import beame.components.baritone.api.BaritoneAPI;
import beame.components.baritone.api.IBaritone;
import beame.components.baritone.api.process.IMineProcess;
import beame.module.Category;
import beame.module.Module;
import beame.setting.SettingList.BooleanSetting;
import beame.setting.SettingList.EnumSetting;
import events.Event;
import events.impl.player.EventUpdate;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.item.PickaxeItem;
import net.minecraft.util.math.BlockPos;
import beame.util.math.TimerUtil;
import beame.components.baritone.api.pathing.goals.GoalXZ;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.inventory.container.ClickType;
import beame.components.baritone.api.pathing.path.IPathExecutor;
import beame.components.baritone.api.pathing.movement.IMovement;
import beame.components.baritone.pathing.movement.movements.MovementPillar;
import beame.util.math.RaytraceUtility;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.lang.reflect.Field;

public class AutoMiner extends Module {
    // Выбор руд для добычи
    private final EnumSetting ores = new EnumSetting("Добывать",
            new BooleanSetting("Алмазная руда", true),
            new BooleanSetting("Железная руда", false),
            new BooleanSetting("Золотая руда", false),
            new BooleanSetting("Угольная руда", false)
    );

    private IMineProcess mineProcess;
    private static final int DEFAULT_RADIUS = 30;
    private static final int EAT_THRESHOLD = 18;
    private boolean isEating = false;
    private int previousSlot = -1;
    // Sequence after finishing mining
    private final String[] AN_COMMANDS = new String[]{
            "/an217", "/an218", "/an216", "/an313", "/an312", "/an308", "/an309",
            "/an211", "/an115", "/an602", "/an505", "/an311", "/an312", "/an104",
            "/an212", "/an213", "/an503", "/an504", "/an507", "/an506"
    };
    private int anIndex = 0;
    private boolean chainInProgress = false;
    private int chainStage = 0; // 0 idle, 1 wait 5s after /an, 2 wait 12s after /warp, 3 moving forward
    private final TimerUtil chainTimer = new TimerUtil();
    private boolean prevMineActive = false;
    private static final double PICKAXE_MIN_PCT = 0.20; // 20%
    private boolean haltedFromHub = false;
    private boolean isUnstucking = false;
    private BlockPos unstuckBreakingPos = null;
    private final TimerUtil unstuckTimer = new TimerUtil();
    // Save and override Baritone render settings to hide path/boxes while AutoMiner works
    private Boolean prevRenderPath = null;
    // ===== ЗАСТРЕВАНИЕ ПО КООРДИНАТАМ (5 сек на одном месте) =====
    private BlockPos lastStuckCheckPos = null;
    private final TimerUtil stuckTimer = new TimerUtil();


    public AutoMiner() {
        super("FTNuker", Category.Misc, true, "Автоматически ходит и добывает выбранные руды");
        addSettings(ores);
    }

    @Override
    protected boolean onEnable() {
        IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
        if (baritone == null) return false;
        mineProcess = baritone.getMineProcess();
        haltedFromHub = false;
        prevMineActive = false;

        // Hide Baritone path/goal/selection boxes while AutoMiner is active
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath == null) prevRenderPath = settings.renderPath.value;
            settings.renderPath.value = false;
        } catch (Throwable ignored) {}

       

        List<Block> targets = new ArrayList<>();
        if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
        if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
        if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
        if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

        if (targets.isEmpty()) {
            // Нет выбранных блоков — не запускаем майнинг, модуль остаётся включён
            return true;
        }

        // Запуск майнинга выбранных блоков, без ограничения по количеству
        mineProcess.mine(targets.toArray(new Block[0]));
        // Сразу ограничим цели радиусом, чтобы старт происходил в рамках DEFAULT_RADIUS
        filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
        return true;
    }

    @Override
    protected void onDisable() {
        if (mineProcess != null) {
            mineProcess.cancel();
        }
        // Restore Baritone rendering settings
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath != null) {
                settings.renderPath.value = prevRenderPath;
                prevRenderPath = null;
            }
        } catch (Throwable ignored) {}
       
        // Сброс клика атаки на случай, если держим для разлома блока
        try {
            mc.gameSettings.keyBindAttack.setPressed(false);
            if (isUnstucking) {
                mc.playerController.resetBlockRemoving();
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
        } catch (Throwable ignored) {}
    }

    // Возвращает true, если выполнили действие (заменили кирку или ушли на /hub)
    private boolean ensurePickaxeDurabilityOrHub() {
        ItemStack main = mc.player.getHeldItemMainhand();
        boolean hasPickaxeInHand = main != null && main.getItem() instanceof PickaxeItem;
        if (hasPickaxeInHand) {
            double pct = remainingPct(main);
            if (pct <= PICKAXE_MIN_PCT) {
                // Найти лучшую кирку с >20%
                int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
                if (best != -1) {
                    switchToSlot(best);
                    return true; // заменили
                } else {
                    // Все кирки <=20% (или нет кирок) — уходим в /hub и стоп
                    mc.player.sendChatMessage("/hub");
                    haltedFromHub = true;
                    return true;
                }
            }
        } else {
            // В руке не кирка: попробуем взять подходящую кирку >20%, если есть
            int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
            if (best != -1) {
                switchToSlot(best);
                return true;
            }
            // Нет подходящей кирки >20% — уходим в /hub и стоп
            mc.player.sendChatMessage("/hub");
            haltedFromHub = true;
            return true;
        }
        return false;
    }

    private int findBestPickaxeSlotAboveThreshold(double minPct) {
        int bestSlot = -1;
        double bestPct = -1.0;
        // Проверяем хотбар 0..8 и инвентарь 9..35
        for (int i = 0; i < 36; i++) {
            ItemStack s = mc.player.inventory.getStackInSlot(i);
            if (s == null || s.isEmpty() || !(s.getItem() instanceof PickaxeItem)) continue;
            double pct = remainingPct(s);
            if (pct > minPct && pct > bestPct) {
                bestPct = pct;
                bestSlot = i;
            }
        }
        return bestSlot;
    }

    private double remainingPct(ItemStack stack) {
        int max = stack.getMaxDamage();
        if (max <= 0) return 1.0; // небьющийся предмет
        int used = stack.getDamage();
        int remaining = Math.max(0, max - used);
        return (double) remaining / (double) max;
    }

    private void switchToSlot(int invIndex) {
        if (invIndex < 0 || invIndex >= 36) return;
        int currentHotbar = mc.player.inventory.currentItem; // 0..8
        if (invIndex <= 8) {
            // Уже в хотбаре
            if (currentHotbar != invIndex) {
                mc.player.inventory.currentItem = invIndex;
            }
        } else {
            // В инвентаре: свапаем с текущим хотбар слотом
            int containerSlot = invIndex; // 9..35
            int windowId = mc.player.openContainer.windowId;
            mc.playerController.windowClick(windowId, containerSlot, currentHotbar, ClickType.SWAP, mc.player);
        }
    }

    @Override
    public void event(Event event) {
        if (event instanceof EventUpdate) {
            IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
            if (baritone == null || mc.player == null) return;
            if (haltedFromHub) return;

            // 1) Если голоден — остановиться, поесть, затем продолжить
            boolean hungry = mc.player.getFoodStats().getFoodLevel() < EAT_THRESHOLD;
            if (hungry) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                // Важно: не запускать /an после отмены майнинга из-за еды
                // Сбросим prevMineActive, чтобы не сработало условие prevMineActive && !currentMineActive
                prevMineActive = false;
                if (!isEating) {
                    int foodSlot = findFoodHotbarSlot();
                    if (foodSlot != -1 || hasFoodInHands()) {
                        startEating(foodSlot);
                    }
                } else {
                    continueEating();
                }
                return;
            } else if (isEating) {
                stopEating();
            }

            // 1b) Проверка прочности кирки и замена / выход в /hub
            if (ensurePickaxeDurabilityOrHub()) {
                // либо заменили кирку, либо ушли на /hub и остановились
                if (haltedFromHub) {
                    if (mineProcess != null && mineProcess.isActive()) mineProcess.cancel();
                    chainInProgress = false;
                    return;
                }
                // если была замена инструмента, продолжаем дальше
            }

            // 1c) Если застряли/душимся в блоках — ломаем блок перед собой и ничего больше не делаем в этот тик
            if (handleSuffocationUnstuck()) {
                prevMineActive = mineProcess != null && mineProcess.isActive();
                return;
            }

            // 2) Если есть выбранные руды — майним, иначе стоим
            List<Block> targets = new ArrayList<>();
            if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
            if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
            if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
            if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

            boolean currentMineActive = mineProcess != null && mineProcess.isActive();

            // 2a-Застревание: если 5 секунд на одних координатах во время майнинга — делаем /warp mine и идём вперёд
            {
                BlockPos cur = mc.player.getPosition();
                if (lastStuckCheckPos == null || !lastStuckCheckPos.equals(cur)) {
                    lastStuckCheckPos = cur;
                    stuckTimer.reset();
                } else if (currentMineActive && !chainInProgress && !isEating) {
                    if (stuckTimer.finished(5000)) {
                        if (mineProcess != null && mineProcess.isActive()) {
                            mineProcess.cancel();
                        }
                        mc.player.sendChatMessage("/warp mine");
                        chainInProgress = true;
                        chainStage = 21; // ждать ~10с, затем идти вперёд на 9 блоков
                        chainTimer.reset();
                        prevMineActive = currentMineActive;
                        return;
                    }
                }
            }

            // 2a0) Если баритон пытается строиться вверх (пиллар) к руде — вместо этого выполняем warp-сценарий
            if (!chainInProgress && !isEating) {
                try {
                    IPathExecutor exec = baritone.getPathingBehavior().getCurrent();
                    if (exec != null && exec.getPath() != null && exec.getPath().movements() != null && !exec.getPath().movements().isEmpty()) {
                        int idx = Math.min(Math.max(exec.getPosition(), 0), exec.getPath().movements().size() - 1);
                        IMovement mv = exec.getPath().movements().get(idx);
                        if (mv instanceof MovementPillar) {
                            if (mineProcess != null && mineProcess.isActive()) {
                                mineProcess.cancel();
                            }
                            mc.player.sendChatMessage("/warp mine");
                            chainInProgress = true;
                            chainStage = 21; // ждать 10 секунд, затем идти вперёд на 9 блоков
                            chainTimer.reset();
                            prevMineActive = currentMineActive;
                            return;
                        }
                    }
                } catch (Throwable ignored) {}
            }

            // 2a) Обработка последовательности после завершения майнинга И/ИЛИ warp-сценариев
            if (chainInProgress) {
                // Выполняем этапы: 1) ждать 5с => /warp mine; 2) ждать 12с => пройти вперёд 5 блоков; 3) дождаться завершения движения
                switch (chainStage) {
                    case 1 -> {
                        if (chainTimer.finished(5000)) {
                            mc.player.sendChatMessage("/warp mine");
                            chainStage = 2;
                            chainTimer.reset();
                        }
                    }
                    case 2 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 3;
                        }
                    }
                    case 3 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            // Движение завершено, завершаем цепочку, далее общий код перезапустит майнинг
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                    case 21 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 22;
                        }
                    }
                    case 22 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                }
                // Поддерживаем ограничение радиуса, даже пока идёт цепочка
                filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
                prevMineActive = currentMineActive;
                return; // Не перезапускаем майнинг, пока идёт цепочка
            }

            if (targets.isEmpty()) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                prevMineActive = currentMineActive;
                return;
            }

            // 2b) Детектируем окончание майнинга и запускаем цепочку команд
            if (prevMineActive && !currentMineActive && !isEating) {
                // Завершён майнинг: отправляем следующий /an и запускаем таймер на 5 секунд
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1;
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // 2c) Если процесс не активен и нет цепочки — перезапускаем майнинг
            if (mineProcess != null && !currentMineActive && !chainInProgress) {
                mineProcess.mine(targets.toArray(new Block[0]));
            }

            // 3) Ограничение целей радиусом
            filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);

            // 3a) Если в радиусе нет выбранной руды — запустить цепочку /an -> /warp mine -> идти вперёд
            if (!chainInProgress && !isEating && currentMineActive && noTargetsInRadius(baritone)) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1; // ждать 5 секунд, затем /warp mine
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // Обновляем предыдущее состояние активности майнинга
            prevMineActive = currentMineActive;
        }
    }

    private void filterTargetsWithinRadius(IBaritone baritone, int radius) {
        if (baritone == null || mc.player == null) return;
        if (mineProcess == null) return;
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            if (locs == null || locs.isEmpty()) return;

            BlockPos playerPos = mc.player.getPosition();
            double maxSq = (double) radius * (double) radius;
            List<BlockPos> filtered = locs.stream()
                    .filter(p -> p != null && playerPos.distanceSq(p) <= maxSq)
                    .collect(Collectors.toCollection(ArrayList::new));

            // Replace with a new list to avoid concurrent modification
            fKnown.set(impl, filtered);
        } catch (Throwable ignored) {
            // fail silently to avoid crashing if internals change
        }
    }

    private boolean noTargetsInRadius(IBaritone baritone) {
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return true;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            return locs == null || locs.isEmpty();
        } catch (Throwable ignored) {
            return false;
        }
    }

    // ===== ЕДА =====
    private boolean hasFoodInHands() {
        if (mc.player == null) return false;
        ItemStack main = mc.player.getHeldItemMainhand();
        ItemStack off = mc.player.getHeldItemOffhand();
        return (!main.isEmpty() && main.getItem().isFood()) || (!off.isEmpty() && off.getItem().isFood());
    }

    private int findFoodHotbarSlot() {
        if (mc.player == null) return -1;
        for (int i = 0; i < 9; i++) {
            ItemStack stack = mc.player.inventory.getStackInSlot(i);
            if (!stack.isEmpty() && stack.getItem().isFood()) {
                return i;
            }
        }
        return -1;
    }

    private void startEating(int foodSlot) {
        isEating = true;
        if (!hasFoodInHands()) {
            if (foodSlot == -1) {
                isEating = false;
                return;
            }
            previousSlot = mc.player.inventory.currentItem;
            mc.player.inventory.currentItem = foodSlot;
        }
        continueEating();
    }

    private void continueEating() {
        if (mc.currentScreen == null) {
            mc.gameSettings.keyBindUseItem.setPressed(true);
        }
        if (mc.player.getFoodStats().getFoodLevel() >= EAT_THRESHOLD || !hasFoodInHands()) {
            stopEating();
        }
    }

    private void stopEating() {
        mc.gameSettings.keyBindUseItem.setPressed(false);
        isEating = false;
        if (previousSlot != -1 && mc.player != null) {
            mc.player.inventory.currentItem = previousSlot;
            previousSlot = -1;
        }
    }

    // ===== АНТИ-ЗАСТРЕВАНИЕ (ломаем блок перед собой при удушье) =====
    private boolean handleSuffocationUnstuck() {
        if (mc.player == null || mc.world == null) return false;
        boolean inside = mc.player.isEntityInsideOpaqueBlock();
        if (!inside) {
            // Не душимся — сброс состояния
            if (isUnstucking) {
                try {
                    mc.gameSettings.keyBindAttack.setPressed(false);
                    mc.playerController.resetBlockRemoving();
                } catch (Throwable ignored) {}
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
            return false;
        }

        // Отменяем майнинг, чтобы не мешал разлому
        if (mineProcess != null && mineProcess.isActive()) {
            mineProcess.cancel();
        }

        // Находим блок перед взглядом игрока (до 2 блока)
        RayTraceResult rt = RaytraceUtility.rayTrace(2.5, mc.player.rotationYaw, mc.player.rotationPitch, mc.player);
        net.minecraft.util.math.BlockPos targetPos = null;
        Direction face = Direction.UP;
        if (rt != null && rt.getType() == RayTraceResult.Type.BLOCK && rt instanceof BlockRayTraceResult brt) {
            targetPos = brt.getPos();
            face = brt.getFace();
        }
        if (targetPos == null) {
            // fallback: блок на уровне глаз
            targetPos = new net.minecraft.util.math.BlockPos(mc.player.getEyePosition(1.0f));
            face = Direction.UP;
        }

        if (mc.world.isAirBlock(targetPos)) {
            // если перед нами воздух, пробуем блок в ногах
            targetPos = mc.player.getPosition();
        }

        if (!mc.world.isAirBlock(targetPos)) {
            try {
                // Начинаем ломать и продолжаем до разрушения
                if (unstuckBreakingPos == null || !unstuckBreakingPos.equals(targetPos)) {
                    mc.playerController.syncCurrentPlayItem();
                    mc.playerController.clickBlock(targetPos, face);
                    unstuckBreakingPos = targetPos;
                }
                mc.playerController.onPlayerDamageBlock(targetPos, face);
                mc.player.swingArm(Hand.MAIN_HAND);
                mc.gameSettings.keyBindAttack.setPressed(true);
                isUnstucking = true;
            } catch (Throwable ignored) {}
        }
        return true;
    }
}

жду сообщение "cursor", ps это другая нейронка
и нахуя сливать гпт функцию?
 
красава, замусорил форум своей никчемной ии функцией, так держать!!
и что с этого? главное что бы оно норм работало и код был не самим дерьмовим. А так норм вроде
Просто для меня важно больше как работает сама функция, и работает ли она вообще. Я не хотел гнать сразу говорю.
 
"Если баритон пытается строиться вверх (пиллар) к руде — вместо этого выполняем warp-сценарий" - Че за бред? А запретить баритону строиться не судьба? Не просто так же там настройка есть..
 
Всем привет, моя вторая тема в кратце ходит по анкам добывает на шахтe что выберешь. !нужен баритон!
Java:
Expand Collapse Copy
import beame.components.baritone.api.BaritoneAPI;
import beame.components.baritone.api.IBaritone;
import beame.components.baritone.api.process.IMineProcess;
import beame.module.Category;
import beame.module.Module;
import beame.setting.SettingList.BooleanSetting;
import beame.setting.SettingList.EnumSetting;
import events.Event;
import events.impl.player.EventUpdate;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.item.PickaxeItem;
import net.minecraft.util.math.BlockPos;
import beame.util.math.TimerUtil;
import beame.components.baritone.api.pathing.goals.GoalXZ;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.inventory.container.ClickType;
import beame.components.baritone.api.pathing.path.IPathExecutor;
import beame.components.baritone.api.pathing.movement.IMovement;
import beame.components.baritone.pathing.movement.movements.MovementPillar;
import beame.util.math.RaytraceUtility;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.lang.reflect.Field;

public class AutoMiner extends Module {
    // Выбор руд для добычи
    private final EnumSetting ores = new EnumSetting("Добывать",
            new BooleanSetting("Алмазная руда", true),
            new BooleanSetting("Железная руда", false),
            new BooleanSetting("Золотая руда", false),
            new BooleanSetting("Угольная руда", false)
    );

    private IMineProcess mineProcess;
    private static final int DEFAULT_RADIUS = 30;
    private static final int EAT_THRESHOLD = 18;
    private boolean isEating = false;
    private int previousSlot = -1;
    // Sequence after finishing mining
    private final String[] AN_COMMANDS = new String[]{
            "/an217", "/an218", "/an216", "/an313", "/an312", "/an308", "/an309",
            "/an211", "/an115", "/an602", "/an505", "/an311", "/an312", "/an104",
            "/an212", "/an213", "/an503", "/an504", "/an507", "/an506"
    };
    private int anIndex = 0;
    private boolean chainInProgress = false;
    private int chainStage = 0; // 0 idle, 1 wait 5s after /an, 2 wait 12s after /warp, 3 moving forward
    private final TimerUtil chainTimer = new TimerUtil();
    private boolean prevMineActive = false;
    private static final double PICKAXE_MIN_PCT = 0.20; // 20%
    private boolean haltedFromHub = false;
    private boolean isUnstucking = false;
    private BlockPos unstuckBreakingPos = null;
    private final TimerUtil unstuckTimer = new TimerUtil();
    // Save and override Baritone render settings to hide path/boxes while AutoMiner works
    private Boolean prevRenderPath = null;
    // ===== ЗАСТРЕВАНИЕ ПО КООРДИНАТАМ (5 сек на одном месте) =====
    private BlockPos lastStuckCheckPos = null;
    private final TimerUtil stuckTimer = new TimerUtil();


    public AutoMiner() {
        super("FTNuker", Category.Misc, true, "Автоматически ходит и добывает выбранные руды");
        addSettings(ores);
    }

    @Override
    protected boolean onEnable() {
        IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
        if (baritone == null) return false;
        mineProcess = baritone.getMineProcess();
        haltedFromHub = false;
        prevMineActive = false;

        // Hide Baritone path/goal/selection boxes while AutoMiner is active
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath == null) prevRenderPath = settings.renderPath.value;
            settings.renderPath.value = false;
        } catch (Throwable ignored) {}

       

        List<Block> targets = new ArrayList<>();
        if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
        if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
        if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
        if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

        if (targets.isEmpty()) {
            // Нет выбранных блоков — не запускаем майнинг, модуль остаётся включён
            return true;
        }

        // Запуск майнинга выбранных блоков, без ограничения по количеству
        mineProcess.mine(targets.toArray(new Block[0]));
        // Сразу ограничим цели радиусом, чтобы старт происходил в рамках DEFAULT_RADIUS
        filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
        return true;
    }

    @Override
    protected void onDisable() {
        if (mineProcess != null) {
            mineProcess.cancel();
        }
        // Restore Baritone rendering settings
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath != null) {
                settings.renderPath.value = prevRenderPath;
                prevRenderPath = null;
            }
        } catch (Throwable ignored) {}
       
        // Сброс клика атаки на случай, если держим для разлома блока
        try {
            mc.gameSettings.keyBindAttack.setPressed(false);
            if (isUnstucking) {
                mc.playerController.resetBlockRemoving();
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
        } catch (Throwable ignored) {}
    }

    // Возвращает true, если выполнили действие (заменили кирку или ушли на /hub)
    private boolean ensurePickaxeDurabilityOrHub() {
        ItemStack main = mc.player.getHeldItemMainhand();
        boolean hasPickaxeInHand = main != null && main.getItem() instanceof PickaxeItem;
        if (hasPickaxeInHand) {
            double pct = remainingPct(main);
            if (pct <= PICKAXE_MIN_PCT) {
                // Найти лучшую кирку с >20%
                int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
                if (best != -1) {
                    switchToSlot(best);
                    return true; // заменили
                } else {
                    // Все кирки <=20% (или нет кирок) — уходим в /hub и стоп
                    mc.player.sendChatMessage("/hub");
                    haltedFromHub = true;
                    return true;
                }
            }
        } else {
            // В руке не кирка: попробуем взять подходящую кирку >20%, если есть
            int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
            if (best != -1) {
                switchToSlot(best);
                return true;
            }
            // Нет подходящей кирки >20% — уходим в /hub и стоп
            mc.player.sendChatMessage("/hub");
            haltedFromHub = true;
            return true;
        }
        return false;
    }

    private int findBestPickaxeSlotAboveThreshold(double minPct) {
        int bestSlot = -1;
        double bestPct = -1.0;
        // Проверяем хотбар 0..8 и инвентарь 9..35
        for (int i = 0; i < 36; i++) {
            ItemStack s = mc.player.inventory.getStackInSlot(i);
            if (s == null || s.isEmpty() || !(s.getItem() instanceof PickaxeItem)) continue;
            double pct = remainingPct(s);
            if (pct > minPct && pct > bestPct) {
                bestPct = pct;
                bestSlot = i;
            }
        }
        return bestSlot;
    }

    private double remainingPct(ItemStack stack) {
        int max = stack.getMaxDamage();
        if (max <= 0) return 1.0; // небьющийся предмет
        int used = stack.getDamage();
        int remaining = Math.max(0, max - used);
        return (double) remaining / (double) max;
    }

    private void switchToSlot(int invIndex) {
        if (invIndex < 0 || invIndex >= 36) return;
        int currentHotbar = mc.player.inventory.currentItem; // 0..8
        if (invIndex <= 8) {
            // Уже в хотбаре
            if (currentHotbar != invIndex) {
                mc.player.inventory.currentItem = invIndex;
            }
        } else {
            // В инвентаре: свапаем с текущим хотбар слотом
            int containerSlot = invIndex; // 9..35
            int windowId = mc.player.openContainer.windowId;
            mc.playerController.windowClick(windowId, containerSlot, currentHotbar, ClickType.SWAP, mc.player);
        }
    }

    @Override
    public void event(Event event) {
        if (event instanceof EventUpdate) {
            IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
            if (baritone == null || mc.player == null) return;
            if (haltedFromHub) return;

            // 1) Если голоден — остановиться, поесть, затем продолжить
            boolean hungry = mc.player.getFoodStats().getFoodLevel() < EAT_THRESHOLD;
            if (hungry) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                // Важно: не запускать /an после отмены майнинга из-за еды
                // Сбросим prevMineActive, чтобы не сработало условие prevMineActive && !currentMineActive
                prevMineActive = false;
                if (!isEating) {
                    int foodSlot = findFoodHotbarSlot();
                    if (foodSlot != -1 || hasFoodInHands()) {
                        startEating(foodSlot);
                    }
                } else {
                    continueEating();
                }
                return;
            } else if (isEating) {
                stopEating();
            }

            // 1b) Проверка прочности кирки и замена / выход в /hub
            if (ensurePickaxeDurabilityOrHub()) {
                // либо заменили кирку, либо ушли на /hub и остановились
                if (haltedFromHub) {
                    if (mineProcess != null && mineProcess.isActive()) mineProcess.cancel();
                    chainInProgress = false;
                    return;
                }
                // если была замена инструмента, продолжаем дальше
            }

            // 1c) Если застряли/душимся в блоках — ломаем блок перед собой и ничего больше не делаем в этот тик
            if (handleSuffocationUnstuck()) {
                prevMineActive = mineProcess != null && mineProcess.isActive();
                return;
            }

            // 2) Если есть выбранные руды — майним, иначе стоим
            List<Block> targets = new ArrayList<>();
            if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
            if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
            if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
            if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

            boolean currentMineActive = mineProcess != null && mineProcess.isActive();

            // 2a-Застревание: если 5 секунд на одних координатах во время майнинга — делаем /warp mine и идём вперёд
            {
                BlockPos cur = mc.player.getPosition();
                if (lastStuckCheckPos == null || !lastStuckCheckPos.equals(cur)) {
                    lastStuckCheckPos = cur;
                    stuckTimer.reset();
                } else if (currentMineActive && !chainInProgress && !isEating) {
                    if (stuckTimer.finished(5000)) {
                        if (mineProcess != null && mineProcess.isActive()) {
                            mineProcess.cancel();
                        }
                        mc.player.sendChatMessage("/warp mine");
                        chainInProgress = true;
                        chainStage = 21; // ждать ~10с, затем идти вперёд на 9 блоков
                        chainTimer.reset();
                        prevMineActive = currentMineActive;
                        return;
                    }
                }
            }

            // 2a0) Если баритон пытается строиться вверх (пиллар) к руде — вместо этого выполняем warp-сценарий
            if (!chainInProgress && !isEating) {
                try {
                    IPathExecutor exec = baritone.getPathingBehavior().getCurrent();
                    if (exec != null && exec.getPath() != null && exec.getPath().movements() != null && !exec.getPath().movements().isEmpty()) {
                        int idx = Math.min(Math.max(exec.getPosition(), 0), exec.getPath().movements().size() - 1);
                        IMovement mv = exec.getPath().movements().get(idx);
                        if (mv instanceof MovementPillar) {
                            if (mineProcess != null && mineProcess.isActive()) {
                                mineProcess.cancel();
                            }
                            mc.player.sendChatMessage("/warp mine");
                            chainInProgress = true;
                            chainStage = 21; // ждать 10 секунд, затем идти вперёд на 9 блоков
                            chainTimer.reset();
                            prevMineActive = currentMineActive;
                            return;
                        }
                    }
                } catch (Throwable ignored) {}
            }

            // 2a) Обработка последовательности после завершения майнинга И/ИЛИ warp-сценариев
            if (chainInProgress) {
                // Выполняем этапы: 1) ждать 5с => /warp mine; 2) ждать 12с => пройти вперёд 5 блоков; 3) дождаться завершения движения
                switch (chainStage) {
                    case 1 -> {
                        if (chainTimer.finished(5000)) {
                            mc.player.sendChatMessage("/warp mine");
                            chainStage = 2;
                            chainTimer.reset();
                        }
                    }
                    case 2 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 3;
                        }
                    }
                    case 3 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            // Движение завершено, завершаем цепочку, далее общий код перезапустит майнинг
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                    case 21 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 22;
                        }
                    }
                    case 22 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                }
                // Поддерживаем ограничение радиуса, даже пока идёт цепочка
                filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
                prevMineActive = currentMineActive;
                return; // Не перезапускаем майнинг, пока идёт цепочка
            }

            if (targets.isEmpty()) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                prevMineActive = currentMineActive;
                return;
            }

            // 2b) Детектируем окончание майнинга и запускаем цепочку команд
            if (prevMineActive && !currentMineActive && !isEating) {
                // Завершён майнинг: отправляем следующий /an и запускаем таймер на 5 секунд
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1;
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // 2c) Если процесс не активен и нет цепочки — перезапускаем майнинг
            if (mineProcess != null && !currentMineActive && !chainInProgress) {
                mineProcess.mine(targets.toArray(new Block[0]));
            }

            // 3) Ограничение целей радиусом
            filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);

            // 3a) Если в радиусе нет выбранной руды — запустить цепочку /an -> /warp mine -> идти вперёд
            if (!chainInProgress && !isEating && currentMineActive && noTargetsInRadius(baritone)) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1; // ждать 5 секунд, затем /warp mine
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // Обновляем предыдущее состояние активности майнинга
            prevMineActive = currentMineActive;
        }
    }

    private void filterTargetsWithinRadius(IBaritone baritone, int radius) {
        if (baritone == null || mc.player == null) return;
        if (mineProcess == null) return;
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            if (locs == null || locs.isEmpty()) return;

            BlockPos playerPos = mc.player.getPosition();
            double maxSq = (double) radius * (double) radius;
            List<BlockPos> filtered = locs.stream()
                    .filter(p -> p != null && playerPos.distanceSq(p) <= maxSq)
                    .collect(Collectors.toCollection(ArrayList::new));

            // Replace with a new list to avoid concurrent modification
            fKnown.set(impl, filtered);
        } catch (Throwable ignored) {
            // fail silently to avoid crashing if internals change
        }
    }

    private boolean noTargetsInRadius(IBaritone baritone) {
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return true;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            return locs == null || locs.isEmpty();
        } catch (Throwable ignored) {
            return false;
        }
    }

    // ===== ЕДА =====
    private boolean hasFoodInHands() {
        if (mc.player == null) return false;
        ItemStack main = mc.player.getHeldItemMainhand();
        ItemStack off = mc.player.getHeldItemOffhand();
        return (!main.isEmpty() && main.getItem().isFood()) || (!off.isEmpty() && off.getItem().isFood());
    }

    private int findFoodHotbarSlot() {
        if (mc.player == null) return -1;
        for (int i = 0; i < 9; i++) {
            ItemStack stack = mc.player.inventory.getStackInSlot(i);
            if (!stack.isEmpty() && stack.getItem().isFood()) {
                return i;
            }
        }
        return -1;
    }

    private void startEating(int foodSlot) {
        isEating = true;
        if (!hasFoodInHands()) {
            if (foodSlot == -1) {
                isEating = false;
                return;
            }
            previousSlot = mc.player.inventory.currentItem;
            mc.player.inventory.currentItem = foodSlot;
        }
        continueEating();
    }

    private void continueEating() {
        if (mc.currentScreen == null) {
            mc.gameSettings.keyBindUseItem.setPressed(true);
        }
        if (mc.player.getFoodStats().getFoodLevel() >= EAT_THRESHOLD || !hasFoodInHands()) {
            stopEating();
        }
    }

    private void stopEating() {
        mc.gameSettings.keyBindUseItem.setPressed(false);
        isEating = false;
        if (previousSlot != -1 && mc.player != null) {
            mc.player.inventory.currentItem = previousSlot;
            previousSlot = -1;
        }
    }

    // ===== АНТИ-ЗАСТРЕВАНИЕ (ломаем блок перед собой при удушье) =====
    private boolean handleSuffocationUnstuck() {
        if (mc.player == null || mc.world == null) return false;
        boolean inside = mc.player.isEntityInsideOpaqueBlock();
        if (!inside) {
            // Не душимся — сброс состояния
            if (isUnstucking) {
                try {
                    mc.gameSettings.keyBindAttack.setPressed(false);
                    mc.playerController.resetBlockRemoving();
                } catch (Throwable ignored) {}
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
            return false;
        }

        // Отменяем майнинг, чтобы не мешал разлому
        if (mineProcess != null && mineProcess.isActive()) {
            mineProcess.cancel();
        }

        // Находим блок перед взглядом игрока (до 2 блока)
        RayTraceResult rt = RaytraceUtility.rayTrace(2.5, mc.player.rotationYaw, mc.player.rotationPitch, mc.player);
        net.minecraft.util.math.BlockPos targetPos = null;
        Direction face = Direction.UP;
        if (rt != null && rt.getType() == RayTraceResult.Type.BLOCK && rt instanceof BlockRayTraceResult brt) {
            targetPos = brt.getPos();
            face = brt.getFace();
        }
        if (targetPos == null) {
            // fallback: блок на уровне глаз
            targetPos = new net.minecraft.util.math.BlockPos(mc.player.getEyePosition(1.0f));
            face = Direction.UP;
        }

        if (mc.world.isAirBlock(targetPos)) {
            // если перед нами воздух, пробуем блок в ногах
            targetPos = mc.player.getPosition();
        }

        if (!mc.world.isAirBlock(targetPos)) {
            try {
                // Начинаем ломать и продолжаем до разрушения
                if (unstuckBreakingPos == null || !unstuckBreakingPos.equals(targetPos)) {
                    mc.playerController.syncCurrentPlayItem();
                    mc.playerController.clickBlock(targetPos, face);
                    unstuckBreakingPos = targetPos;
                }
                mc.playerController.onPlayerDamageBlock(targetPos, face);
                mc.player.swingArm(Hand.MAIN_HAND);
                mc.gameSettings.keyBindAttack.setPressed(true);
                isUnstucking = true;
            } catch (Throwable ignored) {}
        }
        return true;
    }
}

жду сообщение "cursor", ps это другая нейронка
kiro windsurf antigravity cursor
 
Всем привет, моя вторая тема в кратце ходит по анкам добывает на шахтe что выберешь. !нужен баритон!
Java:
Expand Collapse Copy
import beame.components.baritone.api.BaritoneAPI;
import beame.components.baritone.api.IBaritone;
import beame.components.baritone.api.process.IMineProcess;
import beame.module.Category;
import beame.module.Module;
import beame.setting.SettingList.BooleanSetting;
import beame.setting.SettingList.EnumSetting;
import events.Event;
import events.impl.player.EventUpdate;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.item.PickaxeItem;
import net.minecraft.util.math.BlockPos;
import beame.util.math.TimerUtil;
import beame.components.baritone.api.pathing.goals.GoalXZ;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.inventory.container.ClickType;
import beame.components.baritone.api.pathing.path.IPathExecutor;
import beame.components.baritone.api.pathing.movement.IMovement;
import beame.components.baritone.pathing.movement.movements.MovementPillar;
import beame.util.math.RaytraceUtility;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.lang.reflect.Field;

public class AutoMiner extends Module {
    // Выбор руд для добычи
    private final EnumSetting ores = new EnumSetting("Добывать",
            new BooleanSetting("Алмазная руда", true),
            new BooleanSetting("Железная руда", false),
            new BooleanSetting("Золотая руда", false),
            new BooleanSetting("Угольная руда", false)
    );

    private IMineProcess mineProcess;
    private static final int DEFAULT_RADIUS = 30;
    private static final int EAT_THRESHOLD = 18;
    private boolean isEating = false;
    private int previousSlot = -1;
    // Sequence after finishing mining
    private final String[] AN_COMMANDS = new String[]{
            "/an217", "/an218", "/an216", "/an313", "/an312", "/an308", "/an309",
            "/an211", "/an115", "/an602", "/an505", "/an311", "/an312", "/an104",
            "/an212", "/an213", "/an503", "/an504", "/an507", "/an506"
    };
    private int anIndex = 0;
    private boolean chainInProgress = false;
    private int chainStage = 0; // 0 idle, 1 wait 5s after /an, 2 wait 12s after /warp, 3 moving forward
    private final TimerUtil chainTimer = new TimerUtil();
    private boolean prevMineActive = false;
    private static final double PICKAXE_MIN_PCT = 0.20; // 20%
    private boolean haltedFromHub = false;
    private boolean isUnstucking = false;
    private BlockPos unstuckBreakingPos = null;
    private final TimerUtil unstuckTimer = new TimerUtil();
    // Save and override Baritone render settings to hide path/boxes while AutoMiner works
    private Boolean prevRenderPath = null;
    // ===== ЗАСТРЕВАНИЕ ПО КООРДИНАТАМ (5 сек на одном месте) =====
    private BlockPos lastStuckCheckPos = null;
    private final TimerUtil stuckTimer = new TimerUtil();


    public AutoMiner() {
        super("FTNuker", Category.Misc, true, "Автоматически ходит и добывает выбранные руды");
        addSettings(ores);
    }

    @Override
    protected boolean onEnable() {
        IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
        if (baritone == null) return false;
        mineProcess = baritone.getMineProcess();
        haltedFromHub = false;
        prevMineActive = false;

        // Hide Baritone path/goal/selection boxes while AutoMiner is active
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath == null) prevRenderPath = settings.renderPath.value;
            settings.renderPath.value = false;
        } catch (Throwable ignored) {}

       

        List<Block> targets = new ArrayList<>();
        if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
        if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
        if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
        if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

        if (targets.isEmpty()) {
            // Нет выбранных блоков — не запускаем майнинг, модуль остаётся включён
            return true;
        }

        // Запуск майнинга выбранных блоков, без ограничения по количеству
        mineProcess.mine(targets.toArray(new Block[0]));
        // Сразу ограничим цели радиусом, чтобы старт происходил в рамках DEFAULT_RADIUS
        filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
        return true;
    }

    @Override
    protected void onDisable() {
        if (mineProcess != null) {
            mineProcess.cancel();
        }
        // Restore Baritone rendering settings
        try {
            var settings = BaritoneAPI.getSettings();
            if (prevRenderPath != null) {
                settings.renderPath.value = prevRenderPath;
                prevRenderPath = null;
            }
        } catch (Throwable ignored) {}
       
        // Сброс клика атаки на случай, если держим для разлома блока
        try {
            mc.gameSettings.keyBindAttack.setPressed(false);
            if (isUnstucking) {
                mc.playerController.resetBlockRemoving();
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
        } catch (Throwable ignored) {}
    }

    // Возвращает true, если выполнили действие (заменили кирку или ушли на /hub)
    private boolean ensurePickaxeDurabilityOrHub() {
        ItemStack main = mc.player.getHeldItemMainhand();
        boolean hasPickaxeInHand = main != null && main.getItem() instanceof PickaxeItem;
        if (hasPickaxeInHand) {
            double pct = remainingPct(main);
            if (pct <= PICKAXE_MIN_PCT) {
                // Найти лучшую кирку с >20%
                int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
                if (best != -1) {
                    switchToSlot(best);
                    return true; // заменили
                } else {
                    // Все кирки <=20% (или нет кирок) — уходим в /hub и стоп
                    mc.player.sendChatMessage("/hub");
                    haltedFromHub = true;
                    return true;
                }
            }
        } else {
            // В руке не кирка: попробуем взять подходящую кирку >20%, если есть
            int best = findBestPickaxeSlotAboveThreshold(PICKAXE_MIN_PCT);
            if (best != -1) {
                switchToSlot(best);
                return true;
            }
            // Нет подходящей кирки >20% — уходим в /hub и стоп
            mc.player.sendChatMessage("/hub");
            haltedFromHub = true;
            return true;
        }
        return false;
    }

    private int findBestPickaxeSlotAboveThreshold(double minPct) {
        int bestSlot = -1;
        double bestPct = -1.0;
        // Проверяем хотбар 0..8 и инвентарь 9..35
        for (int i = 0; i < 36; i++) {
            ItemStack s = mc.player.inventory.getStackInSlot(i);
            if (s == null || s.isEmpty() || !(s.getItem() instanceof PickaxeItem)) continue;
            double pct = remainingPct(s);
            if (pct > minPct && pct > bestPct) {
                bestPct = pct;
                bestSlot = i;
            }
        }
        return bestSlot;
    }

    private double remainingPct(ItemStack stack) {
        int max = stack.getMaxDamage();
        if (max <= 0) return 1.0; // небьющийся предмет
        int used = stack.getDamage();
        int remaining = Math.max(0, max - used);
        return (double) remaining / (double) max;
    }

    private void switchToSlot(int invIndex) {
        if (invIndex < 0 || invIndex >= 36) return;
        int currentHotbar = mc.player.inventory.currentItem; // 0..8
        if (invIndex <= 8) {
            // Уже в хотбаре
            if (currentHotbar != invIndex) {
                mc.player.inventory.currentItem = invIndex;
            }
        } else {
            // В инвентаре: свапаем с текущим хотбар слотом
            int containerSlot = invIndex; // 9..35
            int windowId = mc.player.openContainer.windowId;
            mc.playerController.windowClick(windowId, containerSlot, currentHotbar, ClickType.SWAP, mc.player);
        }
    }

    @Override
    public void event(Event event) {
        if (event instanceof EventUpdate) {
            IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
            if (baritone == null || mc.player == null) return;
            if (haltedFromHub) return;

            // 1) Если голоден — остановиться, поесть, затем продолжить
            boolean hungry = mc.player.getFoodStats().getFoodLevel() < EAT_THRESHOLD;
            if (hungry) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                // Важно: не запускать /an после отмены майнинга из-за еды
                // Сбросим prevMineActive, чтобы не сработало условие prevMineActive && !currentMineActive
                prevMineActive = false;
                if (!isEating) {
                    int foodSlot = findFoodHotbarSlot();
                    if (foodSlot != -1 || hasFoodInHands()) {
                        startEating(foodSlot);
                    }
                } else {
                    continueEating();
                }
                return;
            } else if (isEating) {
                stopEating();
            }

            // 1b) Проверка прочности кирки и замена / выход в /hub
            if (ensurePickaxeDurabilityOrHub()) {
                // либо заменили кирку, либо ушли на /hub и остановились
                if (haltedFromHub) {
                    if (mineProcess != null && mineProcess.isActive()) mineProcess.cancel();
                    chainInProgress = false;
                    return;
                }
                // если была замена инструмента, продолжаем дальше
            }

            // 1c) Если застряли/душимся в блоках — ломаем блок перед собой и ничего больше не делаем в этот тик
            if (handleSuffocationUnstuck()) {
                prevMineActive = mineProcess != null && mineProcess.isActive();
                return;
            }

            // 2) Если есть выбранные руды — майним, иначе стоим
            List<Block> targets = new ArrayList<>();
            if (ores.get("Алмазная руда").get()) targets.add(Blocks.DIAMOND_ORE);
            if (ores.get("Железная руда").get()) targets.add(Blocks.IRON_ORE);
            if (ores.get("Золотая руда").get()) targets.add(Blocks.GOLD_ORE);
            if (ores.get("Угольная руда").get()) targets.add(Blocks.COAL_ORE);

            boolean currentMineActive = mineProcess != null && mineProcess.isActive();

            // 2a-Застревание: если 5 секунд на одних координатах во время майнинга — делаем /warp mine и идём вперёд
            {
                BlockPos cur = mc.player.getPosition();
                if (lastStuckCheckPos == null || !lastStuckCheckPos.equals(cur)) {
                    lastStuckCheckPos = cur;
                    stuckTimer.reset();
                } else if (currentMineActive && !chainInProgress && !isEating) {
                    if (stuckTimer.finished(5000)) {
                        if (mineProcess != null && mineProcess.isActive()) {
                            mineProcess.cancel();
                        }
                        mc.player.sendChatMessage("/warp mine");
                        chainInProgress = true;
                        chainStage = 21; // ждать ~10с, затем идти вперёд на 9 блоков
                        chainTimer.reset();
                        prevMineActive = currentMineActive;
                        return;
                    }
                }
            }

            // 2a0) Если баритон пытается строиться вверх (пиллар) к руде — вместо этого выполняем warp-сценарий
            if (!chainInProgress && !isEating) {
                try {
                    IPathExecutor exec = baritone.getPathingBehavior().getCurrent();
                    if (exec != null && exec.getPath() != null && exec.getPath().movements() != null && !exec.getPath().movements().isEmpty()) {
                        int idx = Math.min(Math.max(exec.getPosition(), 0), exec.getPath().movements().size() - 1);
                        IMovement mv = exec.getPath().movements().get(idx);
                        if (mv instanceof MovementPillar) {
                            if (mineProcess != null && mineProcess.isActive()) {
                                mineProcess.cancel();
                            }
                            mc.player.sendChatMessage("/warp mine");
                            chainInProgress = true;
                            chainStage = 21; // ждать 10 секунд, затем идти вперёд на 9 блоков
                            chainTimer.reset();
                            prevMineActive = currentMineActive;
                            return;
                        }
                    }
                } catch (Throwable ignored) {}
            }

            // 2a) Обработка последовательности после завершения майнинга И/ИЛИ warp-сценариев
            if (chainInProgress) {
                // Выполняем этапы: 1) ждать 5с => /warp mine; 2) ждать 12с => пройти вперёд 5 блоков; 3) дождаться завершения движения
                switch (chainStage) {
                    case 1 -> {
                        if (chainTimer.finished(5000)) {
                            mc.player.sendChatMessage("/warp mine");
                            chainStage = 2;
                            chainTimer.reset();
                        }
                    }
                    case 2 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 3;
                        }
                    }
                    case 3 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            // Движение завершено, завершаем цепочку, далее общий код перезапустит майнинг
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                    case 21 -> {
                        if (chainTimer.finished(10000)) {
                            Vector3d origin = mc.player.getPositionVec();
                            float yaw = mc.player.rotationYaw;
                            baritone.getCustomGoalProcess().setGoalAndPath(GoalXZ.fromDirection(origin, yaw, 9.0));
                            chainStage = 22;
                        }
                    }
                    case 22 -> {
                        if (!baritone.getCustomGoalProcess().isActive()) {
                            chainInProgress = false;
                            chainStage = 0;
                        }
                    }
                }
                // Поддерживаем ограничение радиуса, даже пока идёт цепочка
                filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);
                prevMineActive = currentMineActive;
                return; // Не перезапускаем майнинг, пока идёт цепочка
            }

            if (targets.isEmpty()) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                prevMineActive = currentMineActive;
                return;
            }

            // 2b) Детектируем окончание майнинга и запускаем цепочку команд
            if (prevMineActive && !currentMineActive && !isEating) {
                // Завершён майнинг: отправляем следующий /an и запускаем таймер на 5 секунд
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1;
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // 2c) Если процесс не активен и нет цепочки — перезапускаем майнинг
            if (mineProcess != null && !currentMineActive && !chainInProgress) {
                mineProcess.mine(targets.toArray(new Block[0]));
            }

            // 3) Ограничение целей радиусом
            filterTargetsWithinRadius(baritone, DEFAULT_RADIUS);

            // 3a) Если в радиусе нет выбранной руды — запустить цепочку /an -> /warp mine -> идти вперёд
            if (!chainInProgress && !isEating && currentMineActive && noTargetsInRadius(baritone)) {
                if (mineProcess != null && mineProcess.isActive()) {
                    mineProcess.cancel();
                }
                String cmd = AN_COMMANDS[anIndex];
                anIndex = (anIndex + 1) % AN_COMMANDS.length;
                mc.player.sendChatMessage(cmd);
                chainInProgress = true;
                chainStage = 1; // ждать 5 секунд, затем /warp mine
                chainTimer.reset();
                prevMineActive = currentMineActive;
                return;
            }

            // Обновляем предыдущее состояние активности майнинга
            prevMineActive = currentMineActive;
        }
    }

    private void filterTargetsWithinRadius(IBaritone baritone, int radius) {
        if (baritone == null || mc.player == null) return;
        if (mineProcess == null) return;
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            if (locs == null || locs.isEmpty()) return;

            BlockPos playerPos = mc.player.getPosition();
            double maxSq = (double) radius * (double) radius;
            List<BlockPos> filtered = locs.stream()
                    .filter(p -> p != null && playerPos.distanceSq(p) <= maxSq)
                    .collect(Collectors.toCollection(ArrayList::new));

            // Replace with a new list to avoid concurrent modification
            fKnown.set(impl, filtered);
        } catch (Throwable ignored) {
            // fail silently to avoid crashing if internals change
        }
    }

    private boolean noTargetsInRadius(IBaritone baritone) {
        try {
            Object impl = baritone.getMineProcess();
            Field fKnown = impl.getClass().getDeclaredField("knownOreLocations");
            fKnown.setAccessible(true);
            Object val = fKnown.get(impl);
            if (!(val instanceof List)) return true;
            @SuppressWarnings("unchecked")
            List<BlockPos> locs = (List<BlockPos>) val;
            return locs == null || locs.isEmpty();
        } catch (Throwable ignored) {
            return false;
        }
    }

    // ===== ЕДА =====
    private boolean hasFoodInHands() {
        if (mc.player == null) return false;
        ItemStack main = mc.player.getHeldItemMainhand();
        ItemStack off = mc.player.getHeldItemOffhand();
        return (!main.isEmpty() && main.getItem().isFood()) || (!off.isEmpty() && off.getItem().isFood());
    }

    private int findFoodHotbarSlot() {
        if (mc.player == null) return -1;
        for (int i = 0; i < 9; i++) {
            ItemStack stack = mc.player.inventory.getStackInSlot(i);
            if (!stack.isEmpty() && stack.getItem().isFood()) {
                return i;
            }
        }
        return -1;
    }

    private void startEating(int foodSlot) {
        isEating = true;
        if (!hasFoodInHands()) {
            if (foodSlot == -1) {
                isEating = false;
                return;
            }
            previousSlot = mc.player.inventory.currentItem;
            mc.player.inventory.currentItem = foodSlot;
        }
        continueEating();
    }

    private void continueEating() {
        if (mc.currentScreen == null) {
            mc.gameSettings.keyBindUseItem.setPressed(true);
        }
        if (mc.player.getFoodStats().getFoodLevel() >= EAT_THRESHOLD || !hasFoodInHands()) {
            stopEating();
        }
    }

    private void stopEating() {
        mc.gameSettings.keyBindUseItem.setPressed(false);
        isEating = false;
        if (previousSlot != -1 && mc.player != null) {
            mc.player.inventory.currentItem = previousSlot;
            previousSlot = -1;
        }
    }

    // ===== АНТИ-ЗАСТРЕВАНИЕ (ломаем блок перед собой при удушье) =====
    private boolean handleSuffocationUnstuck() {
        if (mc.player == null || mc.world == null) return false;
        boolean inside = mc.player.isEntityInsideOpaqueBlock();
        if (!inside) {
            // Не душимся — сброс состояния
            if (isUnstucking) {
                try {
                    mc.gameSettings.keyBindAttack.setPressed(false);
                    mc.playerController.resetBlockRemoving();
                } catch (Throwable ignored) {}
                isUnstucking = false;
                unstuckBreakingPos = null;
            }
            return false;
        }

        // Отменяем майнинг, чтобы не мешал разлому
        if (mineProcess != null && mineProcess.isActive()) {
            mineProcess.cancel();
        }

        // Находим блок перед взглядом игрока (до 2 блока)
        RayTraceResult rt = RaytraceUtility.rayTrace(2.5, mc.player.rotationYaw, mc.player.rotationPitch, mc.player);
        net.minecraft.util.math.BlockPos targetPos = null;
        Direction face = Direction.UP;
        if (rt != null && rt.getType() == RayTraceResult.Type.BLOCK && rt instanceof BlockRayTraceResult brt) {
            targetPos = brt.getPos();
            face = brt.getFace();
        }
        if (targetPos == null) {
            // fallback: блок на уровне глаз
            targetPos = new net.minecraft.util.math.BlockPos(mc.player.getEyePosition(1.0f));
            face = Direction.UP;
        }

        if (mc.world.isAirBlock(targetPos)) {
            // если перед нами воздух, пробуем блок в ногах
            targetPos = mc.player.getPosition();
        }

        if (!mc.world.isAirBlock(targetPos)) {
            try {
                // Начинаем ломать и продолжаем до разрушения
                if (unstuckBreakingPos == null || !unstuckBreakingPos.equals(targetPos)) {
                    mc.playerController.syncCurrentPlayItem();
                    mc.playerController.clickBlock(targetPos, face);
                    unstuckBreakingPos = targetPos;
                }
                mc.playerController.onPlayerDamageBlock(targetPos, face);
                mc.player.swingArm(Hand.MAIN_HAND);
                mc.gameSettings.keyBindAttack.setPressed(true);
                isUnstucking = true;
            } catch (Throwable ignored) {}
        }
        return true;
    }
}

жду сообщение "cursor", ps это другая нейронка
Самый лучший гпт дипсик баритон
Самый лучший гпт дипсик баритон
Хотя не как по мне это SuperMegaUltraJopaDuperSuperMegaDeepSeekChatGptClaudeGrokUltraDuperJuperWindsurfVsCodeMegalodonUltaMortisaJuperShelisUltoiGptDeeepseekUltraJuper
 
kiro windsurf antigravity cursor
я писал что это не курсор курсор лимит токенов
Самый лучший гпт дипсик баритон

Хотя не как по мне это SuperMegaUltraJopaDuperSuperMegaDeepSeekChatGptClaudeGrokUltraDuperJuperWindsurfVsCodeMegalodonUltaMortisaJuperShelisUltoiGptDeeepseekUltraJuper
хах даже смешно дипсик такое написать бы не смог ну смогу бы только весь код красный и все багнуто работало
"Если баритон пытается строиться вверх (пиллар) к руде — вместо этого выполняем warp-сценарий" - Че за бред? А запретить баритону строиться не судьба? Не просто так же там настройка есть..
ну переделай под себя/
 
Назад
Сверху Снизу