"""Dump Visual Tool locked camera/fog. 11/09/2026."""
from __future__ import annotations

import ctypes
import ctypes.wintypes as w
import struct
import sys

k32 = ctypes.WinDLL("kernel32", use_last_error=True)
k32.OpenProcess.restype = w.HANDLE
k32.ReadProcessMemory.argtypes = [
    w.HANDLE, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t)
]
k32.ReadProcessMemory.restype = w.BOOL
k32.MapViewOfFile.restype = ctypes.c_void_p


def rpm(h, addr, n):
    buf = (ctypes.c_ubyte * n)()
    got = ctypes.c_size_t(0)
    if not k32.ReadProcessMemory(h, ctypes.c_void_p(addr), buf, n, ctypes.byref(got)):
        return None
    return bytes(buf[: got.value])


def read_ipc():
    h = k32.OpenFileMappingW(0x0004, False, "Local\\AutoPOE2_VisualTool_v1")
    if not h:
        return None
    view = k32.MapViewOfFile(h, 0x0004, 0, 0, 48)
    buf = ctypes.string_at(view, 48)
    magic, seq, cap, cur, flags, status = struct.unpack_from("<IIffII", buf, 0)
    cam, fog = struct.unpack_from("<QQ", buf, 0x18)
    pid, err = struct.unpack_from("<II", buf, 0x28)
    return {
        "magic": magic, "cap": cap, "cur": cur, "flags": flags, "status": status,
        "cam": cam, "fog": fog, "pid": pid, "err": err,
    }


def main():
    ipc = read_ipc()
    print("ipc", ipc, flush=True)
    if not ipc:
        return
    h = k32.OpenProcess(0x410, False, ipc["pid"])
    print("OpenProcess", bool(h), ctypes.get_last_error(), flush=True)
    cam = ipc["cam"]
    fog = ipc["fog"]
    b = rpm(h, cam, 0x80)
    print("cam_hex", None if not b else b[:24].hex(), flush=True)
    if b:
        vt = struct.unpack_from("<Q", b, 0)[0]
        print(f"vtable={vt:#x} in_mod={0x7FF6AFC20000 <= vt < 0x7FF6AFC20000 + 0x4C9E000}", flush=True)
        names = {
            0x08: "posX?", 0x0C: "posY?", 0x10: "posZ?",
            0x14: "tgtX?", 0x18: "tgtY?", 0x1C: "tgtZ?",
            0x20: "pitch?", 0x24: "yaw?", 0x28: "roll?",
            0x2C: "cur", 0x30: "min", 0x34: "max", 0x38: "fov",
            0x3C: "zNear", 0x40: "zFar", 0x44: "smooth",
        }
        for o in range(0x08, 0x50, 4):
            v = struct.unpack_from("<f", b, o)[0]
            u = struct.unpack_from("<I", b, o)[0]
            tag = names.get(o, "")
            print(f"  +{o:#04x} f={v:14.4f} u32={u:#010x} {tag}", flush=True)
        print("ascii", repr(b[:64]), flush=True)
    fb = rpm(h, fog, 16)
    if fb:
        print("fog", struct.unpack("<ffff", fb), flush=True)


if __name__ == "__main__":
    main()
