# 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": ""}`。 ### 拍卖行接口(本次新增) | 方法 | 路径 | 说明 | |------|------|------| | 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 端口。