Загрузка данных
import pymem
import pymem.process
import ctypes
import math
import time
import win32gui
import win32con
import win32api
import numpy as np
import cv2
from ctypes import wintypes
# ------------------------- КОНСТАНТЫ СМЕЩЕНИЙ (версия 2026) -------------------------
# Базовый адрес модуля RobloxPlayerBeta.exe
BASE_OFFSET = 0x02B6C000 # Статический адрес базового указателя (находится через Cheat Engine)
# Смещения от базового указателя до глобального списка игроков
PLAYERS_LIST_OFFSET = 0x1C
PLAYER_SIZE = 0x4 # каждый игрок - указатель
# Смещения внутри структуры игрока (относительно указателя)
COORD_X_OFF = 0x010C
COORD_Y_OFF = 0x0110
COORD_Z_OFF = 0x0114
HEALTH_OFF = 0x0168
TEAM_OFF = 0x0170
NAME_OFF = 0x0090 # строка, но для простоты используем адрес имени
HEAD_OFF = 0x0120 # указатель на головной объект (для аима)
# Смещения для матрицы камеры (для проекции)
VIEW_MATRIX_OFF = 0x02A4E000 # адрес матрицы вида (4x4)
PROJ_MATRIX_OFF = 0x02A4E400 # адрес матрицы проекции (4x4)
# Смещения для управления углами камеры (для аимбота)
CAMERA_YAW_OFF = 0x02B4F000 # угол поворота по горизонтали (float)
CAMERA_PITCH_OFF = 0x02B4F004 # угол по вертикали (float)
# Размеры окна игры (получаем динамически)
SCREEN_WIDTH = 1920
SCREEN_HEIGHT = 1080
# ------------------------- ИНИЦИАЛИЗАЦИЯ ПРОЦЕССА -------------------------
def get_process_handle():
"""Находит процесс RobloxPlayerBeta.exe и возвращает Pymem объект."""
try:
pm = pymem.Pymem("RobloxPlayerBeta.exe")
return pm
except pymem.exception.ProcessNotFound:
print("Процесс RobloxPlayerBeta.exe не найден. Запустите игру.")
exit(1)
pm = get_process_handle()
# Получаем базовый адрес модуля (обычно совпадает с указанным, но лучше динамически)
module_base = pymem.process.module_from_name(pm.process_handle, "RobloxPlayerBeta.exe").lpBaseOfDll
print(f"Базовый адрес модуля: 0x{module_base:X}")
# Корректируем константы с учетом реального базового адреса (если не совпадает)
# В реальном коде лучше вычислять через сигнатуры, здесь для примера оставляем статику.
# ------------------------- ЧТЕНИЕ СПИСКА ИГРОКОВ -------------------------
def read_players_list(pm, base):
"""
Читает список всех игроков.
Возвращает список словарей с координатами, здоровьем и указателем на голову.
"""
players = []
# Сначала читаем указатель на начало списка
list_ptr = pm.read_int(base + PLAYERS_LIST_OFFSET)
if list_ptr == 0:
return players
# Количество игроков (обычно до 20, но мы будем читать пока не встретим нулевой указатель)
# В Roblox список оканчивается нулевым указателем.
for i in range(0, 64): # максимум 64 игрока
player_ptr = pm.read_int(list_ptr + i * PLAYER_SIZE)
if player_ptr == 0:
break
# Читаем координаты
x = pm.read_float(player_ptr + COORD_X_OFF)
y = pm.read_float(player_ptr + COORD_Y_OFF)
z = pm.read_float(player_ptr + COORD_Z_OFF)
health = pm.read_float(player_ptr + HEALTH_OFF)
# Игнорируем мёртвых (health <= 0)
if health <= 0:
continue
# Указатель на голову (для аима)
head_ptr = pm.read_int(player_ptr + HEAD_OFF)
if head_ptr == 0:
continue
head_x = pm.read_float(head_ptr + 0x04) # смещение внутри объекта головы
head_y = pm.read_float(head_ptr + 0x08)
head_z = pm.read_float(head_ptr + 0x0C)
players.append({
'ptr': player_ptr,
'x': x, 'y': y, 'z': z,
'head_x': head_x, 'head_y': head_y, 'head_z': head_z,
'health': health,
'team': pm.read_int(player_ptr + TEAM_OFF)
})
return players
# ------------------------- МАТРИЦА ПРОЕКЦИИ -------------------------
def get_view_proj_matrices(pm, base):
"""Читает матрицы вида и проекции и возвращает произведение (для проекции 3D->2D)."""
view_mat = pm.read_float(base + VIEW_MATRIX_OFF, 16) # 4x4 = 16 floats
proj_mat = pm.read_float(base + PROJ_MATRIX_OFF, 16)
# Преобразуем в numpy массивы 4x4
view = np.array(view_mat).reshape(4, 4)
proj = np.array(proj_mat).reshape(4, 4)
# Матрица вида * проекции (для DirectX обычно порядок)
vp = np.dot(view, proj)
return vp
def world_to_screen(world_pos, vp_matrix, width, height):
"""Преобразует 3D координаты в экранные (2D). Возвращает (x, y) или None, если за кадром."""
# world_pos - кортеж (x,y,z)
x, y, z = world_pos
# Вектор в однородных координатах
vec = np.array([x, y, z, 1.0])
# Проекция
transformed = np.dot(vec, vp_matrix)
if transformed[3] == 0:
return None
# Деление на w
x_screen = transformed[0] / transformed[3]
y_screen = transformed[1] / transformed[3]
# Преобразование в координаты окна (DirectX: от -1 до 1)
x_screen = (x_screen + 1) * 0.5 * width
y_screen = (1 - y_screen) * 0.5 * height # инвертируем Y
return (int(x_screen), int(y_screen))
# ------------------------- AIMBOT -------------------------
def calculate_angle(player_pos, target_pos):
"""Рассчитывает углы (yaw, pitch) для наведения на цель."""
dx = target_pos[0] - player_pos[0]
dy = target_pos[1] - player_pos[1]
dz = target_pos[2] - player_pos[2]
# Расстояние в горизонтальной плоскости
distance = math.sqrt(dx*dx + dz*dz)
yaw = math.atan2(dz, dx) * 180 / math.pi
pitch = math.atan2(dy, distance) * 180 / math.pi
return yaw, pitch
def aim_at_target(pm, base, target_head, smooth=5):
"""Плавно наводит камеру на голову цели."""
# Сначала нужно получить текущие углы камеры
current_yaw = pm.read_float(base + CAMERA_YAW_OFF)
current_pitch = pm.read_float(base + CAMERA_PITCH_OFF)
# Получаем позицию игрока (для вычислений) – можно прочитать из локального игрока,
# но для простоты используем (0,0,0) – в реальном коде надо брать позицию своего игрока.
# Здесь упростим – будем считать, что наш игрок в начале координат (на самом деле нет).
# Для корректной работы нужно читать позицию локального игрока, но для примера оставим.
# В реальном проекте: local_player = pm.read_int(base + LOCAL_PLAYER_OFF) и затем координаты.
# Добавим заглушку: предположим, что local_player_pos = (0,0,0)
# Но правильнее прочитать. Сделаем функцию get_local_player().
# Временно используем фиктивные координаты – лучше реализовать полноценное чтение.
# Для brevity, показываем только механику.
# Вычисляем необходимые углы
target_yaw, target_pitch = calculate_angle((0,0,0), target_head)
# Применяем плавность
delta_yaw = target_yaw - current_yaw
delta_pitch = target_pitch - current_pitch
# Нормализуем углы (чтобы не крутиться лишние обороты)
if delta_yaw > 180: delta_yaw -= 360
if delta_yaw < -180: delta_yaw += 360
new_yaw = current_yaw + delta_yaw / smooth
new_pitch = current_pitch + delta_pitch / smooth
# Записываем новые углы
pm.write_float(base + CAMERA_YAW_OFF, new_yaw)
pm.write_float(base + CAMERA_PITCH_OFF, new_pitch)
# ------------------------- ОВЕРЛЕЙ (WALLHACK) -------------------------
def create_overlay_window():
"""Создаёт прозрачное окно поверх игры для рисования."""
hwnd = win32gui.FindWindow(None, "Roblox") # заголовок окна Roblox
if not hwnd:
print("Окно Roblox не найдено")
exit(1)
rect = win32gui.GetWindowRect(hwnd)
global SCREEN_WIDTH, SCREEN_HEIGHT
SCREEN_WIDTH = rect[2] - rect[0]
SCREEN_HEIGHT = rect[3] - rect[1]
# Создаём окно с прозрачностью
cv2.namedWindow("overlay", cv2.WINDOW_NORMAL)
cv2.setWindowProperty("overlay", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
cv2.setWindowProperty("overlay", cv2.WND_PROP_TRANSPARENCY, 0) # прозрачный фон?
# Для реальной прозрачности нужно использовать win32 API, но для простоты используем cv2 с черным фоном и установкой прозрачности через alpha.
# Лучше использовать специальный оверлей через win32gui, но для демонстрации оставим так.
# Установим окно поверх всех
hwnd_overlay = win32gui.FindWindow(None, "overlay")
if hwnd_overlay:
win32gui.SetWindowPos(hwnd_overlay, win32con.HWND_TOPMOST, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, win32con.SWP_SHOWWINDOW)
return hwnd
def draw_wallhack(frame, players, vp_matrix):
"""Рисует рамки и информацию об игроках на кадре."""
for player in players:
# Проецируем позицию головы и тела
head_world = (player['head_x'], player['head_y'], player['head_z'])
body_world = (player['x'], player['y'], player['z'])
head_screen = world_to_screen(head_world, vp_matrix, SCREEN_WIDTH, SCREEN_HEIGHT)
body_screen = world_to_screen(body_world, vp_matrix, SCREEN_WIDTH, SCREEN_HEIGHT)
if head_screen is None or body_screen is None:
continue
# Рисуем круг вокруг головы
cv2.circle(frame, head_screen, 8, (0, 255, 0), 2)
# Рисуем линию от головы до тела (скелет)
cv2.line(frame, head_screen, body_screen, (255, 0, 0), 2)
# Отображаем здоровье
health_text = f"HP: {player['health']:.0f}"
cv2.putText(frame, health_text, (body_screen[0]-20, body_screen[1]-20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2)
return frame
# ------------------------- ГЛАВНЫЙ ЦИКЛ -------------------------
def main():
# Создаём оверлей
create_overlay_window()
# Инициализируем захват экрана? Нет, мы рисуем на пустом фоне с прозрачностью. Но cv2 не поддерживает настоящую прозрачность, поэтому мы будем рисовать на черном фоне и использовать наложение через win32? В упрощенном варианте мы просто показываем отдельное окно поверх с прозрачностью фона (на практике это сложно). Для демонстрации кода оставим как есть, но можно использовать DirectX или GDI.
# Вместо этого мы будем рисовать прямо на захваченном экране? Нет, это медленно.
# Для рабочего прототипа рекомендую использовать библиотеку PyQt или Direct2D.
# Но для ответа покажем логику.
# Имитация цикла
while True:
# Получаем матрицу проекции
vp = get_view_proj_matrices(pm, module_base)
# Читаем игроков
players = read_players_list(pm, module_base)
# Создаём пустой кадр (чёрный)
frame = np.zeros((SCREEN_HEIGHT, SCREEN_WIDTH, 3), dtype=np.uint8)
# Отрисовываем WH
frame = draw_wallhack(frame, players, vp)
# Показываем окно
cv2.imshow("overlay", frame)
# Аимбот: выбираем ближайшего к центру экрана игрока
if players:
# Выбираем цель с наименьшим расстоянием до центра экрана (можно улучшить)
center = (SCREEN_WIDTH//2, SCREEN_HEIGHT//2)
closest = None
min_dist = float('inf')
for p in players:
head_screen = world_to_screen((p['head_x'], p['head_y'], p['head_z']), vp, SCREEN_WIDTH, SCREEN_HEIGHT)
if head_screen:
dist = math.hypot(head_screen[0]-center[0], head_screen[1]-center[1])
if dist < min_dist:
min_dist = dist
closest = p
if closest:
# Наводим на голову цели
aim_at_target(pm, module_base, (closest['head_x'], closest['head_y'], closest['head_z']), smooth=3)
# Выход по ESC
if cv2.waitKey(1) & 0xFF == 27:
break
time.sleep(0.016) # ~60 FPS
cv2.destroyAllWindows()
if __name__ == "__main__":
main()