# 03. Nghiên cứu Nhật ký Sự kiện Thời gian Thực (Realtime Log Telemetry Research)

> **Tệp Nguồn (khảo sát 05/09/2026)**: `LatestClient.txt` & `Client.txt`  
> **Hành vi vận hành 10/09/2026**: ưu tiên `Client.txt` (đủ Generating + SCENE); `LatestClient.txt` chỉ fallback — xem `docs/development/27_control_center_companion_contract_and_ui.md`.
> **Phương pháp tiếp cận**: Cảm biến Sự kiện Dự phòng (Zero-Risk Secondary Telemetry Sensor)

---

## 1. Khảo sát Cấu trúc Nhật ký Game POE2

Client Path of Exile 2 liên tục ghi nhận toàn bộ các sự kiện vận hành quan trọng vào tệp `LatestClient.txt` (dung lượng phiên chơi hiện tại: ~5 MB; tệp tích lũy `Client.txt`: ~126 MB).

### Cú pháp Chuẩn của một Dòng Log:
```text
YYYY/MM/DD HH:MM:SS [TickOffset] [Hash] [LOG_LEVEL Client PID] Nội_dung_sự_kiện
```
*Ví dụ thực tế trích xuất từ phiên chơi:*
```text
2026/09/05 18:18:39 114637656 91c6cc1  [INFO Client 25032] Connecting to instance server at 172.241.4.89:21360
2026/09/05 18:18:39 114637765 2caa229f [DEBUG Client 25032] Generating level 1 area "G1_1" with seed 13361591
2026/09/05 18:18:40 114638250 f0c29df3 [INFO Client 25032] Tile hash: 78899133
2026/09/05 18:18:40 114638265 7fbd1225 [INFO Client 25032] [SCENE] Set Source [The Riverbank]
2026/09/05 18:18:52 114650343 4cba6a94 [INFO Client 25032] [LOADING SCREEN] (The Riverbank) Duration = 12.6816 seconds
```

---

## 2. Bảng Nhận dạng Sự kiện Trọng yếu (Telemetry Event Signatures)

Hệ thống bot tận dụng các mẫu sự kiện này để theo dõi trạng thái trò chơi mà **hoàn toàn không cần đọc bộ nhớ RAM**, mang lại sự an toàn tuyệt đối 100%:

| Loại Sự kiện | Biểu thức Chính quy (Regex Signature) | Ý nghĩa Vận hành & Hành động của Bot |
| :--- | :--- | :--- |
| **Tạo Instance Mới** | `Generating level (\d+) area "([^"]+)" with seed (\d+)` | Lưu trữ `AreaCode` và `Seed` để nạp dữ liệu NavMesh tương ứng; reset trạng thái bản đồ. |
| **Chuyển Đổi Khu Vực** | `\[SCENE\] Set Source \[([^\]]+)\]` | Xác định tên khu vực (ví dụ: `The Riverbank`, `Ogham`, `Hideout`). Chuyển chế độ sang di chuyển chiến đấu hoặc về thị trấn. |
| **Kết Thúc Tải Màn** | `\[LOADING SCREEN\] \([^)]+\) Duration = ([\d\.]+) seconds` | Màn hình tải hoàn tất; bot chính thức bắt đầu kích hoạt điều khiển phím/chuột. |
| **Mất / Nhận Focus** | `\[WINDOW\] (Lost focus\|Focus gained)` | Nhận biết khi nào người chơi chuyển sang cửa sổ khác (Alt-Tab) để tự động dừng bot. |
| **Tin Nhắn Kênh Trade** | `^\$([^:]+): (.+)` | Thu thập dữ liệu giao dịch thị trường (ví dụ: giá chạy Trial, mua bán Divine). |
| **Tin Nhắn Thì Thầm** | `^@From ([^:]+): (.+)` | **Báo động Khẩn cấp**: Có người chơi thì thầm vào tài khoản. Đẩy thông báo cho `SafetySupervisorAgent` xử lý. |
| **Mất Kết Nối Bất Thường** | `Abnormal disconnect: (.+)` | Game bị ngắt kết nối mạng. Tạm dừng chu trình, đợi 30s để tự động thử đăng nhập lại. |
| **Khóa Tài Khoản / Unlock Code** | `Your account has been locked (.+)` | Báo động đỏ: Tài khoản bị khóa IP lạ hoặc kiểm tra bảo mật. Ngắt toàn bộ hoạt động. |

---

## 3. Mã nguồn Module Cảm biến Nhật ký (Python Realtime Log Tailer)

Dưới đây là module đọc log bất đồng bộ (Non-blocking Asynchronous Log Tailer) được tích hợp vào Tier 2:

```python
"""
Realtime Log Telemetry Tailer for POE2
Path: C:\Program Files (x86)\Grinding Gear Games\Path of Exile 2\logs\LatestClient.txt
"""

import os
import re
import time
from typing import Callable

LOG_PATH = r"C:\Program Files (x86)\Grinding Gear Games\Path of Exile 2\logs\LatestClient.txt"

# Các biểu thức chính quy nhận dạng sự kiện
RE_AREA_GEN = re.compile(r'Generating level (\d+) area "([^"]+)" with seed (\d+)')
RE_SCENE = re.compile(r'\[SCENE\] Set Source \[([^\]]+)\]')
RE_LOADING = re.compile(r'\[LOADING SCREEN\] \(([^)]+)\) Duration = ([\d\.]+) seconds')
RE_WHISPER = re.compile(r'@From ([^:]+): (.+)')

class POE2LogSensor:
    def __init__(self, log_path: str = LOG_PATH):
        self.log_path = log_path
        self.current_area = ""
        self.is_loading = False

    def listen(self, on_area_enter: Callable, on_whisper: Callable):
        if not os.path.exists(self.log_path):
            print(f"[LogSensor] Chưa tìm thấy file log tại: {self.log_path}")
            return

        with open(self.log_path, "r", encoding="utf-8", errors="ignore") as f:
            # Nhảy tới cuối file để chỉ đọc sự kiện mới phát sinh
            f.seek(0, os.SEEK_END)
            print("[LogSensor] Đang lắng nghe sự kiện từ LatestClient.txt...")

            while True:
                line = f.readline()
                if not line:
                    time.sleep(0.05) # Nghỉ 50ms kiểm tra dòng mới
                    continue

                # Bắt sự kiện chuyển khu vực
                match_scene = RE_SCENE.search(line)
                if match_scene:
                    self.current_area = match_scene.group(1)
                    print(f"[Log Event] Bước vào khu vực: {self.current_area}")
                    on_area_enter(self.current_area)

                # Bắt tin nhắn thì thầm từ người chơi khác / GM
                match_whisper = RE_WHISPER.search(line)
                if match_whisper:
                    sender, msg = match_whisper.groups()
                    print(f"[Log Alert] Nhận Whisper từ {sender}: {msg}")
                    on_whisper(sender, msg)
```
