Начинающий
- Статус
- Оффлайн
- Регистрация
- 26 Янв 2025
- Сообщения
- 28
- Реакции
- 0
- Выберите загрузчик игры
- Fabric
applefarm.java:
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; }
}
}
сс не будет я хочу спать насчет работоспособности не знаю можете проверить
(деобф делал с ии)
