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


# language: Python, file: cs2_cheat.py
# external CS2 cheat with auto-updating offsets
import ctypes
import ctypes.wintypes as wt
import json
import math
import os
import struct
import sys
import threading
import time
import tkinter as tk
import urllib.request
from dataclasses import dataclass, field
from typing import Optional

import pymem

# ---------- AUTO OFFSETS ----------
# Мы берем оффсеты напрямую из открытого репозитория, который обновляется сам.
OFFSETS_URL = "https://raw.githubusercontent.com/a2x/cs2-dumper/main/output/offsets.json"
CLIENT_DLL_URL = "https://raw.githubusercontent.com/a2x/cs2-dumper/main/output/client_dll.json"

@dataclass
class Offsets:
    dwEntityList: int = 0
    dwLocalPlayer: int = 0
    dwViewMatrix: int = 0
    m_iHealth: int = 0
    m_iTeamNum: int = 0
    m_vecOrigin: int = 0
    m_dwBoneMatrix: int = 0
    m_angEyeAngles: int = 0

def fetch_url(url: str) -> dict:
    try:
        req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
        with urllib.request.urlopen(req, timeout=10) as response:
            return json.loads(response.read().decode())
    except Exception as e:
        print(f"[!] Ошибка скачивания оффсетов: {e}")
        return {}

def load_offsets() -> Offsets:
    o = Offsets()
    print("[*] Скачиваем свежие оффсеты...")
    
    data_offsets = fetch_url(OFFSETS_URL)
    data_client = fetch_url(CLIENT_DLL_URL)
    
    if not data_offsets or not data_client:
        print("[!] Не удалось скачать. Проверь интернет.")
        return o

    # Парсим offsets.json (там client.dll)
    client = data_offsets.get("client.dll", {})
    o.dwEntityList  = client.get("dwEntityList", 0)
    o.dwLocalPlayer = client.get("dwLocalPlayer", 0)
    o.dwViewMatrix  = client.get("dwViewMatrix", 0)
    
    # Парсим client_dll.json (там netvars для классов)
    # В a2x дампере netvars лежат в структуре классов
    classes = data_client.get("client.dll", {}).get("classes", {})
    
    # Ищем нужные поля в классах C_CSPlayerPawn и т.д.
    for class_name, class_data in classes.items():
        fields = class_data.get("fields", {})
        for field_name, field_offset in fields.items():
            if field_name == "m_iHealth":
                o.m_iHealth = field_offset
            elif field_name == "m_iTeamNum":
                o.m_iTeamNum = field_offset
            elif field_name == "m_vecOrigin":
                o.m_vecOrigin = field_offset
            elif field_name == "m_dwBoneMatrix":
                o.m_dwBoneMatrix = field_offset
            elif field_name == "m_angEyeAngles":
                o.m_angEyeAngles = field_offset

    print(f"[+] Оффсеты загружены: EntityList={hex(o.dwEntityList)}, Health={hex(o.m_iHealth)}")
    return o

# ---------- math ----------
@dataclass
class Vec3:
    x: float = 0.0
    y: float = 0.0
    z: float = 0.0

def v3sub(a: Vec3, b: Vec3) -> Vec3:
    return Vec3(a.x - b.x, a.y - b.y, a.z - b.z)

def calc_angle(src: Vec3, dst: Vec3) -> Vec3:
    d = v3sub(dst, src)
    hyp = math.sqrt(d.x * d.x + d.y * d.y)
    return Vec3(
        math.atan2(-d.z, hyp) * 57.29578,
        math.atan2(d.y, d.x) * 57.29578,
        0.0,
    )

def world_to_screen(w: Vec3, vm: list[float], sw: int, sh: int) -> Optional[tuple[float, float]]:
    cx = w.x * vm[0] + w.y * vm[4] + w.z * vm[8]  + vm[12]
    cy = w.x * vm[1] + w.y * vm[5] + w.z * vm[9]  + vm[13]
    cw = w.x * vm[3] + w.y * vm[7] + w.z * vm[11] + vm[15]
    if cw < 0.01:
        return None
    return ((sw * 0.5) * ((cx / cw) + 1.0), (sh * 0.5) * (1.0 - (cy / cw)))

# ---------- memory ----------
class GameMemory:
    def __init__(self) -> None:
        self.pm: Optional[pymem.Pymem] = None
        self.client: int = 0
        self.off = Offsets()

    def attach(self) -> bool:
        try:
            self.pm = pymem.Pymem("cs2.exe")
            self.client = pymem.process.module_from_name(
                self.pm.process_handle, "client.dll"
            ).lpBaseOfDll
            self.off = load_offsets()
            return True
        except Exception as e:
            print(f"[!] Ошибка подключения: {e}")
            return False

    def read(self, addr: int, fmt: str):
        try:
            size = struct.calcsize(fmt)
            buf = self.pm.read_bytes(addr, size)
            return struct.unpack(fmt, buf)[0]
        except Exception:
            return None

    def read_vec3(self, addr: int) -> Vec3:
        try:
            buf = self.pm.read_bytes(addr, 12)
            return Vec3(*struct.unpack("fff", buf))
        except Exception:
            return Vec3()

    def read_view_matrix(self, addr: int) -> list[float]:
        try:
            buf = self.pm.read_bytes(addr, 64)
            return list(struct.unpack("16f", buf))
        except Exception:
            return [0.0] * 16

# ---------- entities ----------
@dataclass
class Player:
    addr: int
    health: int
    team: int
    origin: Vec3
    bones: int

@dataclass
class WorldState:
    local: int = 0
    local_origin: Vec3 = field(default_factory=Vec3)
    local_team: int = 0
    local_angles: Vec3 = field(default_factory=Vec3)
    view_matrix: list[float] = field(default_factory=lambda: [0.0] * 16)
    players: list[Player] = field(default_factory=list)

def read_world(mem: GameMemory) -> WorldState:
    ws = WorldState()
    if not mem.pm or not mem.client:
        return ws
    o = mem.off
    ws.local = mem.read(mem.client + o.dwLocalPlayer, "Q") or 0
    if not ws.local:
        return ws
    ws.local_origin = mem.read_vec3(ws.local + o.m_vecOrigin)
    ws.local_team = mem.read(ws.local + o.m_iTeamNum, "i") or 0
    ws.local_angles = mem.read_vec3(ws.local + o.m_angEyeAngles)
    ws.view_matrix = mem.read_view_matrix(mem.client + o.dwViewMatrix)

    ent_list = mem.read(mem.client + o.dwEntityList, "Q") or 0
    if not ent_list:
        return ws

    for i in range(1, 64):
        ent = mem.read(ent_list + i * 0x8, "Q")
        if not ent:
            continue
        hp = mem.read(ent + o.m_iHealth, "i")
        if hp is None or hp <= 0 or hp > 100:
            continue
        ws.players.append(Player(
            addr=ent,
            health=hp,
            team=mem.read(ent + o.m_iTeamNum, "i") or 0,
            origin=mem.read_vec3(ent + o.m_vecOrigin),
            bones=mem.read(ent + o.m_dwBoneMatrix, "Q") or 0,
        ))
    return ws

HEAD_BONE = 6

def bone_pos(mem: GameMemory, bones: int, bone_id: int) -> Vec3:
    if not bones:
        return Vec3()
    base = bones + bone_id * 0x40
    return Vec3(
        mem.read(base + 0x30, "f") or 0.0,
        mem.read(base + 0x34, "f") or 0.0,
        mem.read(base + 0x38, "f") or 0.0,
    )

# ---------- mouse / aim ----------
class MOUSEINPUT(ctypes.Structure):
    _fields_ = [
        ("dx", wt.LONG),
        ("dy", wt.LONG),
        ("mouseData", wt.DWORD),
        ("dwFlags", wt.DWORD),
        ("time", wt.DWORD),
        ("dwExtraInfo", ctypes.POINTER(wt.ULONG)),
    ]

class INPUT(ctypes.Structure):
    class _I(ctypes.Union):
        _fields_ = [("mi", MOUSEINPUT)]
    _anonymous_ = ("i",)
    _fields_ = [("type", wt.DWORD), ("i", _I)]

INPUT_MOUSE = 0
MOUSEEVENTF_MOVE = 0x0001

def move_mouse(dx: float, dy: float) -> None:
    inp = INPUT()
    inp.type = INPUT_MOUSE
    inp.mi = MOUSEINPUT(int(dx), int(dy), 0, MOUSEEVENTF_MOVE, 0, None)
    ctypes.windll.user32.SendInput(1, ctypes.byref(inp), ctypes.sizeof(INPUT))

@dataclass
class AimConfig:
    enabled: bool = True
    fov: float = 8.0
    smooth: float = 0.35
    bone: int = HEAD_BONE
    vk: int = 0x02  # RBUTTON
    px_per_deg: float = 10.0

def do_aim(ws: WorldState, mem: GameMemory, cfg: AimConfig) -> None:
    if not cfg.enabled or not ws.local:
        return
    if not (ctypes.windll.user32.GetAsyncKeyState(cfg.vk) & 0x8000):
        return

    view = ws.local_angles
    best_ang: Optional[Vec3] = None
    best_d = cfg.fov

    for p in ws.players:
        if p.team == ws.local_team:
            continue
        target = bone_pos(mem, p.bones, cfg.bone)
        if target.x == 0.0 and target.y == 0.0 and target.z == 0.0:
            continue
        ang = calc_angle(ws.local_origin, target)
        dy = ang.y - view.y
        while dy > 180:  dy -= 360
        while dy < -180: dy += 360
        dp = ang.x - view.x
        d = math.sqrt(dy * dy + dp * dp)
        if d < best_d:
            best_d = d
            best_ang = ang

    if best_ang is None:
        return

    dy = best_ang.y - view.y
    while dy > 180:  dy -= 360
    while dy < -180: dy += 360
    dp = best_ang.x - view.x

    move_mouse(dy * cfg.px_per_deg * cfg.smooth,
               -dp * cfg.px_per_deg * cfg.smooth)

# ---------- overlay (tkinter, click-through) ----------
TRANSPARENT = "#010203"

class Overlay:
    def __init__(self, mem: GameMemory) -> None:
        self.mem = mem
        self.root = tk.Tk()
        self.root.title("overlay")
        self.root.attributes("-topmost", True)
        self.root.attributes("-fullscreen", True)
        self.root.configure(bg=TRANSPARENT)
        try:
            self.root.wm_attributes("-transparentcolor", TRANSPARENT)
        except tk.TclError:
            pass
        self.canvas = tk.Canvas(self.root, bg=TRANSPARENT, highlightthickness=0)
        self.canvas.pack(fill="both", expand=True)
        self.sw = self.root.winfo_screenwidth()
        self.sh = self.root.winfo_screenheight()
        self.root.after(10, self.tick)

    def tick(self) -> None:
        try:
            ws = read_world(self.mem)
            self.draw(ws)
        except Exception:
            pass
        self.root.after(10, self.tick)

    def draw(self, ws: WorldState) -> None:
        self.canvas.delete("all")
        if not ws.local:
            return
        for p in ws.players:
            if p.team == ws.local_team:
                continue
            head = bone_pos(self.mem, p.bones, HEAD_BONE)
            feet = Vec3(p.origin.x, p.origin.y, p.origin.z - 72.0)
            tp = world_to_screen(head, ws.view_matrix, self.sw, self.sh)
            bp = world_to_screen(feet, ws.view_matrix, self.sw, self.sh)
            if not tp or not bp:
                continue
            h = bp[1] - tp[1]
            if h <= 2 or h > self.sh:
                continue
            w = h * 0.5
            x1, x2 = tp[0] - w / 2, tp[0] + w / 2
            self.canvas.create_rectangle(x1, tp[1], x2, bp[1], outline="red", width=2)
            self.canvas.create_rectangle(x1 - 6, tp[1], x1 - 3, bp[1], fill="#333", outline="")
            hp_h = (bp[1] - tp[1]) * (p.health / 100.0)
            self.canvas.create_rectangle(x1 - 6, bp[1] - hp_h, x1 - 3, bp[1], fill="#0f0", outline="")
        self.root.update_idletasks()

    def run(self) -> None:
        self.root.mainloop()

# ---------- main ----------
def main() -> int:
    mem = GameMemory()
    print("[*] Ожидание запуска cs2.exe...")
    while not mem.attach():
        time.sleep(2)
    print(f"[+] Подключено. client.dll @ {hex(mem.client)}")

    cfg = AimConfig()
    overlay = Overlay(mem)

    def aim_loop() -> None:
        while True:
            try:
                ws = read_world(mem)
                do_aim(ws, mem, cfg)
            except Exception:
                pass
            time.sleep(0.002)

    threading.Thread(target=aim_loop, daemon=True).start()
    overlay.run()
    return 0

if __name__ == "__main__":
    sys.exit(main())