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


import keyboard
import time
import threading
import pyautogui
from pynput.mouse import Controller, Button
from pynput.keyboard import Key, Controller as KeyboardController
import json
import os
import traceback
import sys

try:
    import win32api
    import win32con
    DIRECT_INPUT = True
except ImportError:
    DIRECT_INPUT = False
    print("Предупреждение: win32api не установлен.")

class ParkourBot:
    def __init__(self):
        self.running = False
        self.paused = False
        self.block_found = False
        self.current_pitch = 0
        self.min_pitch = 15
        self.step_down = 2
        self.scan_speed = 10
        
        self.mouse = Controller()
        self.keyboard_controller = KeyboardController()
        
        # Расширенные настройки времени
        self.timings = {
            # Прыжок
            'jump_delay': 0.1,           # Задержка перед прыжком
            'jump_hold': 0.15,           # Длительность удержания пробела
            'double_jump_delay': 0.05,   # Задержка между двойными прыжками
            
            # Движение
            'forward_time': 0.3,         # Время движения вперёд
            'acceleration_time': 0.15,   # Время разгона перед прыжком
            'post_jump_forward': 0.2,    # Движение вперёд после прыжка
            
            # Камера
            'camera_reset_delay': 0.2,   # Задержка выпрямления камеры
            'camera_up_angle': 5,        # На сколько поднимать камеру перед прыжком (пиксели)
            'camera_up_delay': 0.1,      # Задержка подъёма камеры
            
            # Стабилизация
            'landing_delay': 0.5,        # Задержка после приземления
            'stabilization_time': 0.1,   # Время стабилизации
            
            # Сканирование
            'block_check_delay': 0.05,   # Задержка между проверками
            'scan_rotation_speed': 0.02, # Скорость вращения
            'scan_angle_step': 10,       # Шаг угла сканирования
            
            # Паузы
            'resume_delay': 0.3,         # Задержка перед возобновлением
        }
        
        # Состояние клавиш
        self.keys_pressed = {
            'w': False,
            'space': False
        }
        
        # Цвета блоков
        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),
        ]
        
        self.load_settings()
    
    def release_all_keys(self):
        """Освобождает все зажатые клавиши"""
        try:
            if self.keys_pressed['w']:
                keyboard.release('w')
                self.keys_pressed['w'] = False
            if self.keys_pressed['space']:
                keyboard.release('space')
                self.keys_pressed['space'] = False
        except:
            pass
    
    def load_settings(self):
        """Загружает настройки из файла"""
        try:
            if os.path.exists('parkour_settings.json'):
                with open('parkour_settings.json', 'r', encoding='utf-8') as f:
                    saved_timings = json.load(f)
                    self.timings.update(saved_timings)
                    print("✓ Предыдущие настройки загружены")
                    return True
        except Exception as e:
            print(f"⚠ Не удалось загрузить настройки: {e}")
        return False
    
    def save_settings(self):
        """Сохраняет настройки в файл"""
        try:
            with open('parkour_settings.json', 'w', encoding='utf-8') as f:
                json.dump(self.timings, f, indent=4, ensure_ascii=False)
            print("✓ Настройки сохранены")
            return True
        except Exception as e:
            print(f"⚠ Не удалось сохранить настройки: {e}")
            return False
    
    def configure_timings(self):
        """Расширенная настройка времени"""
        try:
            print("\n" + "="*60)
            print("НАСТРОЙКА ПАРАМЕТРОВ БОТА")
            print("="*60)
            
            # Проверяем, есть ли сохранённые настройки
            has_saved = os.path.exists('parkour_settings.json')
            if has_saved:
                print("\nНайдены сохранённые настройки!")
                use_saved = input("Использовать сохранённые настройки? (Y/n): ").strip().lower()
                if use_saved != 'n':
                    print("✓ Используются сохранённые настройки")
                    self.show_current_settings()
                    return
            
            print("\nВведите значения (Enter - оставить текущее, 0 - сбросить на стандартное)")
            print("="*60)
            
            # Группы настроек
            settings_groups = {
                "НАСТРОЙКИ ПРЫЖКА": [
                    ('jump_delay', 'Задержка перед прыжком', 0.05, 0.5, 'сек'),
                    ('jump_hold', 'Длительность удержания пробела', 0.05, 0.5, 'сек'),
                    ('double_jump_delay', 'Задержка между двойными прыжками', 0.01, 0.2, 'сек'),
                ],
                "НАСТРОЙКИ ДВИЖЕНИЯ": [
                    ('forward_time', 'Время движения вперёд', 0.1, 1.0, 'сек'),
                    ('acceleration_time', 'Время разгона перед прыжком', 0.05, 0.5, 'сек'),
                    ('post_jump_forward', 'Движение вперёд после прыжка', 0.1, 0.5, 'сек'),
                ],
                "НАСТРОЙКИ КАМЕРЫ": [
                    ('camera_reset_delay', 'Скорость выпрямления камеры', 0.05, 0.5, 'сек'),
                    ('camera_up_angle', 'Подъём камеры перед прыжком', 0, 20, 'пикселей'),
                    ('camera_up_delay', 'Задержка подъёма камеры', 0.05, 0.3, 'сек'),
                ],
                "СТАБИЛИЗАЦИЯ": [
                    ('landing_delay', 'Ожидание приземления', 0.1, 1.0, 'сек'),
                    ('stabilization_time', 'Время стабилизации', 0.05, 0.5, 'сек'),
                    ('resume_delay', 'Задержка перед продолжением', 0.1, 1.0, 'сек'),
                ],
                "СКАНИРОВАНИЕ": [
                    ('block_check_delay', 'Задержка между проверками', 0.01, 0.2, 'сек'),
                    ('scan_rotation_speed', 'Скорость вращения', 0.01, 0.1, 'сек'),
                    ('scan_angle_step', 'Шаг угла сканирования', 5, 30, 'градусов'),
                ]
            }
            
            # Стандартные значения для сброса
            default_timings = self.timings.copy()
            
            for group_name, settings in settings_groups.items():
                print(f"\n{'─'*40}")
                print(f"▶ {group_name}")
                print('─'*40)
                
                for setting_key, description, min_val, max_val, unit in settings:
                    current = self.timings[setting_key]
                    print(f"\n  {description}")
                    print(f"  Текущее: {current} {unit} (от {min_val} до {max_val})")
                    
                    user_input = input("  Новое значение: ").strip()
                    
                    if user_input == "":
                        print(f"  ✓ Оставлено: {current} {unit}")
                    elif user_input == "0":
                        self.timings[setting_key] = default_timings[setting_key]
                        print(f"  ✓ Сброшено на: {default_timings[setting_key]} {unit}")
                    else:
                        try:
                            new_value = float(user_input)
                            if min_val <= new_value <= max_val:
                                self.timings[setting_key] = new_value
                                print(f"  ✓ Установлено: {new_value} {unit}")
                            else:
                                print(f"  ⚠ Значение должно быть от {min_val} до {max_val}")
                        except ValueError:
                            print("  ⚠ Введите число!")
            
            self.save_settings()
            
            # Тестовый прыжок
            print("\n" + "="*60)
            print("ТЕСТОВЫЙ ПРЫЖОК")
            print("="*60)
            print("\nПереключитесь на Minecraft для теста!")
            
            for i in range(3, 0, -1):
                print(f"  {i}...")
                time.sleep(1)
            
            # Тест с подъёмом камеры
            print("  Поднимаю камеру...")
            self.move_mouse_relative(0, -self.timings['camera_up_angle'])
            time.sleep(self.timings['camera_up_delay'])
            
            print("  Прыжок!")
            keyboard.press('space')
            time.sleep(self.timings['jump_hold'])
            keyboard.release('space')
            
            # Возвращаем камеру
            self.move_mouse_relative(0, self.timings['camera_up_angle'])
            time.sleep(0.5)
            
            print("✓ Тест завершён")
            print("="*60)
            
        except Exception as e:
            print(f"⚠ Ошибка при настройке: {e}")
            traceback.print_exc()
    
    def show_current_settings(self):
        """Показывает текущие настройки"""
        print("\n" + "="*50)
        print("ТЕКУЩИЕ НАСТРОЙКИ:")
        print("="*50)
        for key, value in self.timings.items():
            print(f"  {key}: {value}")
        print("="*50)
    
    def move_mouse_relative(self, dx, dy):
        """Безопасное движение мыши"""
        try:
            if DIRECT_INPUT:
                win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, int(dx), int(dy), 0, 0)
            else:
                current_pos = self.mouse.position
                self.mouse.position = (current_pos[0] + dx, current_pos[1] + dy)
        except:
            pass
    
    def find_block(self):
        """Поиск блока на экране"""
        try:
            screenshot = pyautogui.screenshot()
            width, height = screenshot.size
            
            center_x = width // 2
            center_y = height // 2
            
            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)
            
            return False, None
        except:
            return False, None
    
    def color_similar(self, color1, color2, tolerance):
        """Сравнение цветов"""
        try:
            return (abs(color1[0] - color2[0]) < tolerance and
                    abs(color1[1] - color2[1]) < tolerance and
                    abs(color1[2] - color2[2]) < tolerance)
        except:
            return False
    
    def raise_camera_for_jump(self):
        """Поднимает камеру перед прыжком"""
        try:
            if self.timings['camera_up_angle'] > 0:
                print(f"  Подъём камеры на {self.timings['camera_up_angle']} пикселей")
                self.move_mouse_relative(0, -self.timings['camera_up_angle'])
                time.sleep(self.timings['camera_up_delay'])
        except Exception as e:
            print(f"  ⚠ Ошибка подъёма камеры: {e}")
    
    def lower_camera_after_jump(self):
        """Опускает камеру после прыжка"""
        try:
            if self.timings['camera_up_angle'] > 0:
                self.move_mouse_relative(0, self.timings['camera_up_angle'])
                time.sleep(self.timings['camera_up_delay'])
        except:
            pass
    
    def reset_camera(self):
        """Выпрямление камеры"""
        try:
            if self.current_pitch > 0:
                steps = 5
                pitch_per_step = self.current_pitch / steps
                
                for i in range(steps):
                    if not self.running or self.paused:
                        break
                    self.move_mouse_relative(0, -pitch_per_step)
                    time.sleep(self.timings['camera_reset_delay'] / steps)
                
                self.current_pitch = 0
        except:
            pass
    
    def rotate_head_horizontal(self):
        """Горизонтальное сканирование"""
        try:
            for rotation in range(2):
                if not self.running or self.paused:
                    break
                
                for i in range(0, 180, self.timings['scan_angle_step']):
                    if not self.running or self.paused:
                        break
                    
                    self.move_mouse_relative(self.timings['scan_angle_step'], 0)
                    time.sleep(self.timings['scan_rotation_speed'])
                    
                    found, block_pos = self.find_block()
                    if found:
                        return True, block_pos
            
            return False, None
        except:
            return False, None
    
    def look_down(self):
        """Опускание головы"""
        try:
            if self.current_pitch < self.min_pitch:
                self.move_mouse_relative(0, self.step_down)
                self.current_pitch += self.step_down
        except:
            pass
    
    def perform_acceleration(self):
        """Разгон перед прыжком"""
        try:
            print("  Разгон...")
            keyboard.press('w')
            self.keys_pressed['w'] = True
            
            # Постепенное ускорение
            accel_steps = 5
            step_time = self.timings['acceleration_time'] / accel_steps
            
            for i in range(accel_steps):
                if not self.running or self.paused:
                    break
                time.sleep(step_time)
            
            print(f"  Разгон завершён ({self.timings['acceleration_time']} сек)")
        except Exception as e:
            print(f"  ⚠ Ошибка разгона: {e}")
    
    def perform_jump(self, jump_type="medium_jump"):
        """Выполнение прыжка с ускорением и подъёмом камеры"""
        try:
            print(f"\n{'='*30}")
            print(f"ВЫПОЛНЕНИЕ ПРЫЖКА ({jump_type})")
            print('='*30)
            
            # 1. Выпрямляем камеру если нужно
            self.reset_camera()
            time.sleep(self.timings['jump_delay'])
            
            # 2. Разгон
            self.perform_acceleration()
            
            # 3. Поднимаем камеру для прыжка
            self.raise_camera_for_jump()
            
            # 4. Прыжок
            print("  Прыжок!")
            if jump_type == "high_jump":
                # Высокий прыжок с двойным нажатием
                keyboard.press('space')
                self.keys_pressed['space'] = True
                time.sleep(self.timings['jump_hold'] * 1.3)
                keyboard.release('space')
                self.keys_pressed['space'] = False
                
                time.sleep(self.timings['double_jump_delay'])
                
                keyboard.press('space')
                self.keys_pressed['space'] = True
                time.sleep(self.timings['jump_hold'] * 0.7)
                keyboard.release('space')
                self.keys_pressed['space'] = False
                
            elif jump_type == "medium_jump":
                # Средний прыжок
                keyboard.press('space')
                self.keys_pressed['space'] = True
                time.sleep(self.timings['jump_hold'])
                keyboard.release('space')
                self.keys_pressed['space'] = False
                
            else:
                # Низкий прыжок
                keyboard.press('space')
                self.keys_pressed['space'] = True
                time.sleep(self.timings['jump_hold'] * 0.7)
                keyboard.release('space')
                self.keys_pressed['space'] = False
            
            # 5. Опускаем камеру обратно
            self.lower_camera_after_jump()
            
            # 6. Движение вперёд после прыжка
            time.sleep(self.timings['post_jump_forward'])
            
            # 7. Отпускаем движение вперёд
            keyboard.release('w')
            self.keys_pressed['w'] = False
            
            # 8. Приземление и стабилизация
            print("  Приземление...")
            time.sleep(self.timings['landing_delay'])
            time.sleep(self.timings['stabilization_time'])
            
            print("✓ Прыжок завершён")
            print('='*30 + '\n')
            
        except Exception as e:
            print(f"⚠ Ошибка прыжка: {e}")
            self.release_all_keys()
    
    def parkour_cycle(self):
        """Основной цикл с поддержкой паузы"""
        print("\nЗапуск цикла паркура...")
        
        while self.running:
            try:
                # Проверка паузы
                if self.paused:
                    time.sleep(0.1)
                    continue
                
                # Поиск блока
                found, block_pos = self.find_block()
                
                if found:
                    print("✓ Блок обнаружен!")
                    self.perform_jump("medium_jump")
                    time.sleep(self.timings['resume_delay'])
                    
                else:
                    print("Поиск блока...")
                    found_in_scan, _ = self.rotate_head_horizontal()
                    
                    if found_in_scan:
                        self.perform_jump("medium_jump")
                    else:
                        self.look_down()
                        if self.current_pitch >= self.min_pitch:
                            self.reset_camera()
                    
                    time.sleep(self.timings['block_check_delay'])
                    
            except Exception as e:
                print(f"Ошибка в цикле: {e}")
                self.release_all_keys()
                time.sleep(0.5)
    
    def start(self):
        """Запуск бота с улучшенным управлением паузой"""
        try:
            # Настройка
            self.configure_timings()
            
            print("\n" + "="*60)
            print("БОТ ПАРКУРА ЗАПУЩЕН!")
            print("="*60)
            print("\nУПРАВЛЕНИЕ:")
            print("  F8 - Пауза/Продолжение")
            print("  F9 - Полная остановка")
            print("  F10 - Показать настройки")
            print("="*60)
            
            self.running = True
            self.paused = False
            
            # Запуск основного цикла
            bot_thread = threading.Thread(target=self.parkour_cycle)
            bot_thread.daemon = True
            bot_thread.start()
            
            # Обработка команд
            f8_pressed = False
            f10_pressed = False
            
            while self.running:
                try:
                    # Обработка F8 с защитой от дребезга
                    if keyboard.is_pressed('F8'):
                        if not f8_pressed:
                            f8_pressed = True
                            self.paused = not self.paused
                            
                            if self.paused:
                                print("\n⏸ ПАУЗА")
                                self.release_all_keys()
                            else:
                                print("\n▶ ПРОДОЛЖЕНИЕ")
                                time.sleep(self.timings['resume_delay'])
                    else:
                        f8_pressed = False
                    
                    # Обработка F10
                    if keyboard.is_pressed('F10'):
                        if not f10_pressed:
                            f10_pressed = True
                            was_paused = self.paused
                            self.paused = True
                            self.show_current_settings()
                            self.paused = was_paused
                    else:
                        f10_pressed = False
                    
                    # Остановка
                    if keyboard.is_pressed('F9'):
                        self.r