Files
AIC-Project/docs/superpowers/specs/2026-07-06-dev-server-config-design.md
2026-07-10 10:24:29 +08:00

114 lines
6.7 KiB
Markdown

# 内网发现:探测 IP 可配置化 + 移除组播
日期:2026-07-06
状态:已批准(方案 B)
前置:`2026-07-06-multicast-discovery-design.md`(组播方案,实测跨网段不通,本 spec 将其代码移除)
## 背景与问题
2026-07-06 真机实测:手机(172.30.37.x)→ 开发机(192.168.130.40)跨网段,组播 1.5s 无回复——路由器未开组播路由(IGMP/PIM),组播与广播一样出不了网段。跨网段唯一可靠路径是**单播已知 IP**,但该 IP 目前写死在代码里(`DevExtraProbeIps`),换机器/换网段要改代码重打包。
## 目标
1. **删除全部组播代码**(实测无效,不留死代码)。
2. 探测 IP 改为**设备本地配置**:`persistentDataPath/dev_server.txt`
3. 底包发现失败且需要目标时,**真机上弹输入框**让开发者直接输入开发机 IP,探测成功自动写入配置,之后重启不再询问。
4. 删除写死的 `192.168.130.40`,完全由配置文件接替。
## 非目标
- 不做通用设置界面;输入框仅服务于内网发现这一场景。
- 不支持多 IP / IP:端口(端口固定 48923);配置文件只存一行 IPv4。
- 热更层不弹框(底包阶段已处理,热更层只复用配置)。
- 不改发现协议(magic/端口/编解码不变)。
## 行为规格
### 底包启动流程(`LoadDll.CoLocalDiscoverThenDownload`,仅 bLocal 内网模式)
```
第1轮 Discover(1500ms, targets=广播+loopback+定向广播+文件IP(若有)) ─成功→ 用发现的 CDN 根,照旧 DownLoadAssets
│失败
挂 DevServerPrompt(输入框预填 DevServerConfig.Load() 旧值,可为空) ←──────────┐
│[确定](输入 IP) │
↓ │
IP 格式非法 → 弹框内红字"IP 格式不对",留在弹框 ─────────────────────────────┤
第2轮 Discover(1500ms, 含输入IP) ─失败→ 弹框内红字"探测失败",留在弹框可改可重试┘
│成功
DevServerConfig.Save(输入IP) → 销毁弹框 → 照旧 DownLoadAssets
任意时刻 [跳过] → UpdateServer 回退 http://127.0.0.1:15081/...(现状行为)
```
- 文件**有**记录且第 1 轮失败(开发机换 IP 等)→ 同样弹框,预填旧值(用户确认的行为)。
- 弹框期间加载流程等待,不超时。
- 探测成功但成功来源无法区分(广播/文件 IP),第 1 轮成功**不**写文件——只有弹框输入并验证成功才写。
### 热更层(`DevServerDiscovery`,GameLauncher/DevServerSwitchUI 用)
- 构造探测目标时读 `DevServerConfig.Load()`,非空则加入 targets。不弹框。调用方零改动。
## 组件设计
### 1. `Client\Assets\Base\DevServerConfig.cs`(新,静态类,全局命名空间)
- `static string FilePath``Application.persistentDataPath + "/dev_server.txt"`
- `static string Load()`:读首行 → Trim → `IPAddress.TryParse` 通过才返回,否则 null;文件不存在/IO 异常 → null(静默)
- `static void Save(string ip)`:整文件写入单行;IO 异常静默吞
- **仅底包使用**。核实发现 `XWorld.Link.asmdef` 引用列表里没有 Base 程序集,热更层引用不到;为 dev 工具改 asmdef 引用不值当,热更层按本项目"内联+两边同步"惯例(协议编解码已如此)在 `DevServerDiscovery` 内联同语义的最小读取实现
- **主线程限制**:`Application.persistentDataPath` 不能在后台线程访问,`Load()/Save()` 只能在主线程调;发现线程需要的值由调用方在主线程读好传入/存字段
### 2. `Client\Assets\Base\DevServerPrompt.cs`(新,MonoBehaviour,全局命名空间)
- 纯 IMGUI(OnGUI),风格参照热更层 `DevServerSwitchUI` 的 box/横排布局
- 字段:`string InputIp`(初始 = 预填值)、`State state`(`Waiting | Confirmed | Skipped`)、`string Error`(非空则红字显示)
- OnGUI:提示语("内网发现失败,请输入开发机 IP")+ TextField + [确定] [跳过]
- [确定] → `state = Confirmed`(探测由外部做,失败后外部把 `Error` 置上并把 state 拨回 Waiting)
- [跳过] → `state = Skipped`
- 不做网络、不做文件 IO——只是输入框
### 3. `Client\Assets\Base\LocalCdnDiscovery.cs`(改)
- 删:组播常量/TTL/逐网卡发送/`GetLocalIPv4Addresses`/相关注释、`DevExtraProbeIps` 整个字段
- 改:`Discover(string token, int durationMs)``Discover(string token, int durationMs, string extraProbeIp = null)`;`extraProbeIp` 能 TryParse 则加入 targets
- 调用方(LoadDll)自行决定传文件值还是弹框输入值
### 4. `Client\Assets\Script\xmain\MiniGame\DevServerDiscovery.cs`(改)
- 删:同上组播相关、`DevExtraProbeIps`
- 加:内联 `ReadConfiguredProbeIp()`(读 dev_server.txt 首行+IPv4 校验,与 `DevServerConfig.Load()` 语义一致,见组件 1 的说明);**构造函数**(主线程)里读取存入字段,`Run()`(后台线程)构造 targets 时使用
### 5. `Client\Assets\Base\LoadDll.cs`(改)
- `CoLocalDiscoverThenDownload` 按上面流程图重写:两轮发现 + 弹框等待循环;弹框对象 `gameObject.AddComponent<DevServerPrompt>()`,结束后 `Destroy`
- 第 1 轮把 `DevServerConfig.Load()` 传入 `Discover``extraProbeIp`
### 6. 组播代码删除清单
- `Client\Assets\Framework\Shared\Protocol\DevDiscovery.cs`:删 `MulticastGroup` 常量及注释
- `Server\Gateway\DevDiscoveryResponder.cs`:删 `JoinMulticastOnAllNics` 方法、构造函数调用行、`using System.Net.NetworkInformation;`
- `Server\Gateway.Tests\DevDiscoveryResponderTests.cs`:删 `MulticastQuery_ReceivesReply`
- 两份客户端:删 TTL 设置、组播端点/网卡列表构建、逐网卡发送循环、零网卡兜底、`GetLocalIPv4Addresses`,注释还原为"单播兜底"语义(指向配置文件而非写死 IP)
## 错误处理
- 文件 IO、IP 解析:全部静默容错,失败等同"无配置"
- 弹框输入非法 IP:[确定] 直接在弹框显示"IP 格式不对",不发起探测
- 探测线程异常:沿用现有 catch-all,视为失败回到弹框
## 测试与验收
1. `dotnet test Server/Server.sln` 全量通过(删组播测试后)
2. 编辑器同机:loopback 一轮即中,弹框不出现,行为与改前一致
3. 真机跨网段首启:第 1 轮失败 → 弹框 → 输入 192.168.130.40 → 探测成功 → 写文件 → 正常加载
4. 真机重启:文件已有记录,第 1 轮直接命中,不弹框
5. 开发机换 IP:第 1 轮失败 → 弹框预填旧值 → 改新 IP → 成功覆写
6. [跳过]:回退 127.0.0.1,与现状一致
## 风险
- IMGUI TextField 在个别 Android 输入法上体验一般(dev 工具可接受;Unity 移动端 IMGUI 会自动唤起软键盘)
- 底包改动须重打 APK 才能上真机(部署铁律,验收时注意)