docs/zh/direct-connect.md
Rama main · réplica de lectura del repositorio original.
# 玩家直连(实验性)
玩家直连适合不想单独部署公网 DiceFrame 服务的小团。房主在自己的 DiceFrame 中创建临时房间,为朋友生成一次性链接码;连接建立后,玩家的游戏请求通过 WebRTC 数据通道直达房主,存档、模型配置、规则和 GM 处理仍由房主掌管。
DiceFrame Hub 只参与短暂的连接握手,不代理游戏包体或保存跑团正文。房主应只把链接码发给认识并信任的玩家。
## 从首页加入好友
普通邀请链接是玩家加入好友的默认入口。房主进入游玩页,点击“邀请好友”并复制生成的邀请链接;玩家可以直接打开链接,也可以回到首页的“加入好友”入口粘贴链接。二维码仍然可以用 DiceFrame App 扫描,或在支持的设备上打开其中的普通链接。
普通邀请链接通常包含 `#/join?game=...` 形式的游戏信息。它会进入公开 Web 游玩流程,并继续使用服务端的席位凭据、角色身份绑定和访问校验;玩家不需要从链接中提取房间、玩家 ID 或其它字段,也不需要配置模型。`DFP2-...` 是高级玩家直连码,不能当作普通邀请链接打开。
房主只有在需要实验性的客户端直连时,才应从首页“加入好友”中的“更多连接方式”进入“发起直连(实验性)”,创建临时直连房间并发送生成的直连码。直连码和普通邀请链接用途不同,直连仍由房主保持在线并承担权威状态。
## 邀请已有角色与新玩家
直连创建页会显示存档中的角色席位。房主点击一次创建房间后,系统会按存档批量生成全部可用的 P2P 链接码:
- 每个已有角色自动获得一枚绑定身份的链接码。玩家连接后会恢复该角色,不会重复建卡或再次占位。
- 每个剩余空位自动获得一枚“新玩家”链接码。该码会进入建卡页,并在建卡完成后才占用存档席位;没有发出或没有使用的码不会占位。
- 每枚直连链接码只允许使用系统为它绑定的已有角色,普通新玩家链接码不能认领其他已占用角色。
- 一次开房生成的总数同时受存档席位与 DiceFrame Hub 单房人数上限约束。
- 公开 Web 游玩仍可使用角色旁的“网页操作链接”。该链接丢失后可以随时重新复制;它与 5 分钟失效的直连链接码不是同一种凭证。
因此,存档即使已经满员,只要其中有房主之外的已有角色,仍然可以创建直连房间让这些角色回来继续游玩。
## 使用前须知
- 链接码一次性使用,并在 5 分钟后过期。
- 房主必须保持 DiceFrame 和当前直连房间在线;房主离开后,房间和对局连接会失效。
- 对称 NAT、严格防火墙、企业网络或禁用 WebRTC 的浏览器可能无法建立直连。
- 实验版只转发明确支持的游戏 JSON 操作。二进制附件、语音识别音频上传和部分自定义媒体不会通过直连传输,界面会隐藏入口或回退到内置资源。
- 直连不是公网服务器替代品,不适合无人值守的长期房间。
## 权限与隐私
房主仍是权威端:每名连接者会映射到系统为该链接绑定或由该链接新建的玩家身份,只能执行加入、提交行动、查看本人信息、处理本人确认事项和编辑本人角色等白名单操作。客户端额外发送的字段会被剥离;请求还受到速率和并发限制。
玩家提交的行动、角色数据和对局请求会到达房主设备,并可能被房主配置的模型服务处理。使用前应让参与者了解房主和模型服务的隐私边界。
## 对普通开发流程的影响
玩家直连是可选适配层,不改变骰子、规则、世界书、存档或回合核心。没有活动的直连会话,或者请求不属于当前直连游戏时,前端继续使用原有 HTTP/SSE 路径。
因此,普通源码开发仍然只需要:
```powershell
python web_server.py
cd frontend-v2
npm run dev
```
开发普通单机、局域网 WebUI、Bot、规则或内容包时不需要启动 DiceFrame Hub,也不需要配置 WebRTC。只有调试玩家直连本身时才需要可用的 Hub 握手服务和两个浏览器端。
代码边界如下:
- 后端 Hub 路由只负责获取握手配置和创建临时房间。
- 前端直连协议、会话与游戏桥集中在 `frontend-v2/src/peer/`。
- `frontend-v2/src/api/client.ts` 只有一个可空的请求拦截点;没有活动直连客户端时立即回到普通网络请求。
- 房主桥接层调用已有本地游戏 API,不复制第二套骰子或规则引擎。
## 开发者回归测试
```powershell
cd frontend-v2
npm run test
npm run typecheck
npm run build
```
其中直连协议、邀请码、游戏操作白名单、身份恢复和“无活动直连时回到普通 HTTP”都有独立测试。涉及连接界面或真实浏览器协作时,再运行 `npm run test:e2e`。