Загрузка данных
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.total_look_down = 0
self.shift_pressed = False
self.mouse = Controller()
self.timings = {
'start_delay': 5,
'head_raise_angle': 40,
'head_raise_steps': 5,
'scan_rotation_speed': 0.02,
'scan_angle_step': 10,
'scan_look_down_step': 2,
'scan_look_down_max': 60,
'scan_rotations': 2,
'camera_up_angle': 30,
'camera_up_delay': 0.05,
'first_w_time': 0.08,
'w_gap': 0.03,
'second_w_time': 0.05,
'jump_hold': 0.1,
'post_jump_forward': 0.15,
'shift_delay': 0.2,
'center_look_down_angle': 80,
'center_accuracy': 30,
'center_move_step': 0.05,
'center_find_delay': 0.3,
'landing_delay': 0.3,
'stabilization_time': 0.1,
'cycle_delay': 0.3,
'color_tolerance': 15,
}
self.base_colors = [
(255, 23, 23),
(255, 29, 30),
(188, 17, 18),
(196, 17, 18),
]
self.generate_color_palette()
self.settings_file = os.path.join(os.getcwd(), 'parkour_settings.json')
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
h, s, v = colorsys.rgb_to_hsv(r/255.0, g/255.0, b/255.0)
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("Сгенерировано оттенков красного: " + str(len(self.block_colors)))
def load_settings(self):
try:
if os.path.exists(self.settings_file):
with open(self.settings_file, '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("Настройки загружены")
except Exception as e:
print("Стандартные настройки: " + str(e))
def save_settings(self):
try:
save_data = dict(self.timings)
save_data['base_colors'] = self.base_colors
try:
with open(self.settings_file, 'w', encoding='utf-8') as f:
json.dump(save_data, f, indent=4, ensure_ascii=False)
print("Настройки сохранены")
except PermissionError:
home_dir = os.path.expanduser('~')
backup_file = os.path.join(home_dir, 'parkour_settings.json')
with open(backup_file, 'w', encoding='utf-8') as f:
json.dump(save_data, f, indent=4, ensure_ascii=False)
print("Настройки сохранены в " + backup_file)
except Exception as e:
print("Ошибка сохранения: " + str(e))
def release_keys(self):
try:
keyboard.release('w')
keyboard.release('a')
keyboard.release('s')
keyboard.release('d')
keyboard.release('space')
keyboard.release('shift')
self.shift_pressed = False
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(self, pixel, color):
try:
tolerance = self.timings['color_tolerance']
dr = abs(pixel[0] - color[0])
dg = abs(pixel[1] - color[1])
db = abs(pixel[2] - color[2])
max_diff = 255.0 * 3.0
actual_diff = float(dr + dg + db)
similarity = 100.0 - (actual_diff / max_diff * 100.0)
return similarity >= (100.0 - tolerance)
except:
return False
def find_block_position(self):
"""Ищет красную точку и возвращает (dx, dy) смещение от центра"""
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(pixel, color):
return (0, 0)
# Ищем вокруг центра
search_radius = 150
step = 10
for dy in range(-search_radius, search_radius + 1, step):
for dx in range(-search_radius, search_radius + 1, step):
px = cx + dx
py = cy + dy
if px < 0 or px >= w or py < 0 or py >= h:
continue
try:
pixel = screenshot.getpixel((px, py))
for color in self.block_colors:
if self.color_match(pixel, color):
return (dx, dy)
except:
continue
return None
except Exception as e:
print("Ошибка поиска позиции: " + str(e))
return None
def find_block(self):
"""Проверяет, в центре ли красная точка"""
pos = self.find_block_position()
if pos is None:
return False
dx, dy = pos
accuracy = self.timings['center_accuracy']
return abs(dx) <= accuracy and abs(dy) <= accuracy
def raise_head(self):
print(" [ПОДЪЁМ ГОЛОВЫ]")
angle = self.timings['head_raise_angle']
steps = self.timings['head_raise_steps']
for _ in range(steps):
if not self.running or self.paused:
break
self.move_mouse(0, -angle)
time.sleep(0.02)
self.total_look_down = max(0, self.total_look_down - angle * steps)
time.sleep(0.1)
print(" Голова поднята")
def scan_for_block(self):
print(" [ПОИСК БЛОКА] Вращение + опускание головы...")
look_down_current = 0
look_down_max = self.timings['scan_look_down_max']
look_down_step = self.timings['scan_look_down_step']
scan_step = self.timings['scan_angle_step']
rotations = self.timings['scan_rotations']
total_steps = (360 // scan_step) * rotations
# Защита от деления на ноль
if look_down_step <= 0 or look_down_max <= 0:
look_down_every_n_steps = total_steps + 1
else:
look_down_every_n_steps = max(1, total_steps // (look_down_max // look_down_step))
step_count = 0
for rotation in range(rotations):
if not self.running or self.paused:
break
for _ in range(0, 360, scan_step):
if not self.running or self.paused:
break
self.move_mouse(scan_step, 0)
time.sleep(self.timings['scan_rotation_speed'])
step_count += 1
if step_count % look_down_every_n_steps == 0 and look_down_current < look_down_max:
self.move_mouse(0, look_down_step)
look_down_current += look_down_step
if self.find_block():
print(" БЛОК НАЙДЕН!")
self.total_look_down += look_down_current
return True
self.total_look_down += look_down_current
print(" Блок не найден")
return False
def do_jump(self):
print("=" * 40)
print("[ПРЫЖОК]")
print("=" * 40)
# Отпускаем шифт если был зажат
if self.shift_pressed:
keyboard.release('shift')
self.shift_pressed = False
time.sleep(0.05)
print(" Подъём камеры...")
angle = self.timings['camera_up_angle']
for _ in range(5):
self.move_mouse(0, -angle)
time.sleep(0.005)
time.sleep(self.timings['camera_up_delay'])
print(" Разгон W W...")
keyboard.press('w')
time.sleep(self.timings['first_w_time'])
keyboard.release('w')
time.sleep(self.timings['w_gap'])
keyboard.press('w')
time.sleep(self.timings['second_w_time'])
print(" ПРЫЖОК!")
keyboard.press('space')
time.sleep(self.timings['jump_hold'])
keyboard.release('space')
jump_time = time.time()
time.sleep(self.timings['post_jump_forward'])
keyboard.release('w')
print(" Приземление...")
time.sleep(self.timings['landing_delay'])
# Опускаем камеру обратно
for _ in range(5):
self.move_mouse(0, angle)
time.sleep(0.005)
# Шифт
elapsed = time.time() - jump_time
shift_wait = max(0, self.timings['shift_delay'] - elapsed)
if shift_wait > 0:
time.sleep(shift_wait)
print(" Зажимаю шифт...")
keyboard.press('shift')
self.shift_pressed = True
time.sleep(self.timings['stabilization_time'])
print("Прыжок завершён")
print("=" * 40)
def center_on_block(self):
"""Центрирование на шифте: голова вниз, WASD к красной точке"""
print("=" * 40)
print("[ЦЕНТРИРОВАНИЕ НА ШИФТЕ]")
print("=" * 40)
# Убеждаемся что шифт зажат
if not self.shift_pressed:
keyboard.press('shift')
self.shift_pressed = True
time.sleep(0.05)
# Опускаем голову вниз
print(" Опускание головы...")
angle = self.timings['center_look_down_angle']
for _ in range(5):
self.move_mouse(0, angle)
time.sleep(0.01)
self.total_look_down += angle * 5
time.sleep(0.3)
accuracy = self.timings['center_accuracy']
max_attempts = 40
for attempt in range(max_attempts):
if not self.running or self.paused:
break
pos = self.find_block_position()
if pos is None:
print(" Точка не видна, шаг назад...")
keyboard.press('s')
time.sleep(self.timings['center_move_step'])
keyboard.release('s')
time.sleep(0.05)
continue
dx, dy = pos
if abs(dx) <= accuracy and abs(dy) <= accuracy:
print(" ТОЧКА В ЦЕНТРЕ! (dx=" + str(dx) + " dy=" + str(dy) + ")")
time.sleep(self.timings['center_find_delay'])
print("Центрирование завершено")
print("=" * 40)
return True
print(" Смещение: dx=" + str(dx) + " dy=" + str(dy))
# Определяем клавиши для движения
keys_to_press = []
if dx < -accuracy:
keys_to_press.append('a')
elif dx > accuracy:
keys_to_press.append('d')
if dy < -accuracy:
keys_to_press.append('w')
elif dy > accuracy:
keys_to_press.append('s')
# Нажимаем клавиши
for key in keys_to_press:
keyboard.press(key)
time.sleep(self.timings['center_move_step'])
# Отпускаем клавиши
for key in keys_to_press:
keyboard.release(key)
time.sleep(0.02)
print(" Не удалось отцентрироваться")
print("=" * 40)
return False
def main_loop(self):
print("\n=== ЗАПУСК ЦИКЛА ===\n")
while self.running:
if self.paused:
time.sleep(0.1)
continue
try:
# Шаг 1: Подъём головы
self.raise_head()
# Шаг 2: Поиск блока
found = self.scan_for_block()
if found:
# Шаг 3: Прыжок
self.do_jump()
# Шаг 4: Центрирование на шифте
self.center_on_block()
else:
print(" Пропуск цикла (блок не найден)")
if self.shift_pressed:
keyboard.release('shift')
self.shift_pressed = False
time.sleep(self.timings['cycle_delay'])
except Exception as e:
print("Ошибка: " + str(e))
traceback.print_exc()
self.release_keys()
time.sleep(0.5)
def setup_menu(self):
print("=" * 50)
print("НАСТРОЙКА БОТА")
print("=" * 50)
if os.path.exists(self.settings_file):
use = input("Загрузить сохранённые настройки? (Y/n): ").strip().lower()
if use == 'n':
print("Настройка заново...")
else:
print("Загружены сохранённые настройки")
self.show_settings()
return
print("Вводите значения или Enter (пропустить)")
print("Введите 0 для сброса на стандартное\n")
settings_groups = [
("ЗАДЕРЖКА СТАРТА", [
('start_delay', 'Задержка перед запуском', 1, 15, 'сек'),
]),
("ЦВЕТА", [
('color_tolerance', 'Допуск цвета (%)', 5, 50, '%'),
]),
("1. ПОДЪЁМ ГОЛОВЫ", [
('head_raise_angle', 'Угол подъёма', 10, 200, 'пикс'),
('head_raise_steps', 'Шагов подъёма', 2, 10, 'шагов'),
]),
("2. ПОИСК БЛОКА", [
('scan_rotation_speed', 'Скорость вращения', 0.01, 0.1, 'сек'),
('scan_angle_step', 'Шаг вращения', 5, 30, 'градусов'),
('scan_look_down_step', 'Шаг опускания', 1, 10, 'пикс'),
('scan_look_down_max', 'Макс. опускание', 10, 200, 'пикс'),
('scan_rotations', 'Оборотов', 1, 5, 'раз'),
]),
("3. ПРЫЖОК", [
('camera_up_angle', 'Подъём камеры', 10, 200, 'пикс'),
('first_w_time', 'Первое W', 0.03, 0.2, 'сек'),
('w_gap', 'Пауза между W', 0.01, 0.1, 'сек'),
('second_w_time', 'Второе W', 0.03, 0.2, 'сек'),
('jump_hold', 'Длительность прыжка', 0.05, 0.5, 'сек'),
('post_jump_forward', 'Полёт вперёд', 0.05, 0.5, 'сек'),
]),
("4. ШИФТ", [
('shift_delay', 'Задержка перед шифтом', 0.1, 1.0, 'сек'),
]),
("5. ЦЕНТРИРОВАНИЕ", [
('center_look_down_angle', 'Опускание головы', 10, 200, 'пикс'),
('center_accuracy', 'Точность центра', 10, 60, 'пикс'),
('center_move_step', 'Шаг движения', 0.02, 0.2, 'сек'),
('center_find_delay', 'Пауза после', 0.1, 0.5, 'сек'),
]),
("ПРИЗЕМЛЕНИЕ", [
('landing_delay', 'Ожидание приземления', 0.1, 1.0, 'сек'),
('stabilization_time', 'Стабилизация', 0.05, 0.3, 'сек'),
]),
]
defaults = dict(self.timings)
for group_name, params in settings_groups:
print("--- " + group_name + " ---")
for key, desc, min_v, max_v, unit in params:
cur = self.timings[key]
print(desc)
print("Текущее: " + str(cur) + " " + unit + " (от " + str(min_v) + " до " + str(max_v) + ")")
inp = input("> ").strip()
if inp == "":
print("Оставлено: " + str(cur) + " " + unit)
elif inp == "0":
self.timings[key] = defaults[key]
print("Сброшено: " + str(defaults[key]) + " " + unit)
else:
try:
val = float(inp)
if min_v <= val <= max_v:
self.timings[key] = val
print("Установлено: " + str(val) + " " + unit)
else:
print("Значение должно быть от " + str(min_v) + " до " + str(max_v))
except:
print("Введите число!")
self.save_settings()
print("Настройка завершена!\n")
def show_settings(self):
print("\nТекущие настройки:")
print(" Задержка старта: " + str(self.timings['start_delay']) + " сек")
print(" Подъём головы: " + str(self.timings['head_raise_angle']) + " пикс")
print(" Макс. опускание: " + str(self.timings['scan_look_down_max']) + " пикс")
print(" Камера прыжка: " + str(self.timings['camera_up_angle']) + " пикс")
print(" Шифт через: " + str(self.timings['shift_delay']) + " сек")
print(" Точность центра: " + str(self.timings['center_accuracy']) + " пикс")
print(" Допуск цвета: " + str(self.timings['color_tolerance']) + "%\n")
def start(self):
self.setup_menu()
print("=" * 50)
print("БОТ ЗАПУСКАЕТСЯ...")
print("=" * 50)
delay = self.timings['start_delay']
print("Задержка: " + str(delay) + " сек. Переключитесь на Minecraft!")
for i in range(int(delay), 0, -1):
print(" " + str(i) + "...")
time.sleep(1)
print("СТАРТ!")
print("=" * 50)
print("ЦИКЛ:")
print(" 1. Подъём головы")
print(" 2. Вращение + опускание (поиск)")
print(" 3. Прыжок W W")
print(" 4. Шифт + голова вниз")
print(" 5. WASD к красной точке")
print("F8 - Пауза | F9 - Стоп")
print("=" * 50)
self.running = True
self.paused = False
thread = threading.Thread(target=self.main_loop)
th