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

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

5.7 KiB
Raw Permalink Blame History

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

编译命令

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):

{
  "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 端口。