diff --git a/README.md b/README.md index 3736dd5..3b245cd 100644 --- a/README.md +++ b/README.md @@ -1,119 +1,211 @@ -# DNF90 单机模拟器 · 源码仓库 +# DNF90 灵宝小竹单机版 · 源码仓库 -一个 DNF90 单机模拟器(非私服)的完整源码 monorepo,包含**服务端(Go)**、**客户端补丁(C++)**、**GM 管理工具 / 启动器(Python)**、**一键换装工具(C#)**,以及**本地 PVF 解析套件(Go)**。 +《地下城与勇士》90 级版本的**本地单机模拟器**(非私服、不联网、不开服)完整源码 monorepo:服务端、客户端补丁、整合启动器、游戏内 GM 控制台,以及 PVF 解析套件。 -> 本仓库只含源码,不含编译产物(exe/dll)与美术/PVF 资源。clone 后需按各自子目录的说明编译。 +- 当前版本:**v2026.11.05** +- 维护:汉服电脑宅团队(灵宝仙尊 联合 淡竹茹 开发) +- 官方 QQ 群:**1128511524** +- 仓库只存源码,不含 exe/dll、美术与 PVF 资源;发布包另走网盘 + +> 本模拟器资源禁止倒卖,请到官方微信公众号或社群下载。 --- -## 目录结构 +## 一、它由哪几块组成 ``` -DNF90-Source/ +┌──────────────────────────────────────────────────────────────┐ +│ DNF90启动器.exe (launcher/, Python + pywebview) │ +│ 127.0.0.1:19527 · 单文件 PyInstaller · 六页单窗口 │ +│ ├─ 开始:拉起 / 停止本地服务端,显示连接状态 │ +│ ├─ GM工具:角色 / 道具 / 邮件 / 背包 / 拍卖行 / 任务 / 副本 │ +│ ├─ 一键换装:装备方案套用(Admin API) │ +│ ├─ 游戏设置:活动 / 频道开关 │ +│ ├─ 游戏更新:当前更新 + 历史更新(仓库 Release 合并本地日志) │ +│ └─ 关于我们:赞助码 / QQ群 / 公众号 │ +└───────────────┬──────────────────────────┬───────────────────┘ + │ Native API │ 启动 GM 页服务 + │ 127.0.0.1:18111 │ python gmweb/serve.py + ▼ ▼ +┌───────────────────────────┐ ┌────────────────────────────────┐ +│ DNF90Server.exe (server/) │ │ GM 控制台网页 (gmweb/) │ +│ Go · Admin / GM 接口 │◄──┤ 127.0.0.1:18112 → 代理 18111 │ +│ SQLite: runtime/data/*.db │ │ 游戏内嵌窗口 800×720 │ +└───────────────────────────┘ └────────────────────────────────┘ + ▲ + │ 客户端内嵌调用(DLL 指纹校验) +┌───────────────┴──────────────────────────────────────────────┐ +│ 90CN.dll (client-patch/, C++) 被 90CN_web.ini 控制 │ +│ 接管游戏自带面板 → 弹自己的 WebView2 窗口指向 18112 │ +└──────────────────────────────────────────────────────────────┘ +``` + +## 二、目录结构 + +``` +90CNServer/ ├── server/ DNF90 服务端(Go,模块 longheng.io/server) -├── client-patch/ 客户端补丁(C++,90CN.dll 源码) +│ ├── cmd/server/{dnf90,control,doctor} 主程序 / 控制台 / 自检 +│ ├── internal/ pkg/ 业务与基础库 +│ └── build_verify/ 构建校验脚本(不参与发布) +├── client-patch/ 客户端补丁(C++ / MSVC,含 90CN_web.ini) +├── launcher/ 整合启动器 + 内置 GM 工具(Python 3.15 + pywebview) +│ └── qr/ 关于页二维码(alipay / wechat / gzh / qq) +├── gmweb/ 游戏内 GM 控制台网页(纯静态 + serve.py 反代) +│ └── qr/ 控制台关于页二维码 ├── loadout-tool/ 一键换装工具(C# / .NET) -├── launcher/ 整合启动器 + GM 管理工具(Python + pywebview) -├── gmtool/ GM 工具旧版(Python + FastAPI,已被 launcher 取代,保留参考) +├── gmtool/ GM 工具旧版(FastAPI,已被 launcher 取代,仅留参考) ├── pvf/ PVF 解析套件(Go,模块 pvfine,GPL-3.0) │ └── cmd/pvfexport/ 物品名称表导出工具 -└── docs/ 开发文档 +├── docs/ 开发文档 + 发布物料模板(release/) +└── README.md ``` ---- +## 三、子项目速览 -## 子项目速览 +| 目录 | 语言 / 技术栈 | 说明 | +|------|--------------|------| +| `server/` | Go 1.26.5(`longheng.io/server`) | 服务端主体;Admin/GM HTTP 接口、拍卖行、背包、任务、副本、点券 | +| `client-patch/` | C++ / MSVC vcxproj | `90CN.dll`:面板接管、安图恩兼容、蛇腹剑修复、战斗面板布局等 | +| `launcher/` | Python 3.15(32 位)+ pywebview 6 + PyInstaller | 单 EXE 启动器,六页单窗口,内置完整 GM 工具与更新日志 | +| `gmweb/` | 纯 HTML/CSS/JS + Python 标准库 | 游戏内 GM 控制台页面,`serve.py` 反代 18111 并注入 admin token | +| `loadout-tool/` | C# / .NET | 独立换装工具,通过 Admin API 操作 | +| `gmtool/` | Python + FastAPI | GM 工具旧版,保留参考 | +| `pvf/` | Go 1.26(`pvfine`,GPL-3.0) | PVF 解析库 + `pvfexport` 物品名导出 | -| 目录 | 语言 | 模块/技术栈 | 说明 | -|------|------|------------|------| -| `server/` | Go 1.26 | `longheng.io/server` | DNF90 服务端,含 GM 拍卖行接口、自动补足上架、背包管理 | -| `client-patch/` | C++ | MSVC / vcxproj | 90CN 客户端补丁,含安图恩兼容、蛇腹剑修复等 | -| `loadout-tool/` | C# | .NET | 一键换装工具,通过 Admin API 操作 | -| `launcher/` | Python 3.15 | pywebview + PyInstaller | 单 EXE 启动器 + 内置 GM 工具(双数据源) | -| `gmtool/` | Python | FastAPI | GM 工具旧版(独立服务 + 网页) | -| `pvf/` | Go 1.26 | `pvfine`(GPL-3.0) | PVF 解析库 + `pvfexport` 物品名导出工具 | +## 四、快速开始 ---- +### 4.1 只想要能玩的成品 -## 快速开始 +1. 从官方渠道下载发布包(网盘),解压到**非中文、无空格**路径,例如 `D:\DNF90` +2. 双击 `DNF90启动器.exe` +3. 点「开始」拉起服务端,等日志出现「服务已就绪」再进游戏(首次约 85 秒) +4. 进游戏后点小井盖即可打开 GM 控制台 -### 1. 服务端(server/) +### 4.2 从源码编译 -要求 Go ≥ 1.26(`go.mod` 声明 1.26.5)。建议配置国内镜像: +**服务端**(Go ≥ 1.26.5,建议国内镜像): ```bash go env -w GOPROXY=https://goproxy.cn,direct go env -w GOSUMDB=sum.golang.google.cn cd server -go build -buildvcs=false -trimpath -o DNF90Server.exe ./cmd/server/dnf90 +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 +go build -buildvcs=false -trimpath -o DNF90Doctor.exe ./cmd/server/doctor ``` -详见 `server/README.md`。 - -### 2. GM 启动器(launcher/) - -要求 Python 3.15(32 位)+ Windows。打包: +**启动器**(Python 3.15 32 位): ```bash cd launcher python -m pip install pywebview pythonnet clr-loader pyinstaller python -m PyInstaller --clean --noconfirm "DNF90启动器.spec" +# 产物:launcher/dist/DNF90启动器.exe ``` -产物在 `launcher/dist/DNF90启动器.exe`。详见 `docs/开发文档.md`。 +> 单文件打包有代价:onefile 会先解包再启动,改完源码必须重新打包;旧进程未退出时会继续占用 19527 端口,看到旧界面先确认进程已杀干净。 -### 3. PVF 解析(pvf/) +**PVF 物品名导出**: ```bash cd pvf -go build ./cmd/pvfexport/ # 物品名称表导出工具 +go build ./cmd/pvfexport/ pvfexport -pvf Script.pvf -out dnf_items.json -compact ``` -详见 `pvf/README.md`。 +**客户端补丁 / 换装工具**:详见 `docs/开发文档.md` 与 `client-patch/`、`loadout-tool/` 各自的工程文件。 -### 4. 客户端补丁(client-patch/)与换装工具(loadout-tool/) +## 五、启动器要点 -详见各自说明,编译命令在 `docs/开发文档.md` 和原 README 中。 +- **单窗口六页**:开始 / GM工具 / 一键换装 / 游戏设置 / 游戏更新 / 关于我们,导航栏左侧切换、右侧状态灯 +- **本地端口** 19527,被占用时自动 +1 顺延(最多 20 次);页面为本地静态资源,响应统一 `Cache-Control: no-store`,避免 WebView2 缓存旧页面 +- **更新日志双来源**:优先读仓库 `Lingbao/90CNServer` 的 Release 接口,再用 EXE 同目录的 `更新日志.txt` 补齐仓库还没发布的版本,按日期去重(仓库优先);断网时只用本地记录并在页面顶部给出黄色提示 +- **当前更新 / 历史更新** 分成两个标签页,历史页显示条数 +- **关于我们**:四行介绍文案 + 三列二维码(赞助我们:支付宝/微信 · 官方QQ群 · 团队公众号),点任意二维码可放大 ---- +## 六、游戏内 GM 控制台(gmweb/) -## 关键设计说明 +- 由 `serve.py` 托管在 `127.0.0.1:18112`,`/api/*` 反代到服务端 `127.0.0.1:18111` 并注入 admin token(token 不进页面 JS) +- 窗口尺寸由 `client-patch/90CN_web.ini` 决定:`width=800 height=720` +- 页面为 **IE11 兼容**写法:不用 flex,统一 `float` + `box-sizing:border-box`;关于页垂直居中用 `position:absolute; top:50%` + `-ms-transform` +- 关于页结构:介绍卡片(712 宽)+ 组合面板三列 `赞助我们 353 | 官方QQ群 178 | 团队公众号 179`,列间一条竖线 +- 静态资源带 `?v=YYYYMMDDx` 版本后缀,改 CSS/JS 后**必须加一版**,否则 IE11 缓存不刷新 + +## 七、二维码与品牌素材替换 + +| 位置 | 用途 | 说明 | +|------|------|------| +| `launcher/qr/` | 启动器「关于我们」 | `alipay.png` / `wechat.png` / `gzh.jpg` / `qq.png`,同名覆盖即替换 | +| `gmweb/qr/` | 游戏内控制台「关于」 | 同上四张 | +| `launcher/sponsor.png` / `sponsor_qr.png` | 旧版赞助页素材 | 历史遗留,可忽略 | + +- 图片缺失不会破图:启动器与 GM 页都会显示「二维码未配置 + 期望路径」占位 +- 启动器打包时 `qr/` 四张图会进 EXE;同时支持在 EXE 同目录放 `qr\` 覆盖(优先级高于内置) +- `launcher/server.py` 的 `/qr/` 是**白名单**路由,只认这四个文件名,防目录穿越 + +## 八、版本号与发布流程 + +1. **改版本号**:`launcher/server.py` 的 `CURRENT_VERSION`(当前 `v2026.11.05`),游戏内与启动器首页都读它 +2. **写更新日志**:在发布包根目录的 `更新日志.txt` 追加一条(日期 + 条目),启动器会自动合并进「游戏更新」 +3. **构建**:服务端三个 exe + 启动器单文件 exe +4. **打发布包**:服务端 runtime、gmweb、启动器、`90CN_web.ini` 一起收齐;**DLL 与 EXE 必须配套**(见下) +5. **发 Release**:在本仓库的 Release 里写发布说明(模板见 `docs/release/发布说明模板.md`) +6. **网盘地址**:把 `docs/release/网盘下载.url` 里的占位地址换成真实分享链接,作为附件上传——十几个 G 的包不适合直传,`.url` 是最省事的缓兵之计 +7. **验证**:启动器首页版本号、更新日志条数、关于页二维码、GM 页三列是否都正常 + +> ⚠️ **DLL 指纹绑定**:`90CN.dll` 的 SHA-256 在编译期编进 `DNF90Server.exe`(`boundDllSHA256`)。换 DLL 必须重编服务端,否则客户端连接会被拒绝。发布包里 DLL 与 EXE 一定要成对。 + +## 九、关键设计说明 ### GM 工具双数据源 -GM 工具(launcher)支持两种数据访问方式,服务端在线时走 Native API(事务一致),离线时走 SQLite 直读: - -- **Native API**:`127.0.0.1:18111` + `X-Admin-Token`,实时操作 -- **SQLite 直读**:直接读写 `Server/runtime/data/dnf90.db` +- **Native API**(服务端在线):`127.0.0.1:18111` + `X-Admin-Token`,实时操作、事务一致 +- **SQLite 直读**(服务端离线):直接读写 `Server/runtime/data/dnf90.db`,可预览与批量改 +- 启动器通过探测 18111 是否监听来切换,界面上以状态灯区分 ### 物品名称离线显示 -`pvf/cmd/pvfexport` 从 `Script.pvf` 提取 `item_id → 名称` 全量映射,导出 `dnf_items.json`。GM 工具放在 `GM配置/` 目录,启动时对比 PVF 与名称表的修改时间,PVF 更新则自动重新导出,实现离线也能显示物品中文名。 +`pvf/cmd/pvfexport` 从 `Script.pvf` 提取 `item_id → 名称` 全量映射导出 `dnf_items.json`,放在 `GM配置/`;启动时对比 PVF 与名称表修改时间,PVF 更新则自动重新导出,离线也能显示中文物品名。 ### GM 拍卖行 -服务端已实现 GM 拍卖行接口(`/local/dnf-gm/auction/*`),支持: -- **免押金上架**(`Deposit=0`) -- **自动补足上架**(背包不足时凭空发放差额再上架) -- **列背包 / 删除背包行**(含穿戴装备) +服务端实现 `/local/dnf-gm/auction/*`:免押金上架(`Deposit=0`)、自动补足上架(背包不足时先发差额)、列背包 / 删除背包行(含穿戴装备)。 ---- +## 十、常见坑 -## 许可证 +| 现象 | 原因 | 处理 | +|------|------|------| +| 启动器还是旧版本号 / 旧品牌 | 旧进程没退,19527 被占,页面连到旧服务 | 任务管理器结束所有 `DNF90启动器.exe` 后重开 | +| 改了 CSS/JS 页面没变 | WebView2 或 IE11 缓存 | 启动器已发 `no-store`;GM 页需改 `?v=` 版本号 | +| 二维码显示空框 | 图片没放进 `qr/` 或缺文件名 | 看占位提示里的期望路径,四个文件名固定 | +| 关于页底部被日志栏盖住 | 内容高度超过可视区 | GM 页 `#body` 的 `bottom` 必须等于 `#log` 实高(含 padding/border) | +| 客户端连不上服务端 | DLL 与 EXE 指纹不匹配 | 用配套的一对重新打包,别混用 | +| 竖线不显示 | CSS 特异性:`.cols .box` 把 border 清掉了 | 分隔线写在 `.cols .box-r` / `.cols .box-m` 上 | -- `server/`、`client-patch/`、`loadout-tool/`、`launcher/`、`gmtool/`:**私有/闭源**,请勿对外公开。 -- `pvf/`:来自开源项目 [pvfine](https://github.com/) ,遵循 **GPL-3.0**(见 `pvf/LICENSE`)。若需合并/分发,注意 GPL 传染性。 +## 十一、文档索引 -> ⚠️ 对外发布服务端时,不要附带本机测试用的深渊掉落修改;远程换装工具不要直接公开 Admin 端口。 +| 文档 | 内容 | +|------|------| +| [docs/README.md](docs/README.md) | 文档总索引与上手路径 | +| [docs/开发文档.md](docs/开发文档.md) | 启动器 / GM 工具:环境、架构、API 契约、打包部署、常见问题 | +| [docs/服务端开发文档.md](docs/服务端开发文档.md) | 服务端架构、GM 接口契约、拍卖行与背包改动 | +| [docs/PVF解析开发文档.md](docs/PVF解析开发文档.md) | pvfine 与 pvfexport、离线名称集成 | +| `server/README.md`、`pvf/README.md`、`launcher/README.md`、`gmtool/README.md` | 各子项目说明 | +| [docs/release/](docs/release/) | 发布说明模板、网盘下载 `.url` 模板 | ---- +## 十二、许可证与声明 -## 贡献与开发 +- `server/`、`client-patch/`、`launcher/`、`gmweb/`、`loadout-tool/`、`gmtool/`:**私有 / 闭源**,请勿公开分发或倒卖 +- `pvf/`:源自开源项目 pvfine,遵循 **GPL-3.0**(见 `pvf/LICENSE`),注意传染性 +- 本模拟器仅供本地单机体验,禁止用于开服运营;资源禁止倒卖,请到官方微信公众号或社群下载 +- 对外发布服务端时不要附带本机测试用的掉落改动;远程换装工具不要直接暴露 Admin 端口 -1. 各子项目独立编译,无跨项目构建依赖。 -2. 提交时请遵守各自目录的 `.gitignore`,勿提交编译产物与 `dnf_items.json`。 -3. 服务端改动涉及 GM 接口时,同步更新 `docs/开发文档.md` 的 API 契约章节。 +## 十三、提交约定 + +1. 各子项目独立编译,无跨目录构建依赖 +2. 不提交编译产物:`launcher/dist/`、`launcher/build/`、`server/build_verify/`、`__pycache__`、`*.exe`/`*.dll`、`dnf_items.json`、`*.pvf` 均已在 `.gitignore` +3. 提交信息用「范围:做了什么」的形式,例如 `启动器:游戏更新拆分为当前/历史双子页,新增关于我们页` +4. 服务端 GM 接口有变化时,同步更新 `docs/服务端开发文档.md` 的 API 契约章节 +5. 改完源码记得回灌运行目录(`Z:\90server` 与桌面发布包),否则跑的还是旧文件