Files
dwarf-fortress-annals/README.md
T

152 lines
7.8 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.
# 矮人要塞编年史 · Dwarf Fortress Annals
把《矮人要塞》(Dwarf Fortress) 世界生成的历史数据,写成**中文战报体连载故事**,自动推送到这个仓库。
本仓库是**成品仓**:放小说章节、迷你年表、人物索引,以及生成它们的代码。
原始 `legends` 导出数据(数百 MB)与游戏存档留在本地,不入库。
---
## 一、它是怎么工作的
```
Windows 侧:Dwarf Fortress 53.16 + DFHack 53.16-r2
│ ① 生成世界(Medium 129×129 / 250 年历史)
│ ② 进入 legends 模式,导出 legends.xml + legends_plus.xml
▼ ③ 经 /mnt/c 文件交换(不需要 WSL↔Windows 网络互访)
WSL2 Ubuntu 侧管道
│ ④ 预处理:剔除 DF 塞进名字里的非法控制字符,CP437 → UTF-8
│ ⑤ 解析史料:40 万条事件 / 4 万位人物 → 事件流 + 年表 + 人物索引
│ ⑥ 切章:10 年一窗,每窗按显著度取前 12 条,同类事件≤4(避免整章讣告)
│ ⑦ 写作:要塞编年史官口吻 / 战报体 / 允许自由演绎
│ ⑧ 校验:正文专名必须能在史料里找到,可疑处标注但不阻断
▼ ⑨ git commit & push
Gitea:gitadmin/dwarf-fortress-annals(本仓库)
```
## 二、目录
| 路径 | 内容 | 入库 |
|---|---|---|
| `output/volumes/v<N>/chapters/` | 连载正文 | ✅ |
| `output/volumes/v<N>/timeline.md` | 迷你年表 | ✅ |
| `output/volumes/v<N>/figures.md` | 人物索引 | ✅ |
| `dfannals/` | 管道源码 | ✅ |
| `scripts/` | 安装、部署、驱动脚本 | ✅ |
| `prompts/chronicler.md` | 写作规范(决定文风与人设) | ✅ |
| `tests/` | 事实校验回归测试(含合成史料样例) | ✅ |
| `data/exports/` | 原始 legends 数据与预处理缓存 | ❌ |
| `data/state.json` | 进度状态(当前世界 / 卷号 / 已写章节) | ❌ |
| `data/GRILL-ME.md` | 立项访谈记录 | ❌ |
## 三、依赖
| 依赖 | 版本 / 说明 |
|---|---|
| Dwarf Fortress | **53.16** 免费版(Bay 12)。必须与 DFHack 严格配对 |
| DFHack | **53.16-r2**。Windows 版经 `dfhooks.dll` 注入,不需要替换启动器 |
| Python | 3.12(用到 `X \| None` 语法) |
| defusedxml | `sudo apt install python3-defusedxml`(解析不可信 XML 用) |
| 写作模型 | 经 `https://wb2api.hajim1.art/v1`(OpenAI 兼容)调用 `cn:deepseek-v4-pro` |
| 发布 | 现有 `~/.ssh/id_ed25519`(已注册到 Gitea 账号 gitadmin) |
> 无独显也能跑:DF 本体不吃 GPU;写故事走云端 API,不做本地推理。
## 四、安装
```bash
# 1) Windows 侧装游戏与 DFHack(经 WSL 的 /mnt/c 操作,免管理员权限)
scripts/install-df.sh --download # Bay12 与 GitHub 在国内较慢,会断点续传
# GitHub 直连不通时改用镜像:https://gh-proxy.com/<原地址>
# 2) 装依赖
sudo apt install -y python3-defusedxml
# 3) 把驱动脚本部署进游戏目录
scripts/deploy-dfhack.sh /mnt/c/Users/$USER_WIN/DwarfFortress
```
## 五、产出一卷(生成新世界 → 导出 → 连载)
```bash
# 1) 启动游戏,停在标题界面
"/mnt/c/Users/23518/DwarfFortress/Dwarf Fortress.exe" &
# 2) 自动生成世界(Medium / 250 年)并导出 legends 数据到 data/exports/
scripts/make-world.sh 3 3
# 3) 一条命令产出下一章并推送
python3 -m dfannals.cli run
```
`make-world.sh` 全程从外部驱动游戏,不需要人工点击:
- 用 `dfannals/screentext` 把画面读成字符网格,`scripts/df-screen.py` 按文字定位按钮
- 用 `dfannals/click` 模拟鼠标、`dfannals/setparams` 直接设定世界参数
- 用 `dfannals/legends` 进入 legends 模式(做法取自 DFHack 官方 `open-legends.lua`)
- 用 `dfannals/act` / `devel/send-key` 发按键
> 备选:DF 自带命令行世界生成器 `"Dwarf Fortress.exe" -gen 1 RANDOM "MEDIUM ISLAND"`,
> 可静默生成并导出,但**不留存档**,因此无法继续进 legends 导出,只适合快速验证参数。
## 六、子命令
```bash
python3 -m dfannals.cli status # 当前世界 / 卷号 / 已写章节
python3 -m dfannals.cli plan # 只看切章方案,不调模型
python3 -m dfannals.cli index # 解析 exports → 年表 + 人物索引
python3 -m dfannals.cli next # 生成下一章(--dry-run 只生成不推送)
python3 -m dfannals.cli run # index + next,一条命令走完
python3 tests/test_factcheck.py # 校验器回归测试
```
实测:**约 2.5 分钟 / 章**(解析 33 秒 + 模型 1–2 分钟),单章 1000–1400 字。
## 七、配置在哪
| 想改什么 | 改哪 |
|---|---|
| 世界大小 / 历史长度 | `scripts/make-world.sh` 的两个档位参数 |
| 切章粒度(几年一章、每章几条、同类上限) | `dfannals/slice.py` 顶部常量 |
| 哪些事件值得写(显著度评分) | `dfannals/score.py` 的 `NARRATIVE` 表 |
| 文风、人设、演绎边界 | `prompts/chronicler.md` |
| 章节字数区间 | `dfannals/config.py` 的 `CHAPTER_MIN/MAX_CHARS` |
| 模型与网关 | `dfannals/config.py` 的 `PROVIDER` / `MODEL` |
| 发布目标、仓库名 | `dfannals/config.py` 的 `GITEA_*` |
**API key 不入库**:脚本运行时从 `~/.pi/agent/auth.json` 读取,只在内存中,不打印、不落盘、不进 git。
## 八、踩过的坑(失败排查参考)
| 症状 | 原因与解法 |
|---|---|
| `not well-formed (invalid token)` | DF 在名字里嵌了 `\x10`/`\x11` 等 CP437 控制字符,XML 1.0 禁止。管道开头的预处理会剔除并转 UTF-8,缓存到 `data/exports/clean/` |
| 事件数莫名翻倍 | 预处理缓存若与原始文件同目录,会被 `*.xml` 扫描当成第二份史料。缓存因此放在子目录 |
| 素材里出现 `HF#-1`、`Site#-1` | DF 用负数占位表示"无此项"。查询接口对负 id 返回空串,渲染时跳过 |
| 校验器把真名报成可疑 | 史料里是全小写程序名(`yemi deermoths`),正文做了首字母大写。已知名字集同时收录两种形式(有回归测试) |
| `dfhack-run "cmd a b"` 报 not recognized | 参数要分开传:`dfhack-run dfannals/click 10 2`,不要整体加引号 |
| 切出几千章 | 40 万条事件里绝大多数是流水账(`change hf state` 7.3 万条)。必须先按显著度筛选,再按时间窗分桶 |
| Bay12 下载只有 ~10KB/s | 官网无国内镜像。放后台断点续传即可(16MB 约 27 分钟) |
| GitHub release 下载 0 字节 | 直连被断。用 `https://gh-proxy.com/` 前缀 |
| 观测 / init 脚本不生效 | 53.16 只执行固定几个 init 文件。改用 `dfhack-run` 从外部驱动,更可靠 |
## 九、写作设定
- **叙述者**:世界档案库里的编年史官——少数亲历,多数事后依据档案与口述追述,因此对陈年旧账有看法
- **口吻**:战报体,严肃的骨架 + 诙谐的血肉,允许吐槽
- **语言**:中文;专有名词保留英文原文(首字母大写以便阅读)
- **演绎边界**:允许虚构对白、心理、场景;**不许发明史料里没有的人名地名**,不许改写史实骨架(年份、参与者、胜负)
- **连载**:同一世界长期连载;一部史写完则用 `make-world.sh` 生成新世界开新卷
## 十、当前状态与限制
- **已完成**:3 卷框架 + 第 1、2 章上线(Mon Sagus 世界,1–250 年,26 章规划)
- **定时任务未启用**:`cron` / 开机自启等稳定运行一段时间后再落地;目前按需手动执行
- **原始数据不入库**:`data/` 已在 `.gitignore` 中
- **诚实说明**:世界创建各步骤均已逐步实测通过,并已整合为 `make-world.sh`;但该脚本尚未作为**单次完整调用**重跑验证(单次约 15 分钟),首次使用时请留意各阶段日志
## 十一、声明
《Dwarf Fortress》版权归 Bay 12 Games 所有。本仓库只包含由其生成数据的**衍生文本**,
不含游戏本体、美术资源或存档。