Загрузка данных
import keyboard
import time
import threading
import pyautogui
from pynput.mouse import Controller
import json
import os
import traceback
import colorsys
try:
import win32api
import win32con
DIRECT_INPUT = True
except ImportError:
DIRECT_INPUT = False
class ParkourBot:
def __init__(self):
self.running = False
self.paused = False
self.current_pitch = 0
self.min_pitch = 15
self.step_down = 2
self.mouse = Controller()
# Настройки времени
self.timings = {
# Прыжок
'jump_delay': 0.1,
'jump_hold': 0.15,
'double_jump_delay': 0.05,
# Ускорение (двойное W)
'first_w_time': 0.15,
'w_press_gap': 0.05,
'second_w_time': 0.1,
# Движение
'forward_time': 0.3,
'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,
# Цвета
'color_tolerance': 15, # Допуск цвета в процентах (0-100)
}
# Базовые цвета блоков (красные оттенки)
self.base_colors = [
(255, 23, 23), # Ярко-красный
(255, 29, 30), # Светло-красный
(188, 17, 18), # Тёмно-красный
(196, 17, 18), # Бордовый
]
# Генерируем расширенную палитру
self.generate_color_palette()
self.load_settings()
def generate_color_palette(self):
"""Создаёт расширенную палитру цветов на основе базовых"""
self.block_colors = []
for base in self.base_colors:
self.block_colors.append(base)
# Генерируем близкие оттенки
r, g, b = base
# Конвертируем в HSV для генерации оттенков
h, s, v = colorsys.rgb_to_hsv(r/255, g/255, b/255)
# Добавляем вариации яркости
for brightness in [0.8, 0.9, 1.1, 1.2]:
new_v = min(1.0, max(0.0, v * brightness))
new_r, new_g, new_b = colorsys.hsv_to_rgb(h, s, new_v)
color = (int(new_r * 255), int(new_g * 255), int(new_b * 255))
if color not in self.block_colors:
self.block_colors.append(color)
# Добавляем вариации насыщенности
for saturation in [0.8, 0.9, 1.1, 1.2]:
new_s = min(1.0, max(0.0, s * saturation))
new_r, new_g, new_b = colorsys.hsv_to_rgb(h, new_s, v)
color = (int(new_r * 255), int(new_g * 255), int(new_b * 255))
if color not in self.block_colors:
self.block_colors.append(color)
print(f"✓ Сгенерировано {len(self.block_colors)} оттенков красного")
def load_settings(self):
"""Загружает настройки из файла"""
try:
if os.path.exists('parkour_settings.json'):
with open('parkour_settings.json', 'r', encoding='utf-8') as f:
saved = json.load(f)
# Загружаем только те настройки, которые есть в файле
for key in self.timings:
if key in saved:
self.timings[key] = saved[key]
# Загружаем базовые цвета если есть
if 'base_colors' in saved:
self.base_colors = [tuple(c) for c in saved['base_colors']]
self.generate_color_palette()
print("✓ Настройки загружены из parkour_settings.json")
return True
else:
print("⚠ Файл настроек не найден, используются стандартные")
except Exception as e:
print(f"⚠ Ошибка загрузки настроек: {e}")
return False
def save_settings(self):
"""Сохраняет настройки в файл"""
try:
# Создаём словарь для сохранения
save_data = {
**self.timings,
'base_colors': self.base_colors
}
with open('parkour_settings.json', 'w', encoding='utf-8') as f:
json.dump(save_data, f, indent=4, ensure_ascii=False)
print("✓ Настройки сохранены в parkour_settings.json")
return True
except Exception as e:
print(f"⚠ Ошибка сохранения: {e}")
return False
def release_keys(self):
"""Отпускает все клавиши"""
try:
keyboard.release('w')
keyboard.release('space')
except:
pass
def move_mouse(self, dx, dy):
"""Движение мыши"""
try:
if DIRECT_INPUT:
win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, int(dx), int(dy), 0, 0)
else:
pos = self.mouse.position
self.mouse.position = (pos[0] + dx, pos[1] + dy)
except:
pass
def color_match_percent(self, color1, color2):
"""
Проверяет схожесть цветов в процентах
Возвращает True если цвета похожи больше чем на tolerance%
"""
try:
tolerance = self.timings['color_tolerance']
# Вычисляем разницу по каждому каналу
dr = abs(color1[0] - color2[0])
dg = abs(color1[1] - color2[1])
db = abs(color1[2] - color2[2])
# Максимальная разница (100%)
max_diff = 255 * 3
# Фактическая разница
actual_diff = dr + dg + db
# Процент схожести
similarity = 100 - (actual_diff / max_diff * 100)
# Проверяем, достаточно ли похожи
return similarity >= (100 - tolerance)
except:
return False
def find_block(self):
"""Поиск блока в центре экрана"""
try:
screenshot = pyautogui.screenshot()
w, h = screenshot.size
cx, cy = w // 2, h // 2
# Проверяем центр
pixel = screenshot.getpixel((cx, cy))
# Проверяем совпадение с любым цветом из палитры
for color in self.block_colors:
if self.color_match_percent(pixel[:3], color):
return True, (cx, cy)
# Если не нашли в центре, проверяем соседние пиксели
for dx in [-5, 0, 5]:
for dy in [-5, 0, 5]:
if dx == 0 and dy == 0:
continue
try:
pixel = screenshot.getpixel((cx + dx, cy + dy))
for color in self.block_colors:
if self.color_match_percent(pixel[:3], color):
return True, (cx + dx, cy + dy)
except:
continue
return False, None
except Exception as e:
print(f"Ошибка поиска: {e}")
return False, None
def reset_camera(self):
"""Выпрямляет камеру"""
if self.current_pitch > 0:
steps = 5
step = self.current_pitch / steps
for _ in range(steps):
if not self.running or self.paused:
break
self.move_mouse(0, -step)
time.sleep(self.timings['camera_reset_delay'] / steps)
self.current_pitch = 0
def camera_up(self):
"""Поднимает камеру для прыжка"""
angle = self.timings['camera_up_angle']
if angle > 0:
self.move_mouse(0, -angle)
time.sleep(self.timings['camera_up_delay'])
def camera_down(self):
"""Опускает камеру обратно"""
angle = self.timings['camera_up_angle']
if angle > 0:
self.move_mouse(0, angle)
time.sleep(self.timings['camera_up_delay'])
def rotate_scan(self):
"""Сканирование поворотом"""
for _ in range(2):
if not self.running or self.paused:
break
for _ in range(0, 180, self.timings['scan_angle_step']):
if not self.running or self.paused:
break
self.move_mouse(self.timings['scan_angle_step'], 0)
time.sleep(self.timings['scan_rotation_speed'])
found, pos = self.find_block()
if found:
return True, pos
return False, None
def look_down(self):
"""Опускает голову при поиске"""
if self.current_pitch < self.min_pitch:
self.move_mouse(0, self.step_down)
self.current_pitch += self.step_down
def do_sprint(self):
"""Ускорение - двойное нажатие W"""
print(" Ускорение (W W)...")
# Первое нажатие W
keyboard.press('w')
time.sleep(self.timings['first_w_time'])
keyboard.release('w')
# Небольшая пауза
time.sleep(self.timings['w_press_gap'])
# Второе нажатие W (удерживаем)
keyboard.press('w')
time.sleep(self.timings['second_w_time'])
def do_jump(self):
"""Выполнение прыжка"""
print("\n" + "="*40)
print("ПРЫЖОК")
print("="*40)
# Выпрямляем камеру
self.reset_camera()
time.sleep(self.timings['jump_delay'])
# Ускорение (двойное W)
self.do_sprint()
# Поднимаем камеру
self.camera_up()
# Прыжок
print(" Прыжок!")
keyboard.press('space')
time.sleep(self.timings['jump_hold'])
keyboard.release('space')
# Опускаем камеру
self.camera_down()
# Движение после прыжка
time.sleep(self.timings['post_jump_forward'])
# Отпускаем W
keyboard.release('w')
# Приземление
print(" Приземление...")
time.sleep(self.timings['landing_delay'])
time.sleep(self.timings['stabilization_time'])
print("✓ Готово\n")
def test_color_detection(self):
"""Тестирует определение цветов"""
print("\n" + "="*50)
print("ТЕСТ ОПРЕДЕЛЕНИЯ ЦВЕТОВ")
print("="*50)
print(f"Допуск цвета: {self.timings['color_tolerance']}%")
print("\nНаведитесь на блок и нажмите Enter")
input("> ")
try:
screenshot = pyautogui.screenshot()
w, h = screenshot.size
cx, cy = w // 2, h // 2
pixel = screenshot.getpixel((cx, cy))
print(f"\nЦвет под прицелом: RGB{pixel[:3]}")
# Проверяем совпадение
best_match = None
best_similarity = 0
for color in self.block_colors:
dr = abs(pixel[0] - color[0])
dg = abs(pixel[1] - color[1])
db = abs(pixel[2] - color[2])
similarity = 100 - ((dr + dg + db) / (255 * 3) * 100)
if similarity > best_similarity:
best_similarity = similarity
best_match = color
if best_match:
print(f"Лучшее совпадение: RGB{best_match}")
print(f"Схожесть: {best_similarity:.1f}%")
if best_similarity >= (100 - self.timings['color_tolerance']):
print("✓ Блок ОБНАРУЖЕН!")
else:
print("✗ Блок НЕ обнаружен (недостаточная схожесть)")
print(f" Требуется: {100 - self.timings['color_tolerance']}%")
print(f" Текущая: {best_similarity:.1f}%")
print(" Совет: увеличьте допуск цвета в настройках")
else:
print("✗ Нет совпадений с палитрой")
except Exception as e:
print(f"Ошибка теста: {e}")
def main_loop(self):
"""Основной цикл"""
print("Запуск...")
while self.running:
if self.paused:
time.sleep(0.1)
continue
try:
found, _ = self.find_block()
if found:
print("✓ Блок найден!")
self.do_jump()
time.sleep(self.timings['resume_delay'])
else:
found_scan, _ = self.rotate_scan()
if found_scan:
self.do_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_keys()
time.sleep(0.5)
def setup_menu(self):
"""Меню настройки"""
print("\n" + "="*50)
print("НАСТРОЙКА БОТА")
print("="*50)
if os.path.exists('parkour_settings.json'):
use = input("\nЗагрузить сохранённые настройки? (Y/n): ").strip().lower()
if use == 'n':
print("Настройка заново...")
else:
print("✓ Загружены сохранённые настройки")
self.show_settings()
return
print("\nВводите значения или Enter (пропустить)")
print("Введите 0 для сброса на стандартное\n")
settings = {
"ЦВЕТА": [
('color_tolerance', 'Допуск цвета (%)', 5, 50, '%'),
],
"ПРЫЖОК": [
('jump_delay', 'Задержка перед прыжком', 0.05, 0.5, 'сек'),
('jump_hold', 'Длительность прыжка', 0.05, 0.5, 'сек'),
('double_jump_delay', 'Пауза между двойным прыжком', 0.01, 0.2, 'сек'),
],
"УСКОРЕНИЕ (ДВОЙНОЕ W)": [
('first_w_time', 'Первое нажатие W (разгон)', 0.05, 0.3, 'сек'),
('w_press_gap', 'Пауза между W', 0.01, 0.2, 'сек'),
('second_w_time', 'Второе нажатие W (перед прыжком)', 0.05, 0.3, 'сек'),
],
"КАМЕРА": [
('camera_up_angle', 'Подъём камеры (пиксели)', 0, 20, 'пикс'),
('camera_up_delay', 'Задержка подъёма', 0.05, 0.3, 'сек'),
],
"СТАБИЛИЗАЦИЯ": [
('landing_delay', 'Ожидание приземления', 0.1, 1.0, 'сек'),
('stabilization_time', 'Стабилизация', 0.05, 0.5, 'сек'),
],
}
defaults = self.timings.copy()
for group, params in settings.items():
print(f"\n--- {group} ---")
for item in params:
key, desc, min_v, max_v, unit = item
cur = self.timings[key]
print(f"\n{desc}")
print(f"Текущее: {cur} {unit} (от {min_v} до {max_v})")
inp = input("> ").strip()
if inp == "":
print(f"✓ {cur} {unit}")
elif inp == "0":
self.timings[key] = defaults[key]
print(f"✓ Сброшено: {defaults[key]} {unit}")
else:
try:
val = float(inp)
if min_v <= val <= max_v:
self.timings[key] = val
print(f"✓ {val} {unit}")
else:
print(f"⚠ От {min_v} до {max_v}")
except:
print("⚠ Число!")
# Тест цветов
print("\n" + "="*50)
print("Хотите протестировать определение цветов?")
test = input("(Y/n): ").strip().lower()
if test != 'n':
self.test_color_detection()
self.save_settings()
# Тест движений
print("\nТест ускорения через 3 сек...")
print("Переключитесь на Minecraft!")
for i in range(3, 0, -1):
print(f"{i}...")
time.sleep(1)
print("Тест W W!")
keyboard.press('w')
time.sleep(self.timings['first_w_time'])
keyboard.release('w')
time.sleep(self.timings['w_press_gap'])
keyboard.press('w')
time.sleep(0.2)
keyboard.release('w')
print("✓ Готово\n")
def show_settings(self):
"""Показывает текущие настройки"""
print("\nТекущие настройки:")
print(f" Допуск цвета: {self.timings['color_tolerance']}%")
print(f" Базовых цветов: {len(self.base_colors)}")
print(f" Всего оттенков: {len(self.block_colors)}")
def start(self):
"""Запуск"""
self.setup_menu()
print("="*50)
print("БОТ ЗАПУЩЕН!")
print("F8 - Пауза | F9 - Стоп | F10 - Тест цвета")
print("="*50)
self.running = True
self.paused = False
# Запуск цикла в потоке
thread = threading.Thread(target=self.main_loop)
thread.daemon = True
thread.start()
# Управление
f8_state = False
f10_state = False
while self.running:
try:
# F8 - пауза
if keyboard.is_pressed('F8'):
if not f8_state:
f8_state = True
self.paused = not self.paused
if self.paused:
print("\n⏸ ПАУЗА")
self.release_keys()
else:
print("\n▶ ПРОДОЛЖЕНИЕ")
time.sleep(0.3)
else:
f8_state = False
# F10 - тест цвета
if keyboard.is_pressed('F10'):
if not f10_state:
f10_state = True
was_paused = self.paused
self.paused = True
self.test_color_detection()
self.paused = was_paused
else:
f10_state = False
# F9 - стоп
if keyboard.is_pressed('F9'):
self.running = False
print("\n✓ СТОП")
break
time.sleep(0.05)
except KeyboardInterrupt:
break
self.release_keys()
print("Выход")
# ============= ЗАПУСК =============
if __name__ == "__main__":
print("="*50)
print("БОТ ПАРКУРА MINECRAFT v4.0")
print("="*50)
print("\nТребования:")
print(" • Запуск от администратора")
print(" • Чувствительность мыши = 0%")
print(" • Оконный режим")
print("\nЦвета блоков: красные оттенки")
print(f" •