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

Часть функционала Releon applefarm

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
26 Янв 2025
Сообщения
28
Реакции
0
Выберите загрузчик игры
  1. Fabric
applefarm.java:
Expand Collapse Copy
package l;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import l.cl;
import l.cm;
import l.BooleanSetting;
import l.ModeSetting;
import l.NumberSetting;
import l.Timer;
import l.RotationUtils; // assuming iy was RotationUtils based on gsdfjkh(slot) which is usually selectSlot
import l.EventUpdate;
import net.minecraft.class_1268;   // Hand
import net.minecraft.class_1269;   // ActionResult
import net.minecraft.EntityType;
import net.minecraft.ClientPlayerEntity;
import net.minecraft.class_1713;   // SlotActionType
import net.minecraft.class_1735;   // ItemStack
import net.minecraft.Item;
import net.minecraft.Items;
import net.minecraft.class_2246;   // Blocks
import net.minecraft.BlockState;
import net.minecraft.class_2350;   // Direction
import net.minecraft.class_239;    // HitResult
import net.minecraft.Vec3d;
import net.minecraft.BlockPos;
import net.minecraft.BlockTags;
import net.minecraft.KeyBinding;   // MathHelper or similar
import net.minecraft.class_3959;   // RaycastContext
import net.minecraft.class_3965;   // BlockHitResult

/**
 * AppleFarmModule - Автоматическая ферма яблок/дерева.
 * Умеет сажать саженцы, удобрять костной мукой и рубить дерево (сам или через Baritone).
 */
public class AppleFarmModule extends cl {
    
    private static final String LEAVES_TYPES = "oak_leaves spruce_leaves birch_leaves jungle_leaves acacia_leaves dark_oak_leaves cherry_leaves mangrove_leaves";
    private static final String LOG_TYPES = "oak_log spruce_log birch_log jungle_log acacia_log dark_oak_log cherry_log mangrove_log";

    // --- Настройки ---
    private final ModeSetting breakMode = new ModeSetting("Режим рубки", "Движок рубки дерева").setOptions("На месте", "Baritone").setSelected("На месте");
    private final BooleanSetting autoStop = new BooleanSetting("Авто-стоп", "Останавливать Baritone после рубки").setEnabled(true).setVisibility(() -> this.breakMode.isSelected("Baritone"));
    
    private final NumberSetting actionDelay = new NumberSetting("Задержка действий (мс)", "Задержка между основными действиями").setDefaultValue(1.0f).setRange(0, 500);
    private final NumberSetting commandDelay = new NumberSetting("Задержка команд (мс)", "Задержка между командами /mine").setDefaultValue(600.0f).setRange(0, 2000);
    private final NumberSetting breakTickDelay = new NumberSetting("Задержка ломания (мс)", "Задержка между ударами по блоку").setDefaultValue(1.0f).setRange(0, 250);
    private final NumberSetting toolSwitchDelay = new NumberSetting("Задержка смены инструмента (мс)", "Минимальное время между сменой топора").setDefaultValue(80.0f).setRange(0, 1000);
    
    private final NumberSetting scanRadius = new NumberSetting("Радиус сканирования", "Радиус поиска дерева").setDefaultValue(6.0f).setRange(1, 10);
    private final NumberSetting scanHeight = new NumberSetting("Высота сканирования", "Высота поиска дерева").setDefaultValue(20.0f).setRange(1, 40);
    private final NumberSetting maxFarmDistance = new NumberSetting("Макс. дистанция", "Максимальное удаление от точки фермы").setDefaultValue(5.0f).setRange(1, 12);
    private final NumberSetting reachDistance = new NumberSetting("Дистанция ломания", "Максимальная дистанция удара").setDefaultValue(5.5f).setRange(1, 6);
    
    private final NumberSetting rotationYawStep = new NumberSetting("Поворот Yaw", "Скорость поворота головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting rotationPitchStep = new NumberSetting("Поворот Pitch", "Скорость наклона головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting breakTolerance = new NumberSetting("Допуск ломания", "Точность наведения для рубки").setDefaultValue(20.0f).setRange(1, 45);
    private final NumberSetting interactTolerance = new NumberSetting("Допуск взаимодействия", "Точность наведения для посадки/удобрения").setDefaultValue(16.0f).setRange(1, 45);

    // --- Таймеры ---
    private final Timer actionTimer = new Timer();
    private final Timer commandTimer = new Timer();
    private final Timer notifyTimer = new Timer();
    private final Timer toolSwitchTimer = new Timer();
    private final Timer breakTimer = new Timer();

    // --- Состояние ---
    private BlockPos farmLocation;
    private BlockPos currentTargetBlock;
    private class_2350 targetBlockSide;
    private boolean isBaritoneMining;
    private boolean hasBaritone;

    public AppleFarmModule() {
        super("AppleFarm", "Apple Farm", Category.MISC);
        this.addSettings(
            this.breakMode, this.autoStop, this.actionDelay, this.commandDelay,
            this.breakTickDelay, this.toolSwitchDelay, this.scanRadius, this.scanHeight,
            this.maxFarmDistance, this.reachDistance, this.rotationYawStep,
            this.rotationPitchStep, this.breakTolerance, this.interactTolerance
        );
    }

    @Override
    public void onEnable() {
        super.onEnable();
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
        
        this.actionTimer.reset();
        this.commandTimer.setMs(this.commandDelay.getValue().longValue());
        this.notifyTimer.setMs(3000L);
        this.toolSwitchTimer.setMs(this.toolSwitchDelay.getValue().longValue());
        this.breakTimer.setMs(this.breakTickDelay.getValue().longValue());
        
        this.hasBaritone = this.detectBaritone();
        if (this.breakMode.isSelected("Baritone") && !this.hasBaritone) {
            this.sendClientMessage("Baritone не найден! Установите Baritone или используйте режим 'На месте'.");
            this.setEnabled(false);
            return;
        }

        this.farmLocation = this.getLookTargetBlock();
        if (this.farmLocation == null) {
            this.sendClientMessage("Не удалось определить точку фермы. Посмотрите на блок земли и включите модуль снова.");
            this.setEnabled(false);
            return;
        }

        if (this.breakMode.isSelected("Baritone")) {
            this.runBaritoneCommand("#set autoTool true");
            this.runBaritoneCommand("#set allowBreak true");
        }
        
        this.sendClientMessage("Ферма запущена на точке " + this.farmLocation.toString() + " в режиме " + this.breakMode.getSelected());
    }

    @Override
    public void onDisable() {
        super.onDisable();
        if (this.breakMode.isSelected("Baritone") && this.hasBaritone && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
        }
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
        this.farmLocation = null;
    }

    @EventHandler
    public void onUpdate(EventUpdate event) {
        if (mc.player == null || mc.world == null) return;

        if (this.farmLocation == null) {
            this.farmLocation = this.getLookTargetBlock();
            if (this.farmLocation == null) return;
        }

        // Проверка дистанции до фермы
        if (mc.player.squaredDistanceTo(this.farmLocation.toCenterPos()) > Math.pow(this.maxFarmDistance.getValue(), 2)) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Слишком далеко от точки фермы! Вернитесь назад.");
                this.notifyTimer.reset();
            }
            if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
                this.runBaritoneCommand("#stop");
                this.isBaritoneMining = false;
            }
            return;
        }

        // Если дерево выросло - рубим
        if (this.isTreeGrown()) {
            if (this.breakMode.isSelected("Baritone")) {
                this.updateBaritoneMining();
            }
            this.performManualChop();
            return;
        }

        // Дерева нет - сбрасываем состояние рубки
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
        
        if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
            this.isBaritoneMining = false;
        }

        if (!this.actionTimer.hasElapsed(this.actionDelay.getValue())) return;
        this.actionTimer.reset();

        // Проверяем посажен ли саженец
        if (!this.isSaplingPlanted()) {
            if (!this.tryPlantSapling()) {
                if (this.notifyTimer.hasElapsed(2500)) {
                    Item sapling = this.findSaplingInInventory();
                    if (sapling == Items.AIR) {
                        this.sendClientMessage("В инвентаре нет саженцев!");
                    } else {
                        this.sendClientMessage("Не удалось посадить саженец " + sapling.getName().getString());
                    }
                    this.notifyTimer.reset();
                }
            }
            return;
        }

        // Если саженец есть - удобряем
        if (!this.tryApplyBoneMeal()) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Нет костной муки, ждем естественного роста...");
                this.notifyTimer.reset();
            }
        }
    }

    private void updateBaritoneMining() {
        if (!this.commandTimer.hasElapsed(this.commandDelay.getValue())) return;
        
        String targets = this.anyLeavesNearby() ? LEAVES_TYPES : LOG_TYPES;
        this.runBaritoneCommand("#mine 1 " + targets);
        this.isBaritoneMining = true;
        this.commandTimer.reset();
    }

    private void performManualChop() {
        if (!this.breakTimer.hasElapsed(this.breakTickDelay.getValue())) return;

        // Если текущая цель пропала или невалидна - ищем новую
        if (this.currentTargetBlock == null || !this.isValidChopTarget(this.currentTargetBlock)) {
            BlockInfo bestBlock = this.findBestBlockToChop();
            if (bestBlock == null) {
                this.currentTargetBlock = null;
                this.targetBlockSide = null;
                return;
            }
            this.currentTargetBlock = bestBlock.getPos();
            this.targetBlockSide = bestBlock.getSide();
        }

        if (this.currentTargetBlock == null || this.targetBlockSide == null) return;

        // Поворачиваемся и рубим
        if (!this.aimAtBlock(this.currentTargetBlock, this.targetBlockSide)) return;

        this.switchToBestTool(this.currentTargetBlock);
        mc.interactionManager.attackBlock(this.currentTargetBlock, this.targetBlockSide);
        mc.player.swingHand(class_1268.field_5808);
        this.breakTimer.reset();
    }

    private boolean tryPlantSapling() {
        Item sapling = this.findSaplingInInventory();
        if (sapling == Items.AIR) return false;

        if (mc.world.getBlockState(this.farmLocation).isIn(BlockTags.field_15462)) return true;
        if (!this.canPlantAt(this.farmLocation)) return false;

        BlockPos plantPos = this.farmLocation.up();
        class_3965 hit = new class_3965(plantPos.toCenterPos(), class_2350.field_11036, plantPos, false);
        
        return this.interactWithItem(sapling, hit);
    }

    private boolean tryApplyBoneMeal() {
        int oldSlot = mc.player.getInventory().selectedSlot;
        int mealSlot = this.getHotbarSlot(Items.BONE_MEAL);
        
        if (mealSlot == -1) {
            int invSlot = this.getInventorySlot(Items.BONE_MEAL);
            if (invSlot == -1) return false;
            
            int swapTo = this.findTrashHotbarSlot();
            if (swapTo == -1) return false;
            
            mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, invSlot, swapTo, class_1713.field_7791, (ClientPlayerEntity)mc.player);
            mealSlot = swapTo;
        }

        iy.gsdfjkh(mealSlot); // switchToSlot
        class_3965 hit = new class_3965(this.farmLocation.toCenterPos(), class_2350.field_11036, this.farmLocation, false);
        
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) {
            if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
            return false;
        }

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);
        
        if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private int findTrashHotbarSlot() {
        for (int i = 0; i < 9; ++i) {
            Item item = mc.player.getInventory().getStack(i).getItem();
            if (item == Items.field_8162) return i; // air
            if (this.isTool(item)) continue;
            return i;
        }
        return -1;
    }

    private boolean isTool(Item item) {
        return item == Items.field_8556 || item == Items.field_22025 || item == Items.field_8527
            || item == Items.field_22026 || item == Items.BONE_MEAL
            || item.getName().getString().contains("Axe") || item.getName().getString().contains("Pickaxe");
    }

    private int getInventorySlot(Item target) {
        for (int i = 9; i < 36; ++i) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private boolean interactWithItem(Item item, class_3965 hit) {
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) return false;
        
        int slot = this.getHotbarSlot(item);
        if (slot == -1) return false;

        int oldSlot = mc.player.getInventory().selectedSlot;
        if (oldSlot != slot) iy.gsdfjkh(slot);

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);

        if (oldSlot != slot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private boolean isTreeGrown() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    if (state.isIn(BlockTags.LOGS) || state.isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private boolean isSaplingPlanted() {
        return mc.world.getBlockState(this.farmLocation.up()).isIn(BlockTags.SAPLINGS);
    }

    private boolean canPlantAt(BlockPos pos) {
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isFullCube(mc.world, pos) && !state.isOf(class_2246.field_10219)) return false; // grass_block
        BlockPos up = pos.up();
        return mc.world.isAir(up) || mc.world.getBlockState(up).isOf(class_2246.field_10202); // tall_grass
    }

    private BlockPos getLookTargetBlock() {
        if (mc.crosshairTarget instanceof class_3965 hit && hit.getType() == class_239.Type.BLOCK) {
            BlockPos pos = hit.getBlockPos();
            if (this.canPlantAt(pos)) return pos;
            if (this.canPlantAt(pos.down())) return pos.down();
        }
        return null;
    }

    private Item findSaplingInInventory() {
        List<Item> types = List.of(Items.field_17535, Items.field_17536, Items.field_17537, Items.field_17538, Items.field_17539, Items.field_17540);
        for (int i = 0; i < 36; i++) {
            Item it = mc.player.getInventory().getStack(i).getItem();
            if (types.contains(it)) return it;
        }
        return Items.AIR;
    }

    private boolean isValidChopTarget(BlockPos pos) {
        if (pos == null) return false;
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isIn(BlockTags.LOGS) && !state.isIn(BlockTags.LEAVES)) return false;
        
        class_2350 side = this.getVisibleSide(pos);
        if (side == null) return false;
        
        this.targetBlockSide = side;
        return mc.player.squaredDistanceTo(pos.toCenterPos()) <= Math.pow(this.reachDistance.getValue(), 2);
    }

    private BlockInfo findBestBlockToChop() {
        List<BlockInfo> logs = new ArrayList<>();
        List<BlockInfo> leaves = new ArrayList<>();
        
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    double distSq = mc.player.squaredDistanceTo(pos.toCenterPos());
                    
                    if (distSq > Math.pow(this.reachDistance.getValue(), 2)) continue;
                    
                    class_2350 side = this.getVisibleSide(pos);
                    if (side == null) continue;

                    BlockInfo info = new BlockInfo(pos, side, distSq);
                    if (state.isIn(BlockTags.LOGS)) logs.add(info);
                    else if (state.isIn(BlockTags.LEAVES)) leaves.add(info);
                }
            }
        }
        
        Comparator<BlockInfo> byDist = Comparator.comparingDouble(BlockInfo::getDistSq);
        if (!leaves.isEmpty()) return leaves.stream().min(byDist).orElse(null);
        return logs.stream().min(byDist).orElse(null);
    }

    private boolean anyLeavesNearby() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    if (mc.world.getBlockState(this.farmLocation.add(x, y, z)).isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private class_2350 getVisibleSide(BlockPos pos) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d center = pos.toCenterPos();
        for (class_2350 side : class_2350.values()) {
            Vec3d point = center.add(new Vec3d(side.getOffsetX() * 0.49, side.getOffsetY() * 0.49, side.getOffsetZ() * 0.49));
            class_3965 hit = mc.world.raycast(new class_3959(eyes, point, class_3959.class_3960.field_17559, class_3959.class_242.field_1348, mc.player));
            if (hit != null && hit.getType() == class_239.Type.BLOCK && hit.getBlockPos().equals(pos)) return hit.getSide();
        }
        return null;
    }

    private boolean aimAtBlock(BlockPos pos, class_2350 side) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d hitVec = pos.toCenterPos().add(new Vec3d(side.getOffsetX() * 0.5, side.getOffsetY() * 0.5, side.getOffsetZ() * 0.5));
        return this.rotateAndCheckAim(hitVec, this.breakTolerance.getValue());
    }

    private boolean rotateAndCheckAim(Vec3d target, float tolerance) {
        Vec3d eyes = mc.player.getEyePos();
        double dx = target.x - eyes.x;
        double dy = target.y - eyes.y;
        double dz = target.z - eyes.z;
        double dist = Math.sqrt(dx * dx + dz * dz);
        
        float yaw = (float) (Math.toDegrees(Math.atan2(dz, dx)) - 90.0);
        float pitch = (float) (-Math.toDegrees(Math.atan2(dy, dist)));
        
        float currentYaw = mc.player.getYaw();
        float currentPitch = mc.player.getPitch();
        
        float diffYaw = RotationUtils.getAngleDiff(yaw, currentYaw);
        float diffPitch = RotationUtils.getAngleDiff(pitch, currentPitch);
        
        float stepYaw = this.rotationYawStep.getValue();
        float stepPitch = this.rotationPitchStep.getValue();
        
        float nextYaw = currentYaw + Math.max(-stepYaw, Math.min(stepYaw, diffYaw));
        float nextPitch = Math.max(-90.0f, Math.min(90.0f, currentPitch + Math.max(-stepPitch, Math.min(stepPitch, diffPitch))));

        mc.player.setYaw(nextYaw);
        mc.player.setPitch(nextPitch);
        mc.player.headYaw = nextYaw;
        mc.player.bodyYaw = nextYaw;

        return Math.abs(diffYaw) <= tolerance && Math.abs(diffPitch) <= tolerance;
    }

    private void switchToBestTool(BlockPos pos) {
        if (!this.toolSwitchTimer.hasElapsed(this.toolSwitchDelay.getValue())) return;
        
        BlockState state = mc.world.getBlockState(pos);
        int bestSlot = -1;
        float bestSpeed = 1.0f;
        
        for (int i = 0; i < 9; i++) {
            float speed = mc.player.getInventory().getStack(i).getMiningSpeedMultiplier(state);
            if (speed > bestSpeed) {
                bestSpeed = speed;
                bestSlot = i;
            }
        }
        
        if (bestSlot != -1 && bestSlot != mc.player.getInventory().selectedSlot) {
            iy.gsdfjkh(bestSlot);
            this.toolSwitchTimer.reset();
        }
    }

    private int getHotbarSlot(Item target) {
        for (int i = 0; i < 9; i++) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private void runBaritoneCommand(String cmd) {
        if (mc.player != null && mc.player.networkHandler != null) {
            mc.player.networkHandler.sendChatCommand(cmd.startsWith("/") ? cmd.substring(1) : cmd);
        }
    }

    private boolean detectBaritone() {
        try {
            Class.forName("baritone.api.BaritoneAPI");
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    // Вспомогательный класс для хранения данных о блоке
    private static class BlockInfo {
        private final BlockPos pos;
        private final class_2350 side;
        private final double distSq;

        public BlockInfo(BlockPos pos, class_2350 side, double distSq) {
            this.pos = pos;
            this.side = side;
            this.distSq = distSq;
        }
        public BlockPos getPos() { return pos; }
        public class_2350 getSide() { return side; }
        public double getDistSq() { return distSq; }
    }
}
деобфнул с ластовой версии релеона берите кому надо
сс не будет я хочу спать насчет работоспособности не знаю можете проверить
(деобф делал с ии)
 
applefarm.java:
Expand Collapse Copy
package l;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import l.cl;
import l.cm;
import l.BooleanSetting;
import l.ModeSetting;
import l.NumberSetting;
import l.Timer;
import l.RotationUtils; // assuming iy was RotationUtils based on gsdfjkh(slot) which is usually selectSlot
import l.EventUpdate;
import net.minecraft.class_1268;   // Hand
import net.minecraft.class_1269;   // ActionResult
import net.minecraft.EntityType;
import net.minecraft.ClientPlayerEntity;
import net.minecraft.class_1713;   // SlotActionType
import net.minecraft.class_1735;   // ItemStack
import net.minecraft.Item;
import net.minecraft.Items;
import net.minecraft.class_2246;   // Blocks
import net.minecraft.BlockState;
import net.minecraft.class_2350;   // Direction
import net.minecraft.class_239;    // HitResult
import net.minecraft.Vec3d;
import net.minecraft.BlockPos;
import net.minecraft.BlockTags;
import net.minecraft.KeyBinding;   // MathHelper or similar
import net.minecraft.class_3959;   // RaycastContext
import net.minecraft.class_3965;   // BlockHitResult

/**
 * AppleFarmModule - Автоматическая ферма яблок/дерева.
 * Умеет сажать саженцы, удобрять костной мукой и рубить дерево (сам или через Baritone).
 */
public class AppleFarmModule extends cl {
   
    private static final String LEAVES_TYPES = "oak_leaves spruce_leaves birch_leaves jungle_leaves acacia_leaves dark_oak_leaves cherry_leaves mangrove_leaves";
    private static final String LOG_TYPES = "oak_log spruce_log birch_log jungle_log acacia_log dark_oak_log cherry_log mangrove_log";

    // --- Настройки ---
    private final ModeSetting breakMode = new ModeSetting("Режим рубки", "Движок рубки дерева").setOptions("На месте", "Baritone").setSelected("На месте");
    private final BooleanSetting autoStop = new BooleanSetting("Авто-стоп", "Останавливать Baritone после рубки").setEnabled(true).setVisibility(() -> this.breakMode.isSelected("Baritone"));
   
    private final NumberSetting actionDelay = new NumberSetting("Задержка действий (мс)", "Задержка между основными действиями").setDefaultValue(1.0f).setRange(0, 500);
    private final NumberSetting commandDelay = new NumberSetting("Задержка команд (мс)", "Задержка между командами /mine").setDefaultValue(600.0f).setRange(0, 2000);
    private final NumberSetting breakTickDelay = new NumberSetting("Задержка ломания (мс)", "Задержка между ударами по блоку").setDefaultValue(1.0f).setRange(0, 250);
    private final NumberSetting toolSwitchDelay = new NumberSetting("Задержка смены инструмента (мс)", "Минимальное время между сменой топора").setDefaultValue(80.0f).setRange(0, 1000);
   
    private final NumberSetting scanRadius = new NumberSetting("Радиус сканирования", "Радиус поиска дерева").setDefaultValue(6.0f).setRange(1, 10);
    private final NumberSetting scanHeight = new NumberSetting("Высота сканирования", "Высота поиска дерева").setDefaultValue(20.0f).setRange(1, 40);
    private final NumberSetting maxFarmDistance = new NumberSetting("Макс. дистанция", "Максимальное удаление от точки фермы").setDefaultValue(5.0f).setRange(1, 12);
    private final NumberSetting reachDistance = new NumberSetting("Дистанция ломания", "Максимальная дистанция удара").setDefaultValue(5.5f).setRange(1, 6);
   
    private final NumberSetting rotationYawStep = new NumberSetting("Поворот Yaw", "Скорость поворота головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting rotationPitchStep = new NumberSetting("Поворот Pitch", "Скорость наклона головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting breakTolerance = new NumberSetting("Допуск ломания", "Точность наведения для рубки").setDefaultValue(20.0f).setRange(1, 45);
    private final NumberSetting interactTolerance = new NumberSetting("Допуск взаимодействия", "Точность наведения для посадки/удобрения").setDefaultValue(16.0f).setRange(1, 45);

    // --- Таймеры ---
    private final Timer actionTimer = new Timer();
    private final Timer commandTimer = new Timer();
    private final Timer notifyTimer = new Timer();
    private final Timer toolSwitchTimer = new Timer();
    private final Timer breakTimer = new Timer();

    // --- Состояние ---
    private BlockPos farmLocation;
    private BlockPos currentTargetBlock;
    private class_2350 targetBlockSide;
    private boolean isBaritoneMining;
    private boolean hasBaritone;

    public AppleFarmModule() {
        super("AppleFarm", "Apple Farm", Category.MISC);
        this.addSettings(
            this.breakMode, this.autoStop, this.actionDelay, this.commandDelay,
            this.breakTickDelay, this.toolSwitchDelay, this.scanRadius, this.scanHeight,
            this.maxFarmDistance, this.reachDistance, this.rotationYawStep,
            this.rotationPitchStep, this.breakTolerance, this.interactTolerance
        );
    }

    @Override
    public void onEnable() {
        super.onEnable();
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
       
        this.actionTimer.reset();
        this.commandTimer.setMs(this.commandDelay.getValue().longValue());
        this.notifyTimer.setMs(3000L);
        this.toolSwitchTimer.setMs(this.toolSwitchDelay.getValue().longValue());
        this.breakTimer.setMs(this.breakTickDelay.getValue().longValue());
       
        this.hasBaritone = this.detectBaritone();
        if (this.breakMode.isSelected("Baritone") && !this.hasBaritone) {
            this.sendClientMessage("Baritone не найден! Установите Baritone или используйте режим 'На месте'.");
            this.setEnabled(false);
            return;
        }

        this.farmLocation = this.getLookTargetBlock();
        if (this.farmLocation == null) {
            this.sendClientMessage("Не удалось определить точку фермы. Посмотрите на блок земли и включите модуль снова.");
            this.setEnabled(false);
            return;
        }

        if (this.breakMode.isSelected("Baritone")) {
            this.runBaritoneCommand("#set autoTool true");
            this.runBaritoneCommand("#set allowBreak true");
        }
       
        this.sendClientMessage("Ферма запущена на точке " + this.farmLocation.toString() + " в режиме " + this.breakMode.getSelected());
    }

    @Override
    public void onDisable() {
        super.onDisable();
        if (this.breakMode.isSelected("Baritone") && this.hasBaritone && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
        }
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
        this.farmLocation = null;
    }

    @EventHandler
    public void onUpdate(EventUpdate event) {
        if (mc.player == null || mc.world == null) return;

        if (this.farmLocation == null) {
            this.farmLocation = this.getLookTargetBlock();
            if (this.farmLocation == null) return;
        }

        // Проверка дистанции до фермы
        if (mc.player.squaredDistanceTo(this.farmLocation.toCenterPos()) > Math.pow(this.maxFarmDistance.getValue(), 2)) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Слишком далеко от точки фермы! Вернитесь назад.");
                this.notifyTimer.reset();
            }
            if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
                this.runBaritoneCommand("#stop");
                this.isBaritoneMining = false;
            }
            return;
        }

        // Если дерево выросло - рубим
        if (this.isTreeGrown()) {
            if (this.breakMode.isSelected("Baritone")) {
                this.updateBaritoneMining();
            }
            this.performManualChop();
            return;
        }

        // Дерева нет - сбрасываем состояние рубки
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
       
        if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
            this.isBaritoneMining = false;
        }

        if (!this.actionTimer.hasElapsed(this.actionDelay.getValue())) return;
        this.actionTimer.reset();

        // Проверяем посажен ли саженец
        if (!this.isSaplingPlanted()) {
            if (!this.tryPlantSapling()) {
                if (this.notifyTimer.hasElapsed(2500)) {
                    Item sapling = this.findSaplingInInventory();
                    if (sapling == Items.AIR) {
                        this.sendClientMessage("В инвентаре нет саженцев!");
                    } else {
                        this.sendClientMessage("Не удалось посадить саженец " + sapling.getName().getString());
                    }
                    this.notifyTimer.reset();
                }
            }
            return;
        }

        // Если саженец есть - удобряем
        if (!this.tryApplyBoneMeal()) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Нет костной муки, ждем естественного роста...");
                this.notifyTimer.reset();
            }
        }
    }

    private void updateBaritoneMining() {
        if (!this.commandTimer.hasElapsed(this.commandDelay.getValue())) return;
       
        String targets = this.anyLeavesNearby() ? LEAVES_TYPES : LOG_TYPES;
        this.runBaritoneCommand("#mine 1 " + targets);
        this.isBaritoneMining = true;
        this.commandTimer.reset();
    }

    private void performManualChop() {
        if (!this.breakTimer.hasElapsed(this.breakTickDelay.getValue())) return;

        // Если текущая цель пропала или невалидна - ищем новую
        if (this.currentTargetBlock == null || !this.isValidChopTarget(this.currentTargetBlock)) {
            BlockInfo bestBlock = this.findBestBlockToChop();
            if (bestBlock == null) {
                this.currentTargetBlock = null;
                this.targetBlockSide = null;
                return;
            }
            this.currentTargetBlock = bestBlock.getPos();
            this.targetBlockSide = bestBlock.getSide();
        }

        if (this.currentTargetBlock == null || this.targetBlockSide == null) return;

        // Поворачиваемся и рубим
        if (!this.aimAtBlock(this.currentTargetBlock, this.targetBlockSide)) return;

        this.switchToBestTool(this.currentTargetBlock);
        mc.interactionManager.attackBlock(this.currentTargetBlock, this.targetBlockSide);
        mc.player.swingHand(class_1268.field_5808);
        this.breakTimer.reset();
    }

    private boolean tryPlantSapling() {
        Item sapling = this.findSaplingInInventory();
        if (sapling == Items.AIR) return false;

        if (mc.world.getBlockState(this.farmLocation).isIn(BlockTags.field_15462)) return true;
        if (!this.canPlantAt(this.farmLocation)) return false;

        BlockPos plantPos = this.farmLocation.up();
        class_3965 hit = new class_3965(plantPos.toCenterPos(), class_2350.field_11036, plantPos, false);
       
        return this.interactWithItem(sapling, hit);
    }

    private boolean tryApplyBoneMeal() {
        int oldSlot = mc.player.getInventory().selectedSlot;
        int mealSlot = this.getHotbarSlot(Items.BONE_MEAL);
       
        if (mealSlot == -1) {
            int invSlot = this.getInventorySlot(Items.BONE_MEAL);
            if (invSlot == -1) return false;
           
            int swapTo = this.findTrashHotbarSlot();
            if (swapTo == -1) return false;
           
            mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, invSlot, swapTo, class_1713.field_7791, (ClientPlayerEntity)mc.player);
            mealSlot = swapTo;
        }

        iy.gsdfjkh(mealSlot); // switchToSlot
        class_3965 hit = new class_3965(this.farmLocation.toCenterPos(), class_2350.field_11036, this.farmLocation, false);
       
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) {
            if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
            return false;
        }

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);
       
        if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private int findTrashHotbarSlot() {
        for (int i = 0; i < 9; ++i) {
            Item item = mc.player.getInventory().getStack(i).getItem();
            if (item == Items.field_8162) return i; // air
            if (this.isTool(item)) continue;
            return i;
        }
        return -1;
    }

    private boolean isTool(Item item) {
        return item == Items.field_8556 || item == Items.field_22025 || item == Items.field_8527
            || item == Items.field_22026 || item == Items.BONE_MEAL
            || item.getName().getString().contains("Axe") || item.getName().getString().contains("Pickaxe");
    }

    private int getInventorySlot(Item target) {
        for (int i = 9; i < 36; ++i) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private boolean interactWithItem(Item item, class_3965 hit) {
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) return false;
       
        int slot = this.getHotbarSlot(item);
        if (slot == -1) return false;

        int oldSlot = mc.player.getInventory().selectedSlot;
        if (oldSlot != slot) iy.gsdfjkh(slot);

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);

        if (oldSlot != slot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private boolean isTreeGrown() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    if (state.isIn(BlockTags.LOGS) || state.isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private boolean isSaplingPlanted() {
        return mc.world.getBlockState(this.farmLocation.up()).isIn(BlockTags.SAPLINGS);
    }

    private boolean canPlantAt(BlockPos pos) {
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isFullCube(mc.world, pos) && !state.isOf(class_2246.field_10219)) return false; // grass_block
        BlockPos up = pos.up();
        return mc.world.isAir(up) || mc.world.getBlockState(up).isOf(class_2246.field_10202); // tall_grass
    }

    private BlockPos getLookTargetBlock() {
        if (mc.crosshairTarget instanceof class_3965 hit && hit.getType() == class_239.Type.BLOCK) {
            BlockPos pos = hit.getBlockPos();
            if (this.canPlantAt(pos)) return pos;
            if (this.canPlantAt(pos.down())) return pos.down();
        }
        return null;
    }

    private Item findSaplingInInventory() {
        List<Item> types = List.of(Items.field_17535, Items.field_17536, Items.field_17537, Items.field_17538, Items.field_17539, Items.field_17540);
        for (int i = 0; i < 36; i++) {
            Item it = mc.player.getInventory().getStack(i).getItem();
            if (types.contains(it)) return it;
        }
        return Items.AIR;
    }

    private boolean isValidChopTarget(BlockPos pos) {
        if (pos == null) return false;
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isIn(BlockTags.LOGS) && !state.isIn(BlockTags.LEAVES)) return false;
       
        class_2350 side = this.getVisibleSide(pos);
        if (side == null) return false;
       
        this.targetBlockSide = side;
        return mc.player.squaredDistanceTo(pos.toCenterPos()) <= Math.pow(this.reachDistance.getValue(), 2);
    }

    private BlockInfo findBestBlockToChop() {
        List<BlockInfo> logs = new ArrayList<>();
        List<BlockInfo> leaves = new ArrayList<>();
       
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
       
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    double distSq = mc.player.squaredDistanceTo(pos.toCenterPos());
                   
                    if (distSq > Math.pow(this.reachDistance.getValue(), 2)) continue;
                   
                    class_2350 side = this.getVisibleSide(pos);
                    if (side == null) continue;

                    BlockInfo info = new BlockInfo(pos, side, distSq);
                    if (state.isIn(BlockTags.LOGS)) logs.add(info);
                    else if (state.isIn(BlockTags.LEAVES)) leaves.add(info);
                }
            }
        }
       
        Comparator<BlockInfo> byDist = Comparator.comparingDouble(BlockInfo::getDistSq);
        if (!leaves.isEmpty()) return leaves.stream().min(byDist).orElse(null);
        return logs.stream().min(byDist).orElse(null);
    }

    private boolean anyLeavesNearby() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    if (mc.world.getBlockState(this.farmLocation.add(x, y, z)).isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private class_2350 getVisibleSide(BlockPos pos) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d center = pos.toCenterPos();
        for (class_2350 side : class_2350.values()) {
            Vec3d point = center.add(new Vec3d(side.getOffsetX() * 0.49, side.getOffsetY() * 0.49, side.getOffsetZ() * 0.49));
            class_3965 hit = mc.world.raycast(new class_3959(eyes, point, class_3959.class_3960.field_17559, class_3959.class_242.field_1348, mc.player));
            if (hit != null && hit.getType() == class_239.Type.BLOCK && hit.getBlockPos().equals(pos)) return hit.getSide();
        }
        return null;
    }

    private boolean aimAtBlock(BlockPos pos, class_2350 side) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d hitVec = pos.toCenterPos().add(new Vec3d(side.getOffsetX() * 0.5, side.getOffsetY() * 0.5, side.getOffsetZ() * 0.5));
        return this.rotateAndCheckAim(hitVec, this.breakTolerance.getValue());
    }

    private boolean rotateAndCheckAim(Vec3d target, float tolerance) {
        Vec3d eyes = mc.player.getEyePos();
        double dx = target.x - eyes.x;
        double dy = target.y - eyes.y;
        double dz = target.z - eyes.z;
        double dist = Math.sqrt(dx * dx + dz * dz);
       
        float yaw = (float) (Math.toDegrees(Math.atan2(dz, dx)) - 90.0);
        float pitch = (float) (-Math.toDegrees(Math.atan2(dy, dist)));
       
        float currentYaw = mc.player.getYaw();
        float currentPitch = mc.player.getPitch();
       
        float diffYaw = RotationUtils.getAngleDiff(yaw, currentYaw);
        float diffPitch = RotationUtils.getAngleDiff(pitch, currentPitch);
       
        float stepYaw = this.rotationYawStep.getValue();
        float stepPitch = this.rotationPitchStep.getValue();
       
        float nextYaw = currentYaw + Math.max(-stepYaw, Math.min(stepYaw, diffYaw));
        float nextPitch = Math.max(-90.0f, Math.min(90.0f, currentPitch + Math.max(-stepPitch, Math.min(stepPitch, diffPitch))));

        mc.player.setYaw(nextYaw);
        mc.player.setPitch(nextPitch);
        mc.player.headYaw = nextYaw;
        mc.player.bodyYaw = nextYaw;

        return Math.abs(diffYaw) <= tolerance && Math.abs(diffPitch) <= tolerance;
    }

    private void switchToBestTool(BlockPos pos) {
        if (!this.toolSwitchTimer.hasElapsed(this.toolSwitchDelay.getValue())) return;
       
        BlockState state = mc.world.getBlockState(pos);
        int bestSlot = -1;
        float bestSpeed = 1.0f;
       
        for (int i = 0; i < 9; i++) {
            float speed = mc.player.getInventory().getStack(i).getMiningSpeedMultiplier(state);
            if (speed > bestSpeed) {
                bestSpeed = speed;
                bestSlot = i;
            }
        }
       
        if (bestSlot != -1 && bestSlot != mc.player.getInventory().selectedSlot) {
            iy.gsdfjkh(bestSlot);
            this.toolSwitchTimer.reset();
        }
    }

    private int getHotbarSlot(Item target) {
        for (int i = 0; i < 9; i++) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private void runBaritoneCommand(String cmd) {
        if (mc.player != null && mc.player.networkHandler != null) {
            mc.player.networkHandler.sendChatCommand(cmd.startsWith("/") ? cmd.substring(1) : cmd);
        }
    }

    private boolean detectBaritone() {
        try {
            Class.forName("baritone.api.BaritoneAPI");
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    // Вспомогательный класс для хранения данных о блоке
    private static class BlockInfo {
        private final BlockPos pos;
        private final class_2350 side;
        private final double distSq;

        public BlockInfo(BlockPos pos, class_2350 side, double distSq) {
            this.pos = pos;
            this.side = side;
            this.distSq = distSq;
        }
        public BlockPos getPos() { return pos; }
        public class_2350 getSide() { return side; }
        public double getDistSq() { return distSq; }
    }
}
деобфнул с ластовой версии релеона берите кому надо
сс не будет я хочу спать насчет работоспособности не знаю можете проверить
(деобф делал с ии)
ээ чат гпт это ну сделай деобф вот короче код вот короче ну сними защиту вооот
 
ээ чат гпт это ну сделай деобф вот короче код вот короче ну сними защиту вооот
я пытался ваще написать фулл деобфер чтобы слить сурсеке релеона не получилось крч
 
applefarm.java:
Expand Collapse Copy
package l;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import l.cl;
import l.cm;
import l.BooleanSetting;
import l.ModeSetting;
import l.NumberSetting;
import l.Timer;
import l.RotationUtils; // assuming iy was RotationUtils based on gsdfjkh(slot) which is usually selectSlot
import l.EventUpdate;
import net.minecraft.class_1268;   // Hand
import net.minecraft.class_1269;   // ActionResult
import net.minecraft.EntityType;
import net.minecraft.ClientPlayerEntity;
import net.minecraft.class_1713;   // SlotActionType
import net.minecraft.class_1735;   // ItemStack
import net.minecraft.Item;
import net.minecraft.Items;
import net.minecraft.class_2246;   // Blocks
import net.minecraft.BlockState;
import net.minecraft.class_2350;   // Direction
import net.minecraft.class_239;    // HitResult
import net.minecraft.Vec3d;
import net.minecraft.BlockPos;
import net.minecraft.BlockTags;
import net.minecraft.KeyBinding;   // MathHelper or similar
import net.minecraft.class_3959;   // RaycastContext
import net.minecraft.class_3965;   // BlockHitResult

/**
 * AppleFarmModule - Автоматическая ферма яблок/дерева.
 * Умеет сажать саженцы, удобрять костной мукой и рубить дерево (сам или через Baritone).
 */
public class AppleFarmModule extends cl {
   
    private static final String LEAVES_TYPES = "oak_leaves spruce_leaves birch_leaves jungle_leaves acacia_leaves dark_oak_leaves cherry_leaves mangrove_leaves";
    private static final String LOG_TYPES = "oak_log spruce_log birch_log jungle_log acacia_log dark_oak_log cherry_log mangrove_log";

    // --- Настройки ---
    private final ModeSetting breakMode = new ModeSetting("Режим рубки", "Движок рубки дерева").setOptions("На месте", "Baritone").setSelected("На месте");
    private final BooleanSetting autoStop = new BooleanSetting("Авто-стоп", "Останавливать Baritone после рубки").setEnabled(true).setVisibility(() -> this.breakMode.isSelected("Baritone"));
   
    private final NumberSetting actionDelay = new NumberSetting("Задержка действий (мс)", "Задержка между основными действиями").setDefaultValue(1.0f).setRange(0, 500);
    private final NumberSetting commandDelay = new NumberSetting("Задержка команд (мс)", "Задержка между командами /mine").setDefaultValue(600.0f).setRange(0, 2000);
    private final NumberSetting breakTickDelay = new NumberSetting("Задержка ломания (мс)", "Задержка между ударами по блоку").setDefaultValue(1.0f).setRange(0, 250);
    private final NumberSetting toolSwitchDelay = new NumberSetting("Задержка смены инструмента (мс)", "Минимальное время между сменой топора").setDefaultValue(80.0f).setRange(0, 1000);
   
    private final NumberSetting scanRadius = new NumberSetting("Радиус сканирования", "Радиус поиска дерева").setDefaultValue(6.0f).setRange(1, 10);
    private final NumberSetting scanHeight = new NumberSetting("Высота сканирования", "Высота поиска дерева").setDefaultValue(20.0f).setRange(1, 40);
    private final NumberSetting maxFarmDistance = new NumberSetting("Макс. дистанция", "Максимальное удаление от точки фермы").setDefaultValue(5.0f).setRange(1, 12);
    private final NumberSetting reachDistance = new NumberSetting("Дистанция ломания", "Максимальная дистанция удара").setDefaultValue(5.5f).setRange(1, 6);
   
    private final NumberSetting rotationYawStep = new NumberSetting("Поворот Yaw", "Скорость поворота головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting rotationPitchStep = new NumberSetting("Поворот Pitch", "Скорость наклона головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting breakTolerance = new NumberSetting("Допуск ломания", "Точность наведения для рубки").setDefaultValue(20.0f).setRange(1, 45);
    private final NumberSetting interactTolerance = new NumberSetting("Допуск взаимодействия", "Точность наведения для посадки/удобрения").setDefaultValue(16.0f).setRange(1, 45);

    // --- Таймеры ---
    private final Timer actionTimer = new Timer();
    private final Timer commandTimer = new Timer();
    private final Timer notifyTimer = new Timer();
    private final Timer toolSwitchTimer = new Timer();
    private final Timer breakTimer = new Timer();

    // --- Состояние ---
    private BlockPos farmLocation;
    private BlockPos currentTargetBlock;
    private class_2350 targetBlockSide;
    private boolean isBaritoneMining;
    private boolean hasBaritone;

    public AppleFarmModule() {
        super("AppleFarm", "Apple Farm", Category.MISC);
        this.addSettings(
            this.breakMode, this.autoStop, this.actionDelay, this.commandDelay,
            this.breakTickDelay, this.toolSwitchDelay, this.scanRadius, this.scanHeight,
            this.maxFarmDistance, this.reachDistance, this.rotationYawStep,
            this.rotationPitchStep, this.breakTolerance, this.interactTolerance
        );
    }

    @Override
    public void onEnable() {
        super.onEnable();
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
       
        this.actionTimer.reset();
        this.commandTimer.setMs(this.commandDelay.getValue().longValue());
        this.notifyTimer.setMs(3000L);
        this.toolSwitchTimer.setMs(this.toolSwitchDelay.getValue().longValue());
        this.breakTimer.setMs(this.breakTickDelay.getValue().longValue());
       
        this.hasBaritone = this.detectBaritone();
        if (this.breakMode.isSelected("Baritone") && !this.hasBaritone) {
            this.sendClientMessage("Baritone не найден! Установите Baritone или используйте режим 'На месте'.");
            this.setEnabled(false);
            return;
        }

        this.farmLocation = this.getLookTargetBlock();
        if (this.farmLocation == null) {
            this.sendClientMessage("Не удалось определить точку фермы. Посмотрите на блок земли и включите модуль снова.");
            this.setEnabled(false);
            return;
        }

        if (this.breakMode.isSelected("Baritone")) {
            this.runBaritoneCommand("#set autoTool true");
            this.runBaritoneCommand("#set allowBreak true");
        }
       
        this.sendClientMessage("Ферма запущена на точке " + this.farmLocation.toString() + " в режиме " + this.breakMode.getSelected());
    }

    @Override
    public void onDisable() {
        super.onDisable();
        if (this.breakMode.isSelected("Baritone") && this.hasBaritone && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
        }
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
        this.farmLocation = null;
    }

    @EventHandler
    public void onUpdate(EventUpdate event) {
        if (mc.player == null || mc.world == null) return;

        if (this.farmLocation == null) {
            this.farmLocation = this.getLookTargetBlock();
            if (this.farmLocation == null) return;
        }

        // Проверка дистанции до фермы
        if (mc.player.squaredDistanceTo(this.farmLocation.toCenterPos()) > Math.pow(this.maxFarmDistance.getValue(), 2)) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Слишком далеко от точки фермы! Вернитесь назад.");
                this.notifyTimer.reset();
            }
            if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
                this.runBaritoneCommand("#stop");
                this.isBaritoneMining = false;
            }
            return;
        }

        // Если дерево выросло - рубим
        if (this.isTreeGrown()) {
            if (this.breakMode.isSelected("Baritone")) {
                this.updateBaritoneMining();
            }
            this.performManualChop();
            return;
        }

        // Дерева нет - сбрасываем состояние рубки
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
       
        if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
            this.isBaritoneMining = false;
        }

        if (!this.actionTimer.hasElapsed(this.actionDelay.getValue())) return;
        this.actionTimer.reset();

        // Проверяем посажен ли саженец
        if (!this.isSaplingPlanted()) {
            if (!this.tryPlantSapling()) {
                if (this.notifyTimer.hasElapsed(2500)) {
                    Item sapling = this.findSaplingInInventory();
                    if (sapling == Items.AIR) {
                        this.sendClientMessage("В инвентаре нет саженцев!");
                    } else {
                        this.sendClientMessage("Не удалось посадить саженец " + sapling.getName().getString());
                    }
                    this.notifyTimer.reset();
                }
            }
            return;
        }

        // Если саженец есть - удобряем
        if (!this.tryApplyBoneMeal()) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Нет костной муки, ждем естественного роста...");
                this.notifyTimer.reset();
            }
        }
    }

    private void updateBaritoneMining() {
        if (!this.commandTimer.hasElapsed(this.commandDelay.getValue())) return;
       
        String targets = this.anyLeavesNearby() ? LEAVES_TYPES : LOG_TYPES;
        this.runBaritoneCommand("#mine 1 " + targets);
        this.isBaritoneMining = true;
        this.commandTimer.reset();
    }

    private void performManualChop() {
        if (!this.breakTimer.hasElapsed(this.breakTickDelay.getValue())) return;

        // Если текущая цель пропала или невалидна - ищем новую
        if (this.currentTargetBlock == null || !this.isValidChopTarget(this.currentTargetBlock)) {
            BlockInfo bestBlock = this.findBestBlockToChop();
            if (bestBlock == null) {
                this.currentTargetBlock = null;
                this.targetBlockSide = null;
                return;
            }
            this.currentTargetBlock = bestBlock.getPos();
            this.targetBlockSide = bestBlock.getSide();
        }

        if (this.currentTargetBlock == null || this.targetBlockSide == null) return;

        // Поворачиваемся и рубим
        if (!this.aimAtBlock(this.currentTargetBlock, this.targetBlockSide)) return;

        this.switchToBestTool(this.currentTargetBlock);
        mc.interactionManager.attackBlock(this.currentTargetBlock, this.targetBlockSide);
        mc.player.swingHand(class_1268.field_5808);
        this.breakTimer.reset();
    }

    private boolean tryPlantSapling() {
        Item sapling = this.findSaplingInInventory();
        if (sapling == Items.AIR) return false;

        if (mc.world.getBlockState(this.farmLocation).isIn(BlockTags.field_15462)) return true;
        if (!this.canPlantAt(this.farmLocation)) return false;

        BlockPos plantPos = this.farmLocation.up();
        class_3965 hit = new class_3965(plantPos.toCenterPos(), class_2350.field_11036, plantPos, false);
       
        return this.interactWithItem(sapling, hit);
    }

    private boolean tryApplyBoneMeal() {
        int oldSlot = mc.player.getInventory().selectedSlot;
        int mealSlot = this.getHotbarSlot(Items.BONE_MEAL);
       
        if (mealSlot == -1) {
            int invSlot = this.getInventorySlot(Items.BONE_MEAL);
            if (invSlot == -1) return false;
           
            int swapTo = this.findTrashHotbarSlot();
            if (swapTo == -1) return false;
           
            mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, invSlot, swapTo, class_1713.field_7791, (ClientPlayerEntity)mc.player);
            mealSlot = swapTo;
        }

        iy.gsdfjkh(mealSlot); // switchToSlot
        class_3965 hit = new class_3965(this.farmLocation.toCenterPos(), class_2350.field_11036, this.farmLocation, false);
       
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) {
            if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
            return false;
        }

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);
       
        if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private int findTrashHotbarSlot() {
        for (int i = 0; i < 9; ++i) {
            Item item = mc.player.getInventory().getStack(i).getItem();
            if (item == Items.field_8162) return i; // air
            if (this.isTool(item)) continue;
            return i;
        }
        return -1;
    }

    private boolean isTool(Item item) {
        return item == Items.field_8556 || item == Items.field_22025 || item == Items.field_8527
            || item == Items.field_22026 || item == Items.BONE_MEAL
            || item.getName().getString().contains("Axe") || item.getName().getString().contains("Pickaxe");
    }

    private int getInventorySlot(Item target) {
        for (int i = 9; i < 36; ++i) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private boolean interactWithItem(Item item, class_3965 hit) {
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) return false;
       
        int slot = this.getHotbarSlot(item);
        if (slot == -1) return false;

        int oldSlot = mc.player.getInventory().selectedSlot;
        if (oldSlot != slot) iy.gsdfjkh(slot);

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);

        if (oldSlot != slot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private boolean isTreeGrown() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    if (state.isIn(BlockTags.LOGS) || state.isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private boolean isSaplingPlanted() {
        return mc.world.getBlockState(this.farmLocation.up()).isIn(BlockTags.SAPLINGS);
    }

    private boolean canPlantAt(BlockPos pos) {
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isFullCube(mc.world, pos) && !state.isOf(class_2246.field_10219)) return false; // grass_block
        BlockPos up = pos.up();
        return mc.world.isAir(up) || mc.world.getBlockState(up).isOf(class_2246.field_10202); // tall_grass
    }

    private BlockPos getLookTargetBlock() {
        if (mc.crosshairTarget instanceof class_3965 hit && hit.getType() == class_239.Type.BLOCK) {
            BlockPos pos = hit.getBlockPos();
            if (this.canPlantAt(pos)) return pos;
            if (this.canPlantAt(pos.down())) return pos.down();
        }
        return null;
    }

    private Item findSaplingInInventory() {
        List<Item> types = List.of(Items.field_17535, Items.field_17536, Items.field_17537, Items.field_17538, Items.field_17539, Items.field_17540);
        for (int i = 0; i < 36; i++) {
            Item it = mc.player.getInventory().getStack(i).getItem();
            if (types.contains(it)) return it;
        }
        return Items.AIR;
    }

    private boolean isValidChopTarget(BlockPos pos) {
        if (pos == null) return false;
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isIn(BlockTags.LOGS) && !state.isIn(BlockTags.LEAVES)) return false;
       
        class_2350 side = this.getVisibleSide(pos);
        if (side == null) return false;
       
        this.targetBlockSide = side;
        return mc.player.squaredDistanceTo(pos.toCenterPos()) <= Math.pow(this.reachDistance.getValue(), 2);
    }

    private BlockInfo findBestBlockToChop() {
        List<BlockInfo> logs = new ArrayList<>();
        List<BlockInfo> leaves = new ArrayList<>();
       
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
       
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    double distSq = mc.player.squaredDistanceTo(pos.toCenterPos());
                   
                    if (distSq > Math.pow(this.reachDistance.getValue(), 2)) continue;
                   
                    class_2350 side = this.getVisibleSide(pos);
                    if (side == null) continue;

                    BlockInfo info = new BlockInfo(pos, side, distSq);
                    if (state.isIn(BlockTags.LOGS)) logs.add(info);
                    else if (state.isIn(BlockTags.LEAVES)) leaves.add(info);
                }
            }
        }
       
        Comparator<BlockInfo> byDist = Comparator.comparingDouble(BlockInfo::getDistSq);
        if (!leaves.isEmpty()) return leaves.stream().min(byDist).orElse(null);
        return logs.stream().min(byDist).orElse(null);
    }

    private boolean anyLeavesNearby() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    if (mc.world.getBlockState(this.farmLocation.add(x, y, z)).isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private class_2350 getVisibleSide(BlockPos pos) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d center = pos.toCenterPos();
        for (class_2350 side : class_2350.values()) {
            Vec3d point = center.add(new Vec3d(side.getOffsetX() * 0.49, side.getOffsetY() * 0.49, side.getOffsetZ() * 0.49));
            class_3965 hit = mc.world.raycast(new class_3959(eyes, point, class_3959.class_3960.field_17559, class_3959.class_242.field_1348, mc.player));
            if (hit != null && hit.getType() == class_239.Type.BLOCK && hit.getBlockPos().equals(pos)) return hit.getSide();
        }
        return null;
    }

    private boolean aimAtBlock(BlockPos pos, class_2350 side) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d hitVec = pos.toCenterPos().add(new Vec3d(side.getOffsetX() * 0.5, side.getOffsetY() * 0.5, side.getOffsetZ() * 0.5));
        return this.rotateAndCheckAim(hitVec, this.breakTolerance.getValue());
    }

    private boolean rotateAndCheckAim(Vec3d target, float tolerance) {
        Vec3d eyes = mc.player.getEyePos();
        double dx = target.x - eyes.x;
        double dy = target.y - eyes.y;
        double dz = target.z - eyes.z;
        double dist = Math.sqrt(dx * dx + dz * dz);
       
        float yaw = (float) (Math.toDegrees(Math.atan2(dz, dx)) - 90.0);
        float pitch = (float) (-Math.toDegrees(Math.atan2(dy, dist)));
       
        float currentYaw = mc.player.getYaw();
        float currentPitch = mc.player.getPitch();
       
        float diffYaw = RotationUtils.getAngleDiff(yaw, currentYaw);
        float diffPitch = RotationUtils.getAngleDiff(pitch, currentPitch);
       
        float stepYaw = this.rotationYawStep.getValue();
        float stepPitch = this.rotationPitchStep.getValue();
       
        float nextYaw = currentYaw + Math.max(-stepYaw, Math.min(stepYaw, diffYaw));
        float nextPitch = Math.max(-90.0f, Math.min(90.0f, currentPitch + Math.max(-stepPitch, Math.min(stepPitch, diffPitch))));

        mc.player.setYaw(nextYaw);
        mc.player.setPitch(nextPitch);
        mc.player.headYaw = nextYaw;
        mc.player.bodyYaw = nextYaw;

        return Math.abs(diffYaw) <= tolerance && Math.abs(diffPitch) <= tolerance;
    }

    private void switchToBestTool(BlockPos pos) {
        if (!this.toolSwitchTimer.hasElapsed(this.toolSwitchDelay.getValue())) return;
       
        BlockState state = mc.world.getBlockState(pos);
        int bestSlot = -1;
        float bestSpeed = 1.0f;
       
        for (int i = 0; i < 9; i++) {
            float speed = mc.player.getInventory().getStack(i).getMiningSpeedMultiplier(state);
            if (speed > bestSpeed) {
                bestSpeed = speed;
                bestSlot = i;
            }
        }
       
        if (bestSlot != -1 && bestSlot != mc.player.getInventory().selectedSlot) {
            iy.gsdfjkh(bestSlot);
            this.toolSwitchTimer.reset();
        }
    }

    private int getHotbarSlot(Item target) {
        for (int i = 0; i < 9; i++) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private void runBaritoneCommand(String cmd) {
        if (mc.player != null && mc.player.networkHandler != null) {
            mc.player.networkHandler.sendChatCommand(cmd.startsWith("/") ? cmd.substring(1) : cmd);
        }
    }

    private boolean detectBaritone() {
        try {
            Class.forName("baritone.api.BaritoneAPI");
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    // Вспомогательный класс для хранения данных о блоке
    private static class BlockInfo {
        private final BlockPos pos;
        private final class_2350 side;
        private final double distSq;

        public BlockInfo(BlockPos pos, class_2350 side, double distSq) {
            this.pos = pos;
            this.side = side;
            this.distSq = distSq;
        }
        public BlockPos getPos() { return pos; }
        public class_2350 getSide() { return side; }
        public double getDistSq() { return distSq; }
    }
}
деобфнул с ластовой версии релеона берите кому надо
сс не будет я хочу спать насчет работоспособности не знаю можете проверить
(деобф делал с ии)
Я даун забейте
 
applefarm.java:
Expand Collapse Copy
package l;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import l.cl;
import l.cm;
import l.BooleanSetting;
import l.ModeSetting;
import l.NumberSetting;
import l.Timer;
import l.RotationUtils; // assuming iy was RotationUtils based on gsdfjkh(slot) which is usually selectSlot
import l.EventUpdate;
import net.minecraft.class_1268;   // Hand
import net.minecraft.class_1269;   // ActionResult
import net.minecraft.EntityType;
import net.minecraft.ClientPlayerEntity;
import net.minecraft.class_1713;   // SlotActionType
import net.minecraft.class_1735;   // ItemStack
import net.minecraft.Item;
import net.minecraft.Items;
import net.minecraft.class_2246;   // Blocks
import net.minecraft.BlockState;
import net.minecraft.class_2350;   // Direction
import net.minecraft.class_239;    // HitResult
import net.minecraft.Vec3d;
import net.minecraft.BlockPos;
import net.minecraft.BlockTags;
import net.minecraft.KeyBinding;   // MathHelper or similar
import net.minecraft.class_3959;   // RaycastContext
import net.minecraft.class_3965;   // BlockHitResult

/**
 * AppleFarmModule - Автоматическая ферма яблок/дерева.
 * Умеет сажать саженцы, удобрять костной мукой и рубить дерево (сам или через Baritone).
 */
public class AppleFarmModule extends cl {
   
    private static final String LEAVES_TYPES = "oak_leaves spruce_leaves birch_leaves jungle_leaves acacia_leaves dark_oak_leaves cherry_leaves mangrove_leaves";
    private static final String LOG_TYPES = "oak_log spruce_log birch_log jungle_log acacia_log dark_oak_log cherry_log mangrove_log";

    // --- Настройки ---
    private final ModeSetting breakMode = new ModeSetting("Режим рубки", "Движок рубки дерева").setOptions("На месте", "Baritone").setSelected("На месте");
    private final BooleanSetting autoStop = new BooleanSetting("Авто-стоп", "Останавливать Baritone после рубки").setEnabled(true).setVisibility(() -> this.breakMode.isSelected("Baritone"));
   
    private final NumberSetting actionDelay = new NumberSetting("Задержка действий (мс)", "Задержка между основными действиями").setDefaultValue(1.0f).setRange(0, 500);
    private final NumberSetting commandDelay = new NumberSetting("Задержка команд (мс)", "Задержка между командами /mine").setDefaultValue(600.0f).setRange(0, 2000);
    private final NumberSetting breakTickDelay = new NumberSetting("Задержка ломания (мс)", "Задержка между ударами по блоку").setDefaultValue(1.0f).setRange(0, 250);
    private final NumberSetting toolSwitchDelay = new NumberSetting("Задержка смены инструмента (мс)", "Минимальное время между сменой топора").setDefaultValue(80.0f).setRange(0, 1000);
   
    private final NumberSetting scanRadius = new NumberSetting("Радиус сканирования", "Радиус поиска дерева").setDefaultValue(6.0f).setRange(1, 10);
    private final NumberSetting scanHeight = new NumberSetting("Высота сканирования", "Высота поиска дерева").setDefaultValue(20.0f).setRange(1, 40);
    private final NumberSetting maxFarmDistance = new NumberSetting("Макс. дистанция", "Максимальное удаление от точки фермы").setDefaultValue(5.0f).setRange(1, 12);
    private final NumberSetting reachDistance = new NumberSetting("Дистанция ломания", "Максимальная дистанция удара").setDefaultValue(5.5f).setRange(1, 6);
   
    private final NumberSetting rotationYawStep = new NumberSetting("Поворот Yaw", "Скорость поворота головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting rotationPitchStep = new NumberSetting("Поворот Pitch", "Скорость наклона головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting breakTolerance = new NumberSetting("Допуск ломания", "Точность наведения для рубки").setDefaultValue(20.0f).setRange(1, 45);
    private final NumberSetting interactTolerance = new NumberSetting("Допуск взаимодействия", "Точность наведения для посадки/удобрения").setDefaultValue(16.0f).setRange(1, 45);

    // --- Таймеры ---
    private final Timer actionTimer = new Timer();
    private final Timer commandTimer = new Timer();
    private final Timer notifyTimer = new Timer();
    private final Timer toolSwitchTimer = new Timer();
    private final Timer breakTimer = new Timer();

    // --- Состояние ---
    private BlockPos farmLocation;
    private BlockPos currentTargetBlock;
    private class_2350 targetBlockSide;
    private boolean isBaritoneMining;
    private boolean hasBaritone;

    public AppleFarmModule() {
        super("AppleFarm", "Apple Farm", Category.MISC);
        this.addSettings(
            this.breakMode, this.autoStop, this.actionDelay, this.commandDelay,
            this.breakTickDelay, this.toolSwitchDelay, this.scanRadius, this.scanHeight,
            this.maxFarmDistance, this.reachDistance, this.rotationYawStep,
            this.rotationPitchStep, this.breakTolerance, this.interactTolerance
        );
    }

    @Override
    public void onEnable() {
        super.onEnable();
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
       
        this.actionTimer.reset();
        this.commandTimer.setMs(this.commandDelay.getValue().longValue());
        this.notifyTimer.setMs(3000L);
        this.toolSwitchTimer.setMs(this.toolSwitchDelay.getValue().longValue());
        this.breakTimer.setMs(this.breakTickDelay.getValue().longValue());
       
        this.hasBaritone = this.detectBaritone();
        if (this.breakMode.isSelected("Baritone") && !this.hasBaritone) {
            this.sendClientMessage("Baritone не найден! Установите Baritone или используйте режим 'На месте'.");
            this.setEnabled(false);
            return;
        }

        this.farmLocation = this.getLookTargetBlock();
        if (this.farmLocation == null) {
            this.sendClientMessage("Не удалось определить точку фермы. Посмотрите на блок земли и включите модуль снова.");
            this.setEnabled(false);
            return;
        }

        if (this.breakMode.isSelected("Baritone")) {
            this.runBaritoneCommand("#set autoTool true");
            this.runBaritoneCommand("#set allowBreak true");
        }
       
        this.sendClientMessage("Ферма запущена на точке " + this.farmLocation.toString() + " в режиме " + this.breakMode.getSelected());
    }

    @Override
    public void onDisable() {
        super.onDisable();
        if (this.breakMode.isSelected("Baritone") && this.hasBaritone && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
        }
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
        this.farmLocation = null;
    }

    @EventHandler
    public void onUpdate(EventUpdate event) {
        if (mc.player == null || mc.world == null) return;

        if (this.farmLocation == null) {
            this.farmLocation = this.getLookTargetBlock();
            if (this.farmLocation == null) return;
        }

        // Проверка дистанции до фермы
        if (mc.player.squaredDistanceTo(this.farmLocation.toCenterPos()) > Math.pow(this.maxFarmDistance.getValue(), 2)) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Слишком далеко от точки фермы! Вернитесь назад.");
                this.notifyTimer.reset();
            }
            if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
                this.runBaritoneCommand("#stop");
                this.isBaritoneMining = false;
            }
            return;
        }

        // Если дерево выросло - рубим
        if (this.isTreeGrown()) {
            if (this.breakMode.isSelected("Baritone")) {
                this.updateBaritoneMining();
            }
            this.performManualChop();
            return;
        }

        // Дерева нет - сбрасываем состояние рубки
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
       
        if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
            this.isBaritoneMining = false;
        }

        if (!this.actionTimer.hasElapsed(this.actionDelay.getValue())) return;
        this.actionTimer.reset();

        // Проверяем посажен ли саженец
        if (!this.isSaplingPlanted()) {
            if (!this.tryPlantSapling()) {
                if (this.notifyTimer.hasElapsed(2500)) {
                    Item sapling = this.findSaplingInInventory();
                    if (sapling == Items.AIR) {
                        this.sendClientMessage("В инвентаре нет саженцев!");
                    } else {
                        this.sendClientMessage("Не удалось посадить саженец " + sapling.getName().getString());
                    }
                    this.notifyTimer.reset();
                }
            }
            return;
        }

        // Если саженец есть - удобряем
        if (!this.tryApplyBoneMeal()) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Нет костной муки, ждем естественного роста...");
                this.notifyTimer.reset();
            }
        }
    }

    private void updateBaritoneMining() {
        if (!this.commandTimer.hasElapsed(this.commandDelay.getValue())) return;
       
        String targets = this.anyLeavesNearby() ? LEAVES_TYPES : LOG_TYPES;
        this.runBaritoneCommand("#mine 1 " + targets);
        this.isBaritoneMining = true;
        this.commandTimer.reset();
    }

    private void performManualChop() {
        if (!this.breakTimer.hasElapsed(this.breakTickDelay.getValue())) return;

        // Если текущая цель пропала или невалидна - ищем новую
        if (this.currentTargetBlock == null || !this.isValidChopTarget(this.currentTargetBlock)) {
            BlockInfo bestBlock = this.findBestBlockToChop();
            if (bestBlock == null) {
                this.currentTargetBlock = null;
                this.targetBlockSide = null;
                return;
            }
            this.currentTargetBlock = bestBlock.getPos();
            this.targetBlockSide = bestBlock.getSide();
        }

        if (this.currentTargetBlock == null || this.targetBlockSide == null) return;

        // Поворачиваемся и рубим
        if (!this.aimAtBlock(this.currentTargetBlock, this.targetBlockSide)) return;

        this.switchToBestTool(this.currentTargetBlock);
        mc.interactionManager.attackBlock(this.currentTargetBlock, this.targetBlockSide);
        mc.player.swingHand(class_1268.field_5808);
        this.breakTimer.reset();
    }

    private boolean tryPlantSapling() {
        Item sapling = this.findSaplingInInventory();
        if (sapling == Items.AIR) return false;

        if (mc.world.getBlockState(this.farmLocation).isIn(BlockTags.field_15462)) return true;
        if (!this.canPlantAt(this.farmLocation)) return false;

        BlockPos plantPos = this.farmLocation.up();
        class_3965 hit = new class_3965(plantPos.toCenterPos(), class_2350.field_11036, plantPos, false);
       
        return this.interactWithItem(sapling, hit);
    }

    private boolean tryApplyBoneMeal() {
        int oldSlot = mc.player.getInventory().selectedSlot;
        int mealSlot = this.getHotbarSlot(Items.BONE_MEAL);
       
        if (mealSlot == -1) {
            int invSlot = this.getInventorySlot(Items.BONE_MEAL);
            if (invSlot == -1) return false;
           
            int swapTo = this.findTrashHotbarSlot();
            if (swapTo == -1) return false;
           
            mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, invSlot, swapTo, class_1713.field_7791, (ClientPlayerEntity)mc.player);
            mealSlot = swapTo;
        }

        iy.gsdfjkh(mealSlot); // switchToSlot
        class_3965 hit = new class_3965(this.farmLocation.toCenterPos(), class_2350.field_11036, this.farmLocation, false);
       
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) {
            if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
            return false;
        }

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);
       
        if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private int findTrashHotbarSlot() {
        for (int i = 0; i < 9; ++i) {
            Item item = mc.player.getInventory().getStack(i).getItem();
            if (item == Items.field_8162) return i; // air
            if (this.isTool(item)) continue;
            return i;
        }
        return -1;
    }

    private boolean isTool(Item item) {
        return item == Items.field_8556 || item == Items.field_22025 || item == Items.field_8527
            || item == Items.field_22026 || item == Items.BONE_MEAL
            || item.getName().getString().contains("Axe") || item.getName().getString().contains("Pickaxe");
    }

    private int getInventorySlot(Item target) {
        for (int i = 9; i < 36; ++i) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private boolean interactWithItem(Item item, class_3965 hit) {
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) return false;
       
        int slot = this.getHotbarSlot(item);
        if (slot == -1) return false;

        int oldSlot = mc.player.getInventory().selectedSlot;
        if (oldSlot != slot) iy.gsdfjkh(slot);

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);

        if (oldSlot != slot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private boolean isTreeGrown() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    if (state.isIn(BlockTags.LOGS) || state.isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private boolean isSaplingPlanted() {
        return mc.world.getBlockState(this.farmLocation.up()).isIn(BlockTags.SAPLINGS);
    }

    private boolean canPlantAt(BlockPos pos) {
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isFullCube(mc.world, pos) && !state.isOf(class_2246.field_10219)) return false; // grass_block
        BlockPos up = pos.up();
        return mc.world.isAir(up) || mc.world.getBlockState(up).isOf(class_2246.field_10202); // tall_grass
    }

    private BlockPos getLookTargetBlock() {
        if (mc.crosshairTarget instanceof class_3965 hit && hit.getType() == class_239.Type.BLOCK) {
            BlockPos pos = hit.getBlockPos();
            if (this.canPlantAt(pos)) return pos;
            if (this.canPlantAt(pos.down())) return pos.down();
        }
        return null;
    }

    private Item findSaplingInInventory() {
        List<Item> types = List.of(Items.field_17535, Items.field_17536, Items.field_17537, Items.field_17538, Items.field_17539, Items.field_17540);
        for (int i = 0; i < 36; i++) {
            Item it = mc.player.getInventory().getStack(i).getItem();
            if (types.contains(it)) return it;
        }
        return Items.AIR;
    }

    private boolean isValidChopTarget(BlockPos pos) {
        if (pos == null) return false;
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isIn(BlockTags.LOGS) && !state.isIn(BlockTags.LEAVES)) return false;
       
        class_2350 side = this.getVisibleSide(pos);
        if (side == null) return false;
       
        this.targetBlockSide = side;
        return mc.player.squaredDistanceTo(pos.toCenterPos()) <= Math.pow(this.reachDistance.getValue(), 2);
    }

    private BlockInfo findBestBlockToChop() {
        List<BlockInfo> logs = new ArrayList<>();
        List<BlockInfo> leaves = new ArrayList<>();
       
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
       
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    double distSq = mc.player.squaredDistanceTo(pos.toCenterPos());
                   
                    if (distSq > Math.pow(this.reachDistance.getValue(), 2)) continue;
                   
                    class_2350 side = this.getVisibleSide(pos);
                    if (side == null) continue;

                    BlockInfo info = new BlockInfo(pos, side, distSq);
                    if (state.isIn(BlockTags.LOGS)) logs.add(info);
                    else if (state.isIn(BlockTags.LEAVES)) leaves.add(info);
                }
            }
        }
       
        Comparator<BlockInfo> byDist = Comparator.comparingDouble(BlockInfo::getDistSq);
        if (!leaves.isEmpty()) return leaves.stream().min(byDist).orElse(null);
        return logs.stream().min(byDist).orElse(null);
    }

    private boolean anyLeavesNearby() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    if (mc.world.getBlockState(this.farmLocation.add(x, y, z)).isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private class_2350 getVisibleSide(BlockPos pos) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d center = pos.toCenterPos();
        for (class_2350 side : class_2350.values()) {
            Vec3d point = center.add(new Vec3d(side.getOffsetX() * 0.49, side.getOffsetY() * 0.49, side.getOffsetZ() * 0.49));
            class_3965 hit = mc.world.raycast(new class_3959(eyes, point, class_3959.class_3960.field_17559, class_3959.class_242.field_1348, mc.player));
            if (hit != null && hit.getType() == class_239.Type.BLOCK && hit.getBlockPos().equals(pos)) return hit.getSide();
        }
        return null;
    }

    private boolean aimAtBlock(BlockPos pos, class_2350 side) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d hitVec = pos.toCenterPos().add(new Vec3d(side.getOffsetX() * 0.5, side.getOffsetY() * 0.5, side.getOffsetZ() * 0.5));
        return this.rotateAndCheckAim(hitVec, this.breakTolerance.getValue());
    }

    private boolean rotateAndCheckAim(Vec3d target, float tolerance) {
        Vec3d eyes = mc.player.getEyePos();
        double dx = target.x - eyes.x;
        double dy = target.y - eyes.y;
        double dz = target.z - eyes.z;
        double dist = Math.sqrt(dx * dx + dz * dz);
       
        float yaw = (float) (Math.toDegrees(Math.atan2(dz, dx)) - 90.0);
        float pitch = (float) (-Math.toDegrees(Math.atan2(dy, dist)));
       
        float currentYaw = mc.player.getYaw();
        float currentPitch = mc.player.getPitch();
       
        float diffYaw = RotationUtils.getAngleDiff(yaw, currentYaw);
        float diffPitch = RotationUtils.getAngleDiff(pitch, currentPitch);
       
        float stepYaw = this.rotationYawStep.getValue();
        float stepPitch = this.rotationPitchStep.getValue();
       
        float nextYaw = currentYaw + Math.max(-stepYaw, Math.min(stepYaw, diffYaw));
        float nextPitch = Math.max(-90.0f, Math.min(90.0f, currentPitch + Math.max(-stepPitch, Math.min(stepPitch, diffPitch))));

        mc.player.setYaw(nextYaw);
        mc.player.setPitch(nextPitch);
        mc.player.headYaw = nextYaw;
        mc.player.bodyYaw = nextYaw;

        return Math.abs(diffYaw) <= tolerance && Math.abs(diffPitch) <= tolerance;
    }

    private void switchToBestTool(BlockPos pos) {
        if (!this.toolSwitchTimer.hasElapsed(this.toolSwitchDelay.getValue())) return;
       
        BlockState state = mc.world.getBlockState(pos);
        int bestSlot = -1;
        float bestSpeed = 1.0f;
       
        for (int i = 0; i < 9; i++) {
            float speed = mc.player.getInventory().getStack(i).getMiningSpeedMultiplier(state);
            if (speed > bestSpeed) {
                bestSpeed = speed;
                bestSlot = i;
            }
        }
       
        if (bestSlot != -1 && bestSlot != mc.player.getInventory().selectedSlot) {
            iy.gsdfjkh(bestSlot);
            this.toolSwitchTimer.reset();
        }
    }

    private int getHotbarSlot(Item target) {
        for (int i = 0; i < 9; i++) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private void runBaritoneCommand(String cmd) {
        if (mc.player != null && mc.player.networkHandler != null) {
            mc.player.networkHandler.sendChatCommand(cmd.startsWith("/") ? cmd.substring(1) : cmd);
        }
    }

    private boolean detectBaritone() {
        try {
            Class.forName("baritone.api.BaritoneAPI");
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    // Вспомогательный класс для хранения данных о блоке
    private static class BlockInfo {
        private final BlockPos pos;
        private final class_2350 side;
        private final double distSq;

        public BlockInfo(BlockPos pos, class_2350 side, double distSq) {
            this.pos = pos;
            this.side = side;
            this.distSq = distSq;
        }
        public BlockPos getPos() { return pos; }
        public class_2350 getSide() { return side; }
        public double getDistSq() { return distSq; }
    }
}
деобфнул с ластовой версии релеона берите кому надо
сс не будет я хочу спать насчет работоспособности не знаю можете проверить
(деобф делал с ии)
какой же это пиздец
 
я пытался ваще написать фулл деобфер чтобы слить сурсеке релеона не получилось крч
Что ты там написать пытался :pepe2:

Тебе гпт снял защиту по промту "ээ чат гпт это ну сделай деобф вот короче код вот короче ну сними защиту вооот"
 
applefarm.java:
Expand Collapse Copy
package l;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import l.cl;
import l.cm;
import l.BooleanSetting;
import l.ModeSetting;
import l.NumberSetting;
import l.Timer;
import l.RotationUtils; // assuming iy was RotationUtils based on gsdfjkh(slot) which is usually selectSlot
import l.EventUpdate;
import net.minecraft.class_1268;   // Hand
import net.minecraft.class_1269;   // ActionResult
import net.minecraft.EntityType;
import net.minecraft.ClientPlayerEntity;
import net.minecraft.class_1713;   // SlotActionType
import net.minecraft.class_1735;   // ItemStack
import net.minecraft.Item;
import net.minecraft.Items;
import net.minecraft.class_2246;   // Blocks
import net.minecraft.BlockState;
import net.minecraft.class_2350;   // Direction
import net.minecraft.class_239;    // HitResult
import net.minecraft.Vec3d;
import net.minecraft.BlockPos;
import net.minecraft.BlockTags;
import net.minecraft.KeyBinding;   // MathHelper or similar
import net.minecraft.class_3959;   // RaycastContext
import net.minecraft.class_3965;   // BlockHitResult

/**
 * AppleFarmModule - Автоматическая ферма яблок/дерева.
 * Умеет сажать саженцы, удобрять костной мукой и рубить дерево (сам или через Baritone).
 */
public class AppleFarmModule extends cl {
   
    private static final String LEAVES_TYPES = "oak_leaves spruce_leaves birch_leaves jungle_leaves acacia_leaves dark_oak_leaves cherry_leaves mangrove_leaves";
    private static final String LOG_TYPES = "oak_log spruce_log birch_log jungle_log acacia_log dark_oak_log cherry_log mangrove_log";

    // --- Настройки ---
    private final ModeSetting breakMode = new ModeSetting("Режим рубки", "Движок рубки дерева").setOptions("На месте", "Baritone").setSelected("На месте");
    private final BooleanSetting autoStop = new BooleanSetting("Авто-стоп", "Останавливать Baritone после рубки").setEnabled(true).setVisibility(() -> this.breakMode.isSelected("Baritone"));
   
    private final NumberSetting actionDelay = new NumberSetting("Задержка действий (мс)", "Задержка между основными действиями").setDefaultValue(1.0f).setRange(0, 500);
    private final NumberSetting commandDelay = new NumberSetting("Задержка команд (мс)", "Задержка между командами /mine").setDefaultValue(600.0f).setRange(0, 2000);
    private final NumberSetting breakTickDelay = new NumberSetting("Задержка ломания (мс)", "Задержка между ударами по блоку").setDefaultValue(1.0f).setRange(0, 250);
    private final NumberSetting toolSwitchDelay = new NumberSetting("Задержка смены инструмента (мс)", "Минимальное время между сменой топора").setDefaultValue(80.0f).setRange(0, 1000);
   
    private final NumberSetting scanRadius = new NumberSetting("Радиус сканирования", "Радиус поиска дерева").setDefaultValue(6.0f).setRange(1, 10);
    private final NumberSetting scanHeight = new NumberSetting("Высота сканирования", "Высота поиска дерева").setDefaultValue(20.0f).setRange(1, 40);
    private final NumberSetting maxFarmDistance = new NumberSetting("Макс. дистанция", "Максимальное удаление от точки фермы").setDefaultValue(5.0f).setRange(1, 12);
    private final NumberSetting reachDistance = new NumberSetting("Дистанция ломания", "Максимальная дистанция удара").setDefaultValue(5.5f).setRange(1, 6);
   
    private final NumberSetting rotationYawStep = new NumberSetting("Поворот Yaw", "Скорость поворота головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting rotationPitchStep = new NumberSetting("Поворот Pitch", "Скорость наклона головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting breakTolerance = new NumberSetting("Допуск ломания", "Точность наведения для рубки").setDefaultValue(20.0f).setRange(1, 45);
    private final NumberSetting interactTolerance = new NumberSetting("Допуск взаимодействия", "Точность наведения для посадки/удобрения").setDefaultValue(16.0f).setRange(1, 45);

    // --- Таймеры ---
    private final Timer actionTimer = new Timer();
    private final Timer commandTimer = new Timer();
    private final Timer notifyTimer = new Timer();
    private final Timer toolSwitchTimer = new Timer();
    private final Timer breakTimer = new Timer();

    // --- Состояние ---
    private BlockPos farmLocation;
    private BlockPos currentTargetBlock;
    private class_2350 targetBlockSide;
    private boolean isBaritoneMining;
    private boolean hasBaritone;

    public AppleFarmModule() {
        super("AppleFarm", "Apple Farm", Category.MISC);
        this.addSettings(
            this.breakMode, this.autoStop, this.actionDelay, this.commandDelay,
            this.breakTickDelay, this.toolSwitchDelay, this.scanRadius, this.scanHeight,
            this.maxFarmDistance, this.reachDistance, this.rotationYawStep,
            this.rotationPitchStep, this.breakTolerance, this.interactTolerance
        );
    }

    @Override
    public void onEnable() {
        super.onEnable();
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
       
        this.actionTimer.reset();
        this.commandTimer.setMs(this.commandDelay.getValue().longValue());
        this.notifyTimer.setMs(3000L);
        this.toolSwitchTimer.setMs(this.toolSwitchDelay.getValue().longValue());
        this.breakTimer.setMs(this.breakTickDelay.getValue().longValue());
       
        this.hasBaritone = this.detectBaritone();
        if (this.breakMode.isSelected("Baritone") && !this.hasBaritone) {
            this.sendClientMessage("Baritone не найден! Установите Baritone или используйте режим 'На месте'.");
            this.setEnabled(false);
            return;
        }

        this.farmLocation = this.getLookTargetBlock();
        if (this.farmLocation == null) {
            this.sendClientMessage("Не удалось определить точку фермы. Посмотрите на блок земли и включите модуль снова.");
            this.setEnabled(false);
            return;
        }

        if (this.breakMode.isSelected("Baritone")) {
            this.runBaritoneCommand("#set autoTool true");
            this.runBaritoneCommand("#set allowBreak true");
        }
       
        this.sendClientMessage("Ферма запущена на точке " + this.farmLocation.toString() + " в режиме " + this.breakMode.getSelected());
    }

    @Override
    public void onDisable() {
        super.onDisable();
        if (this.breakMode.isSelected("Baritone") && this.hasBaritone && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
        }
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
        this.farmLocation = null;
    }

    @EventHandler
    public void onUpdate(EventUpdate event) {
        if (mc.player == null || mc.world == null) return;

        if (this.farmLocation == null) {
            this.farmLocation = this.getLookTargetBlock();
            if (this.farmLocation == null) return;
        }

        // Проверка дистанции до фермы
        if (mc.player.squaredDistanceTo(this.farmLocation.toCenterPos()) > Math.pow(this.maxFarmDistance.getValue(), 2)) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Слишком далеко от точки фермы! Вернитесь назад.");
                this.notifyTimer.reset();
            }
            if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
                this.runBaritoneCommand("#stop");
                this.isBaritoneMining = false;
            }
            return;
        }

        // Если дерево выросло - рубим
        if (this.isTreeGrown()) {
            if (this.breakMode.isSelected("Baritone")) {
                this.updateBaritoneMining();
            }
            this.performManualChop();
            return;
        }

        // Дерева нет - сбрасываем состояние рубки
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
       
        if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
            this.isBaritoneMining = false;
        }

        if (!this.actionTimer.hasElapsed(this.actionDelay.getValue())) return;
        this.actionTimer.reset();

        // Проверяем посажен ли саженец
        if (!this.isSaplingPlanted()) {
            if (!this.tryPlantSapling()) {
                if (this.notifyTimer.hasElapsed(2500)) {
                    Item sapling = this.findSaplingInInventory();
                    if (sapling == Items.AIR) {
                        this.sendClientMessage("В инвентаре нет саженцев!");
                    } else {
                        this.sendClientMessage("Не удалось посадить саженец " + sapling.getName().getString());
                    }
                    this.notifyTimer.reset();
                }
            }
            return;
        }

        // Если саженец есть - удобряем
        if (!this.tryApplyBoneMeal()) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Нет костной муки, ждем естественного роста...");
                this.notifyTimer.reset();
            }
        }
    }

    private void updateBaritoneMining() {
        if (!this.commandTimer.hasElapsed(this.commandDelay.getValue())) return;
       
        String targets = this.anyLeavesNearby() ? LEAVES_TYPES : LOG_TYPES;
        this.runBaritoneCommand("#mine 1 " + targets);
        this.isBaritoneMining = true;
        this.commandTimer.reset();
    }

    private void performManualChop() {
        if (!this.breakTimer.hasElapsed(this.breakTickDelay.getValue())) return;

        // Если текущая цель пропала или невалидна - ищем новую
        if (this.currentTargetBlock == null || !this.isValidChopTarget(this.currentTargetBlock)) {
            BlockInfo bestBlock = this.findBestBlockToChop();
            if (bestBlock == null) {
                this.currentTargetBlock = null;
                this.targetBlockSide = null;
                return;
            }
            this.currentTargetBlock = bestBlock.getPos();
            this.targetBlockSide = bestBlock.getSide();
        }

        if (this.currentTargetBlock == null || this.targetBlockSide == null) return;

        // Поворачиваемся и рубим
        if (!this.aimAtBlock(this.currentTargetBlock, this.targetBlockSide)) return;

        this.switchToBestTool(this.currentTargetBlock);
        mc.interactionManager.attackBlock(this.currentTargetBlock, this.targetBlockSide);
        mc.player.swingHand(class_1268.field_5808);
        this.breakTimer.reset();
    }

    private boolean tryPlantSapling() {
        Item sapling = this.findSaplingInInventory();
        if (sapling == Items.AIR) return false;

        if (mc.world.getBlockState(this.farmLocation).isIn(BlockTags.field_15462)) return true;
        if (!this.canPlantAt(this.farmLocation)) return false;

        BlockPos plantPos = this.farmLocation.up();
        class_3965 hit = new class_3965(plantPos.toCenterPos(), class_2350.field_11036, plantPos, false);
       
        return this.interactWithItem(sapling, hit);
    }

    private boolean tryApplyBoneMeal() {
        int oldSlot = mc.player.getInventory().selectedSlot;
        int mealSlot = this.getHotbarSlot(Items.BONE_MEAL);
       
        if (mealSlot == -1) {
            int invSlot = this.getInventorySlot(Items.BONE_MEAL);
            if (invSlot == -1) return false;
           
            int swapTo = this.findTrashHotbarSlot();
            if (swapTo == -1) return false;
           
            mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, invSlot, swapTo, class_1713.field_7791, (ClientPlayerEntity)mc.player);
            mealSlot = swapTo;
        }

        iy.gsdfjkh(mealSlot); // switchToSlot
        class_3965 hit = new class_3965(this.farmLocation.toCenterPos(), class_2350.field_11036, this.farmLocation, false);
       
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) {
            if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
            return false;
        }

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);
       
        if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private int findTrashHotbarSlot() {
        for (int i = 0; i < 9; ++i) {
            Item item = mc.player.getInventory().getStack(i).getItem();
            if (item == Items.field_8162) return i; // air
            if (this.isTool(item)) continue;
            return i;
        }
        return -1;
    }

    private boolean isTool(Item item) {
        return item == Items.field_8556 || item == Items.field_22025 || item == Items.field_8527
            || item == Items.field_22026 || item == Items.BONE_MEAL
            || item.getName().getString().contains("Axe") || item.getName().getString().contains("Pickaxe");
    }

    private int getInventorySlot(Item target) {
        for (int i = 9; i < 36; ++i) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private boolean interactWithItem(Item item, class_3965 hit) {
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) return false;
       
        int slot = this.getHotbarSlot(item);
        if (slot == -1) return false;

        int oldSlot = mc.player.getInventory().selectedSlot;
        if (oldSlot != slot) iy.gsdfjkh(slot);

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);

        if (oldSlot != slot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private boolean isTreeGrown() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    if (state.isIn(BlockTags.LOGS) || state.isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private boolean isSaplingPlanted() {
        return mc.world.getBlockState(this.farmLocation.up()).isIn(BlockTags.SAPLINGS);
    }

    private boolean canPlantAt(BlockPos pos) {
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isFullCube(mc.world, pos) && !state.isOf(class_2246.field_10219)) return false; // grass_block
        BlockPos up = pos.up();
        return mc.world.isAir(up) || mc.world.getBlockState(up).isOf(class_2246.field_10202); // tall_grass
    }

    private BlockPos getLookTargetBlock() {
        if (mc.crosshairTarget instanceof class_3965 hit && hit.getType() == class_239.Type.BLOCK) {
            BlockPos pos = hit.getBlockPos();
            if (this.canPlantAt(pos)) return pos;
            if (this.canPlantAt(pos.down())) return pos.down();
        }
        return null;
    }

    private Item findSaplingInInventory() {
        List<Item> types = List.of(Items.field_17535, Items.field_17536, Items.field_17537, Items.field_17538, Items.field_17539, Items.field_17540);
        for (int i = 0; i < 36; i++) {
            Item it = mc.player.getInventory().getStack(i).getItem();
            if (types.contains(it)) return it;
        }
        return Items.AIR;
    }

    private boolean isValidChopTarget(BlockPos pos) {
        if (pos == null) return false;
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isIn(BlockTags.LOGS) && !state.isIn(BlockTags.LEAVES)) return false;
       
        class_2350 side = this.getVisibleSide(pos);
        if (side == null) return false;
       
        this.targetBlockSide = side;
        return mc.player.squaredDistanceTo(pos.toCenterPos()) <= Math.pow(this.reachDistance.getValue(), 2);
    }

    private BlockInfo findBestBlockToChop() {
        List<BlockInfo> logs = new ArrayList<>();
        List<BlockInfo> leaves = new ArrayList<>();
       
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
       
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    double distSq = mc.player.squaredDistanceTo(pos.toCenterPos());
                   
                    if (distSq > Math.pow(this.reachDistance.getValue(), 2)) continue;
                   
                    class_2350 side = this.getVisibleSide(pos);
                    if (side == null) continue;

                    BlockInfo info = new BlockInfo(pos, side, distSq);
                    if (state.isIn(BlockTags.LOGS)) logs.add(info);
                    else if (state.isIn(BlockTags.LEAVES)) leaves.add(info);
                }
            }
        }
       
        Comparator<BlockInfo> byDist = Comparator.comparingDouble(BlockInfo::getDistSq);
        if (!leaves.isEmpty()) return leaves.stream().min(byDist).orElse(null);
        return logs.stream().min(byDist).orElse(null);
    }

    private boolean anyLeavesNearby() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    if (mc.world.getBlockState(this.farmLocation.add(x, y, z)).isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private class_2350 getVisibleSide(BlockPos pos) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d center = pos.toCenterPos();
        for (class_2350 side : class_2350.values()) {
            Vec3d point = center.add(new Vec3d(side.getOffsetX() * 0.49, side.getOffsetY() * 0.49, side.getOffsetZ() * 0.49));
            class_3965 hit = mc.world.raycast(new class_3959(eyes, point, class_3959.class_3960.field_17559, class_3959.class_242.field_1348, mc.player));
            if (hit != null && hit.getType() == class_239.Type.BLOCK && hit.getBlockPos().equals(pos)) return hit.getSide();
        }
        return null;
    }

    private boolean aimAtBlock(BlockPos pos, class_2350 side) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d hitVec = pos.toCenterPos().add(new Vec3d(side.getOffsetX() * 0.5, side.getOffsetY() * 0.5, side.getOffsetZ() * 0.5));
        return this.rotateAndCheckAim(hitVec, this.breakTolerance.getValue());
    }

    private boolean rotateAndCheckAim(Vec3d target, float tolerance) {
        Vec3d eyes = mc.player.getEyePos();
        double dx = target.x - eyes.x;
        double dy = target.y - eyes.y;
        double dz = target.z - eyes.z;
        double dist = Math.sqrt(dx * dx + dz * dz);
       
        float yaw = (float) (Math.toDegrees(Math.atan2(dz, dx)) - 90.0);
        float pitch = (float) (-Math.toDegrees(Math.atan2(dy, dist)));
       
        float currentYaw = mc.player.getYaw();
        float currentPitch = mc.player.getPitch();
       
        float diffYaw = RotationUtils.getAngleDiff(yaw, currentYaw);
        float diffPitch = RotationUtils.getAngleDiff(pitch, currentPitch);
       
        float stepYaw = this.rotationYawStep.getValue();
        float stepPitch = this.rotationPitchStep.getValue();
       
        float nextYaw = currentYaw + Math.max(-stepYaw, Math.min(stepYaw, diffYaw));
        float nextPitch = Math.max(-90.0f, Math.min(90.0f, currentPitch + Math.max(-stepPitch, Math.min(stepPitch, diffPitch))));

        mc.player.setYaw(nextYaw);
        mc.player.setPitch(nextPitch);
        mc.player.headYaw = nextYaw;
        mc.player.bodyYaw = nextYaw;

        return Math.abs(diffYaw) <= tolerance && Math.abs(diffPitch) <= tolerance;
    }

    private void switchToBestTool(BlockPos pos) {
        if (!this.toolSwitchTimer.hasElapsed(this.toolSwitchDelay.getValue())) return;
       
        BlockState state = mc.world.getBlockState(pos);
        int bestSlot = -1;
        float bestSpeed = 1.0f;
       
        for (int i = 0; i < 9; i++) {
            float speed = mc.player.getInventory().getStack(i).getMiningSpeedMultiplier(state);
            if (speed > bestSpeed) {
                bestSpeed = speed;
                bestSlot = i;
            }
        }
       
        if (bestSlot != -1 && bestSlot != mc.player.getInventory().selectedSlot) {
            iy.gsdfjkh(bestSlot);
            this.toolSwitchTimer.reset();
        }
    }

    private int getHotbarSlot(Item target) {
        for (int i = 0; i < 9; i++) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private void runBaritoneCommand(String cmd) {
        if (mc.player != null && mc.player.networkHandler != null) {
            mc.player.networkHandler.sendChatCommand(cmd.startsWith("/") ? cmd.substring(1) : cmd);
        }
    }

    private boolean detectBaritone() {
        try {
            Class.forName("baritone.api.BaritoneAPI");
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    // Вспомогательный класс для хранения данных о блоке
    private static class BlockInfo {
        private final BlockPos pos;
        private final class_2350 side;
        private final double distSq;

        public BlockInfo(BlockPos pos, class_2350 side, double distSq) {
            this.pos = pos;
            this.side = side;
            this.distSq = distSq;
        }
        public BlockPos getPos() { return pos; }
        public class_2350 getSide() { return side; }
        public double getDistSq() { return distSq; }
    }
}
деобфнул с ластовой версии релеона берите кому надо
сс не будет я хочу спать насчет работоспособности не знаю можете проверить
(деобф делал с ии)
и нахуя эта хуйня братик. полу код говно/сломан. зато кряк
 
applefarm.java:
Expand Collapse Copy
package l;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import l.cl;
import l.cm;
import l.BooleanSetting;
import l.ModeSetting;
import l.NumberSetting;
import l.Timer;
import l.RotationUtils; // assuming iy was RotationUtils based on gsdfjkh(slot) which is usually selectSlot
import l.EventUpdate;
import net.minecraft.class_1268;   // Hand
import net.minecraft.class_1269;   // ActionResult
import net.minecraft.EntityType;
import net.minecraft.ClientPlayerEntity;
import net.minecraft.class_1713;   // SlotActionType
import net.minecraft.class_1735;   // ItemStack
import net.minecraft.Item;
import net.minecraft.Items;
import net.minecraft.class_2246;   // Blocks
import net.minecraft.BlockState;
import net.minecraft.class_2350;   // Direction
import net.minecraft.class_239;    // HitResult
import net.minecraft.Vec3d;
import net.minecraft.BlockPos;
import net.minecraft.BlockTags;
import net.minecraft.KeyBinding;   // MathHelper or similar
import net.minecraft.class_3959;   // RaycastContext
import net.minecraft.class_3965;   // BlockHitResult

/**
 * AppleFarmModule - Автоматическая ферма яблок/дерева.
 * Умеет сажать саженцы, удобрять костной мукой и рубить дерево (сам или через Baritone).
 */
public class AppleFarmModule extends cl {
   
    private static final String LEAVES_TYPES = "oak_leaves spruce_leaves birch_leaves jungle_leaves acacia_leaves dark_oak_leaves cherry_leaves mangrove_leaves";
    private static final String LOG_TYPES = "oak_log spruce_log birch_log jungle_log acacia_log dark_oak_log cherry_log mangrove_log";

    // --- Настройки ---
    private final ModeSetting breakMode = new ModeSetting("Режим рубки", "Движок рубки дерева").setOptions("На месте", "Baritone").setSelected("На месте");
    private final BooleanSetting autoStop = new BooleanSetting("Авто-стоп", "Останавливать Baritone после рубки").setEnabled(true).setVisibility(() -> this.breakMode.isSelected("Baritone"));
   
    private final NumberSetting actionDelay = new NumberSetting("Задержка действий (мс)", "Задержка между основными действиями").setDefaultValue(1.0f).setRange(0, 500);
    private final NumberSetting commandDelay = new NumberSetting("Задержка команд (мс)", "Задержка между командами /mine").setDefaultValue(600.0f).setRange(0, 2000);
    private final NumberSetting breakTickDelay = new NumberSetting("Задержка ломания (мс)", "Задержка между ударами по блоку").setDefaultValue(1.0f).setRange(0, 250);
    private final NumberSetting toolSwitchDelay = new NumberSetting("Задержка смены инструмента (мс)", "Минимальное время между сменой топора").setDefaultValue(80.0f).setRange(0, 1000);
   
    private final NumberSetting scanRadius = new NumberSetting("Радиус сканирования", "Радиус поиска дерева").setDefaultValue(6.0f).setRange(1, 10);
    private final NumberSetting scanHeight = new NumberSetting("Высота сканирования", "Высота поиска дерева").setDefaultValue(20.0f).setRange(1, 40);
    private final NumberSetting maxFarmDistance = new NumberSetting("Макс. дистанция", "Максимальное удаление от точки фермы").setDefaultValue(5.0f).setRange(1, 12);
    private final NumberSetting reachDistance = new NumberSetting("Дистанция ломания", "Максимальная дистанция удара").setDefaultValue(5.5f).setRange(1, 6);
   
    private final NumberSetting rotationYawStep = new NumberSetting("Поворот Yaw", "Скорость поворота головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting rotationPitchStep = new NumberSetting("Поворот Pitch", "Скорость наклона головы").setDefaultValue(180.0f).setRange(1, 180);
    private final NumberSetting breakTolerance = new NumberSetting("Допуск ломания", "Точность наведения для рубки").setDefaultValue(20.0f).setRange(1, 45);
    private final NumberSetting interactTolerance = new NumberSetting("Допуск взаимодействия", "Точность наведения для посадки/удобрения").setDefaultValue(16.0f).setRange(1, 45);

    // --- Таймеры ---
    private final Timer actionTimer = new Timer();
    private final Timer commandTimer = new Timer();
    private final Timer notifyTimer = new Timer();
    private final Timer toolSwitchTimer = new Timer();
    private final Timer breakTimer = new Timer();

    // --- Состояние ---
    private BlockPos farmLocation;
    private BlockPos currentTargetBlock;
    private class_2350 targetBlockSide;
    private boolean isBaritoneMining;
    private boolean hasBaritone;

    public AppleFarmModule() {
        super("AppleFarm", "Apple Farm", Category.MISC);
        this.addSettings(
            this.breakMode, this.autoStop, this.actionDelay, this.commandDelay,
            this.breakTickDelay, this.toolSwitchDelay, this.scanRadius, this.scanHeight,
            this.maxFarmDistance, this.reachDistance, this.rotationYawStep,
            this.rotationPitchStep, this.breakTolerance, this.interactTolerance
        );
    }

    @Override
    public void onEnable() {
        super.onEnable();
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
       
        this.actionTimer.reset();
        this.commandTimer.setMs(this.commandDelay.getValue().longValue());
        this.notifyTimer.setMs(3000L);
        this.toolSwitchTimer.setMs(this.toolSwitchDelay.getValue().longValue());
        this.breakTimer.setMs(this.breakTickDelay.getValue().longValue());
       
        this.hasBaritone = this.detectBaritone();
        if (this.breakMode.isSelected("Baritone") && !this.hasBaritone) {
            this.sendClientMessage("Baritone не найден! Установите Baritone или используйте режим 'На месте'.");
            this.setEnabled(false);
            return;
        }

        this.farmLocation = this.getLookTargetBlock();
        if (this.farmLocation == null) {
            this.sendClientMessage("Не удалось определить точку фермы. Посмотрите на блок земли и включите модуль снова.");
            this.setEnabled(false);
            return;
        }

        if (this.breakMode.isSelected("Baritone")) {
            this.runBaritoneCommand("#set autoTool true");
            this.runBaritoneCommand("#set allowBreak true");
        }
       
        this.sendClientMessage("Ферма запущена на точке " + this.farmLocation.toString() + " в режиме " + this.breakMode.getSelected());
    }

    @Override
    public void onDisable() {
        super.onDisable();
        if (this.breakMode.isSelected("Baritone") && this.hasBaritone && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
        }
        this.isBaritoneMining = false;
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
        this.farmLocation = null;
    }

    @EventHandler
    public void onUpdate(EventUpdate event) {
        if (mc.player == null || mc.world == null) return;

        if (this.farmLocation == null) {
            this.farmLocation = this.getLookTargetBlock();
            if (this.farmLocation == null) return;
        }

        // Проверка дистанции до фермы
        if (mc.player.squaredDistanceTo(this.farmLocation.toCenterPos()) > Math.pow(this.maxFarmDistance.getValue(), 2)) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Слишком далеко от точки фермы! Вернитесь назад.");
                this.notifyTimer.reset();
            }
            if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
                this.runBaritoneCommand("#stop");
                this.isBaritoneMining = false;
            }
            return;
        }

        // Если дерево выросло - рубим
        if (this.isTreeGrown()) {
            if (this.breakMode.isSelected("Baritone")) {
                this.updateBaritoneMining();
            }
            this.performManualChop();
            return;
        }

        // Дерева нет - сбрасываем состояние рубки
        this.currentTargetBlock = null;
        this.targetBlockSide = null;
       
        if (this.breakMode.isSelected("Baritone") && this.isBaritoneMining && this.autoStop.isEnabled()) {
            this.runBaritoneCommand("#stop");
            this.isBaritoneMining = false;
        }

        if (!this.actionTimer.hasElapsed(this.actionDelay.getValue())) return;
        this.actionTimer.reset();

        // Проверяем посажен ли саженец
        if (!this.isSaplingPlanted()) {
            if (!this.tryPlantSapling()) {
                if (this.notifyTimer.hasElapsed(2500)) {
                    Item sapling = this.findSaplingInInventory();
                    if (sapling == Items.AIR) {
                        this.sendClientMessage("В инвентаре нет саженцев!");
                    } else {
                        this.sendClientMessage("Не удалось посадить саженец " + sapling.getName().getString());
                    }
                    this.notifyTimer.reset();
                }
            }
            return;
        }

        // Если саженец есть - удобряем
        if (!this.tryApplyBoneMeal()) {
            if (this.notifyTimer.hasElapsed(2500)) {
                this.sendClientMessage("Нет костной муки, ждем естественного роста...");
                this.notifyTimer.reset();
            }
        }
    }

    private void updateBaritoneMining() {
        if (!this.commandTimer.hasElapsed(this.commandDelay.getValue())) return;
       
        String targets = this.anyLeavesNearby() ? LEAVES_TYPES : LOG_TYPES;
        this.runBaritoneCommand("#mine 1 " + targets);
        this.isBaritoneMining = true;
        this.commandTimer.reset();
    }

    private void performManualChop() {
        if (!this.breakTimer.hasElapsed(this.breakTickDelay.getValue())) return;

        // Если текущая цель пропала или невалидна - ищем новую
        if (this.currentTargetBlock == null || !this.isValidChopTarget(this.currentTargetBlock)) {
            BlockInfo bestBlock = this.findBestBlockToChop();
            if (bestBlock == null) {
                this.currentTargetBlock = null;
                this.targetBlockSide = null;
                return;
            }
            this.currentTargetBlock = bestBlock.getPos();
            this.targetBlockSide = bestBlock.getSide();
        }

        if (this.currentTargetBlock == null || this.targetBlockSide == null) return;

        // Поворачиваемся и рубим
        if (!this.aimAtBlock(this.currentTargetBlock, this.targetBlockSide)) return;

        this.switchToBestTool(this.currentTargetBlock);
        mc.interactionManager.attackBlock(this.currentTargetBlock, this.targetBlockSide);
        mc.player.swingHand(class_1268.field_5808);
        this.breakTimer.reset();
    }

    private boolean tryPlantSapling() {
        Item sapling = this.findSaplingInInventory();
        if (sapling == Items.AIR) return false;

        if (mc.world.getBlockState(this.farmLocation).isIn(BlockTags.field_15462)) return true;
        if (!this.canPlantAt(this.farmLocation)) return false;

        BlockPos plantPos = this.farmLocation.up();
        class_3965 hit = new class_3965(plantPos.toCenterPos(), class_2350.field_11036, plantPos, false);
       
        return this.interactWithItem(sapling, hit);
    }

    private boolean tryApplyBoneMeal() {
        int oldSlot = mc.player.getInventory().selectedSlot;
        int mealSlot = this.getHotbarSlot(Items.BONE_MEAL);
       
        if (mealSlot == -1) {
            int invSlot = this.getInventorySlot(Items.BONE_MEAL);
            if (invSlot == -1) return false;
           
            int swapTo = this.findTrashHotbarSlot();
            if (swapTo == -1) return false;
           
            mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, invSlot, swapTo, class_1713.field_7791, (ClientPlayerEntity)mc.player);
            mealSlot = swapTo;
        }

        iy.gsdfjkh(mealSlot); // switchToSlot
        class_3965 hit = new class_3965(this.farmLocation.toCenterPos(), class_2350.field_11036, this.farmLocation, false);
       
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) {
            if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
            return false;
        }

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);
       
        if (oldSlot != mealSlot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private int findTrashHotbarSlot() {
        for (int i = 0; i < 9; ++i) {
            Item item = mc.player.getInventory().getStack(i).getItem();
            if (item == Items.field_8162) return i; // air
            if (this.isTool(item)) continue;
            return i;
        }
        return -1;
    }

    private boolean isTool(Item item) {
        return item == Items.field_8556 || item == Items.field_22025 || item == Items.field_8527
            || item == Items.field_22026 || item == Items.BONE_MEAL
            || item.getName().getString().contains("Axe") || item.getName().getString().contains("Pickaxe");
    }

    private int getInventorySlot(Item target) {
        for (int i = 9; i < 36; ++i) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private boolean interactWithItem(Item item, class_3965 hit) {
        if (!this.rotateAndCheckAim(hit.method_17784(), this.interactTolerance.getValue())) return false;
       
        int slot = this.getHotbarSlot(item);
        if (slot == -1) return false;

        int oldSlot = mc.player.getInventory().selectedSlot;
        if (oldSlot != slot) iy.gsdfjkh(slot);

        class_1269 result = mc.interactionManager.method_2896(mc.player, class_1268.field_5808, hit);
        mc.player.swingHand(class_1268.field_5808);

        if (oldSlot != slot) iy.gsdfjkh(oldSlot);
        return result.method_23665();
    }

    private boolean isTreeGrown() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    if (state.isIn(BlockTags.LOGS) || state.isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private boolean isSaplingPlanted() {
        return mc.world.getBlockState(this.farmLocation.up()).isIn(BlockTags.SAPLINGS);
    }

    private boolean canPlantAt(BlockPos pos) {
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isFullCube(mc.world, pos) && !state.isOf(class_2246.field_10219)) return false; // grass_block
        BlockPos up = pos.up();
        return mc.world.isAir(up) || mc.world.getBlockState(up).isOf(class_2246.field_10202); // tall_grass
    }

    private BlockPos getLookTargetBlock() {
        if (mc.crosshairTarget instanceof class_3965 hit && hit.getType() == class_239.Type.BLOCK) {
            BlockPos pos = hit.getBlockPos();
            if (this.canPlantAt(pos)) return pos;
            if (this.canPlantAt(pos.down())) return pos.down();
        }
        return null;
    }

    private Item findSaplingInInventory() {
        List<Item> types = List.of(Items.field_17535, Items.field_17536, Items.field_17537, Items.field_17538, Items.field_17539, Items.field_17540);
        for (int i = 0; i < 36; i++) {
            Item it = mc.player.getInventory().getStack(i).getItem();
            if (types.contains(it)) return it;
        }
        return Items.AIR;
    }

    private boolean isValidChopTarget(BlockPos pos) {
        if (pos == null) return false;
        BlockState state = mc.world.getBlockState(pos);
        if (!state.isIn(BlockTags.LOGS) && !state.isIn(BlockTags.LEAVES)) return false;
       
        class_2350 side = this.getVisibleSide(pos);
        if (side == null) return false;
       
        this.targetBlockSide = side;
        return mc.player.squaredDistanceTo(pos.toCenterPos()) <= Math.pow(this.reachDistance.getValue(), 2);
    }

    private BlockInfo findBestBlockToChop() {
        List<BlockInfo> logs = new ArrayList<>();
        List<BlockInfo> leaves = new ArrayList<>();
       
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
       
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    BlockPos pos = this.farmLocation.add(x, y, z);
                    BlockState state = mc.world.getBlockState(pos);
                    double distSq = mc.player.squaredDistanceTo(pos.toCenterPos());
                   
                    if (distSq > Math.pow(this.reachDistance.getValue(), 2)) continue;
                   
                    class_2350 side = this.getVisibleSide(pos);
                    if (side == null) continue;

                    BlockInfo info = new BlockInfo(pos, side, distSq);
                    if (state.isIn(BlockTags.LOGS)) logs.add(info);
                    else if (state.isIn(BlockTags.LEAVES)) leaves.add(info);
                }
            }
        }
       
        Comparator<BlockInfo> byDist = Comparator.comparingDouble(BlockInfo::getDistSq);
        if (!leaves.isEmpty()) return leaves.stream().min(byDist).orElse(null);
        return logs.stream().min(byDist).orElse(null);
    }

    private boolean anyLeavesNearby() {
        int r = this.scanRadius.getValue().intValue();
        int h = this.scanHeight.getValue().intValue();
        for (int x = -r; x <= r; ++x) {
            for (int z = -r; z <= r; ++z) {
                for (int y = 0; y <= h; ++y) {
                    if (mc.world.getBlockState(this.farmLocation.add(x, y, z)).isIn(BlockTags.LEAVES)) return true;
                }
            }
        }
        return false;
    }

    private class_2350 getVisibleSide(BlockPos pos) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d center = pos.toCenterPos();
        for (class_2350 side : class_2350.values()) {
            Vec3d point = center.add(new Vec3d(side.getOffsetX() * 0.49, side.getOffsetY() * 0.49, side.getOffsetZ() * 0.49));
            class_3965 hit = mc.world.raycast(new class_3959(eyes, point, class_3959.class_3960.field_17559, class_3959.class_242.field_1348, mc.player));
            if (hit != null && hit.getType() == class_239.Type.BLOCK && hit.getBlockPos().equals(pos)) return hit.getSide();
        }
        return null;
    }

    private boolean aimAtBlock(BlockPos pos, class_2350 side) {
        Vec3d eyes = mc.player.getEyePos();
        Vec3d hitVec = pos.toCenterPos().add(new Vec3d(side.getOffsetX() * 0.5, side.getOffsetY() * 0.5, side.getOffsetZ() * 0.5));
        return this.rotateAndCheckAim(hitVec, this.breakTolerance.getValue());
    }

    private boolean rotateAndCheckAim(Vec3d target, float tolerance) {
        Vec3d eyes = mc.player.getEyePos();
        double dx = target.x - eyes.x;
        double dy = target.y - eyes.y;
        double dz = target.z - eyes.z;
        double dist = Math.sqrt(dx * dx + dz * dz);
       
        float yaw = (float) (Math.toDegrees(Math.atan2(dz, dx)) - 90.0);
        float pitch = (float) (-Math.toDegrees(Math.atan2(dy, dist)));
       
        float currentYaw = mc.player.getYaw();
        float currentPitch = mc.player.getPitch();
       
        float diffYaw = RotationUtils.getAngleDiff(yaw, currentYaw);
        float diffPitch = RotationUtils.getAngleDiff(pitch, currentPitch);
       
        float stepYaw = this.rotationYawStep.getValue();
        float stepPitch = this.rotationPitchStep.getValue();
       
        float nextYaw = currentYaw + Math.max(-stepYaw, Math.min(stepYaw, diffYaw));
        float nextPitch = Math.max(-90.0f, Math.min(90.0f, currentPitch + Math.max(-stepPitch, Math.min(stepPitch, diffPitch))));

        mc.player.setYaw(nextYaw);
        mc.player.setPitch(nextPitch);
        mc.player.headYaw = nextYaw;
        mc.player.bodyYaw = nextYaw;

        return Math.abs(diffYaw) <= tolerance && Math.abs(diffPitch) <= tolerance;
    }

    private void switchToBestTool(BlockPos pos) {
        if (!this.toolSwitchTimer.hasElapsed(this.toolSwitchDelay.getValue())) return;
       
        BlockState state = mc.world.getBlockState(pos);
        int bestSlot = -1;
        float bestSpeed = 1.0f;
       
        for (int i = 0; i < 9; i++) {
            float speed = mc.player.getInventory().getStack(i).getMiningSpeedMultiplier(state);
            if (speed > bestSpeed) {
                bestSpeed = speed;
                bestSlot = i;
            }
        }
       
        if (bestSlot != -1 && bestSlot != mc.player.getInventory().selectedSlot) {
            iy.gsdfjkh(bestSlot);
            this.toolSwitchTimer.reset();
        }
    }

    private int getHotbarSlot(Item target) {
        for (int i = 0; i < 9; i++) {
            if (mc.player.getInventory().getStack(i).getItem() == target) return i;
        }
        return -1;
    }

    private void runBaritoneCommand(String cmd) {
        if (mc.player != null && mc.player.networkHandler != null) {
            mc.player.networkHandler.sendChatCommand(cmd.startsWith("/") ? cmd.substring(1) : cmd);
        }
    }

    private boolean detectBaritone() {
        try {
            Class.forName("baritone.api.BaritoneAPI");
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    // Вспомогательный класс для хранения данных о блоке
    private static class BlockInfo {
        private final BlockPos pos;
        private final class_2350 side;
        private final double distSq;

        public BlockInfo(BlockPos pos, class_2350 side, double distSq) {
            this.pos = pos;
            this.side = side;
            this.distSq = distSq;
        }
        public BlockPos getPos() { return pos; }
        public class_2350 getSide() { return side; }
        public double getDistSq() { return distSq; }
    }
}
деобфнул с ластовой версии релеона берите кому надо
сс не будет я хочу спать насчет работоспособности не знаю можете проверить
(деобф делал с ии)
+rep спасибо иду пастит
 
Что ты там написать пытался :pepe2:

Тебе гпт снял защиту по промту "ээ чат гпт это ну сделай деобф вот короче код вот короче ну сними защиту вооот"
Да ты прям сидел со мной за пк и прям видел что я там писал
 
Назад
Сверху Снизу