# 06. Đặc tả Giao tiếp Liên tiến trình & Bộ nhớ Game (IPC & Memory API Specification)

> **Giao thức**: Lock-Free Shared Memory Ring Buffer + FlatBuffers / Binary Structs  
> **Tên đối tượng ánh xạ (Named Shared Memory)**: `Local\POE2_Auto_SharedMem_v1`  
> **Kích thước Khối nhớ**: 4 MB (Cố định, trang bị Aligned 64-byte Cache Line)

---

## 1. Cấu trúc Khối Bộ nhớ Chia sẻ (Shared Memory Layout)

Khối bộ nhớ chia sẻ được chia làm 3 phân vùng chính:
1. **Header & Synchronization Block (64 bytes)**: Chứa cờ đồng bộ nguyên tử (Atomic Sequence Counters) và trạng thái nhịp tim (Heartbeat).
2. **Telemetry Outgoing Buffer (3 MB)**: Vùng ghi dữ liệu từ Tier 1 (C++ Core) gửi sang cho Tier 2 (Python Antigravity Agents).
3. **Command Incoming Buffer (1 MB)**: Vùng nhận lệnh điều khiển vĩ mô từ Tier 2 gửi ngược về cho Tier 1 thực thi.

```mermaid
graph TD
    subgraph "Khối Bộ nhớ Chia sẻ: Local\\POE2_Auto_SharedMem_v1 (4 MB)"
        Header["Header & Sync Counters (0x0000 - 0x0FFF)"]
        Telemetry["Telemetry Outgoing Ring Buffer (0x1000 - 0x2FFFFF)"]
        Commands["Command Incoming Ring Buffer (0x300000 - 0x3FFFFF)"]
    end
```

---

## 2. Định nghĩa Cấu trúc Nhị phân C++ (Binary Protocol Headers)

```cpp
#pragma once
#include <cstdint>

#define SHARED_MEM_MAGIC 0x504F45324155544FULL // "POE2AUTO"
#define SHARED_MEM_NAME "Local\\POE2_Auto_SharedMem_v1"
#define MAX_ENTITIES_PER_SNAPSHOT 256
#define TERRAIN_GRID_DIM 128

#pragma pack(push, 1)

// ==========================================
// 1. HEADER ĐỒNG BỘ (64 bytes - 1 cache line)
// ==========================================
struct SharedMemoryHeader {
    uint64_t magic;              // +0  "POE2AUTO" (0x504F45324155544F)
    uint32_t protocolVersion;    // +8  0x00050005 (v0.5.5)
    uint32_t isRunning;          // +12 1: Hoạt động, 0: Yêu cầu ngắt khẩn cấp
    
    // Con trỏ tuần tự nguyên tử (Atomic Counters)
    uint64_t telemetrySequence;  // +16 Seqlock: slot dữ liệu hợp lệ = (seq & 1)
    uint64_t commandSequence;    // +24 Write-cursor của hàng đợi lệnh (Agent là producer duy nhất)
    uint64_t commandReadIndex;   // +32 Read-cursor của hàng đợi lệnh (Core là consumer duy nhất)
    
    uint64_t lastCoreHeartbeat;  // +40 Unix timestamp (ms) từ C++ Core
    uint64_t lastAgentHeartbeat; // +48 Unix timestamp (ms) từ Python Agent
    uint64_t reserved;           // +56 Đệm đủ 64 bytes cho 1 cache line
};

// ==========================================
// 2. DỮ LIỆU TELEMETRY TỪ GAME (CORE -> AGENT)
// ==========================================
struct PlayerTelemetryData {
    float posX, posY, posZ;       // +0  Tọa độ nhân vật trong không gian game
    float yaw, pitch;             // +12 Hướng nhìn và góc nhắm chuột
    
    uint32_t currentHP, maxHP;    // +20
    uint32_t currentMana, maxMana;// +28
    uint32_t currentES, maxES;    // +36 Energy Shield
    uint32_t currentSpirit, maxSpirit; // +44 Tài nguyên Spirit đặc thù POE2
    
    uint32_t activeWeaponSet;     // +52 1 hoặc 2
    uint32_t movementFlags;       // +56 Bit 0: Moving, Bit 1: Rolling, Bit 2: Idle
    uint64_t debuffMask;          // +60 Bitmask: Freeze, Shock, Bleed, Corrupted Blood...
}; // Kích thước: 68 bytes

struct EntityTelemetryData {
    uint32_t id;                  // +0  Unique Entity ID trong instance
    uint16_t type;                // +4  1: Monster, 2: ItemDrop, 3: Portal, 4: NPC
    uint16_t rarity;              // +6  0: White, 1: Magic, 2: Rare, 3: Unique
    
    float posX, posY, posZ;       // +8
    float distanceToPlayer;       // +20
    
    uint32_t currentHP, maxHP;    // +24
    uint16_t staggerProgress;     // +32 0 - 10000 (0% - 100% thanh Stagger của Boss)
    uint16_t currentAnimationId;  // +34 Mã hoạt ảnh hiện tại (dùng bắt đòn đập của Boss)
    
    uint32_t extraFlags;          // +36 Bit 0: IsBoss, Bit 1: IsTargetable, Bit 2: IsDead
    char name[48];                // +40 Tên thực thể hoặc tên vật phẩm
}; // Kích thước: 88 bytes

struct AreaTelemetryData {
    uint64_t areaLoadTimestampMs; // +0  Thời điểm loading screen kết thúc (Unix ms)
    uint32_t areaLevel;           // +8  Level khu vực
    uint32_t areaSeed;            // +12 Seed địa hình ngẫu nhiên (cache key cho NavMesh)
    char     areaCode[32];        // +16 "G1_1", "MapWorldsBeach"...
    char     areaName[48];        // +48 "The Riverbank", "Hideout"...
}; // Kích thước: 96 bytes

struct TelemetryPacket {
    uint64_t snapshotId;          // +0
    uint64_t timestamp;           // +8
    
    PlayerTelemetryData player;   // +16 (68 bytes)
    
    uint32_t entityCount;         // +84
    EntityTelemetryData entities[MAX_ENTITIES_PER_SNAPSHOT]; // +88 (256 * 88 = 22,528 bytes)
    
    // Lưới địa hình thu gọn quanh người chơi (128x128 ô)
    // 0: Không đi được (Tường/Vực), 1: Đi được bình thường, 2: Vũng nguy hiểm
    uint8_t terrainWalkability[TERRAIN_GRID_DIM * TERRAIN_GRID_DIM]; // +22,616 (16,384 bytes)

    // Dữ liệu khu vực cập nhật realtime từ LogSensor (Zero-Risk)
    AreaTelemetryData area;       // +39,000 (96 bytes)
}; // Tổng kích thước: 39,096 bytes (< 64KB slot stride)

// ==========================================
// 3. LỆNH ĐIỀU KHIỂN VĨ MÔ (AGENT -> CORE)
// ==========================================
enum class MacroOpCode : uint32_t {
    IDLE = 0,
    NAVIGATE_TO_COORD = 1,        // Di chuyển tới tọa độ (X, Y, Z)
    ENGAGE_TARGET = 2,            // Tấn công quái vật chỉ định (Target Entity ID)
    PICKUP_ITEM = 3,              // Nhặt vật phẩm chỉ định (Item Entity ID)
    CAST_EMERGENCY_PORTAL = 4,    // Dùng Portal về thành khẩn cấp
    EXECUTE_STASH_ROUTINE = 5,    // Bắt đầu quy trình cất đồ vào rương
    EXECUTE_VENDOR_ROUTINE = 6,   // Bắt đầu quy trình bán rác cho NPC
    TRIGGER_WORLD_MAP_TRAVEL = 96,// Dịch chuyển World Map qua phím U
    TRIGGER_AUTO_LOGIN = 97,      // Tự động kết nối lại khi mất mạng
    RECALIBRATE_XYZ = 98,         // Yêu cầu quét lại tọa độ XYZ
    PANIC_STOP = 99               // Dừng khẩn cấp toàn bộ hành động
};

struct CommandPacket {
    uint64_t commandId;           // +0
    MacroOpCode opCode;           // +8
    
    float targetX, targetY, targetZ; // +12
    uint32_t targetEntityId;      // +24
    
    uint32_t priority;            // +28 Độ ưu tiên (1: Cao nhất, 10: Thấp nhất)
    uint32_t timeoutMs;           // +32 Hết thời gian thì tự động hủy lệnh nếu kẹt
}; // Kích thước: 36 bytes (đệm trong 64-byte command slot)

#pragma pack(pop)
```

---

## 3. Bản đồ Chữ ký Bộ nhớ (Memory Signatures & Offsets POE2 v0.5.5)

Dưới đây là bảng mẫu mẫu chữ ký nhị phân (Pattern Scanning / AOB) dùng để dò tìm các cấu trúc cốt lõi trong client `PathOfExile.exe` phiên bản 0.5.5:

> [!WARNING]
> **[OBSOLETE — BỊ CẤM DÙNG LÀM TRI THỨC SỐNG]** (10/09/2026, `TASK-RE-PIPELINE-2026`)
> Bằng chứng thực địa `bin/Release/memprobe_report.txt`: cả 4 pattern dưới đây đều
> `[MISS]` trên client build `0x6A9E477A` (section `.data` đã dịch −0x1000 so với build
> sinh ra chúng). Bảng này chỉ còn giá trị tham khảo lịch sử. Tri thức AOB sinh động
> hiện do **Static RE Pipeline** cung cấp qua Offset Registry build-keyed — xem
> [25_static_reverse_engineering_pipeline_and_offset_registry.md](file:///c:/Projects/AutoPOE2/docs/development/25_static_reverse_engineering_pipeline_and_offset_registry.md)
> và `tools/re_pipeline/` (cổng INV-SIG-UNIQUE: pattern phải khớp đúng 1 lần trong `.text`).

| Tên Đối tượng | Mẫu Chữ ký Nhị phân (AOB Pattern) | Cách Tính Địa chỉ Base |
| :--- | :--- | :--- |
| **InGameState Base** | `48 8B 05 ? ? ? ? 48 8B 48 20 48 85 C9 74 0A 48 8B 01 FF 50 18` | `RIP + *(int32_t*)(Pattern + 3) + 7` |
| **Camera Object** | Build cũ: `48 8D 0D ? ? ? ? F3 0F 10 41 2C F3 0F 10 49 34 0F 2F C1`. Build 11/09/2026: thêm `48 8B 05 ? ? ? ? F3 0F 10 40 2C` (RIP = **con trỏ**, deref) + heuristic `+0x2C/+0x34` (FOV có thể là radian hoặc độ). Xem spec 02 §2.2. | `RIP+7+disp32`; nếu `mov r64,[rip]` thì deref QWORD |
| **Volumetric Fog Constants** | `48 8B 0D ? ? ? ? F3 0F 11 05 ? ? ? ? 48 85 C9 74 ? E8` | Trỏ tới Constant Buffer của Render Context |
| **Entity List Root** | `48 8B 0D ? ? ? ? E8 ? ? ? ? 48 8B F8 48 85 C0 74 ? 48 8B 58 08` | `InGameState + 0x3E8 -> EntityMap` |
| **AreaExplorationData** | `48 8B 05 ? ? ? ? 48 8B 40 38 48 8B 88 ? ? ? ? 48 85 C9 74` | Trỏ tới mảng mờ bản đồ (Visibility Mask) |

---

## 4. Giao diện Python Kết nối IPC (Python IPC Bridge)

Trong tiến trình Python của Antigravity Agent Swarm, tầng IPC sử dụng module `mmap` và `ctypes` để ánh xạ bộ nhớ chia sẻ với tốc độ đọc cực đại:

```python
"""
IPC Bridge for AutoPOE2 (v1.1 Protocol)
Maps C++ Shared Memory directly via mmap/ctypes with Seqlock & SPSC Ring Buffer.
"""

import mmap
import ctypes
import struct
import time
from typing import Optional, Tuple

SHARED_MEM_NAME = "Local\\POE2_Auto_SharedMem_v1"
SHARED_MEM_SIZE = 4 * 1024 * 1024
SHARED_MEM_MAGIC = 0x504F45324155544F

# Offsets v1.1
SEQ_OFFSET = 0x10              # telemetrySequence (Seqlock)
CMD_WRITE_OFFSET = 0x18        # commandSequence
CMD_READ_OFFSET = 0x20         # commandReadIndex
AGENT_HEARTBEAT_OFFSET = 0x30  # lastAgentHeartbeat
TELEMETRY_SLOT0_OFFSET = 0x1000
TELEMETRY_SLOT_STRIDE = 0x10000
COMMAND_QUEUE_OFFSET = 0x300000
COMMAND_QUEUE_CAPACITY = 16
COMMAND_SLOT_STRIDE = 64

class PlayerTelemetryData(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        ("posX", ctypes.c_float),
        ("posY", ctypes.c_float),
        ("posZ", ctypes.c_float),
        ("yaw", ctypes.c_float),
        ("pitch", ctypes.c_float),
        ("currentHP", ctypes.c_uint32),
        ("maxHP", ctypes.c_uint32),
        ("currentMana", ctypes.c_uint32),
        ("maxMana", ctypes.c_uint32),
        ("currentES", ctypes.c_uint32),
        ("maxES", ctypes.c_uint32),
        ("currentSpirit", ctypes.c_uint32),
        ("maxSpirit", ctypes.c_uint32),
        ("activeWeaponSet", ctypes.c_uint32),
        ("movementFlags", ctypes.c_uint32),
        ("debuffMask", ctypes.c_uint64),
    ]

class AreaTelemetryData(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        ("areaLoadTimestampMs", ctypes.c_uint64),
        ("areaLevel", ctypes.c_uint32),
        ("areaSeed", ctypes.c_uint32),
        ("areaCode", ctypes.c_char * 32),
        ("areaName", ctypes.c_char * 48),
    ]

class IPCBridge:
    def __init__(self, tag_name: str = SHARED_MEM_NAME):
        self.tag_name = tag_name
        self.shm: Optional[mmap.mmap] = None
        self._connect()

    def _connect(self) -> bool:
        try:
            self.shm = mmap.mmap(-1, SHARED_MEM_SIZE, tagname=self.tag_name)
            return True
        except Exception:
            self.shm = None
            return False

    def update_heartbeat(self):
        """Cập nhật nhịp tim Agent mỗi 200ms - 1s."""
        if self.shm:
            now_ms = int(time.time() * 1000)
            self.shm.seek(AGENT_HEARTBEAT_OFFSET)
            self.shm.write(struct.pack("<Q", now_ms))

    def read_telemetry_seqlock(self, retries: int = 16) -> Optional[Tuple[int, PlayerTelemetryData, AreaTelemetryData]]:
        """Đọc snapshot telemetry chống rách bằng thuật toán Seqlock."""
        if not self.shm and not self._connect():
            return None

        for _ in range(retries):
            # 1. Đọc Sequence trước
            self.shm.seek(SEQ_OFFSET)
            s1 = struct.unpack("<Q", self.shm.read(8))[0]
            slot = s1 & 1
            slot_offset = TELEMETRY_SLOT0_OFFSET if slot == 0 else (TELEMETRY_SLOT0_OFFSET + TELEMETRY_SLOT_STRIDE)

            # 2. Đọc Player (+16 byte sau snapshotId và timestamp)
            self.shm.seek(slot_offset + 16)
            player_bytes = self.shm.read(ctypes.sizeof(PlayerTelemetryData))
            player = PlayerTelemetryData.from_buffer_copy(player_bytes)

            # 3. Đọc Area (+39000 byte từ slot_offset)
            self.shm.seek(slot_offset + 39000)
            area_bytes = self.shm.read(ctypes.sizeof(AreaTelemetryData))
            area = AreaTelemetryData.from_buffer_copy(area_bytes)

            # 4. Đọc Sequence sau để kiểm chứng không bị rách
            self.shm.seek(SEQ_OFFSET)
            s2 = struct.unpack("<Q", self.shm.read(8))[0]
            if s1 == s2:
                return (s1, player, area)

        return None

    def send_command(self, op_code: int, target_x: float = 0.0, target_y: float = 0.0, target_z: float = 0.0, target_id: int = 0) -> bool:
        """Gửi lệnh vào SPSC Command Ring Buffer (16 slot)."""
        if not self.shm and not self._connect():
            return False

        # Đọc Write và Read cursors
        self.shm.seek(CMD_WRITE_OFFSET)
        w = struct.unpack("<Q", self.shm.read(8))[0]
        self.shm.seek(CMD_READ_OFFSET)
        r = struct.unpack("<Q", self.shm.read(8))[0]

        if (w - r) >= COMMAND_QUEUE_CAPACITY:
            return False  # Hàng đợi đã đầy

        slot_idx = w % COMMAND_QUEUE_CAPACITY
        slot_offset = COMMAND_QUEUE_OFFSET + (slot_idx * COMMAND_SLOT_STRIDE)

        pkt = struct.pack("<QIfffIII", int(time.time() * 1000), op_code, target_x, target_y, target_z, target_id, 1, 5000)
        self.shm.seek(slot_offset)
        self.shm.write(pkt.ljust(COMMAND_SLOT_STRIDE, b'\x00'))

        # Publish write cursor mới
        self.shm.seek(CMD_WRITE_OFFSET)
        self.shm.write(struct.pack("<Q", w + 1))
        return True
```

---

## 5. Phụ lục: Changelog Giao thức v1.1 (Đã triển khai - Hoàn tất Giai đoạn 1)

Bố cục dưới đây là bố cục **thực tế đã hiện thực hoá** trong mã nguồn (`src/core/common/protocol.hpp`, `src/core/ipc/shared_memory.cpp`) và đã được kiểm chứng bằng bộ unit test (`tests/test_core.cpp`, chạy qua `ctest`) và kiểm thử E2E liên tiến trình (`scripts/test_ipc_bridge.py`).

### 5.1. Bố cục Bộ nhớ (Memory Map v1.1)

| Offset | Phân vùng | Ghi chú |
| :--- | :--- | :--- |
| `0x000000` | Header 64 bytes | 1 cache line, chứa các cursor nguyên tử |
| `0x001000` | Telemetry slot 0 (ping) | 64 KB/slot (`TELEMETRY_SLOT_STRIDE = 0x10000`) |
| `0x011000` | Telemetry slot 1 (pong) | Double-buffer chống torn-read |
| `0x300000` | Command Ring Buffer | 16 slot x 64 bytes (`COMMAND_QUEUE_CAPACITY = 16`) |

### 5.2. Cấu trúc Header (64 bytes)

```cpp
struct SharedMemoryHeader {
    uint64_t magic;              // +0  "POE2AUTO"
    uint32_t protocolVersion;    // +8  0x00050005 (v0.5.5)
    uint32_t isRunning;          // +12 1: chạy, 0: yêu cầu ngắt
    uint64_t telemetrySequence;  // +16 Seqlock: slot dữ liệu hợp lệ = (seq & 1)
    uint64_t commandSequence;    // +24 Write-cursor hàng đợi lệnh (Agent là producer duy nhất)
    uint64_t commandReadIndex;   // +32 Read-cursor hàng đợi lệnh (Core là consumer duy nhất)
    uint64_t lastCoreHeartbeat;  // +40 Unix ms từ C++ Core
    uint64_t lastAgentHeartbeat; // +48 Unix ms từ Python Agent
    uint64_t reserved;           // +56 Đệm đủ 64 bytes cache line
};
```

### 5.3. Quy tắc Seqlock Telemetry (Core -> Agent)

- **Writer (Core)**: ghi vào slot `((seq + 1) & 1)` bằng `memcpy`, sau đó mới publish `store(seq + 1, release)`. Nhờ vậy độc giả không bao giờ thấy sequence mới kèm dữ liệu cũ.
- **Reader (Agent)**: `load(seq, acquire)` -> copy từ slot `(seq & 1)` -> `load(seq)` lần nữa. Hai giá trị bằng nhau => snapshot nguyên vẹn; khác nhau => retry (hiếm khi xảy ra vì writer dùng slot đối diện).
- Đã kiểm chứng stress test: >25 triệu lần đọc song song với writer 2kHz, **0 torn-read**.

### 5.4. Quy tắc Hàng đợi Lệnh SPSC Ring (Agent -> Core)

- **Producer (Agent)**: nếu `w - r < 16`, ghi lệnh vào slot `(w % 16)` rồi `store(w + 1, release)`. Khi đầy, producer phải chờ (không ghi đè).
- **Consumer (Core)**: nếu `r != w`, copy lệnh từ slot `(r % 16)` rồi `store(r + 1, release)`. Thứ tự FIFO toàn cục luôn được bảo đảm.

### 5.5. Watchdog Nhịp tim 2 chiều

- Agent (Python) cập nhật `lastAgentHeartbeat` định kỳ (khuyến nghị mỗi 200ms - 1s).
- Core kiểm tra mỗi tick 120Hz: nếu Agent **từng kết nối** nhưng mất nhịp tim quá `kAgentWatchdogTimeoutMs` (mặc định 5000ms trong `main.cpp`), Core tự `RequestStop()` ngắt an toàn.
- Cờ dòng lệnh `--move` của Core quyết định việc thực thi di chuyển chuột thật khi xử lý lệnh `NAVIGATE_TO_COORD`.

### 5.6. Bổ sung v1.1.1: AreaTelemetryData (Giai đoạn 2.1 - đã triển khai)

TelemetryPacket mở rộng thêm 96 bytes cuối gói (tổng 39096 bytes) chứa dữ liệu khu vực
đọc từ cảm biến nhật ký `Client.txt` (fallback `LatestClient.txt`, Zero-Risk - không cần đọc RAM):

```cpp
struct AreaTelemetryData {
    uint64_t areaLoadTimestampMs;  // +0  Thời điểm loading screen kết thúc (Unix ms)
    uint32_t areaLevel;            // +8  Level khu vực
    uint32_t areaSeed;             // +12 Seed địa hình ngẫu nhiên (cache key cho NavMesh)
    char     areaCode[32];         // +16 "G1_1", "MapWorldsBeach"...
    char     areaName[48];         // +48 "The Riverbank", "Hideout"...
};
```

Cảm biến nhận dạng sự kiện bằng regex (docs/research/03): tạo instance mới,
chuyển khu vực, kết thúc tải màn, whisper, mất kết nối bất thường, khóa tài khoản.
Module liên quan: `src/core/sensor/log_sensor.hpp/.cpp`.

Tầng đọc bộ nhớ (Giai đoạn 2.2) đã hiện thực khung `IMemoryReader` với back-end
`ReadProcessMemoryReader` (`src/core/memory/`), kèm `AobScanner` quét pattern nhị phân
và `OffsetsStore` cache offset ra file cấu hình (chống hard-code khi game patch).

---

## 6. Phụ lục: Đặc tả Tệp Cấu hình Con trỏ Tĩnh (`offsets.toml`)

Để thích ứng khi game client cập nhật hoặc khởi động lại mà không cần biên dịch lại mã nguồn C++, các offset tương đối và chuỗi Pointer Chain tĩnh được sinh tự động bởi công cụ `AutoPOE2_MemProbe.exe` / `AobScanner` và lưu trữ tại `bin/Release/offsets.toml`:

```toml
# AutoPOE2 offsets cache - auto-generated by AobScanner / MemProbe
static_rva = 0x4434ce0
num_offsets = 0x2
offset_1 = 0x48
offset_2 = 0x1ad
entity_map_offset = 0x3e8
terrain_offset = 0x0
```

> [!IMPORTANT]
> **Quy Tắc Kiến Trúc Bất Biến (Zero Absolute Heap Addresses)**:
> Tệp `offsets.toml` **CHỈ ĐƯỢC PHÉP LƯU các offset tương đối** (`static_rva`, `entity_map_offset`, `terrain_offset`) và chuỗi cấp độ con trỏ (`offset_1`, `offset_2`, ...). Tuyệt đối **KHÔNG BAO GIỜ lưu hoặc nạp các địa chỉ Heap tuyệt đối** (`player_addr`, `xyz_addr`, `shield_addr`, `mana_addr`, `spirit_addr`, `ingame_addr`, `terrain_addr`, `camera_addr`, `fog_density_addr`) vào tệp đĩa, do cơ chế ASLR và quản lý Dynamic Heap của Windows sẽ cấp phát lại vùng nhớ sau mỗi phiên chạy và mỗi lần chuyển map. Mọi địa chỉ PlayerState trong phiên chạy được định vị realtime thông qua giải mã chuỗi con trỏ tĩnh O(1) hoặc thuật toán Smart Heap Scanning kết hợp **Cổng Kiểm Thực Đa Chỉ Số (Cross-Vital Validation)**.

### 6.1. Thuật toán Giải mã Con trỏ Đa cấp (Pointer Chain Resolution)

Chuỗi con trỏ được `PlayerFinder::ResolveStaticPointer()` duyệt giải mã theo công thức:

$$\text{StaticAddr} = \text{ModuleBase} + \text{static\_rva}$$
$$P_1 = *(\text{uintptr\_t}*)\text{StaticAddr}$$
$$P_2 = *(\text{uintptr\_t}*)(P_1 + \text{offset\_1})$$
$$\text{TargetHPAddr} = P_2 + \text{offset\_2}$$

### 6.2. Cơ chế Hiệu chuẩn Động Dự phòng & Lọc Heap Thông Minh (Dynamic Calibration & Smart Heap)

Trường hợp game client có cập nhật nhỏ làm đứt chuỗi con trỏ tĩnh, `PlayerFinder` tự động kích hoạt thuật toán lọc vùng nhớ thông minh (Smart Heap Filtering) thay vì quét toàn bộ RAM 8 GB:
- **Lọc thông minh**: Chỉ quét các vùng `MEM_COMMIT`, `MEM_PRIVATE`, `PAGE_READWRITE` có kích thước $64\text{ KB} \le \text{RegionSize} \le 16\text{ MB}$, loại bỏ hoàn toàn 98% bộ nhớ rác đồ họa DirectX 12 và Render Targets $>32\text{MB}$.
- **Tìm kiếm cụm 3 biến**: Tìm cụm 3 biến liên tiếp `{HP, maxHP, maxHP}` (uint32_t) với giá trị `expectedMaxHP` được nạp từ cấu hình hoặc từ cảm biến quang học UI.
- **Tốc độ thực thi**: Hoàn tất trong **150 - 300 ms** (giảm 99% so với thời gian 45 giây của phương pháp quét càn cũ), tự động ghi nhận địa chỉ mới và đưa Core Engine tiếp tục vận hành mà không gián đoạn.
- *(Chi tiết kiến trúc 4 tầng siêu tốc xem tại đặc tả [**13. Đặc Tả Kiến Trúc Nhận Diện HP Siêu Tốc & Tối Ưu Hóa Chuyển Vùng Bản Đồ**](file:///c:/Projects/AutoPOE2/docs/development/13_fast_hp_detection_and_zone_transition_optimization.md))*.

### 6.3. Tọa Độ XYZ & Tham Số Cấu Hình Dòng Lệnh (`AutoPOE2_Core.exe`)

Địa chỉ `xyz_addr` trỏ trực tiếp đến cấu trúc chứa 3 giá trị số thực `float posX, posY, posZ` (12 bytes liên tiếp). `GameSession` đọc địa chỉ này ở tần số 120Hz và nạp vào `packet.player.posX, posY, posZ`.

Bộ điều phối phản xạ `ReflexManager` và giao diện `overlay.cpp` hỗ trợ các cờ cấu hình dòng lệnh tùy biến khi khởi động Core:

| Tham số dòng lệnh | Kiểu dữ liệu | Mặc định | Mô tả chức năng |
| :--- | :---: | :---: | :--- |
| `--autododge` | Flag | Bật | Bật cơ chế tự động lộn nhào né chiêu (Iframe Dodge Roll). |
| `--no-dodge` | Flag | Tắt | Vô hiệu hóa Iframe Dodge Roll. |
| `--kiting` | Flag | Tắt | Kích hoạt tự động thả diều (Dynamic Kiting) giữ cự ly với quái vật. |
| `--no-chicken` | Flag | Tắt | Vô hiệu hóa Auto-Chicken (thoát game khẩn cấp khi nguy kịch). |
| `--flask-hp <f>` | Float (0.0 - 1.0) | `0.55` | Ngưỡng máu kích hoạt Smart Life Flask (phím 1). |
| `--mana-hp <f>` | Float (0.0 - 1.0) | `0.25` | Ngưỡng mana kích hoạt Smart Mana Flask (phím 2). |
| `--burst-hp <f>` | Float (0.0 - 1.0) | `0.22` | Ngưỡng sốc sát thương trong 1 tick kích hoạt Iframe Dodge Roll. |
| `--calibrate-xyz` | Flag | Tắt | Bật chế độ quét hiệu chuẩn tìm lại địa chỉ tọa độ XYZ khi đổi vùng. |
| `--move` | Flag | Tắt | Cho phép Core điều khiển chuột thật khi nhận lệnh `NAVIGATE_TO_COORD`. |

### 6.4. Giao Thức Thu Thập Telemetry & Xử Lý Vòng Đời Chuyển Vùng (Zone Transition Protocol)

Khi người chơi chuyển vùng bản đồ (vào cổng map, chuyển act, hồi sinh hoặc dịch chuyển waypoint), vòng đời của đối tượng bộ nhớ thay đổi hoàn toàn do ASLR và engine game thu hồi đối tượng cũ:

```mermaid
sequenceDiagram
    autonumber
    participant Log as LogSensor (Client.txt)
    participant Core as GameSession (Core 120Hz)
    participant Resolver as FastPointerChainResolver
    participant Optical as HealthGlobeSensor (UI Optical)
    participant Nav as QuestNavigator / ReflexManager

    Log->>Core: OnAreaTransitionStarted ("Connecting to instance...")
    Core->>Core: Invalidate Stale Pointers (m_playerAddr = 0, m_xyzAddr = 0)
    Note over Core: Ngăn ngừa đọc rác bộ nhớ từ instance cũ
    Log->>Core: OnAreaTransitionFinished ("LoadingFinished" / "Entering area")
    par Tầng 1: Pointer Chain Tĩnh
        Core->>Resolver: ResolveLifeComponent(InGameState -> Area -> Player -> Life)
        alt Thành công (0.001 ms)
            Resolver-->>Core: Khóa m_playerAddr mới hợp lệ
        else Thất bại / Hotfix lệch RVA
            Core->>Core: Fallback sang Smart Heap Filter (150-300ms)
        end
    and Tầng 3: Cảm biến Quang học UI (Fallback tức thì)
        Core->>Optical: SampleHealthGlobe() -> hpRatio (1-2 ms)
        Optical-->>Core: Cung cấp expectedMaxHP & normalizedHP (1000)
    end
    Core->>Nav: Micro-step Grace Period Breaker (Tap 'W' 50ms / Click 60px)
    Note over Nav: Giải phóng Grace Period hợp lệ -> Server phát sinh chuyển động
    Core->>Core: AutoPositionScan khóa m_xyzAddr
    Core->>Nav: Bật trạng thái Full Patrol / Combat (Tổng trễ: 1.2 - 2.0s)
```

1. **Thu hồi và Vô hiệu hóa Con trỏ Cũ (Stale Pointer Invalidation)**:
   - Ngay khi `LogSensor` ghi nhận sự kiện chuyển map, `GameSession` lập tức đặt `m_playerAddr = 0` và `m_xyzAddr = 0`.
   - Việc này ngăn chặn tuyệt đối hiện tượng đọc nhầm vùng nhớ rác bị deallocate của instance cũ, loại bỏ nguy cơ crash game hoặc đưa ra quyết định sai.
2. **Cung cấp `expectedMaxHP` từ Cảm biến Quang học & Cấu hình**:
   - Trường hợp Pointer Chain chưa kịp khóa địa chỉ hoặc game vừa cập nhật hotfix, cảm biến quang học Quả cầu máu (Health Globe Sensor) ở Tầng 3 lập tức đọc tỷ lệ $\text{hpRatio}$ từ màn hình game ($1 - 2\text{ ms}$) và nạp mốc chuẩn hóa `expectedMaxHP = 1000` (hoặc nạp từ giá trị người dùng lưu trong GUI).
   - Tham số `expectedMaxHP` này được truyền trực tiếp vào `SmartHeapFilter::ScanFastHP` làm giá trị mục tiêu, giúp việc quét RAM hoàn tất trong chớp mắt mà không cần brute-force.
3. **Chủ động Phá Vỡ Bế Tắc Grace Period (Micro-step Breaker)**:
   - Thay vì đứng yên chờ đợi cạn 60s Grace Period khiến bot bị tê liệt (`maxHP == 0`), hệ thống chủ động kích hoạt 1 xung phím ngắn (`W` 50ms) ngay khi có dữ liệu máu sơ bộ.
   - Thao tác này kích hoạt máy chủ game gửi gói tin biến thiên tọa độ, cho phép `AutoPositionScan` khóa ngay địa chỉ `m_xyzAddr` và đưa hệ thống vào trạng thái tuần tra/chiến đấu trơn tru chỉ sau **1.2 - 2.0 giây**.



