# 02. Kỹ thuật Can thiệp Thị giác & Camera (Engine Visual Modifications)

> **Mục tiêu**: Mở rộng góc nhìn Camera từ 1.5x đến 8.0x và loại bỏ hoàn toàn sương mù thể tích (Volumetric Fog) cũng như sương mù bản đồ (Fog of War) trong client POE2 (v0.5.5).  
> **Nền tảng Đồ họa**: DirectX 12 / Vulkan (x64)

---

## 1. Hệ thống Camera & Kỹ thuật Mở rộng Tầm nhìn (Zoom Hack 1.5x - 8.0x)

### 1.1. Cấu trúc Đối tượng Camera trong POE2 (v0.5.5)

Trong Path of Exile 2, lớp Camera quản lý ma trận góc nhìn (View Matrix), ma trận chiếu (Projection Matrix) và các ràng buộc vật lý về khoảng cách giữa con mắt camera và nhân vật:

```cpp
// Cấu trúc đối tượng Camera trong POE2 Client v0.5.5
struct POE2_Camera {
    void* vtable;               // +0x00: Virtual Method Table
    float posX, posY, posZ;     // +0x08: Tọa độ camera trong không gian 3D
    float targetX, targetY, targetZ; // +0x14: Điểm ngắm (thường khóa vào Player)
    float pitch;                // +0x20: Góc nghiêng (độ nghiêng nhìn từ trên xuống)
    float yaw;                  // +0x24: Góc xoay ngang
    float roll;                 // +0x28: Thường là 0.0f
    
    // Các trường điều khiển khoảng cách và góc nhìn
    float currentDistance;      // +0x2C: Khoảng cách hiện tại (Mặc định: ~38.0f - 45.0f)
    float minDistance;          // +0x30: Khoảng cách zoom gần nhất (~15.0f)
    float maxDistance;          // +0x34: Giới hạn zoom xa mặc định của game (~45.0f)
    float fieldOfView;          // +0x38: Góc mở (FOV dọc, tính bằng Radian, ~0.65 - 0.78 rad)
    
    // Mặt phẳng cắt culling
    float zNear;                // +0x3C: Mặt phẳng cắt gần (~1.0f)
    float zFar;                 // +0x40: Mặt phẳng cắt xa (~150.0f mặc định)
    
    float zoomSmoothingSpeed;   // +0x44: Hệ số nội suy mượt khi cuộn chuột
    uint32_t flags;             // +0x48: Cờ trạng thái camera
};
```

### 1.2. Thách thức khi Zoom xa đến 8.0x và Giải pháp Culling Fix

Nếu chỉ đơn thuần ghi đè `currentDistance = maxDistance * 4.0f` (đẩy camera lên khoảng cách ~180.0f), người chơi sẽ gặp phải 2 hiện tượng lỗi nghiêm trọng trong POE2:
1. **Lỗi Biến mất Địa hình & Đen màn hình (Frustum Culling / ZFar Issue)**:
   - Tham số `zFar` mặc định của POE2 được khóa ở ~150.0f để tiết kiệm hiệu năng render. Khi camera ở khoảng cách 180.0f, toàn bộ mặt đất và nhân vật nằm ngoài khoảng cách `zFar`, dẫn đến việc game không render các đối tượng này (hiện tượng khoảng đen vô tận).
   - **Giải pháp**: Phải đồng thời điều chỉnh `zFar` theo công thức tỷ lệ thuận với hệ số Zoom Factor:
     $$\text{zFar}_{\text{new}} = \text{zFar}_{\text{default}} \times (\text{ZoomFactor} \times 1.25)$$
     *(Ví dụ: Zoom 4x thì $\text{zFar}$ cần nâng từ 150.0f lên ~750.0f).*
2. **Lỗi Không nạp Quái & Lưới va chạm (Entity Streaming Distance)**:
   - POE2 sử dụng hệ thống streaming thực thể theo từng chunk địa hình xung quanh người chơi. Mặc dù camera zoom 4x cho phép người chơi nhìn thấy toàn bộ map, các thực thể ở rìa xa có thể ở trạng thái chưa nạp mesh.
   - **Giải pháp**: Điều chỉnh bán kính nạp dữ liệu hiển thị (Render Distance Threshold) trong cấu trúc `TerrainManager` hoặc giữ quái hiển thị dạng hộp phác họa (Bounding Box ESP) qua lớp phủ Overlay của tool.

### 1.3. Phương pháp Can thiệp Bộ nhớ An toàn (Safe Dynamic In-Memory Patching & Code Patching Dual Architecture)

Hệ thống thiết kế 2 cơ chế can thiệp tương thích theo từng phân tầng sử dụng:

1. **Cơ chế Data-Only Modification (Vùng RAM Động Heap / `.data`) — Dành cho Core Engine (`AutoPOE2_Core.exe`)**:
   - Khi chạy chế độ botting phối hợp reflex chiến đấu (`--zoom <multiplier>`), hệ thống áp dụng kỹ thuật can thiệp trực tiếp vào biến float `maxDistance` và `zFar` trên Heap.
   - Ưu điểm: Không đụng chạm vào phân vùng mã thực thi `.text`, giữ an toàn tối đa trước các cơ chế kiểm tra toàn vẹn bộ nhớ cơ bản.

2. **Cơ chế Native Code Patching trong phân vùng `.text` (Zero Rubberbanding) — Dành cho Standalone Visual Tool (`AutoPOE2_VisualTool.exe`)**:
   - Khắc phục triệt để hiện tượng camera bị giật cục / rubberbanding do tranh chấp giữa chu kỳ External WPM ($50\text{ ms} / 20\text{ Hz}$) và Game Render Loop ($144\text{ FPS} \approx 6.94\text{ ms}$).
   - Áp dụng cấu trúc `CodePatchRecord`, quét AOB vị trí clamp `cmp byte [rax+2Fh], 0` / `comiss`, chuyển quyền an toàn bằng `VirtualProtectEx` (`PAGE_EXECUTE_READWRITE` $\rightarrow$ ghi patch $\rightarrow$ hoàn lại quyền $\rightarrow$ `FlushInstructionCache`).
   - Chi tiết kiến trúc kỹ thuật: Xem [`28_standalone_visual_tool_zoom_and_fog.md`](file:///c:/Projects/AutoPOE2/docs/development/28_standalone_visual_tool_zoom_and_fog.md#9-kiến-trúc-code-patching-trong-phân-vùng-text-native-smooth-zoom--zero-rubberbanding).

- **Panic Restore 1-Frame**: Khi nhấn phím dừng khẩn cấp (`Pause/Break` hoặc `Ctrl+Shift+F12`) hoặc khi tiến trình kết thúc, toàn bộ giá trị gốc (cả giá trị float Heap lẫn mã máy `.text`) được hoàn nguyên sạch sẽ ngay lập tức (< 1ms).

```mermaid
sequenceDiagram
    participant User as Người Dùng / GUI / CLI
    participant Core as AutoPOE2 Core Engine
    participant Visual as VisualModsEngine
    participant POE2 as POE2 Memory (RAM)

    User->>Core: Khởi động với --zoom 2.2 --no-fog
    Core->>Visual: ApplyZoom(2.2f)
    Visual->>POE2: Đọc m_origMaxDistance (45.0f), m_origZFar (150.0f)
    Visual->>POE2: Ghi maxDistance = 99.0f, zFar = 445.5f
    Core->>Visual: DisableFog()
    Visual->>POE2: Đọc m_origFogDensity (1.0f)
    Visual->>POE2: Ghi fogDensity = 0.0f
    Note over POE2: Góc nhìn mở rộng 2.2x, sương mù biến mất, FPS tăng 15-20%
    User->>Core: Bấm Pause/Break (Panic Killswitch)
    Core->>Visual: PanicRestoreAll()
    Visual->>POE2: Khôi phục maxDistance = 45.0f, zFar = 150.0f, fogDensity = 1.0f, hoàn nguyên .text (1-frame)
```

---

## 2. Kỹ thuật Xóa Sương mù (Volumetric Fog & Fog of War Removal)

Trong POE2, sương mù được chia làm 2 hệ thống:
1. **Sương mù Thể tích Môi trường (3D Volumetric Fog & Atmospheric Scatter)**: Hiệu ứng raymarching ngốn 15% - 25% GPU.
2. **Sương mù Che Bản đồ (Minimap / Exploration Fog of War)**: Mảng bitmask che phủ địa hình thế giới.

### 2.1. Vô hiệu hóa Sương mù Thể tích (3D Volumetric Fog Stripping)

POE2 lưu trữ thông số sương mù trong Render Context:

```cpp
struct FogRenderConstants {
    float fogDensity;          // +0x00: Mật độ sương mù (Gốc: 1.0f)
    float fogStartDistance;    // +0x04: Khoảng cách bắt đầu sương
    float fogEndDistance;      // +0x08: Khoảng cách sương mù đặc
    float heightFalloff;       // +0x0C: Độ suy giảm theo chiều cao
};
```

- **Cơ chế Triệt tiêu**: Ghi đè `fogDensity = 0.0f`.
- **Hiệu quả**: Engine đồ họa lập tức bỏ qua chu trình raymarching thể tích, màn hình trong suốt, tăng FPS rõ rệt.

### 2.2. Cơ chế Tự động Dò tìm Địa chỉ Động (Dynamic Memory Auto-Detection)

Để không phụ thuộc vào offset cố định dễ bị vô hiệu hóa sau các bản vá của Path of Exile 2 (`VisualModsEngine::AutoDetect`, 11/09/2026):

1. **Quét mẫu Byte (AOB) — nhiều mẫu, có xác thực struct**:
   - Build cũ (singleton `.data`): `48 8D 0D ? ? ? ? F3 0F 10 41 2C F3 0F 10 49 34 0F 2F C1`
     `lea rcx, [rip+disp]` → địa chỉ `CameraInstance`.
   - Build 11/09/2026 (PID 11644, module 76.6 MB): mẫu kề `+2C` rồi `+34` **không còn**. Camera là object heap, clamp zoom đọc `maxDistance` tại `[rax+0x34]` sau `cmp byte [rax+0x2F], 0`. AutoDetect thử thêm:
     - `48 8B 05 ? ? ? ? F3 0F 10 40 2C` (`mov rax, [rip]` rồi `movss xmm0, [rax+0x2C]`) — RIP là **con trỏ**, phải deref.
     - Các biến thể `lea`/`mov` + `+2C` / `+34`.
   - Fog: mẫu cũ `48 8B 0D ? ? ? ? F3 0F 11 05 ...` nếu còn; fallback `F3 0F 11 05 ? ? ? ?` (RIP `movss`) **chỉ** nhận khi 4 float `density/start/end/falloff` khớp `FogConstants` (không ghi đè hằng `1.0` dùng chung).
2. **Quét cấu trúc (structural) — không bắt FOV radian 0.4–1.4**:
   - Bắt buộc: `currentDistance` `+0x2C` và `maxDistance` `+0x34` hữu hạn, `max ∈ [8, 400]`, `cur ∈ [3, 800]`.
   - **Bắt buộc `minDistance` + FOV** (radian `[0.30, 1.80]` hoặc độ `[5, 90]`). Không khóa khi chỉ có `typical` + `zFar` — hiện trường PID 3132 (11/09/2026) tool ghi `zFar=810` vào buffer chuỗi `"output"` (`vtable=0x0F`), zoom không đổi hình.
   - Bắt buộc vtable **canonical user-mode** (`[0x10000, 2^47)`); `zNear ∈ [0.001, 5]`. Build `6AA2213C` (11:15): object `cur=max=180` với `qword[0]` bit-pattern float + `zNear=8` là ma trận, không phải camera. Vanilla `min=15/max=45` **0 hit** trong 651 MB — cần RE instance, không nới heuristic.
   - Cộng điểm thêm: `zFar` `+0x40` ∈ [20, 50000], vtable nằm trong module.
   - Không persist `camera_addr` / `fog_density_addr` heap vào `offsets.toml` (INV-OFFSET-01).
3. **AOB scanner**: `ScanModule` **bỏ chunk không đọc được** rồi tiếp tục (không cắt cả module). `FindModule` dùng `TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32` rồi fallback `EnumProcessModulesEx`.
4. **Nhật ký**: `bin/Release/visual_tool.log` (engine `CREATE_NO_WINDOW`). Overlay/GUI hiện **Chưa thấy camera** khi đã gắn PID nhưng `camera_ok = 0`.

---

## 3. Cấu Hình & Tham Số Dòng Lệnh CLI

### 3.1. Tham số CLI trong `AutoPOE2_Core.exe`
- `--zoom <multiplier>`: Mở rộng giới hạn zoom camera (ví dụ `--zoom 2.2`). Hệ số an toàn từ `1.0f` đến `4.0f`.
- `--no-fog` hoặc `--disable-fog`: Tắt sương mù thể tích (Volumetric Fog).
- `--camera-addr <hex>`: Gán địa chỉ trực tiếp đối tượng Camera (Hex).
- `--fog-addr <hex>`: Gán địa chỉ trực tiếp đối tượng FogDensity (Hex).

### 3.2. Cấu hình trong `offsets.toml`
```toml
[visual_mods]
# RVA hoặc địa chỉ tĩnh nếu có
camera_rva = 0x0
fog_density_rva = 0x0
default_zoom = 2.2
disable_fog = true
```

---

## 4. Các Bất Biến An Toàn Hệ Thống (System Invariants)

1. **Bất biến Bù trừ Culling (Invariant Culling-Fix)**:
   $$\text{zFar}_{\text{target}} = \text{zFar}_{\text{orig}} \times (\text{ZoomMultiplier} \times 1.35f)$$
   Tuyệt đối không tăng `maxDistance` mà để nguyên `zFar`, tránh lỗi đen màn hình / mất địa hình.
2. **Bất biến Kẹp Giới hạn (Invariant Multiplier Clamping)**:
   Hệ số zoom phải được kẹp trong phạm vi an toàn $[1.0f, 8.0f]$ trước khi ghi vào RAM.
3. **Bất biến Hoàn nguyên Sạch (Invariant Clean Panic Restore)**:
   Khi xảy ra sự kiện Panic (`Pause/Break`, `Ctrl+Shift+F12`) hoặc kết thúc tiến trình, toàn bộ giá trị gốc (`m_origMaxDistance`, `m_origZFar`, `m_origFogDensity`) và các byte mã máy `.text` đã vá bắt buộc phải được phục hồi trong frame hiện tại (< 1ms).
4. **Bất biến Giữ Vững Con Trỏ Điều Khiển (Invariant Stable Camera Life-Cycle)**:
   Không hủy địa chỉ camera (`SetCameraAddress(0)`) khi đang trong phiên điều khiển trừ khi con trỏ trang bị giải phóng hoàn toàn khỏi không gian bộ nhớ ảo tiến trình.

---

## 5. Tool Độc Lập Visual Tool (11/09/2026)

Từ `11/09/2026`, Zoom + xóa sương mù **không** gắn mặc định vào Core/F8. Người chơi dùng **Visual Tool**:

- `run_visual_tool.bat` / `python run_visual_tool.py`
- Engine: `bin/Release/AutoPOE2_VisualTool.exe`
- Trần zoom **1.0x–8.0x** chỉnh bằng con lăn trên thanh GUI; trong game con lăn chọn góc nhìn tới trần đó.
- Hỗ trợ cơ chế Code Patching `.text` triệt tiêu 100% hiện tượng rubberbanding ở $144\text{ FPS}$.
- Core vẫn nhận `--zoom` / `--no-fog` nếu truyền tường minh (tương thích), nhưng **không** đọc `default_zoom` từ `offsets.toml`.

Chi tiết kiến trúc đầy đủ: [`28_standalone_visual_tool_zoom_and_fog.md`](file:///c:/Projects/AutoPOE2/docs/development/28_standalone_visual_tool_zoom_and_fog.md).

