Files
cultivation-world-simulator/docs/specs/avatar-metrics-tracking.md
teps3105 3ddd7868b6 feat: add avatar metrics tracking feature (#111)
* feat: add avatar metrics tracking feature (#110)

Add AvatarMetrics dataclass for tracking avatar state snapshots

- Add AvatarMetrics dataclass for recording monthly snapshots
- Add metrics_history field to Avatar with opt-in tracking
- Implement automatic monthly snapshot recording in Simulator
- Add backward compatibility support for existing save files
- Set default tracking limit to 1200 months (100 years)
- Add comprehensive tests with 100% coverage
- Move documentation to specs directory with simplified chinese

* fix: convert Traditional Chinese comments to Simplified Chinese

修正程式碼中的繁體中文註解為簡體中文,以符合專案規範。

Fix Traditional Chinese comments to Simplified Chinese in codebase.
2026-01-30 23:07:45 +08:00

279 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Avatar 状态追踪功能
## 概述
新增可选的 Avatar 状态追踪功能,用于记录角色成长轨迹。该功能默认关闭,不影响现有游戏逻辑。
## 功能特点
- **可选性**:默认关闭,不影响现有功能
- **轻量**:仅记录关键指标(修为、资源、社交等)
- **不可变**:快照一旦创建不修改
- **持久化**:支持存档/读档
- **自动清理**:默认最多保留 1200 笔记录100 年)
## 使用方式
### 启用追踪
```python
# 启用 Avatar 状态追踪
avatar.enable_metrics_tracking = True
```
### 自动记录
追踪启用后,模拟器会在每月自动调用 `record_metrics()`
```python
# 在 simulator.py 的 _finalize_step() 中自动执行
# avatar.record_metrics() # 每月自动调用
```
### 手动记录并标记事件
```python
from src.classes.avatar_metrics import MetricTag
# 手动记录状态(可选事件标记)
avatar.record_metrics(tags=["breakthrough"])
avatar.record_metrics(tags=[MetricTag.INJURED.value, MetricTag.BATTLE.value])
avatar.record_metrics(tags=["custom_event"]) # 支持自定义标签
```
### 查看摘要
```python
# 获取状态追踪摘要
summary = avatar.get_metrics_summary()
print(summary)
# 输出示例:
# {
# "enabled": True,
# "count": 120,
# "first_record": 100,
# "latest_record": 220,
# "cultivation_growth": 5
# }
```
### 访问历史记录
```python
# 直接访问历史记录列表
for metrics in avatar.metrics_history:
print(f"Month {metrics.timestamp}: Level {metrics.cultivation_level}, HP {metrics.hp}")
```
## 设计原则
### 1. 可选性
- 默认关闭(`enable_metrics_tracking = False`
- 不影响现有 API 和逻辑
- 可随时启用或禁用
### 2. 轻量级
仅记录关键指标:
| 字段 | 类型 | 说明 |
|------|------|------|
| `timestamp` | `MonthStamp` | 记录时间 |
| `age` | `int` | 年龄 |
| `cultivation_level` | `int` | 修为等级 |
| `cultivation_progress` | `int` | 修为进度 |
| `hp` | `float` | 当前生命值 |
| `hp_max` | `float` | 最大生命值 |
| `spirit_stones` | `int` | 灵石数量 |
| `relations_count` | `int` | 关系数量 |
| `known_regions_count` | `int` | 已知区域数量 |
| `tags` | `List[str]` | 事件标签 |
### 3. 不可变性
- 快照一旦创建不修改
- 使用 dataclass 保证结构清晰
- 支持序列化/反序列化
### 4. 向后兼容
- 使用 `default_factory` 避免破坏旧代码
- 存档/读档完全兼容
- 旧存档会使用默认值空列表、False
## 性能影响
### 关闭时
- 零影响(不占用额外内存或 CPU
- `record_metrics()` 直接返回 `None`
### 开启时
- 每月新增约 200 bytes 快照
- 100 年约 240 KB
- **有上限**:默认最多保留 1200 笔记录(可通过 `max_metrics_history` 调整)
```python
# 调整历史记录上限
avatar.max_metrics_history = 600 # 改为 50 年
```
## 默认标签
建议使用 `MetricTag` 枚举中的默认标签:
| 标签 | 值 | 说明 |
|------|-----|------|
| `BREAKTHROUGH` | `"breakthrough"` | 突破 |
| `INJURED` | `"injured"` | 受伤 |
| `RECOVERED` | `"recovered"` | 康复 |
| `SECT_JOIN` | `"sect_join"` | 加入宗门 |
| `SECT_LEAVE` | `"sect_leave"` | 离开宗门 |
| `TECHNIQUE_LEARN` | `"technique_learn"` | 学习功法 |
| `DEATH` | `"death"` | 死亡 |
| `BATTLE` | `"battle"` | 战斗 |
| `DUNGEON` | `"dungeon"` | 探索秘境 |
### 使用标签
```python
from src.classes.avatar_metrics import MetricTag
# 使用枚举(推荐)
avatar.record_metrics(tags=[MetricTag.BREAKTHROUGH.value])
# 多个标签
avatar.record_metrics(tags=[
MetricTag.INJURED.value,
MetricTag.BATTLE.value
])
# 自定义标签(也支持)
avatar.record_metrics(tags=["custom_event", "special_occurrence"])
```
## 数据结构
### AvatarMetrics
```python
@dataclass
class AvatarMetrics:
timestamp: MonthStamp
age: int
cultivation_level: int
cultivation_progress: int
hp: float
hp_max: float
spirit_stones: int
relations_count: int
known_regions_count: int
tags: List[str]
def to_save_dict(self) -> dict:
"""转换为可序列化的字典"""
pass
@classmethod
def from_save_dict(cls, data: dict) -> "AvatarMetrics":
"""从字典重建"""
pass
```
## 序列化
### 存档
状态追踪数据会自动包含在存档中:
```python
save_dict = avatar.to_save_dict()
# 包含:
# - "metrics_history": [...]
# - "enable_metrics_tracking": True
```
### 读档
读档时自动恢复:
```python
avatar = Avatar.from_save_dict(data, world)
# metrics_history 和 enable_metrics_tracking 自动恢复
```
## 注意事项
### 1. 标签的可变性
`tags` 字段使用 `List[str]` 而非 `List[MetricTag]`,提供灵活性:
- 支持默认标签(使用 `MetricTag.value`
- 支持自定义标签
- 允许混合使用
### 2. 自动清理
历史记录超过 `max_metrics_history` 时会自动清理旧记录:
```python
# 保留最新的 N 笔记录
if len(self.metrics_history) > self.max_metrics_history:
self.metrics_history = self.metrics_history[-self.max_metrics_history:]
```
### 3. 不可变性
快照对象本身是可变的Python dataclass 默认),但设计上应视为不可变:
- 创建后不修改 `AvatarMetrics` 对象
- 如需更新,创建新快照
## 使用场景
### 追踪修为成长
```python
# 启用追踪
avatar.enable_metrics_tracking = True
# 模拟运行...
# 自动记录每月状态
# 分析成长
first = avatar.metrics_history[0]
latest = avatar.metrics_history[-1]
print(f"修为增长: {latest.cultivation_level - first.cultivation_level}")
```
### 标记重大事件
```python
# 突破时标记
if avatar.cultivation_progress.realm != old_realm:
avatar.record_metrics(tags=[MetricTag.BREAKTHROUGH.value])
# 受伤时标记
if avatar.hp.value < avatar.hp.max_value * 0.3:
avatar.record_metrics(tags=[MetricTag.INJURED.value])
```
### 分析游戏数据
```python
# 导出数据到 CSV/Pandas
import pandas as pd
data = []
for metrics in avatar.metrics_history:
data.append({
"timestamp": metrics.timestamp,
"age": metrics.age,
"level": metrics.cultivation_level,
"hp": metrics.hp,
"spirit_stones": metrics.spirit_stones,
})
df = pd.DataFrame(data)
df.plot(x="timestamp", y="level")
```