Загрузка данных


import pyautogui
import keyboard
import time
import threading
import random

# Отключаем защитный механизм pyautogui (чтобы мышь могла уходить в край экрана)
pyautogui.FAILSAFE = False

class ParkourBot:
    def __init__(self):
        self.running = False
        self.block_found = False
        self.current_pitch = 0  # Текущий наклон головы (вниз)
        self.min_pitch = 15     # Максимальный наклон вниз (в пикселях движения мыши)
        self.step_down = 2      # Шаг опускания головы за раз
        self.scan_speed = 20    # Скорость горизонтального сканирования (пикселей за шаг)
        
        # Цвета блоков для детекции: 
        # 1. Темно-красный/бордовый (143, 58, 47)
        # 2. Кирпичный/красный (178, 74, 58)
        # 3. Близкие оттенки (добавлены похожие цвета)
        self.block_colors = [
            (143, 58, 47),   # Основной темный красный
            (178, 74, 58),   # Основной кирпичный
            (150, 60, 50),   # Промежуточный темный
            (170, 70, 55),   # Промежуточный светлый
            (160, 65, 52),   # Средний оттенок
            (185, 80, 60),   # Более светлый
            (140, 55, 45),   # Более темный
            (190, 75, 62),   # Светлый вариант
        ]
        
    def find_block(self):
        """Сканирует экран на наличие блока"""
        try:
            screenshot = pyautogui.screenshot()
            width, height = screenshot.size
            
            # Ищем в центральной области экрана (крест прицела)
            center_x = width // 2
            center_y = height // 2
            search_radius = 80  # Радиус поиска вокруг центра
            
            # Сначала проверяем центр (самое вероятное место)
            pixel = screenshot.getpixel((center_x, center_y))
            for block_color in self.block_colors:
                if self.color_similar(pixel, block_color, 25):
                    return True, (center_x, center_y)
            
            # Затем сканируем область вокруг
            for y in range(center_y - search_radius, center_y + search_radius, 8):
                for x in range(center_x - search_radius, center_x + search_radius, 8):
                    try:
                        pixel = screenshot.getpixel((x, y))
                        for block_color in self.block_colors:
                            if self.color_similar(pixel, block_color, 25):
                                return True, (x, y)
                    except:
                        continue
            
            return False, None
        except Exception as e:
            print(f"Ошибка при поиске блока: {e}")
            return False, None
    
    def color_similar(self, color1, color2, tolerance):
        """Проверяет схожесть цветов"""
        return (abs(color1[0] - color2[0]) < tolerance and
                abs(color1[1] - color2[1]) < tolerance and
                abs(color1[2] - color2[2]) < tolerance)
    
    def rotate_head_horizontal(self):
        """Плавный поворот головы по горизонтали на 360 градусов"""
        print("Сканирую по горизонтали...")
        
        # В Minecraft чувствительность обычно такая, что 50 пикселей = ~360 градусов
        # Делаем несколько проходов вправо
        for _ in range(3):  # 3 полных оборота
            if not self.running:
                break
            
            # Двигаем мышь вправо плавно
            for i in range(0, 180, self.scan_speed):
                if not self.running:
                    break
                
                # Используем moveTo с абсолютными координатами для более точного контроля
                pyautogui.moveRel(self.scan_speed, 0, duration=0.02)
                time.sleep(0.01)
                
                # Проверяем блок во время движения
                found, block_pos = self.find_block()
                if found:
                    self.block_found = True
                    print(f"Блок обнаружен при сканировании!")
                    return True
        
        return False
    
    def look_down(self):
        """Опускает голову немного вниз"""
        if self.current_pitch < self.min_pitch:
            pyautogui.moveRel(0, self.step_down, duration=0.05)
            self.current_pitch += self.step_down
            print(f"Опускаю голову. Наклон: {self.current_pitch}")
    
    def reset_head_position(self):
        """Возвращает голову в исходное положение"""
        if self.current_pitch > 0:
            pyautogui.moveRel(0, -self.current_pitch, duration=0.1)
            self.current_pitch = 0
            print("Голова возвращена в исходное положение")
    
    def calculate_jump(self, block_pos):
        """Рассчитывает тип прыжка в зависимости от высоты блока"""
        screen_center_y = pyautogui.size()[1] // 2
        block_y = block_pos[1]
        
        # Определяем высоту блока относительно центра экрана
        height_diff = screen_center_y - block_y
        
        if height_diff > 80:  # Блок высоко
            return "high_jump"
        elif height_diff > 30:  # Блок на средней высоте
            return "medium_jump"
        else:  # Блок близко или ниже
            return "low_jump"
    
    def perform_jump(self, jump_type):
        """Выполняет прыжок с движением вперед"""
        print(f"Прыжок типа: {jump_type}")
        
        # Начинаем движение вперед
        keyboard.press('w')
        time.sleep(0.05)
        
        if jump_type == "high_jump":
            # Прыжок с удержанием для большей высоты
            keyboard.press('space')
            time.sleep(0.15)  # Держим прыжок дольше для высоты
            keyboard.release('space')
            time.sleep(0.1)
            # Дополнительный прыжок если нужно (для двойных прыжков)
            keyboard.press('space')
            time.sleep(0.1)
            keyboard.release('space')
            
        elif jump_type == "medium_jump":
            # Обычный прыжок
            keyboard.press('space')
            time.sleep(0.1)
            keyboard.release('space')
            
        else:  # low_jump
            # Быстрый прыжок
            keyboard.press('space')
            time.sleep(0.05)
            keyboard.release('space')
        
        # Продолжаем движение вперед после прыжка
        time.sleep(0.15)
        keyboard.release('w')
        time.sleep(0.1)
    
    def parkour_cycle(self):
        """Основной цикл паркура"""
        print("Запуск цикла паркура...")
        
        while self.running:
            try:
                # Проверяем наличие блока перед собой
                found, block_pos = self.find_block()
                
                if found:
                    print("Блок найден перед игроком!")
                    self.block_found = True
                    
                    # Рассчитываем и выполняем прыжок
                    jump_type = self.calculate_jump(block_pos)
                    self.perform_jump(jump_type)
                    
                    # Пауза после прыжка
                    time.sleep(0.2)
                    self.block_found = False
                    
                else:
                    print("Блок не найден, начинаю сканирование...")
                    
                    # Сначала пробуем найти блок, вращая голову
                    if not self.rotate_head_horizontal():
                        # Если не нашли после полного оборота, опускаем голову
                        self.look_down()
                        
                        # Если голова слишком низко, возвращаем в исходное положение
                        if self.current_pitch >= self.min_pitch:
                            self.reset_head_position()
                    else:
                        # Если нашли блок при сканировании, выполняем прыжок
                        found_again, block_pos = self.find_block()
                        if found_again:
                            jump_type = self.calculate_jump(block_pos)
                            self.perform_jump(jump_type)
                            self.reset_head_position()
                    
                    time.sleep(0.05)
                    
            except Exception as e:
                print(f"Ошибка в цикле: {e}")
                time.sleep(0.1)
    
    def start(self):
        """Запуск бота"""
        self.running = True
        print("=" * 50)
        print("БОТ ПАРКУРА ЗАПУЩЕН!")
        print("=" * 50)
        print("Управление:")
        print("  F8 - Пауза/Продолжение")
        print("  F9 - Полная остановка")
        print("=" * 50)
        
        # Запускаем основной цикл в отдельном потоке
        bot_thread = threading.Thread(target=self.parkour_cycle)
        bot_thread.daemon = True
        bot_thread.start()
        
        # Ожидаем команды пользователя
        while True:
            if keyboard.is_pressed('F9'):
                self.running = False
                print("\nБот остановлен!")
                break
            elif keyboard.is_pressed('F8'):
                self.running = not self.running
                state = "ПРОДОЛЖЕН" if self.running else "ПРИОСТАНОВЛЕН"
                print(f"\nСтатус: {state}")
                time.sleep(0.5)  # Защита от двойного нажатия
            
            time.sleep(0.1)

# Дополнительный класс с калибровкой
class CalibratedParkourBot(ParkourBot):
    def __init__(self):
        super().__init__()
        self.calibrate_sensitivity()
    
    def calibrate_sensitivity(self):
        """Калибровка чувствительности мыши"""
        print("Калибровка чувствительности...")
        print("Убедитесь, что чувствительность мыши в игре минимальная!")
        
        # Тестовое движение мыши
        pyautogui.moveRel(100, 0, duration=0.5)
        time.sleep(0.5)
        pyautogui.moveRel(-100, 0, duration=0.5)
        
        print("Калибровка завершена!")

# Основная программа
if __name__ == "__main__":
    print("\n" + "=" * 50)
    print("БОТ ДЛЯ ПАРКУРА В MINECRAFT")
    print("=" * 50)
    print("\nИНСТРУКЦИЯ:")
    print("1. Встаньте прямо перед началом паркура")
    print("2. Убедитесь, что окно Minecraft активно")
    print("3. Чувствительность мыши в игре = МИНИМУМ")
    print("4. FOV (угол обзора) = 90")
    print("\nЦВЕТА БЛОКОВ ДЛЯ ПОИСКА:")
    print("  • Темно-красный: RGB(143, 58, 47)")
    print("  • Кирпичный: RGB(178, 74, 58)")
    print("  • И близкие оттенки")
    print("\n" + "=" * 50)
    
    # Создаем и запускаем бота
    bot = ParkourBot()
    
    # Даем время переключиться на окно Minecraft
    print("\nЗапуск через 3 секунды... Переключитесь на Minecraft!")
    for i in range(3, 0, -1):
        print(f"{i}...")
        time.sleep(1)
    
    print("СТАРТ!")
    bot.start()