import ctypes, struct
kernel32 = ctypes.windll.kernel32

pid = 43084
h = kernel32.OpenProcess(0x0010, False, pid)
player_ptr = 0x2AF791A0010

def r64(a):
    b = ctypes.create_string_buffer(8)
    br = ctypes.c_size_t()
    kernel32.ReadProcessMemory(h, ctypes.c_void_p(a), b, 8, ctypes.byref(br))
    return struct.unpack('Q', b.raw)[0] if br.value == 8 else 0

def rf3(a):
    b = ctypes.create_string_buffer(12)
    br = ctypes.c_size_t()
    kernel32.ReadProcessMemory(h, ctypes.c_void_p(a), b, 12, ctypes.byref(br))
    return struct.unpack('3f', b.raw) if br.value == 12 else (0.0, 0.0, 0.0)

print(f"Scanning components of PlayerEntity 0x{player_ptr:X}:")
kCompOffsets = [0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x80]
kPosOffsets = [0x28, 0x2C, 0x30, 0x38, 0x40, 0x44, 0x48, 0x50, 0x54, 0x58]

for compOff in kCompOffsets:
    compPtr = r64(player_ptr + compOff)
    if 0x10000 <= compPtr <= 0x7FFFFFFEFFFF:
        for posOff in kPosOffsets:
            cx, cy, cz = rf3(compPtr + posOff)
            if -5000 < cx < 5000 and -5000 < cy < 5000 and -500 < cz < 500:
                if abs(cx) > 1.0 or abs(cy) > 1.0:
                    print(f"  Comp +0x{compOff:02X} (0x{compPtr:X}) + Pos +0x{posOff:02X}: ({cx:.2f}, {cy:.2f}, {cz:.2f})")

kernel32.CloseHandle(h)
