docs(guide): 配置与调试指南补充 debug/release 一键模式

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 18:21:19 +08:00
co-authored by Claude Opus 4.8
parent 5ab4a0a4b6
commit c8bbae9d88
+509
View File
@@ -0,0 +1,509 @@
# YouleNexus 配置与调试指南
本指南面向在新 Cocos 前端 `YouleNexus` 上做开发联调的工程师,讲清楚两件事:
1. **配置**——渠道身份(agentid/channelid/gameid/marketid/version)从哪来、远程配置文件怎么读、服务器地址怎么定。
2. **调试**——如何一键切到本地/测试服、临时替换渠道身份、跑自动化测试、做真机端到端联调。
对应实现位于 `cocoscreator_projects/YouleNexus/assets/framework/config/`,设计依据见 `docs/superpowers/specs/2026-06-28-config-channel-design.md`。
> **一句话心智模型**:启动时调用 `resolveBootstrap(...)`,它把「构建期默认 + 运行期来源 + 调试 profile + URL 覆盖」合并成最终 `identity`,再决定 `servers`(调试服直连 或 远程配置解析),产出 `{ identity, servers }` 喂给 `NetClient`。
---
## 目录
1. [快速上手(三个最常见场景)](#1-快速上手三个最常见场景)
2. [整体数据流](#2-整体数据流)
3. [渠道身份 ChannelIdentity](#3-渠道身份-channelidentity)
4. [一键切换 debug / release 模式](#4-一键切换-debug--release-模式)
5. [调试 Profiles](#5-调试-profiles)
6. [URL Query 参数清单](#6-url-query-参数清单)
7. [服务器地址是怎么定的](#7-服务器地址是怎么定的)
8. [远程配置文件](#8-远程配置文件)
9. [启动编排 resolveBootstrap 与接入 NetClient](#9-启动编排-resolvebootstrap-与接入-netclient)
10. [原生联调(window.settings / app_*)](#10-原生联调windowsettings--app_)
11. [跑测试与类型检查](#11-跑测试与类型检查)
12. [常见调试场景配方](#12-常见调试场景配方)
13. [真实服务器端到端联调](#13-真实服务器端到端联调)
14. [发布前检查清单](#14-发布前检查清单)
15. [红线:哪些字符串绝不能改](#15-红线哪些字符串绝不能改)
16. [API 速查表](#16-api-速查表)
---
## 1. 快速上手(三个最常见场景)
> 下面假设你在 Cocos 编辑器预览(浏览器/WebView 环境)下调试,地址栏可加 query 参数。
| 我想…… | 怎么做 |
| --- | --- |
| **连本地服务器**(`ws://127.0.0.1:3088`) | 预览 URL 加 `?profile=local`。直接连本地,不抓远程配置。 |
| **用测试配置服**(staging 的 gameserver) | 预览 URL 加 `?profile=staging`。 |
| **临时换一个渠道身份调一个 bug** | URL 加 `?agentid=xxx&channelid=yyy&marketid=2`,覆盖最高优先级,其余不变。 |
更多组合见 [§12 常见调试场景配方](#12-常见调试场景配方)。
---
## 2. 整体数据流
```
┌─────────────────────────────────────────────┐
启动调用 │ resolveBootstrap(opts) │
resolveBootstrap ─────► │ │
│ ① resolveActiveProfile(search) │
│ └─ ACTIVE_PROFILE 或 ?profile= 切换 │
│ │
│ ② 合并身份 resolveIdentity([...]) │
│ defaults < 运行时(native|query) │
│ < profile.identity │
│ < 显式 URL query (最高) │
│ │
│ ③ 决定服务器: │
│ profile.server ? → 直连(跳过远程) │
│ 否则 fetcher.fetch(gameserver) │
│ → getParam 分层取参 │
│ → resolveServers → ws:// 候选 │
└───────────────┬─────────────────────────────┘
│ { identity, servers, rawConfig, profile }
▼
net.setIdentity(identity 相关字段)
new NetClient({ servers }) → net.start()
```
**文件分工**(每个文件单一职责,纯逻辑与 IO 分离,均可在 Node 下测):
| 文件 | 职责 |
| --- | --- |
| `config/identity.ts` | `ChannelIdentity` 类型、`IdentitySource` 接口、`resolveIdentity()` 纯合并 |
| `config/sources/defaults.ts` | `BUILD_IDENTITY` 构建期默认(旧 `version.js` 等价物) |
| `config/sources/query-string.ts` | `queryStringSource()`:H5 从 URL query 读身份 |
| `config/sources/native-settings.ts` | `nativeSettingsSource()`:原生从 `window.settings`/`app_*` 同步读身份 |
| `config/profiles.ts` | `DebugProfile` / `PROFILES` / `resolveActiveProfile()` 调试档位 |
| `config/remote-config.ts` | 远程配置类型、`ConfigFetcher` 接口、`getParam()` 分层取参、`resolveServers()` |
| `config/remote-config-fetcher.ts` | 生产用 `HttpConfigFetcher`(全局 `fetch` 抓取 txt) |
| `config/runtime-mode.ts` | `resolveRuntimeMode()` 运行模式(debug/release)解析,`MODE_OVERRIDE` 手动覆盖 |
| `config/bootstrap.ts` | `resolveBootstrap()` 启动编排,串起以上全部 |
---
## 3. 渠道身份 ChannelIdentity
最终要发给服务器 `player_login` 的渠道身份字段。**属性名就是协议字段名,逐字不可改**(见 [§15](#15-红线哪些字符串绝不能改))。
```ts
interface ChannelIdentity {
agentid: string | number; // 代理商 ID
channelid: string | number; // 渠道 ID
gameid: string; // 游戏标识(每个子游戏固定)
marketid: string | number; // 市场/包渠道 ID
version: string; // 版本号(旧 GameData.Version)
versionCode: number; // 版本码(旧 GameData.versionCode)
}
```
### 各字段从哪来
| 字段 | 主来源 | 说明 |
| --- | --- | --- |
| `gameid` | **编译期固定**(`BUILD_IDENTITY`,每子游戏不同) | 旧工程写死在 `version.js`。一般不随环境变。 |
| `agentid` | 运行期:H5 走 URL query,原生走 `window.settings.getothername('agent')` | 默认值在 `BUILD_IDENTITY`,运行期覆盖。 |
| `channelid` | 运行期:H5 走 URL query,原生走 `window.settings.getchannelName()` | 同上。 |
| `marketid` | 运行期:H5 走 URL query,原生走 `window.settings.getmarketname()`(默认 `4`) | 同上。 |
| `version` / `versionCode` | `BUILD_IDENTITY` 默认;H5 可用 `?version=` 覆盖 | — |
### 合并优先级(低 → 高,后者覆盖前者)
```
BUILD_IDENTITY(构建期默认)
< 运行时来源(原生环境=nativeSettings | H5 环境=queryString)
< profile.identity(当前调试档位的身份覆盖)
< 显式 URL query(最高,方便临时改单字段)
```
`resolveIdentity(sources)` 按数组顺序合并,**只覆盖"有效值"字段**——`undefined`/`null`/`空字符串` 不覆盖(所以一个来源读不到某字段时,不会把已有值清空);注意 **`0` 是有效值**会覆盖(如 `marketid=0`)。
> H5 模式下 `queryString` 同时担任「运行时来源」和「最高覆盖」两个角色,因此在 URL 里写 `?agentid=...` 永远生效且优先级最高。
---
## 4. 一键切换 debug / release 模式
运行模式是比 profile 更高一层的总开关,由 `config/runtime-mode.ts` 提供。
| 模式 | 怎么进入 | profile | URL 覆盖(?profile=/?agentid=…) | 身份来源 | 收发包日志 |
| --- | --- | --- | --- | --- | --- |
| **debug** | debug/预览构建自动进入;或 `MODE_OVERRIDE='debug'` | `?profile=` 可切(默认 prod) | **全部生效** | 原生或 URL(按 `isNative`) | 开(`isDebugger=true`) |
| **release** | release 构建自动进入;或 `MODE_OVERRIDE='release'` | **强制 prod** | **全部忽略** | **只走原生 `window.settings`** | 关 |
### 三种切换姿势
1. **什么都不动**:发 release 包自动 release,编辑器预览自动 debug。模式由 Cocos 全局 `DEBUG` 决定。
2. **release 包里临时调试**:把 `config/runtime-mode.ts` 的 `MODE_OVERRIDE` 设为 `'debug'`。
3. **预览里验证正式行为**:把 `MODE_OVERRIDE` 设为 `'release'`。
> release 之所以能放心锁死 URL:正式包是 Cocos 原生(jsb),渠道身份走 `window.settings`/`app_*`,本就不依赖 URL。
### 接入
```ts
import { resolveRuntimeMode } from 'db://assets/framework/config/runtime-mode';
const isDebugBuild = typeof DEBUG !== 'undefined' ? DEBUG : true; // Cocos 全局
const mode = resolveRuntimeMode(isDebugBuild); // 'debug' | 'release'
// 传给 resolveBootstrap({ mode, ... }),并把 result.isDebugger 传给 NetClient 的 debug 选项
```
---
## 5. 调试 Profiles
Profiles 取代了旧工程的 `Game_Config.Debugger`(`serverType` / `gameserver` / `isDebugger`)。一个 profile 打包了「连哪个服 + 用什么渠道身份 + 日志开关」。
```ts
interface DebugProfile {
name: string;
server?: string; // 显式 ws 调试服地址;给定则跳过远程抓取
gameserver?: string; // 远程配置 txt URL(不含防缓存串)
identity?: Partial<ChannelIdentity>; // 调试用渠道身份覆盖
isDebugger?: boolean; // 收发包日志开关
}
```
### 内置档位(`config/profiles.ts`)
| profile | server(直连) | gameserver(远程配置) | isDebugger | 用途 |
| --- | --- | --- | --- | --- |
| `prod` | — | `http://ylyxservice1.0791ts.cn/config/update_json.txt` | `false` | **正式发布**。走远程配置解析服务器。 |
| `staging` | — | `http://testgame.youlehdyx.com/update_json/ceshi_json.txt` | `true` | 测试配置服。 |
| `local` | `ws://127.0.0.1:3088` | — | `true` | 本地服务器直连,**不抓远程**。 |
### 如何切换
- **默认档位**:`ACTIVE_PROFILE`(当前为 `'prod'`),在 `config/profiles.ts` 顶部常量。
- **临时切换**:URL 加 `?profile=<name>`,例如 `?profile=local`、`?profile=staging`。未知名字会回退到 `ACTIVE_PROFILE`。
```ts
resolveActiveProfile('?profile=local') // → PROFILES.local
resolveActiveProfile('') // → PROFILES.prod(ACTIVE_PROFILE)
resolveActiveProfile('?profile=xxx') // → PROFILES.prod(未知回退)
```
### 加一个自己的档位
直接在 `PROFILES` 里加一项即可,例如连组内某台联调机:
```ts
export const PROFILES: Record<string, DebugProfile> = {
prod: { name: 'prod', gameserver: DEFAULT_GAMESERVER, isDebugger: false },
staging: { name: 'staging', gameserver: STAGING_GAMESERVER, isDebugger: true },
local: { name: 'local', server: 'ws://127.0.0.1:3088', isDebugger: true },
// 新增:直连联调机 + 指定测试渠道身份
lab: { name: 'lab', server: 'ws://192.168.1.50:3088', isDebugger: true,
identity: { agentid: 'test_agent', channelid: 'test_channel' } },
};
```
之后用 `?profile=lab` 即可。
---
## 6. URL Query 参数清单
预览/调试时可在地址栏拼接这些参数(H5 环境生效):
| 参数 | 作用 | 示例 |
| --- | --- | --- |
| `profile` | 切换调试档位 | `?profile=local` |
| `agentid` | 覆盖代理商 ID(最高优先级) | `?agentid=00bA05...` |
| `channelid` | 覆盖渠道 ID | `?channelid=frdt0C...` |
| `marketid` | 覆盖市场 ID | `?marketid=2` |
| `version` | 覆盖版本号 | `?version=1.2` |
多个参数用 `&` 连接:`?profile=staging&agentid=xxx&marketid=2`。
> `gameid` 不从 URL 取(按子游戏固定在 `BUILD_IDENTITY`)。
---
## 7. 服务器地址是怎么定的
`resolveBootstrap` 决定 `servers`(一个 `ws://` 地址数组,交给 `NetClient` 轮询)的顺序:
1. **当前 profile 有 `server`** → 直接用它,**跳过远程配置抓取**(`local`/`lab` 这类直连档位走这条)。
2. **否则**抓远程配置文件(profile 的 `gameserver`,没有就用 `DEFAULT_GAMESERVER`),用 `getParam` 取出连接参数,`resolveServers` 组装候选列表。
3. 远程抓取失败或解析不出地址时:若调用方传了 `fallbackServers` 则降级使用;否则抛 `ConfigFetchError`(交由上层重试,重连本身归 `NetClient`)。
`resolveServers` 取的连接参数键(**逐字一致**原工程,按此优先级):
```
player_server_tcp → visitor_server_tcp → game_server_tcp
```
值形如 `ip:port`,自动加 `ws://` 前缀(已带 `ws://`/`wss://` 的不重复加),并去重。
> **为什么只取 `*_tcp` 不取 `*_http`**:YouleNexus 是 WebSocket-only(对应旧 `netType==0` 分支)。旧工程的 `*_server_http` 属 HTTP 传输模式(`netType==1`),本期不在范围,故有意省略。
---
## 8. 远程配置文件
### 是什么
一个放在配置服务器上的 `.txt` 文件(内容是 JSON),URL 即 profile 的 `gameserver`。抓取时自动追加防缓存时间戳:`<gameserver>?<timestamp>`。
生产抓取实现 `HttpConfigFetcher`(`config/remote-config-fetcher.ts`)用全局 `fetch` GET 该 URL 并 `JSON.parse`,解析失败抛 `ConfigParseError`。
### 结构与分层取参 `getParam`
远程配置是**分层覆盖**结构,越具体的层级优先级越高:
```
data ← 顶层默认
└─ agentlist[ {agentid} ← 按 agentid 匹配
gamelist[ {gameid} ← 再按 gameid 匹配
channellist[ {channelid} ← 再按 channelid
marketlist[ {marketid} ] ← 最后按 marketid
]]]
```
`getParam(config, key, id)` 用当前身份(agentid/gameid/channelid/marketid)逐层下钻,命中的最具体层若带该 `key` 就更新返回值,匹配链中断则返回当前已找到的最具体值(最终可能是顶层默认或 `null`)。这与旧工程 `get_paravalue` 语义逐字一致。
示例:
```jsonc
{
"data": {
"player_server_tcp": "1.1.1.1:1000", // 顶层默认
"agentlist": [{
"agentid": "A",
"player_server_tcp": "2.2.2.2:2000", // A 代理商覆盖
"gamelist": [{
"gameid": "G",
"channellist": [{
"channelid": "C",
"player_server_tcp": "3.3.3.3:3000" // A/G/C 这条最具体 → 命中它
}]
}]
}]
}
}
```
身份 `{agentid:'A', gameid:'G', channelid:'C', ...}` → `getParam(cfg,'player_server_tcp',id)` 得 `3.3.3.3:3000`;若 channelid 换成没配的值,则回退到 `2.2.2.2:2000`;agentid 也没配则回退顶层 `1.1.1.1:1000`。
> 平台/UI 类参数(公告 `menunotice`、跑马灯 `scrollmsg`、客服 `service_*`、登录图 `logimage`、排行榜 `rankList` 等)**复用同一个 `getParam`**,将在后续 platform 层接入;本期只解析了连接相关的服务器地址。
---
## 9. 启动编排 resolveBootstrap 与接入 NetClient
### 签名
```ts
interface BootstrapOptions {
mode: 'debug' | 'release'; // 运行模式(由 resolveRuntimeMode 决定)
win: NativeHost; // 原生注入宿主(≈ window);H5 下传 globalThis/window 即可
search: string; // location.search(如 '?profile=local')
fetcher: ConfigFetcher; // 远程配置抓取;生产传 new HttpConfigFetcher()
isNative: boolean; // 环境判定:原生 WebView=true,H5/浏览器=false(由调用方算)
fallbackServers?: string[];// 远程失败/无地址时降级
cacheBust?: () => string; // 防缓存串注入(默认 String(Date.now()))
}
interface BootstrapResult {
identity: ChannelIdentity;
servers: string[];
rawConfig: RemoteConfig | null; // 直连档位为 null
profile: DebugProfile;
mode: 'debug' | 'release'; // 透传入参 mode
isDebugger: boolean; // 是否开启收发包日志(debug 模式 + profile.isDebugger)
}
function resolveBootstrap(opts: BootstrapOptions): Promise<BootstrapResult>;
```
### 典型接入(生产 / H5 预览)
```ts
import { resolveBootstrap } from 'db://assets/framework/config/bootstrap';
import { resolveRuntimeMode } from 'db://assets/framework/config/runtime-mode';
import { HttpConfigFetcher } from 'db://assets/framework/config/remote-config-fetcher';
import { NetClient } from 'db://assets/framework/net/net-client';
import { CocosWebSocketTransport } from 'db://assets/framework/net/cocos-transport';
async function startup() {
const href = location.href;
const isDebugBuild = typeof DEBUG !== 'undefined' ? DEBUG : true;
const mode = resolveRuntimeMode(isDebugBuild);
const result = await resolveBootstrap({
mode,
win: globalThis as any,
search: location.search,
fetcher: new HttpConfigFetcher(),
isNative: href.indexOf('index.html') > -1, // 等价旧 Logic.isH5Version() 反向
fallbackServers: [], // 可选:填应急地址
});
const net = new NetClient({
servers: result.servers,
transportFactory: () => new CocosWebSocketTransport(),
debug: result.isDebugger,
});
// 渠道身份 + 玩家档案合并成完整 player_login 数据
net.setIdentity({
...result.identity, // agentid/channelid/gameid/marketid/version...
openid, nickname, avatar, sex, province, city, unionid, // 来自登录/微信信息
});
net.on('login', (data) => { /* 解析 parseLoginResponse(data) */ });
net.start();
}
```
> `NetClient.setIdentity` 需要的是完整 `player_login` 字段(`LoginRequestData`)。`resolveBootstrap` 只负责其中的**渠道身份**部分;玩家档案字段(`openid/nickname/avatar/...`)由登录/微信信息提供,二者合并后再 `setIdentity`。
### 环境判定 `isNative`
沿用旧工程 `Logic.isH5Version()` 的判据:**URL 含 `index.html` → 原生 WebView**(`isNative=true`);否则 H5/浏览器(`isNative=false`)。判定逻辑放在调用方,便于测试注入。
---
## 10. 原生联调(window.settings / app_*)
原生模式(`isNative=true`)下,渠道身份从原生注入对象同步读取,**接口名/全局名逐字一致**旧工程:
| 字段 | 主接口 | 全局回退 |
| --- | --- | --- |
| `agentid` | `window.settings.getothername('agent')` | `window.app_agent` |
| `channelid` | `window.settings.getchannelName()` | (无) |
| `marketid` | `window.settings.getmarketname()` | `window.app_market` |
读取做了 `try/catch`:主接口抛错(原生桥未就绪)则尝试全局回退;都拿不到则该字段不覆盖(保留 `BUILD_IDENTITY` 默认)。
> 原生侧需要保证在 H5 启动前注入 `window.settings` 或上述 `app_*` 全局。完整的异步 WVJB 桥(分享/视频/语音/电量等)不在本子系统范围,属后续 sdk 层;本期只做**身份相关的同步读取**。
---
## 11. 跑测试与类型检查
配置/渠道子系统是纯逻辑 + IO 分离设计,全部可在 Node 下自动化测试(无需 Cocos 运行时)。
```bash
# 工作目录:cocoscreator_projects/
cd cocoscreator_projects
npm run test:framework # 跑全部框架测试(node:test + tsx)
npm run typecheck:framework # 类型检查(tsc --noEmit)
```
要点:
- 测试文件在 `cocoscreator_projects/framework-tests/`(**Cocos `assets/` 之外**,不被编辑器编译),实现在 `YouleNexus/assets/framework/`。
- `test:framework` 实际跑的是 `scripts/run-framework-tests.mjs`,递归收集 `framework-tests/**/*.test.ts`。**原因**:本机 Node 20.13 < 20.14,`node --test` 还不支持 glob,故用脚本枚举。
- 依赖 `tsx`、`typescript`、`@types/node`(devDependencies)。
- tsconfig(`tsconfig.framework.json`)开了 `allowImportingTsExtensions`,所以**框架内 import 必须带 `.ts` 后缀**。
> 写测试时注意一个 TS 6.x 坑:对「只在闭包内赋值、初值为 `null`」的变量,经 `assert.ok(x)` 收窄后会被推成 `never`。规避法:把变量声明为 `any`,或在断言处把数据传给纯函数再断言(参考 `framework-tests/integration/login-flow.test.ts`)。
---
## 12. 常见调试场景配方
### A. 连本地服务器跑一局
1. 本地起服务器在 `127.0.0.1:3088`(或改 `local` 档位的 `server`)。
2. 预览 URL 加 `?profile=local`。
3. 这条直连、不抓远程配置;`isDebugger=true` 会输出收发包日志。
### B. 用测试配置服 + 默认渠道
预览 URL 加 `?profile=staging`。走 staging 的 gameserver 解析出服务器地址。
### C. 复现某渠道专属 bug
保持当前档位,URL 追加该渠道的身份:
```
?agentid=<该渠道agentid>&channelid=<该渠道channelid>&marketid=<该渠道marketid>
```
这些覆盖优先级最高,远程配置会据此分层取到该渠道的服务器/参数。
### D. 连组内某台联调机
在 `PROFILES` 里加一个档位(见 [§5](#5-调试-profiles) 的 `lab` 例子),用 `?profile=lab`。
### E. 远程配置服挂了也要能调
给 `resolveBootstrap` 传 `fallbackServers: ['ws://<应急地址>']`,抓取失败时自动降级。
---
## 13. 真实服务器端到端联调
> 对应 Plan 2 的 Task 12 Step 4-5(自动化 mock 已全绿,真机联调需要外部输入)。
**前置**:① 可联调的服务器地址(`ws://ip:port` 或配置服 `gameserver` URL);② 一组后端认可的有效渠道身份(`agentid/channelid/marketid` + 目标子游戏的 `gameid`)。
**步骤**:
1. 用 `cocos-creator-mcp` 的 `debug_execute_script` 注入一段临时调试入口(或挂一个调试脚本),按 [§9](#9-启动编排-resolvebootstrap-与接入-netclient) 的接入示例:`resolveBootstrap` + `HttpConfigFetcher` + `NetClient` + `CocosWebSocketTransport`。
- 想直连:在 `PROFILES` 临时加一档带 `server` 的 profile,或直接 `new NetClient({ servers: ['ws://<联调地址>'] })`。
- 想验证远程配置链路:把 `gameserver` 指向联调配置服,走 `resolveBootstrap` 完整流程。
2. `net.setIdentity({...result.identity, ...玩家档案})`,监听 `open`/`login`/`message`/`slow`/`reconnecting`。
3. `net.start()` 连真机。
4. 断言/观察:收到 `@toconcon` 握手不报错 → 发出 `player_login` → 收到 `player_login` 响应且 `parseLoginResponse(data).ok === true` → console 打印 `playerid`/资产。
5. 用 `debug_get_console_logs` / `debug_screenshot` 留存联调证据。
6. 把联调结论(成功/协议偏差)回填到 `docs/protocol/` 对应章节的「⚠️待服务器确认」项。
---
## 14. 发布前检查清单
- [ ] `config/runtime-mode.ts` 的 `MODE_OVERRIDE` 为 `null`(发布走自动模式,由 release 构建决定)。
- [ ] `config/profiles.ts` 的 `ACTIVE_PROFILE` 为 `'prod'`。
- [ ] `prod` 档位 `isDebugger: false`(不输出收发包日志)。
- [ ] 不依赖任何 `?profile=`/`?agentid=` 之类 URL 覆盖(生产 URL 应是干净的)。
- [ ] 目标子游戏的 `BUILD_IDENTITY.gameid` 正确(每子游戏不同)。
- [ ] `gameserver`(`DEFAULT_GAMESERVER`)指向正式配置服。
- [ ] `npm run test:framework` 全绿、`npm run typecheck:framework` exit 0。
---
## 15. 红线:哪些字符串绝不能改
跨边界到「服务器 / 原生 / 配置服务」的字符串契约**必须逐字不变**(CLAUDE.md 三条红线)。内部变量/类型/函数名可以现代化命名,但下面这些字面量不能动:
- **协议字段名**:`agentid`、`channelid`、`gameid`、`marketid`、`openid`、`version`、`route`、`rpc` 等。
- **原生接口名/全局名**:`window.settings.getothername`、`getchannelName`、`getmarketname`;全局 `app_agent`、`app_market`。
- **远程配置键名**:`agentlist`、`gamelist`、`channellist`、`marketlist` 及其匹配键 `agentid/gameid/channelid/marketid`;连接参数 `player_server_tcp`、`visitor_server_tcp`、`game_server_tcp`(以及未来用到的 `*_http` 等)。
- **gameserver URL 防缓存**:`<url>?<时间戳>` 形式。
改这些之前先核对旧工程源码(`12_Logic.js` 的 `get_paravalue`/`getConfig_Succ`、`05_Func.js` 的 `getothername/getchannelName/getmarketname`、`version.js`、`00_SubGame_Config.js`),不要臆测。
---
## 16. API 速查表
| 符号 | 来自 | 签名 / 说明 |
| --- | --- | --- |
| `resolveRuntimeMode` | `config/runtime-mode.ts` | `(isDebugBuild, override?) => 'debug' | 'release'` 运行模式解析 |
| `resolveBootstrap` | `config/bootstrap.ts` | `(opts: BootstrapOptions) => Promise<BootstrapResult>` 启动编排(入参含 mode,结果含 mode/isDebugger) |
| `BUILD_IDENTITY` | `config/sources/defaults.ts` | 构建期默认渠道身份常量 |
| `resolveIdentity` | `config/identity.ts` | `(sources: IdentitySource[]) => ChannelIdentity` 优先级合并 |
| `queryStringSource` | `config/sources/query-string.ts` | `(search: string) => IdentitySource` H5 URL 身份来源 |
| `nativeSettingsSource` | `config/sources/native-settings.ts` | `(win: NativeHost) => IdentitySource` 原生身份来源 |
| `PROFILES` / `ACTIVE_PROFILE` | `config/profiles.ts` | 档位表 / 当前默认档位名 |
| `resolveActiveProfile` | `config/profiles.ts` | `(search: string) => DebugProfile`,支持 `?profile=` |
| `DEFAULT_GAMESERVER` | `config/profiles.ts` | 正式远程配置 txt URL |
| `getParam` | `config/remote-config.ts` | `(config, key, id) => unknown` 分层取参 |
| `resolveServers` | `config/remote-config.ts` | `(config, id) => string[]` ws 候选地址 |
| `ConfigFetcher` | `config/remote-config.ts` | 抓取接口 `{ fetch(url): Promise<RemoteConfig> }` |
| `HttpConfigFetcher` | `config/remote-config-fetcher.ts` | 生产用 `fetch` 实现 |
| `ConfigFetchError` / `ConfigParseError` | `config/remote-config.ts` | 抓取/解析错误类型 |
---
*文档对应实现已合入 master;如接口有演进,请同步更新本指南。*