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

+147
View File
@@ -0,0 +1,147 @@
# DNF90 服务端开发文档
> 覆盖服务端(Go)的架构、GM 接口契约、编译部署、以及本次新增的拍卖行 / 背包管理改动。
>
> 最后更新:2026-11-03
---
## 一、架构概览
服务端是 Go 单模块(`module longheng.io/server`),采用分层结构:
```
server/
├── cmd/
│ ├── server/dnf90/ 产品入口(主服务进程,产出 DNF90Server.exe)
│ ├── server/control/ 部署控制器(DNF90Control.exe,start/stop/configure)
│ ├── server/doctor/ 部署预检(DNF90Doctor.exe)
│ ├── companionpvf/ PVF 伴随进程
│ └── devtools/ scratch/ 开发调试工具(非产品)
├── internal/
│ ├── app/dnf90/ 单一组合根(路由注册、依赖装配)
│ ├── services/dnfbridge/ 客户端传输 + GM bridge 层(本次改动重点)
│ ├── modules/dnf/ DNF 领域模块(auction、dungeon、character 等)
│ ├── platform/ 框架层(含 platform/pvf PVF 解析)
│ ├── services/logic/dnf/ MySQL 仓储装配
│ └── ...
└── pkg/ 对外包
```
关键入口:
- 主服务:`cmd/server/dnf90/main.go`
- GM 路由:`internal/app/dnf90/gm_tool_compat.go`(兼容层,`/local/dnf-gm/*`)
- GM bridge:`internal/services/dnfbridge/gm_*.go`
---
## 二、编译与部署
### 环境要求
- **Go ≥ 1.26**(`go.mod` 声明 `go 1.26.5`)
- 依赖走国内镜像(加速):`GOPROXY=https://goproxy.cn,direct`、`GOSUMDB=sum.golang.google.cn`
### 编译命令
```bash
cd server
# 主服务端
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
```
编译产物部署到 `90server/Server/runtime/bin/`。
> 若 `go build` 报 "package unsafe is not in std",说明本地 Go SDK 的 src 不完整,
> 需改用完整 toolchain(见 `docs/开发文档.md` 的「Go 环境问题」章节)。
---
## 三、GM 接口契约(`/local/dnf-gm/*`)
GM 接口由 `internal/app/dnf90/gm_tool_compat.go` 注册,bridge 层实现在 `internal/services/dnfbridge/`。
### 认证
所有接口走 admin HTTP 端口(默认 `127.0.0.1:18111`),请求头带 `X-Admin-Token`(token 来自 `instance.json` 的 `adminToken`)。
### 返回结构
统一约定:`{"ok": true, "data": <结果>}`;错误时 `{"error": "<msg>"}`。
### 拍卖行接口(本次新增)
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/local/dnf-gm/auction/listings` | 列出所有挂单,返回 `{listings, escrow_gold}` |
| POST | `/local/dnf-gm/auction/list` | 上架(支持自动补足) |
| POST | `/local/dnf-gm/auction/cancel` | 下架 |
上架请求体(`GMAuctionListRequest`):
```json
{
"seller_id": "角色ID",
"item_id": 10001,
"count": 1,
"unit_price": 10000,
"start_price": -1, // 每件起拍价,-1=不设竞拍
"buyout_price": -1, // 每件一口价,-1=不设一口价
"duration_hours": 24, // 24 或 48
"grant_if_missing": true // 背包不足时自动凭空发放差额再上架
}
```
### 背包管理接口(本次新增)
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/local/dnf-gm/inventory/list?character_id=xxx` | 列角色背包 + 穿戴装备,每行 `{collection, entry_key, item_id, count, bind, item_name}` |
| POST | `/local/dnf-gm/item/delete` | 删除指定背包行(`entry_key` + `collection`,支持 slots/wear) |
---
## 四、本次关键改动说明
### 1. GM 拍卖行(线上上架通道)
- **新增** `internal/services/dnfbridge/gm_auction.go`:
- `GMAuctionListings` / `GMAuctionList` / `GMAuctionCancel` 三个方法。
- 直接调用 `dnfauction.Owner` 的纯数据层 `Register`/`Cancel`/`LoadListing`,**不依赖玩家 session**。
- **新增** `GMInventoryList` 方法(列背包全部道具 + 穿戴装备)。
### 2. 上架免押金
`gm_auction.go` 的 `GMAuctionList` 中,`Register` 的 `Deposit` 设为 `0`(原为 `dnfauction.ListingDepositGold = 10000`)。
服务端 `owner.go` 里是 `if cmd.Deposit > 0` 才扣款,因此 `Deposit=0` 直接跳过押金逻辑。
### 3. 自动补足上架(发放式)
`GMAuctionList` 支持 `grant_if_missing`:卖家背包物品不足时,先调 `GMGrantItem`(`dnfdungeon.Owner.GrantPickupItem`)凭空发放差额到背包,再 `Register` 上架。实现「像发放道具那样直接上架」。
### 4. 路由层
`gm_tool_compat.go` 新增常量与路由:
- `gmAuctionListingsPath` / `gmAuctionListPath` / `gmAuctionCancelPath`
- `gmInventoryListPath`
---
## 五、GM bridge 层约定
- GM 方法都在 `internal/services/dnfbridge/` 包,方法签名形如 `func (s *Service) GMXxx(ctx, req) (resp, error)`。
- 数据访问用 `s.repositoryGroup()`(返回 `dnfrepo.Group`,含 `Inventory`、`Equipment`、`Character` 等仓储)。
- 物品名解析用 `s.currentPVFItemCatalog()`(`dnfpvf` 目录),`ResolveItem(itemID)` 得到 `definition.Name`。
---
## 六、常见坑
1. **`go 1.26.5` 版本声明**:装 ≥1.26 即可,`GOTOOLCHAIN=auto` 会自动下载所需 toolchain。
2. **GM 接口路由**:`gm_tool_compat.go` 里 `gmToolPost` 包装 POST 接口,GET 接口用 `HandleFunc` + `writeGMJSON`。
3. **服务端 `Register` 的校验**:`buyout_price` 必须等于 `unit_price`(或"不设一口价"),`start_price` 在 `[0, unit_price]` 或"不设竞拍",时长只能是 24/48。
4. **对外发布**:不要附带本机测试用的深渊掉落修改;远程换装工具不要公开 Admin 端口。