Files
loneseDocument/HOWTO_REGENERATE_DOCS.md
meishibiezb 29a3f77908 init
2026-06-04 21:44:13 +08:00

416 lines
15 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.
# 文档生成操作手册
## 这篇文章是干什么的
当你需要更新这个项目的文档,或者想把同一套方法套到另一个 UE 项目时,看这个就够了。
本文记录:
1. **踩过的坑** — 初版被骂的 10 项问题,别再犯
2. **正确的文档模板** — 每个单位应该长什么样
3. **完整操作步骤** — 从零到 56 个文档是怎么生成的
4. **工具和命令** — 用了什么、怎么用
---
## 一、血泪教训:初版的 10 项问题
第一次跑完「项目文档化计划」后,被用户逐条指出以下问题,全部在修订版中修正:
| # | 问题 | 初版做法 | 正确做法 |
|---|------|---------|---------|
| 1 | 多个单位合并到一个文件 | `ItemDataStructures.md` 里塞了 3 个 struct | 每个结构体/类/接口/枚举独立一个 .md |
| 2 | "设计用意"和"职责范围"合并 | 一个 `## 设计用意与职责范围` 章节糊在一起 | 拆成两个独立章节 |
| 3 | "职责范围"用二分法 | 写"职责xxx / 不负责yyy" | 自然语言描述工作范围 |
| 4 | 多余的模块 | 文档里出现"变量"、"关键成员"表格 | 不写实现细节,对外接口从调用者视角描述 |
| 5 | 使用方法不引用真代码 | 写"可以这样用"但没有出处 | 每条引用真实文件路径和行号 |
| 6 | 用例编造示例代码 | 写伪代码 `// 继承 AMyActor...` | 只列出项目中实际使用该单位的文件 |
| 7 | `_relationships.md` 太花哨 | ASCII 艺术图、设计模式分析 | 简单的文件级依赖表格 + 文本箭头 |
| 8 | 执行顺序混乱 | 边写接口边写依赖 | 严格:孤立文档 → 关系文档 → 接口+用例 |
| 9 | README.md 没更新 | 还是旧的待办列表 | 更新为完整的文档索引 |
| 10 | "项目内依赖"列名不对 | 用了"说明"列 | 改为"源文件"列,放文件路径 |
### 为什么这些问题很重要
- **合并文件**:后人要找 `FItemView` 的文档时,不能一眼看到文件名,还得打开文件在里面搜。单位名和文件名一一对应,是文档可发现性的底线。
- **设计用意 vs 职责范围**:前者回答"为什么存在",后者回答"管什么事"。混在一起会让维护者搞不清这个类的边界。
- **真实代码引用**:没有行号的使用说明是废纸。半年后代码改了,维护者无法验证文档是否过期。
---
## 二、正确的文档模板
### 2.1 孤立单位文档模板
每个单位class/struct/enum/BP一个 .md 文件,**严格**以下结构:
```markdown
# [单位名称]
## 基本信息
- **类型**: UCLASS / USTRUCT / UENUM / C++ class / Blueprint
- **父类**: XXX没有就写 —)
- **源文件**: path/to/file.h蓝图写 /Game/ 路径)
- **模块**: ModuleName
## 功能概述
[一段话概括这个单位做什么,什么场景用]
## 设计用意
[为什么这样设计,解决什么问题,在系统中的定位]
## 职责范围
[自然语言描述该单位承担的工作范围,它负责什么流程/数据/决策。
禁止使用"职责"/"不负责"二分格式]
## 项目内依赖
| 依赖项 | 关系 | 源文件 |
|--------|------|--------|
| XXX | 包含/引用/继承/调用 | path/to/file.h:行号 |
## 对外接口
[从外部调用者的角度描述:
- C++ 调用者:哪些 public 方法/虚函数可调用
- 蓝图调用者:哪些 UFUNCTION/BlueprintNativeEvent 可调用
- 委托:哪些委托可绑定
- 结构体:哪些 UPROPERTY 字段对外可读写
禁止单纯罗列函数签名]
## 使用方法
[引用项目中的真实代码位置说明如何使用本单位的典型流程。
每条使用方式必须给出源文件和行号出处]
## 用例
[列举项目中实际使用本单位的文件和上下文。不编造示例。
格式:文件路径:行号 — 用途说明]
```
### 2.2 关系文档模板 (`_relationships.md`)
每个模块目录下一个:
```markdown
# [模块名] 依赖关系
## 文件间引用关系
| 源文件 | 引用方式 | 目标文件 | 目标单位 |
|--------|---------|---------|---------|
| XXX.h | #include | YYY.h | YYY |
| XXX.h | forward-declare | — | ZZZ |
## 关键依赖链
[用简单的文本箭头描述关键数据/控制流,如:
DefaultContainer.cpp → ItemFactory::CreateItemInstance → FItemInstance
]
```
### 2.3 README.md 模板
`Document/README.md`,核心是每个模块的完整单位列表表,含:单位名、文件名(链接)、类型、父类。
---
## 三、完整操作步骤
以下是在一个全新的 UE 项目上复现整个过程的操作步骤。
### 前置条件
1. **Claude Code CLI**(本文使用的 AI 编程助手)
- 安装方式见 [Claude Code 官方文档](https://docs.anthropic.com/en/docs/claude-code)
- 关键是它支持 Task 工具(可以启动后台子代理并行干活)
- 支持 MCP用于查询 UE 编辑器中的蓝图信息)
2. **UnrealClaude MCP 插件** — 安装在项目的 `Plugins/UnrealClaude/`
- 提供 `unreal_blueprint_query``unreal_asset_search` 等 MCP 工具
- 用来查询蓝图资产信息(因为在 .uasset 二进制文件上没法直接 grep
3. **ripgrep** (`rg`) — 用于在源代码中搜索单位引用
4. **bash shell** — Windows 上用 Git Bash 或 WSLmacOS/Linux 直接用
### 步骤 1确定文档化范围
先画出要文档化的所有单位清单:
```bash
# 列出所有需要文档化的 C++ 头文件
find Source/ -name "*.h" | grep -v Intermediate | grep -v Generated
find Plugins/ -name "*.h" -path "*/Public/*" | grep -v Intermediate | grep -v Generated
# 列出所有需要文档化的蓝图(通过 MCP
# 在 Claude Code 对话中使用:
# mcp__unrealclaude__unreal_blueprint_query operation=list path_filter=/Game/Blueprints/
```
对每个头文件,手动列出它包含的所有单位(一个 .h 可能包含多个 class/struct/enum。这就是你的文档化清单。
### 步骤 2分析所有源文件
这是最耗时但最关键的一步。你需要从每个源文件中提取:
- 单位的类型、父类、所属模块
- 功能概述(从注释和代码推断)
- 设计意图(为什么存在)
- `#include` 依赖关系
- 前向声明
- public 方法、UFUNCTION、delegate
**用 Claude Code 的做法**(推荐):
启动多个 `Task` 子代理并行分析:
```
对 Claude Code 说:
"用 Explore 子代理分析 D:\workspace\u\lonese\Plugins\Item\ 目录下所有 .h 和 .cpp 文件,
对每个 class/struct/enum 提取:类型、父类、功能、设计意图、依赖、公开方法。"
```
关键提示词要点:
- 让代理先 `Glob` 找到所有 .h 文件,再逐文件 `Read`
- 要求结构化输出(每个单位一个条目)
- 明确列出需要的字段:类型/父类/文件路径/模块/功能/设计意图/include依赖/前向声明/公开方法/UFUNCTION/delegate/BlueprintNativeEvent
**手动做法**(如果没有 AI 工具):
```
对每个 .h 文件:
1. 记录文件中定义的所有 UCLASS/USTRUCT/UENUM/接口
2. 记录每个单位的父类和包含的引擎头文件
3. 搜索 #include "项目内头文件" 记录依赖
4. 搜索 forward declaration
5. 记录 UPROPERTY 和 UFUNCTION 标记
6. 从类/方法注释中提取功能描述
```
结果应该整理成一张大表,每个单位一行,包含上述所有字段。
### 步骤 3阶段 1 — 生成孤立单位文档
对每个单位创建一个 .md 文件,这个阶段**只填**
- 基本信息
- 功能概述
- 设计用意
- 职责范围
- 项目内依赖
**暂不填**(留占位符 `待阶段3填写`
- 对外接口
- 使用方法
- 用例
**用 Claude Code 的做法**
```markdown
对 Claude Code 说:
"在 Document/Plugins/Item/ 下为以下每个单位创建独立的 .md 文件,
遵循 [粘贴模板]。每个单位一个文件,不要合并。
现在只填基本信息、功能概述、设计用意、职责范围、项目内依赖。
对外接口、使用方法、用例三个章节写'待阶段3填写'。"
```
然后把每个单位的结构化分析数据附在后面。
**注意**
- 每个单位**必须独立成文件**,绝对不能合并
- "设计用意"和"职责范围"是**两个独立章节**,不要偷懒合并
- "职责范围"用自然语言,**禁止**出现"职责:/不负责:"这种二分写法
- 依赖表列名必须是 `依赖项 | 关系 | 源文件`
**手动做法**
```
对清单中的每个单位:
1. 创建 Document/[模块]/[单位名].md 文件
2. 从步骤 2 的分析结果中抄入:基本信息、功能概述、设计用意、职责范围、依赖
3. 最后三节写 "待阶段3填写"
```
### 步骤 4阶段 2 — 生成关系文档
基于阶段 1 的依赖数据,为每个模块创建 `_relationships.md`
**用 Claude Code 的做法**
```markdown
对 Claude Code 说:
"为 Document/Plugins/Item/ 创建 _relationships.md。
表格列出每个文件间的 #include/forward-declare 关系。
再列出关键数据/控制流依赖链,用简单文本箭头。"
```
**手动做法**
```
1. 画一张表:
| 源文件 | 引用方式 | 目标文件 | 目标单位 |
2. 从步骤 2 的 #include/forward-declare 数据中抄入
3. 画出关键数据流:
- 创建流程:谁调用谁的什么方法创建什么
- 查询流程:谁通过谁获取什么数据
- 更新流程:数据从哪来,经过谁,到哪去
```
### 步骤 5阶段 3 — 填充接口、使用方法和用例
这是最需要"搜代码"的阶段。
**对外接口**的做法:
```
对每个 C++ 单位:
1. 打开其头文件
2. 找出所有 public/protected 方法
3. 找出所有 UFUNCTION 宏BlueprintCallable/BlueprintNativeEvent/BlueprintImplementableEvent
4. 找出所有 UPROPERTY 宏(尤其是 BlueprintReadOnly/BlueprintReadWrite 的)
5. 找出所有 DECLARE_DELEGATE / DECLARE_DYNAMIC_MULTICAST_DELEGATE
6. 用"调用者视角"重写:不要罗列函数签名,而是描述"外部代码可以做哪些事"
好例子:"调用 GetItemViews() 获取所有物品的只读视图,用于 UI 列表展示"
坏例子:"GetItemViews() const -> TArray<FItemView>"(这是罗列签名)
对每个蓝图单位:
1. 通过 MCP unreal_blueprint_query operation=inspect 查询变量和函数
2. 描述蓝图事件图中可被外部调用的函数和事件
3. 列出可编辑的实例变量
```
**使用方法**的做法:
```
对每个单位:
1. grep 搜索它在项目中的所有使用位置
rg "[单位名]" Source/ Plugins/ --type cpp --type h
2. 读相关代码段,理解它被如何使用
3. 挑选 2-5 个最典型的用法
4. 写成:文件路径:行号 — 在这段代码中是怎么用的
```
**用例**的做法:
```
对每个单位:
1. 从 grep 结果中确定哪些文件会用到它
2. 对每个使用文件写一条:文件路径:行号 — 用途说明
3. 不要伪造。如果某个文件只是 include 了但没实际用,不要写进去
```
**用 Claude Code 的做法**
```markdown
对 Claude Code 说:
"对 Document/Plugins/Item/ 下的所有 .md 文件,
用 Grep 搜索每个单位在 Source/ 和 Plugins/ 中的使用位置,
然后更新对外接口、使用方法、用例三个章节。
要求每条引用有文件路径和行号,只写真实代码中存在的用法。"
```
### 步骤 6阶段 4 — 更新 README.md
```
1. 列出所有 5 个模块
2. 每个模块下列出所有单位、文件名(带链接)、类型、父类
3. 描述文档模板的章节结构
4. 写下统计数字:多少单位、多少文件、覆盖哪些模块
```
### 步骤 7验证
```
□ 每个 .h 中定义的 class/struct/enum 都有对应的 .md 文件
□ 没有多单位合并到一个文件的情况(检查文件名列表跟单位列表一一对应)
□ 每个 .md 的"设计用意"和"职责范围"是两个独立章节
□ "职责范围"中没有出现"不负责"字样(这不是要求删除信息,而是用自然语言描述边界)
□ 每个 _relationships.md 的表格列名是"源文件|引用方式|目标文件|目标单位"
□ 每个使用方法/用例条目都带有文件路径和行号
□ 没有编造的伪代码示例
□ README.md 有完整的文档索引
□ 所有占位符"(待阶段3填写)"已被替换
```
---
## 四、工具速查
### 4.1 Grep 搜索命令
```bash
# 搜索某个类/结构体在项目中的使用
rg "FItemView" Plugins/Item/ Source/ --type-add 'ue:*.h' --type-add 'ue:*.cpp' --type ue -n
# 只列出文件名
rg "IItemContainer" -l
# 搜索 #include 关系
rg '#include.*ItemFactory' Plugins/Item/
```
### 4.2 MCP 蓝图查询命令
在 Claude Code 对话中可以直接用以下工具:
```
# 列出所有蓝图
mcp__unrealclaude__unreal_blueprint_query operation=list path_filter=/Game/Blueprints/ limit=50
# 查看单个蓝图的变量和函数
mcp__unrealclaude__unreal_blueprint_query operation=inspect
blueprint_path=/Game/Blueprints/BP_TestChar
include_variables=true
include_functions=true
# 搜索资产
mcp__unrealclaude__unreal_asset_search class_filter=Blueprint name_pattern=Test
```
### 4.3 Claude Code Task 代理
```
# 启动一个分析代理(后台运行)
Task subagent_type=Explore run_in_background=true
prompt="分析 X 目录下所有头文件..."
# 启动一个写文件的代理(后台运行)
Task subagent_type=general-purpose run_in_background=true
prompt="为以下单位创建/更新文档..."
# 查看代理输出
TaskOutput task_id=<代理ID> block=true timeout=120000
```
---
## 五、作者注
### 我是怎么被骂的
第一轮跑完「项目文档化计划」后,用户逐项检查,指出了 10 个问题(详见第一章)。核心批评:
1. **合并文件是最愚蠢的错误** — 文档的目的是让人查,文件名就是索引。把三个 struct 塞进一个 `ItemDataStructures.md`,等于给后人埋坑。
2. **"设计用意"和"职责范围"不能合并** — 前者是历史/动机,后者是边界。维护者需要知道"为什么存在",也需要知道"管多宽"。
3. **自我编造示例代码** — 我写了一堆 `// 继承 AMyActor 创建自定义 Actor` 的伪代码。用户一眼看出这不是项目里的真实代码。
4. **罗列函数签名** — 对外接口章节写成了 API reference而不是从调用者角度说明"你能干什么"。
5. **花式 ASCII 图**`_relationships.md` 里搞了一堆 ASCII 艺术框图。用户要的是简洁的文件级表格。
### 为什么这个流程可以复现
- **模板化**:每个文档的结构完全一致,没有自由发挥空间
- **可验证**每条引用必须有文件路径和行号grep 一下就能确认
- **分阶段**4 个阶段每条有明确的输入和输出,不会出现循环依赖
- **工具支持**Claude Code 的 Task 代理可以并行处理大量文件MCP 可以查询二进制蓝图
### 如果你没有 Claude Code
整个流程的核心逻辑不依赖 AI 工具。你可以纯手工完成:
1. 在 Excel/Notion 里建一张表,列出所有单位及其分析数据(步骤 2
2. 按模板逐个创建 .md 文件(步骤 3-5
3. 用 grep/VSCode 搜索来验证引用关系(步骤 7
只是一个人做 56 个文档大概需要 3-5 个工作日。
### 后续维护
代码改动后,更新对应文档:
- 新增类:按模板创建新 .md更新 `_relationships.md``README.md`
- 删除类:删除对应 .md更新 `_relationships.md``README.md`
- 修改接口:更新"对外接口"章节和对应的"使用方法"引用
- 修改依赖:更新"项目内依赖"表和 `_relationships.md`