DNF90 服务端与启动器完整源码(含 GM 工具功能增强)

服务端(Go):
- GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面
- GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新
- 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新)
- 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍
- 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0)
- 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算

启动器(Python/JS):
- 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭
- GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐)
- 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
This commit is contained in:
hanfuit committed 2026-11-04 14:31:55 +08:00
commit 645b64fe21
4388 files changed
+1405457

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
# PVF 解析套件开发文档
> 覆盖 PVF 解析库(pvfine)、物品名称表导出工具(pvfexport)、以及与 GM 工具的离线名称显示集成。
>
> 最后更新:2026-11-03
---
## 一、背景
DNF 的 `Script.pvf` 是专有的二进制容器(加密 + 压缩),物品名称(`.equ`/`.stk` 的 `[name]` 段)只存在于 PVF 内。为了让 GM 工具**离线(服务端关闭)也能显示物品中文名**,我们引入了一个 PVF 解析方案。
---
## 二、pvfine 项目(`pvf/`)
`pvf/` 是开源项目 **pvfine**(GPL-3.0)的核心源码,一个 Go 编写的 PVF 编辑器/解析套件,支持 86/90/100/110/115/TW 全版本 `Script.pvf`。
### 结构
```
pvf/
├── internal/pvf/ 核心解析包(Open / Find / Text / ScriptMetadata / ParseListText)
├── internal/ani/ buildmode/ rendering/ ... pvf 依赖的其他内部包
├── internal/mcpserver/ npk/ mod/ script/ ... 编辑器相关
├── config/ go:embed 的索引数据(paths.json 等,编译必需)
├── cmd/
│ ├── annotation-editor/ 注解编辑器
│ └── pvfexport/ 物品名称表导出工具(本仓库新增)
├── services/ frontend/ 编辑器后端/前端
├── main.go 桌面 GUI 入口(Wails)
└── go.mod module pvfine, go 1.26.0
```
### 核心 API(`internal/pvf`)
```go
import "pvfine/internal/pvf"
archive, err := pvf.Open("Script.pvf") // 打开归档(自动识别版本)
defer archive.Release()
idx, found := archive.Find("stackable/stackable.lst") // 找文件索引
text, err := archive.Text(idx) // 读脚本文本
pairs, err := pvf.ParseListText(text) // 解析 .lst -> [{ID, Path}]
meta, err := archive.ScriptMetadata(idx) // 读物品元数据(Name/Rarity)
// meta.Name 即物品名称
```
> 注意:`internal/pvf` 依赖 `internal/ani`、`internal/buildmode`、`internal/rendering`、
> `internal/annotations`、`internal/ruleconfig`、`config` 等包,**不能单独抽出**,
> 需要以整个 `pvfine` 模块作为依赖(或直接在其中添加 cmd 子命令)。
---
## 三、pvfexport 工具(`pvf/cmd/pvfexport/`)
从 `Script.pvf` 提取 `item_id → 名称` 全量映射,导出 JSON。
### 编译
```bash
cd pvf
go build -o pvfexport.exe ./cmd/pvfexport/
```
### 用法
```bash
pvfexport -pvf Script.pvf -out items.json # 完整 JSON(含 path/rarity/kind)
pvfexport -pvf Script.pvf -out dnf_items.json -compact # 紧凑 {item_id: name}(推荐)
```
- `-compact`:只输出 `{item_id: name}` 映射(仅保留有名称的项),体积约 5.7MB(14.6 万条)。
- 完整模式:输出 `{pvf_path, total, items:[{id,name,rarity,path,kind}]}`,约 35MB。
### 实现逻辑
1. `pvf.Open` 打开归档。
2. 读 `stackable/stackable.lst`(堆叠道具)和 `equipment/equipment.lst`(装备),用 `ParseListText` 解析出 `item_id → 路径`。
3. 对每个 item,用 `resolveItemFile` 找文件(路径候选策略复刻服务端 `readDungeonDropText`):
- 直接用 lst 里的路径
- 尝试 `root/` 前缀(`stackable/` / `equipment/`)
- 尝试 `(r)` 修订文件名(90 版本特有)
4. `ScriptMetadata` 读 `[name]` 段得到名称。
---
## 四、与 GM 工具的集成(离线名称显示)
### 名称表存放
名称表 `dnf_items.json` 与 `pvfexport.exe` 放在服务端根目录下的 **`GM配置/`** 目录:
```
90server/
└── GM配置/
├── pvfexport.exe
└── dnf_items.json
```
### 自动重导出
GM 工具(launcher)启动时,`db.py` 的 `_load_item_names()` 会:
1. 定位 `GM配置/dnf_items.json` 和 `Client/Script.pvf`。
2. 对比两者修改时间:
- 名称表**已是最新** → 秒加载(约 0.09 秒)。
- **PVF 被更新**(或名称表缺失)→ 自动调 `pvfexport.exe -compact` 重导出(约 5 秒),再加载。
3. 加 `_EXPORT_LOCK` 锁防并发重复触发。
> 因此:**PVF 新增物品后,只需替换 `Client/Script.pvf`,GM 工具下次启动自动重导名称表,
> 无需重新打包 GM 工具。**
### 注入方式
`server.py` 启动时调用 `db.set_gm_config(GM_CONFIG_DIR, PVF_PATH)` 注入目录与 PVF 路径;
`db.py` 的 `item_name(item_id)` 据此惰性加载名称表。
---
## 五、许可证与合规
- `pvf/` 遵循 **GPL-3.0**(见 `pvf/LICENSE`)。
- 若将 pvfine 与闭源的 server/launcher 合并发布,需注意 **GPL 传染性**:
- 单独分发 pvfexport(独立 Go 进程)可隔离传染;
- 若将 `internal/pvf` 直接 link 进闭源服务端,会触发 GPL 义务。
- 建议:保持 pvfine 作为**独立子模块/子仓库**,通过 CLI 工具(pvfexport)与主项目解耦。