docs:新增 AGENTS.md 作为 AI / 新人接续开发的入口文件

一页纸解决「接手时不知道从哪读、哪些不能碰、改完怎么验」:
- 0 组件与端口速览;1 必读顺序(踩坑记录 P-001/P-002/P-011 列为首要)+ 按改动选文档
- 2 硬规则 R1–R9:DLL 与 exe 成对、改 DLL 要补 CRC 并重编服务端、Z 盘只是部署副本、
  gmweb 只能 IE11、静态 no-store、sys.executable 陷阱、不提交产物、版本号三处一致、声明与 GPL
- 3 构建命令(服务端三个 exe / 启动器单文件 / 客户端补丁 / PVF 导出)
- 4 代码地图:server.py 按功能给出行号区间,其余给模块职责
- 5 验证方法:进程端口、启动器日志、CRC verify、diff -rq,
  以及本项目一直在用的「静态服务 + 无头浏览器截图/量 rect」手法,附分场景清单
- 6 发版七项清单;7 当前状态;8 提交约定;9 不要做的事
- CLAUDE.md 作为指向 AGENTS.md 的兼容入口;根 README 顶部与文档索引、docs/README 同步挂上
This commit is contained in:
hanfuit committed 2026-11-05 17:40:13 +08:00
1 parent adcc5b0f3a
commit 464255a2e2
4 files changed
+251

No files matched your search

+236
View File
@@ -0,0 +1,236 @@
# AGENTS.md
> **给接续开发的 AI 的入口文件。** 先读完这一页再看代码。
> 这里只放三样东西:**哪些规则不能破**、**命令怎么跑**、**改完怎么验证**。
> 背景与完整说明看 [README.md](README.md),历史踩过的坑看 [docs/踩坑记录.md](docs/踩坑记录.md)。
---
## 0. 三十秒认识这个仓库
《地下城与勇士》90 级版本的**本地单机模拟器**,非私服、不联网、不开服。monorepo,四个进程协作:
| 组件 | 目录 | 技术栈 | 端口 / 产物 |
|------|------|--------|------------|
| 整合启动器 | `launcher/` | Python 3.15 **32 位** + pywebview + PyInstaller | `127.0.0.1:19527`,产物 `launcher/dist/DNF90启动器.exe` |
| 服务端 | `server/` | Go 1.26.5(模块 `longheng.io/server`) | `127.0.0.1:18111`(Admin),产物 `DNF90Server.exe` 等三个 |
| 游戏内 GM 控制台 | `gmweb/` | 纯 HTML/CSS/JS + Python 标准库 `serve.py` | `127.0.0.1:18112`,反代 18111 并注入 token |
| 客户端补丁 | `client-patch/` | C++ / MSVC vcxproj | 产物 `90CN.dll`,接管游戏面板弹 WebView2 窗口 |
其余:`pvf/`(PVF 解析,Go,GPL-3.0)、`loadout-tool/`(换装工具,C#)、`gmtool/`(旧版 GM 工具,仅参考)。
**仓库只存源码**:exe / dll / 美术 / PVF 资源都不在库里,成品走网盘。
当前版本 **v2026.11.05**,远程 `origin` = `https://git.hanfuit.com/Lingbao/90CNServer.git`,分支 `main`。
---
## 1. 开工前必读(按顺序,别跳)
1. 本文件(硬规则 + 验证方法)
2. [docs/踩坑记录.md](docs/踩坑记录.md) —— **至少读 P-001 / P-002 / P-011**,这三条是「不知道就会重新踩一遍」的
3. 然后按要改的地方选读:
| 要改什么 | 读哪份 |
|---------|--------|
| 启动器 / GM 工具 / 打包 | [docs/开发文档.md](docs/开发文档.md) |
| 服务端 GM 接口、拍卖行、背包 | [docs/服务端开发文档.md](docs/服务端开发文档.md) |
| 客户端补丁 90CN.dll、CRC 自校验 | [docs/客户端补丁与CRC校验.md](docs/客户端补丁与CRC校验.md) |
| PVF 解析、离线物品名 | [docs/PVF解析开发文档.md](docs/PVF解析开发文档.md) |
| 发版 | [docs/release/README.md](docs/release/README.md) + [发布说明模板](docs/release/发布说明模板.md) |
---
## 2. 硬规则(不是代码风格,违反了就出故障)
**R1|`90CN.dll` 与 `DNF90Server.exe` 是一对,必须同批构建、同批发布。**
服务端编译期把 DLL 的 SHA-256 写进常量 `boundDllSHA256`,DLL 一换指纹就不配套,
客户端能启动但**登录阶段被踢**,服务端日志没有明显报错。只改其中一半是最常见的翻车方式。
**R2|改完 DLL 必须先补 CRC32,再重编服务端。**
`client-patch/tools/build_90cn.ps1` 第三步会自动补;带 `-SkipCrc` 出来的 DLL 不要发布。
自校验失败的表现是客户端弹框退出(详见 P-003 / P-004:CRC 种子别手填、槽位只在 `.data`/`.rdata` 扫)。
**R3|仓库是唯一真源,`Z:\90server` 只是部署副本。**
调试可以直接在部署目录改,但**改完必须回灌仓库**,并用 `diff -rq` 核对(P-011 就是这么漏过
`90CN_web.ini` 和整个 `gmweb/` 的)。提交前 `git status` 确认没有该进的 ini / 静态资源留在外面。
**R4|`gmweb/` 只能写 IE11 兼容代码。**
游戏内嵌的是老 WebView 控件:不用 flex、不用 CSS 变量、不用 `transform`。布局统一
`float` + `box-sizing:border-box`;垂直居中用 `position:absolute; top:50%` + `-ms-transform:translateY(-50%)`。
改完 CSS/JS **必须把 `?v=YYYYMMDDx` 加一版**,否则 IE11 缓存不刷新。
**R5|静态响应统一 `Cache-Control: no-store`。**
启动器侧已在 `server.py` 的 `_send` 里加,新增路由时别绕过它;否则 WebView2 会缓存旧页面,
现象是「改了没生效」,会浪费大量时间。
**R6|单文件打包会改变 `sys.executable` 的含义。**
源码运行时它是 `python.exe`,`--onefile` 打包后**是启动器自己**。任何 `Popen([sys.executable, ...])`
的地方打包前都要重新推一遍;拉起子进程后要**校验副作用**(端口真在监听)而不是校验返回值。
这就是 P-001 的整条成因链,别再犯。
**R7|不提交编译产物。**
`*.exe`、`*.dll`、`launcher/dist/`、`launcher/build/`、`server/build_verify/`、`__pycache__/`、
`launcher/dnf_items.json`、`*.pvf`、`*.log` 已在 `.gitignore`。不要为了「方便别人」把它们塞进库。
**R8|版本号三处一致**:`launcher/server.py` 的 `CURRENT_VERSION`、发布包根目录 `更新日志.txt`、
客户端的版本显示。改一漏二会出现「首页还是旧版本号」。
**R9|品牌与声明不能动。**
「本模拟器资源禁止倒卖,请到官方微信公众号或社群下载」「禁止用于开服」这类声明必须保留;
`pvf/` 源自 pvfine,**GPL-3.0 有传染性**,改它之前先确认许可证影响。
---
## 3. 环境与构建
作者机器上的路径(其他环境自行替换,逻辑不依赖盘符):
```
Python 3.15 32 位 C:\Python315\python.exe # 32 位是硬要求,客户端/工具链都是 32 位
Go ≥ 1.26.5
MSVC Visual Studio(client-patch 用 vcxproj)
部署目录 Z:\90server # 只是副本
桌面发布包 90CN灵宝小竹整合20261105更新补丁\
```
```bash
# 服务端(三个 exe)
cd server
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOSUMDB=sum.golang.google.cn
go build -buildvcs=false -trimpath -o DNF90Server.exe ./cmd/server/dnf90
go build -buildvcs=false -trimpath -o DNF90Control.exe ./cmd/server/control
go build -buildvcs=false -trimpath -o DNF90Doctor.exe ./cmd/server/doctor
# 启动器(单文件)
cd launcher
C:/Python315/python.exe -m pip install pywebview pythonnet clr-loader pyinstaller
C:/Python315/python.exe -m PyInstaller --clean --noconfirm "DNF90启动器.spec"
# → launcher/dist/DNF90启动器.exe
# 客户端补丁(Release|Win32,自动补 CRC)
client-patch\tools\build_90cn.bat
# PVF 物品名导出
cd pvf && go build ./cmd/pvfexport/ && pvfexport -pvf Script.pvf -out dnf_items.json -compact
```
---
## 4. 代码地图
```
launcher/
├── server.py 2809 行,本地 HTTP 服务 + 全部 GM 逻辑 + 窗口启动(核心,占 80% 工作量)
│ ├── 202-360 日志(_logf) / 单实例互斥 / 多调用模式 run_script_instead()
│ ├── 369-430 start_gmweb():拉起 18112 + 就绪校验 + 进程内兜底 ← 高危区,见 P-001
│ ├── 551-686 更新日志:仓库 Release + 本地 txt 合并去重
│ └── 2481-2800 main() / webview2_installed() / show_window() / 窗口清理
├── index.html 234 行,六页骨架(开始/GM工具/一键换装/游戏设置/游戏更新/关于我们)
├── shell.js 804 行,页面路由、更新日志渲染、二维码灯箱
├── shell.css 447 行,页面样式(WebView2 环境,可用现代 CSS)
└── qr/ 四张二维码:alipay.png / wechat.png / gzh.jpg / qq.png
gmweb/ 游戏内控制台,共约 1100 行
├── serve.py 187 行,静态托管 + /api/* 反代 18111 + 注入 admin token + /qr/<name> 白名单
├── index.html / style.css / app.js IE11 约束,别用现代语法
└── qr/ 同上四张
client-patch/
├── 90CN.cpp 客户端补丁主体(极大,改前先搜函数名定位)
├── 90CN_web.ini width=800 height=720 close_action=1 ← 内嵌 GM 页尺寸,改这里不是改代码
└── tools/ build_90cn.ps1(构建+补CRC)/ patch_dll_crc.py(info|verify|patch)
server/cmd/server/ dnf90(主体)/ control(控制台)/ doctor(自检)/ launcher / logtool / 等
```
---
## 5. 改完怎么验证(**别只看代码,必须跑**)
```bash
# 进程与端口(改启动器后必查:正常只有 19527 + 18112 两个监听)
tasklist | findstr DNF90
netstat -ano | findstr "127.0.0.1:19527 127.0.0.1:18112 127.0.0.1:18111"
# 启动器现场日志(出问题先看这个,比猜快得多)
type 启动器日志.txt # exe 同目录;应有 pid / argv / 端口 / 多调用模式
# DLL 自校验状态
C:/Python315/python.exe client-patch/tools/patch_dll_crc.py verify Z:/90server/Client/90CN.dll
C:/Python315/python.exe client-patch/tools/patch_dll_crc.py info Z:/90server/Client/90CN.dll
# 仓库 ↔ 部署目录一致性
diff -rq gmweb Z:/90server/gmweb
diff -q client-patch/90CN_web.ini Z:/90server/Client/90CN_web.ini
```
**看界面的推荐做法**(比肉眼读像素可靠,本项目一直这么验):
```bash
# 1) 起静态服务;2) 注入脚本切到目标页;3) 无头浏览器截图/量尺寸
cd gmweb && C:/Python315/python.exe -m http.server 18198
# 页面里注入:document.getElementById('pane-about').className='pane on';
# (启动器则是给对应 .shell-page 加 active)
msedge --headless=new --disable-gpu --hide-scrollbars --window-size=800,720 \
--screenshot=shot.png --virtual-time-budget=3000 http://127.0.0.1:18198/_t.html
# 量尺寸:把 getBoundingClientRect 结果写进 document.title,再用 --dump-dom | grep title
```
尺寸口径:GM 页内嵌窗口 **800×720**;启动器窗口 **1204×717**。改完两边都看一眼有没有滚动条。
**分场景清单**
| 改了什么 | 必须确认 |
|---------|---------|
| 启动器页面/样式 | 打包 → 杀旧进程 → 启动 → 六页都能切、无滚动条、`启动器日志.txt` 无异常 |
| 启动器 Python 逻辑 | 先跑源码再打包:`cd launcher && DNF90_SERVER_ROOT=Z:/90server DNF90_NO_ELEVATE=1 python server.py`(`SERVER_ROOT` 靠 EXE 同级有 `Server/` 识别,脱离部署目录时用环境变量指定);确认没有新增 `sys.executable` 陷阱 |
| gmweb 页面 | `?v=` 加一版;800×720 截图三列/四页无溢出;`/api/*` 仍能通 |
| 服务端接口 | `go build` 通过;`DNF90Doctor.exe` 自检;启动器「GM工具」页能读到数据 |
| 客户端补丁 | `build_90cn.bat` 全流程(含补 CRC)→ **重编服务端** → 两边一起替换 → 登录验证 |
| 发版 | 按 [docs/release/README.md](docs/release/README.md) 七步走,见第 6 节清单 |
---
## 6. 发版检查清单(缺一项就会有人装不上)
- [ ] `Client\90CN.dll` 与 `Server\runtime\bin\DNF90Server.exe` **成对且指纹一致**
- [ ] `gmweb\` 整个目录(含 `qr\` 四张图)
- [ ] `Client\90CN_web.ini`(缺它回退 1040 宽、`close_action=0`)
- [ ] 启动器 exe + `更新日志.txt`
- [ ] 版本号三处一致(`CURRENT_VERSION` / 客户端显示 / 更新日志)
- [ ] **干净目录**(非中文、无空格)实跑一遍再对外发
- [ ] Release 说明用模板;附件传 `docs/release/网盘下载.url`(别直传十几 G 的包)
---
## 7. 当前状态(2026-11-05)
- 版本 `v2026.11.05`;`main` 与 `origin/main` 同步
- 启动器:六页(开始/GM工具/一键换装/游戏设置/游戏更新[当前|历史]/关于我们),关于页三列二维码
- gmweb:四页,关于页三列(赞助我们 353 | 官方QQ群 178 | 团队公众号 179,面板宽 712)
- 已修复:启动器打包后自我套娃开窗(P-001),带单实例互斥 + 运行日志 + WebView2 固定数据目录
- 已知待办:release 附件 `.url` 里的网盘链接换代时,要同步改 `发布说明模板.md` 表格;`gmtool/` 为旧版遗留,可择机归档
---
## 8. 提交约定
1. 提交信息格式:`范围:做了什么`,例如 `启动器:游戏更新拆分为当前/历史双子页,新增关于我们页`
2. 一次提交一件事;改了接口就同步改对应文档(服务端接口 → `docs/服务端开发文档.md`)
3. 只提交源码与文档;产物走 `.gitignore`
4. 新踩的坑,追加到 `docs/踩坑记录.md`(编号延续 P-0xx,格式照抄现有条目)
5. 推送前 `git status -sb` 确认工作区干净、与 `origin/main` 无分叉
---
## 9. 不要做的事
- ❌ 不要「为了省事」只替换 DLL 或只替换服务端 exe —— 见 R1
- ❌ 不要用 `!important` 硬压 gmweb 的样式问题 —— 先看是哪个选择器赢了(P-005)
- ❌ 不要用现代 CSS/JS 写 `gmweb/` —— 见 R4
- ❌ 不要把 `Z:\90server` 当工作区改完就完事 —— 见 R3
- ❌ 不要在启动器里加「打包后会指向自己」的子进程调用而不做校验 —— 见 R6
- ❌ 不要提交 exe/dll/`dnf_items.json`/PVF 资源
- ❌ 不要把本机测试用的掉落改动带进对外发布的服务端
- ❌ 不要公开分发或倒卖本仓库代码与资源(`pvf/` 除外,但受 GPL-3.0 约束)
+10
View File
@@ -0,0 +1,10 @@
# CLAUDE.md
本仓库的统一入口是 **[AGENTS.md](AGENTS.md)**(硬规则 R1–R9、构建命令、验证方法、代码地图、发版清单)。
开工前请先完整读一遍,再按其中的「开工前必读」选读 `docs/` 下的对应文档。
三条最容易被忽略、且会直接导致故障的规则:
1. `90CN.dll` 与 `DNF90Server.exe` 指纹绑定,**必须成对构建、同批发布**(R1/R2)
2. `gmweb/` 是 IE11 环境,**不能用 flex 等现代 CSS**,改完资源要加 `?v=`(R4)
3. 单文件打包后 `sys.executable` 指向启动器自身,**任何拉起子进程的代码都要校验副作用**(R6)
+3
View File
@@ -10,6 +10,8 @@
> 本模拟器资源禁止倒卖,请到官方微信公众号或社群下载。 > 本模拟器资源禁止倒卖,请到官方微信公众号或社群下载。
> **用 AI 接续开发?先读 [AGENTS.md](AGENTS.md)** —— 硬规则、构建命令、验证方法、代码地图一页看完。
--- ---
## 一、它由哪几块组成 ## 一、它由哪几块组成
@@ -188,6 +190,7 @@ pvfexport -pvf Script.pvf -out dnf_items.json -compact
| 文档 | 内容 | | 文档 | 内容 |
|------|------| |------|------|
| [AGENTS.md](AGENTS.md) | **AI / 新人接续开发入口**:硬规则 R1–R9、构建与验证命令、代码地图、发版清单 |
| [docs/README.md](docs/README.md) | 文档总索引与上手路径 | | [docs/README.md](docs/README.md) | 文档总索引与上手路径 |
| [docs/开发文档.md](docs/开发文档.md) | 启动器 / GM 工具:环境、架构、API 契约、打包部署、常见问题 | | [docs/开发文档.md](docs/开发文档.md) | 启动器 / GM 工具:环境、架构、API 契约、打包部署、常见问题 |
| [docs/服务端开发文档.md](docs/服务端开发文档.md) | 服务端架构、GM 接口契约、拍卖行与背包改动 | | [docs/服务端开发文档.md](docs/服务端开发文档.md) | 服务端架构、GM 接口契约、拍卖行与背包改动 |
+2
View File
@@ -4,6 +4,7 @@
| 文档 | 内容 | | 文档 | 内容 |
|------|------| |------|------|
| [../AGENTS.md](../AGENTS.md) | **入口文件**:给 AI / 新人的一页纸——硬规则、构建命令、验证方法、代码地图、发版清单(开工前先读这份) |
| [开发文档.md](开发文档.md) | **GM 启动器 / 整合工具** 完整开发文档(环境搭建、架构、API 契约、打包部署、常见问题) | | [开发文档.md](开发文档.md) | **GM 启动器 / 整合工具** 完整开发文档(环境搭建、架构、API 契约、打包部署、常见问题) |
| [服务端开发文档.md](服务端开发文档.md) | **服务端(Go)** 架构、GM 接口契约、拍卖行/背包改动、编译部署 | | [服务端开发文档.md](服务端开发文档.md) | **服务端(Go)** 架构、GM 接口契约、拍卖行/背包改动、编译部署 |
| [PVF解析开发文档.md](PVF解析开发文档.md) | **PVF 解析** 套件(pvfine)、pvfexport 工具、离线名称显示集成 | | [PVF解析开发文档.md](PVF解析开发文档.md) | **PVF 解析** 套件(pvfine)、pvfexport 工具、离线名称显示集成 |
@@ -22,6 +23,7 @@
## 快速上手路径 ## 快速上手路径
0. **任何人(含 AI)接手**:先读 [../AGENTS.md](../AGENTS.md),再回来按场景选文档。
1. **只想跑起来**:看根目录 [README](../README.md) 的「快速开始」。 1. **只想跑起来**:看根目录 [README](../README.md) 的「快速开始」。
2. **改 GM 工具(启动器)**:看 [开发文档.md](开发文档.md)。 2. **改 GM 工具(启动器)**:看 [开发文档.md](开发文档.md)。
3. **改服务端 GM 接口**:看 [服务端开发文档.md](服务端开发文档.md) 的「GM 接口契约」。 3. **改服务端 GM 接口**:看 [服务端开发文档.md](服务端开发文档.md) 的「GM 接口契约」。