ViewMatrix Problem

Vasadze

Member
Joined
Sep 22, 2024
Messages
10
Reaction score
0
i tried this for debugging, but screen cords are always 0, 0... is ViewMatrix Problem or my w2s problem?
Code:
import pymem
import pymem.process
import struct
import win32gui
import math
import time
# Offsets 
SAMP_INFO_OFFSET = 0x21A0F8
PPOOL_OFFSET = 0x3CD
PLAYER_POOL_OFFSET = 0x18
MAX_PLAYER_ID_OFFSET = 0x0
REMOTEPLAYER_OFFSET = 0x2E
REMOTEPLAYERDATA_OFFSET = 0x0
ACTOR_OFFSET = 0x0
GTA_ENTITY_OFFSET = 0x40
CAMERA_MATRIX_OFFSET = 0xB6FA2C 

def get_game_window_rect(window_title_substring="GTA:SA"):
    def enum_windows_callback(hwnd, results):
        if win32gui.IsWindowVisible(hwnd):
            title = win32gui.GetWindowText(hwnd)
            if window_title_substring.lower() in title.lower():
                results.append(hwnd)
    results = []
    win32gui.EnumWindows(enum_windows_callback, results)
    if not results:
        return None
    hwnd = results[0]
    rect = win32gui.GetClientRect(hwnd) 
    width = rect[2] - rect[0]
    height = rect[3] - rect[1]
    return hwnd, width, height
def read_matrix(pm: pymem.Pymem, address: int):
    try:
        data = pm.read_bytes(address, 64)  #  64 bytes
        return struct.unpack('<16f', data) 
    except pymem.exception.MemoryReadError:
        return None
    
def world_to_screen(pos, matrix, width, height):
    clip_x = pos[0]*matrix[0] + pos[1]*matrix[1] + pos[2]*matrix[2] + matrix[3]
    clip_y = pos[0]*matrix[4] + pos[1]*matrix[5] + pos[2]*matrix[6] + matrix[7]
    clip_w = pos[0]*matrix[12] + pos[1]*matrix[13] + pos[2]*matrix[14] + matrix[15]
    # You can try lowering this threshold temporarily
    if clip_w < 0.01:
        return None
    ndc_x = clip_x / clip_w
    ndc_y = clip_y / clip_w
    print(f"NDC coords: x={ndc_x}, y={ndc_y}")
    if any(map(lambda v: math.isnan(v) or math.isinf(v), [ndc_x, ndc_y])):
        print("NDC has NaN or Inf")
        return None
    screen_x = int((ndc_x + 1) * 0.5 * width)
    screen_y = int((1 - ndc_y) * 0.5 * height)
    print(f"Screen coords: x={screen_x}, y={screen_y}")
    # Optionally filter out coords outside screen bounds:
    if screen_x < 0 or screen_x > width or screen_y < 0 or screen_y > height:
        print("Screen coords out of bounds")
        # return None  # comment out to see all outputs
    return (screen_x, screen_y)


def read_dword(pm: pymem.Pymem, address: int) -> int:
    try:
        return pm.read_int(address)
    except pymem.exception.MemoryReadError:
        return 0
def read_float(pm: pymem.Pymem, address: int) -> float:
    try:
        data = pm.read_bytes(address, 4)
        return struct.unpack('<f', data)[0]
    except pymem.exception.MemoryReadError:
        return float('nan')
def get_max_player_id(pm: pymem.Pymem, samp_base: int) -> int:
    samp_info = read_dword(pm, samp_base + SAMP_INFO_OFFSET)
    if not samp_info:
        return 0
    samp_pools = read_dword(pm, samp_info + PPOOL_OFFSET)
    if not samp_pools:
        return 0
    player_pool = read_dword(pm, samp_pools + PLAYER_POOL_OFFSET)
    if not player_pool:
        return 0
    max_player_id = read_dword(pm, player_pool + MAX_PLAYER_ID_OFFSET)
    return max_player_id
def get_gta_entity(pm: pymem.Pymem, samp_base: int, playerID: int) -> int | None:
    samp_info = read_dword(pm, samp_base + SAMP_INFO_OFFSET)
    if not samp_info:
        return None
    samp_pools = read_dword(pm, samp_info + PPOOL_OFFSET)
    if not samp_pools:
        return None
    player_pool = read_dword(pm, samp_pools + PLAYER_POOL_OFFSET)
    if not player_pool:
        return None
    max_player_id = read_dword(pm, player_pool + MAX_PLAYER_ID_OFFSET)
    if playerID < 0 or playerID > max_player_id:
        return None
    remote_player_ptr_addr = player_pool + REMOTEPLAYER_OFFSET + (playerID * 4)
    remote_player = read_dword(pm, remote_player_ptr_addr)
    if not remote_player:
        return None
    player_data = read_dword(pm, remote_player + REMOTEPLAYERDATA_OFFSET)
    if not player_data:
        return None
    samp_actor = read_dword(pm, player_data + ACTOR_OFFSET)
    if not samp_actor:
        return None
    gta_entity = read_dword(pm, samp_actor + GTA_ENTITY_OFFSET)
    return gta_entity if gta_entity != 0 else None
def get_player_coords(pm: pymem.Pymem, gta_entity: int):
    if gta_entity == 0:
        return None
    dwAddress = read_dword(pm, gta_entity + 0x14)
    if not dwAddress:
        return None
    x = read_float(pm, dwAddress + 0x30)
    y = read_float(pm, dwAddress + 0x34)
    z = read_float(pm, dwAddress + 0x38)
    if any(coord != coord for coord in (x, y, z)):
        return None
    return (x, y, z)
if __name__ == "__main__":
    pm = pymem.Pymem("gta_sa.exe")
    samp_module = pymem.process.module_from_name(pm.process_handle, "samp.dll")
    samp_base = samp_module.lpBaseOfDll
    window_data = get_game_window_rect()
    if window_data is None:
        print("Game window not found")
        exit()
    hwnd, screen_width, screen_height = window_data
    print(f"Game window found: hwnd={hwnd}, size={screen_width}x{screen_height}")
    print(f"SAMP base address: {hex(samp_base)}")
    while True:
        viewmatrix = read_matrix(pm, CAMERA_MATRIX_OFFSET)
        if not viewmatrix:
            print("Failed to read view matrix")
            time.sleep(0.05)
            continue
        max_id = get_max_player_id(pm, samp_base)
        valid_players = []
        for player_id in range(max_id + 1):
            entity = get_gta_entity(pm, samp_base, player_id)
            if entity is None:
                # print(f"Player {player_id} entity is None")
                continue
            coords = get_player_coords(pm, entity)
            if coords is None:
                # print(f"Player {player_id} coords are None")
                continue
            x, y, z = coords
            #print(f"Player {player_id} coords: X={x:.2f}, Y={y:.2f}, Z={z:.2f}")
            valid_players.append((player_id, coords))
        for player_id, coords in valid_players:
            screen_pos = world_to_screen(coords, viewmatrix, screen_width, screen_height)
            if screen_pos:
                sx, sy = screen_pos
                print(f"PlayerID {player_id} at screen coords: {sx}, {sy}")
        time.sleep(0.05)
 
Top