Гайд Как сделать 3D ESP боксы на Python.

Начинающий
Статус
Оффлайн
Регистрация
21 Мар 2021
Сообщения
94
Реакции[?]
29
Поинты[?]
7K
Хайоу, сегодня я покажу как можно довольно быстро и просто сделать 3D боксы на Python.



Шаг №1 "Установка Python":
Для начала нам необходимо установить интерпретатор Python'а, для этого переходим на официальный сайт языка:
Пожалуйста, авторизуйтесь для просмотра ссылки.


Качаем установщик интерпретатора последней версии, для этого наводим мышь на "Downloads" и нажимаем кнопку "Python 3.10.X".
Запускаем установщик и обязательно нажимаем флаг "Add to PATH" если вы не хотите потом вручную ебаться с изменением системных переменных среды.

Шаг №2 "Установка необходимых модулей и библиотек":
Итак, если первый шаг прошел без проблем, то мы можем открыть консоль и написать команду "pip".

Если вывод консоли не пуст, то все выполнено правильно, вывод должен выглядеть подобным образом:

pip - пакетный менеджер языка Python, он нужен нам для загрузки внешних модулей и библиотек.
Нам понадобится 3 внешних модуля для создания нашего чита:
  • pymemoryapi - модуль для работы с памятью процесса.
  • pyextoverlay - модуль для создания оверлея и рисовки самих ESP.
  • request - модуль для GET и POST запросов. Через него мы будет получать оффсеты.
Для установки модулей нам нужно открыть консоль и написать там команду: pip install <название модуля>.
Также есть возможность скачать несколько модулей за раз, для этого их просто нужно разделить пробелами.
P.S. у меня уже установлены модули, у вас должна будет появиться шкала прогресса и вывод о успешной установки.

Шаг №3 "Написание кода":
После того, как интерпретатор и библиотеки установлены может перейти к написанию кода.

Напишем код в файл содержащий основные функции нашего чита "logic.py":
logic.py:
import ctypes


def get_window_geometry(window_name: str) -> tuple:
    """Получает положение и размер окна по назавнию.

    Возвращает кортеж. (x, y, w, h), содержащий информацию о положении и размере окна."""

    ctypes.windll.user32.SetProcessDPIAware()
    hwnd = ctypes.windll.user32.FindWindowW(0, window_name)
    rect = ctypes.wintypes.RECT()
    ctypes.windll.user32.GetWindowRect(hwnd, ctypes.pointer(rect))

    return (rect.left, rect.top, rect.right, rect.bottom)


def get_view_matrix(process: object, base_module: int, view_matrix_offset: int) -> list:
    """Получает видовую матрицу.

    Возвращает список видовой матрицы, содержащий 16 float чисел."""

    matrix = []
    for i in range(16):
        matrix.append(process.read_float(base_module + view_matrix_offset + 4 * i))

    return matrix


def world_to_screen(view_matrix: list, screen_size: tuple, x: float, y: float, z: float) -> tuple:
    """Транслирует координаты объекта в экранные координаты.

    Возвращает кортеж (x, y), содержащий координаты объекта на плоскости монитора."""

    screen_w = (view_matrix[12] * x) + (view_matrix[13] * y) + (view_matrix[14] * z) + view_matrix[15]
    if screen_w > 0.001:
        screen_x = (view_matrix[0] * x) + (view_matrix[1] * y) + (view_matrix[2] * z) + view_matrix[3]
        screen_y = (view_matrix[4] * x) + (view_matrix[5] * y) + (view_matrix[6] * z) + view_matrix[7]
        camera_x = screen_size[0] // 2
        camera_y = screen_size[1] // 2

        return(camera_x + (camera_x * screen_x // screen_w), camera_y - (camera_y * screen_y // screen_w))
Напишем код с самим читом, включающий ф-ии файла logic.py "main.py":
main.py:
import pymemoryapi
import threading
import requests
import time

from logic import *
from pyextoverlay import *


# Получение оффсетов.
offsets = requests.get("https://raw.githubusercontent.com/frk1/hazedumper/master/csgo.json").json()
dwViewMatrix = int(offsets['signatures']['dwViewMatrix'])
dwLocalPlayer = int(offsets['signatures']['dwLocalPlayer'])
dwEntityList = int(offsets['signatures']["dwEntityList"])
m_vecOrigin = int(offsets['netvars']['m_vecOrigin'])
m_iTeamNum = int(offsets['netvars']['m_iTeamNum'])
m_bDormant = int(offsets['signatures']['m_bDormant'])
m_iHealth = int(offsets['netvars']['m_iHealth'])

# Подключение к процессу и работа с ним.
process = pymemoryapi.Process(process_name="csgo.exe")
base_module = process.get_module_info("client.dll").BaseAddress

# Инициализация и запуск оверлея.
application = application_init()

# 1000 / 17 = ~58.8235 fps
overlay = Overlay(17)
overlay.showFullScreen()
overlay.show()


# Ф-ия - поток ESP
def esp() -> None:
    """Ф-ия ESP (должна вызываться в новом потоке)."""

    print("Запуск ESP.")

    # настройки ESP (RGB цвет, толщина линий бокса).
    box_color = (0, 255, 127)
    line_width = 2

    while True:

        # Сюда мы будет помешять данные отрисовки, которые в дальнейшем будут переноситься в стек отрисовки оверлея.
        esp_lines = []

        # Полученим видовой матрицы и информации о окне игры
        view_matrix = get_view_matrix(process, base_module, dwViewMatrix)
        window_info = get_window_geometry("Counter-Strike: Global Offensive - Direct3D 9")

        # Нахожденим адрес нашего игрока, нужен чтобы не рисовать бокс на самого себя в дальнейшем.
        local_player = process.read_int(base_module + dwLocalPlayer)

        # Игроки - объекты в списке в памяти игры, получаем 32 игрока (с запасом).
        for i in range(32):

            # Получаем самого игрока, его хп и состояние (действущий или бездействующий)
            entity = process.read_int(base_module + dwEntityList + i * 0x10)
            entity_health = process.read_int(entity + m_iHealth)
            dormant = process.read_int(entity + m_bDormant)

            # Если игрок существует, его хп, он не бездействуюий и не является нашим игроком (local player'ом).
            if entity and entity_health and not dormant and entity != local_player:

                # Итерируемся по каждому существующему игроку и получаем его координаты.
                entity_x = process.read_float(entity + m_vecOrigin + 0x0)
                entity_y = process.read_float(entity + m_vecOrigin + 0x4)
                entity_z = process.read_float(entity + m_vecOrigin + 0x8)

                # Пробразовываем координаты игрока в координаты точек (данные 4 точки являются нижней крышкой бокса, которые при соединении дают квадрат).
                bottom1 = world_to_screen(view_matrix, (window_info[2], window_info[3]), entity_x - 15, entity_y + 15, entity_z)
                bottom2 = world_to_screen(view_matrix, (window_info[2], window_info[3]), entity_x + 15, entity_y - 15, entity_z)
                bottom3 = world_to_screen(view_matrix, (window_info[2], window_info[3]), entity_x - 15, entity_y - 15, entity_z)
                bottom4 = world_to_screen(view_matrix, (window_info[2], window_info[3]), entity_x + 15, entity_y + 15, entity_z)

                # Тут все тоже самое, только поднимаем коодинату z, тем самым создавая точки над головой игрока.
                up1 = world_to_screen(view_matrix, (window_info[2], window_info[3]), entity_x - 15, entity_y + 15, entity_z + 75)
                up2 = world_to_screen(view_matrix, (window_info[2], window_info[3]), entity_x + 15, entity_y - 15, entity_z + 75)
                up3 = world_to_screen(view_matrix, (window_info[2], window_info[3]), entity_x - 15, entity_y - 15, entity_z + 75)
                up4 = world_to_screen(view_matrix, (window_info[2], window_info[3]), entity_x + 15, entity_y + 15, entity_z + 75)

                # Проверяем целостность точкек и соединяем их линиями, тем самым создавая бокс (добавляем все линии в наш заготовленный выше список).
                if bottom1 and bottom2 and bottom3 and bottom4 and up1 and up2 and up3 and up4:
                    esp_lines.append({"type": "line", "x1": int(bottom1[0] - 6), "y1": int(bottom1[1]), "x2": int(bottom3[0]) - 6, "y2": int(bottom3[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})
                    esp_lines.append({"type": "line", "x1": int(bottom1[0] - 6), "y1": int(bottom1[1]), "x2": int(bottom4[0]) - 6, "y2": int(bottom4[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})
                    esp_lines.append({"type": "line", "x1": int(bottom4[0] - 6), "y1": int(bottom4[1]), "x2": int(bottom2[0]) - 6, "y2": int(bottom2[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})
                    esp_lines.append({"type": "line", "x1": int(bottom3[0] - 6), "y1": int(bottom3[1]), "x2": int(bottom2[0]) - 6, "y2": int(bottom2[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})

                    esp_lines.append({"type": "line", "x1": int(up1[0] - 6), "y1": int(up1[1]), "x2": int(up3[0]) - 6, "y2": int(up3[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})
                    esp_lines.append({"type": "line", "x1": int(up1[0] - 6), "y1": int(up1[1]), "x2": int(up4[0]) - 6, "y2": int(up4[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})
                    esp_lines.append({"type": "line", "x1": int(up4[0] - 6), "y1": int(up4[1]), "x2": int(up2[0]) - 6, "y2": int(up2[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})
                    esp_lines.append({"type": "line", "x1": int(up3[0] - 6), "y1": int(up3[1]), "x2": int(up2[0]) - 6, "y2": int(up2[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})

                    esp_lines.append({"type": "line", "x1": int(bottom1[0] - 6), "y1": int(bottom1[1]), "x2": int(up1[0]) - 6, "y2": int(up1[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})
                    esp_lines.append({"type": "line", "x1": int(bottom2[0] - 6), "y1": int(bottom2[1]), "x2": int(up2[0]) - 6, "y2": int(up2[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})
                    esp_lines.append({"type": "line", "x1": int(bottom3[0] - 6), "y1": int(bottom3[1]), "x2": int(up3[0]) - 6, "y2": int(up3[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})
                    esp_lines.append({"type": "line", "x1": int(bottom4[0] - 6), "y1": int(bottom4[1]), "x2": int(up4[0]) - 6, "y2": int(up4[1]), "linesize": line_width, "linetype": pentype["solid"], "color": box_color})

        # Переносим содержимое нашего списка (наши линии) в стек отрисовки РАЗОМ, дабы не создавать мерзкие и неприятные блики и визуальные пролаги.
        # Т.к. оверлей работает в отдельном потоке, то по истечению таймера он затриггерит ф-ию отрисовки, которая уже и обработает наш стек.
        # Т.к. все работает в цикле, в начале которого мы и создаем список отрисовки, очищать его нет никакого смысла, ибо это произайдет само.
        overlay.draw_stack = [*esp_lines]
        time.sleep(0.01)


# Запуск потока ESP и оверлея.
# ОБЯЗАТЕЛЬНО СОЗДАВАТЬ ОТДЕЛНЫЙ ПОТОК! т.к. application_start() вызовет уже свой вечный цикл.
threading.Thread(target=esp).start()
application_start(application)


# Запуск потока ESP и оверлея
threading.Thread(target=esp).start()
application_start(application)

Основные идеи и релизация расписаны в комментариях, если вам нужно больше подробностей по работе pyextoverlay или pymemoryapi - вы можете найти информацию тут:
Также стоить помнить, что вы можете спокойно открыть исходный код библиотек предварительно нажав F12, (VScode, Pycharm) когда текстовый курсор находится на желаемом вам объекте, ф-ии или переменной.

Шаг №4 "Запуск чита:
Тут все довольно просто. Вариантов запуска нашего чита несколько.

1. Мы можем запустать наш main.py как обычный исполняемый файл просто нажав по нему 2 раза лкм.
2. Можно запустить скрипт напрямую через интерпретатор, для этого нужно открыть консоль и написать там: python <название файла>.

P.S. Важно чтобы игра была запущена в полном окне без рамок. Боксы будут вести себя неправильно при неполном экране, чтобы это починить нужно менять положение оверлея в точности под положение окна игры.

Пишите ваши мысли, задавайте вопросы (буду пытаться отвечать).
Наш дискорд сервер:
Пожалуйста, авторизуйтесь для просмотра ссылки.

Мой дискорд: Xenely#7771
 
Последнее редактирование:
Сверху Снизу