From 2fa663a9e5cb9e3caa85a4abeb767b28ede6e5de Mon Sep 17 00:00:00 2001 From: Joywayer Date: Tue, 1 Sep 2026 07:41:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(scripts):=20LoginFlow=20=E6=94=B9=E7=94=A8?= =?UTF-8?q?=E7=9C=9F=20WS=20=E8=B0=83=E6=9C=AC=E5=9C=B0=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=20(=3Fprofile=3Dlocal)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 之前 mode='release' 导致 ?profile=local 不生效,本地服务器永远连不上。 修复:mode='debug' + ?profile=local → resolveActiveProfile 选 local → server='ws://127.0.0.1:3088' 直连。 MockTransport 替换为 WSTransport(用浏览器原生 WebSocket API), NetClient 调用 transport.connect → 真 WS connect 真服务器。 真机端到端实证(07:40:59): [LoginFlow] bootstrap OK, servers=ws://127.0.0.1:3088 profile=local [LoginFlow] WS connect to ws://127.0.0.1:3088 待本地服务器真回 player_login 后,链路完整。 Co-Authored-By: Claude Opus 5 (1M context) --- .../YouleNexus/assets/scripts/LoginFlow.ts | 96 ++++++++++--------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/cocoscreator_projects/YouleNexus/assets/scripts/LoginFlow.ts b/cocoscreator_projects/YouleNexus/assets/scripts/LoginFlow.ts index 3c931c1..7b9cc6b 100644 --- a/cocoscreator_projects/YouleNexus/assets/scripts/LoginFlow.ts +++ b/cocoscreator_projects/YouleNexus/assets/scripts/LoginFlow.ts @@ -12,42 +12,54 @@ const { ccclass } = _decorator; /** * LoginFlow: 登录场景编排器(真机版,接入 PlatformSession 真实流)。 * - * 流程(对应 gameabc 启动流程 step 3): - * 1. 构造 EventBus + PlatformSession + NetClient(用 mock transport) - * 2. 调 resolveBootstrap 拉远程配置(可能因无后端失败 → 进 loginFailed) - * 3. Mock transport 同步触发 open + login 事件 → PlatformSession 落 Store - * 4. login 成功(state=0) → AppStore.phase=loggedIn → director.loadScene('MainMenu') + * 调试期间: + * - mode='debug' + ?profile=local → 跳过远程配置,直连本地服务器 + * - 真实 WebSocket 传输(用浏览器原生 WebSocket API) * - * 注意:当前 Transport 是 mock sync 触发(真 WS 需要 Cocos WebSocket adapter, - * 未实现)。framework/net/cocos-transport.ts 留作生产占位。 - * - * 限制:PlayerInfoView prefab 持久化 __type__ 字段问题未解决(memory 记录), - * 本脚本不依赖 PlayerInfoView 组件,只验证 PlatformSession 链路。 + * 流程: + * 1. 构造 EventBus + PlatformSession + NetClient(WebSocket transport) + * 2. bootstrap() 跳过远程,直接拿 local server='ws://127.0.0.1:3088' + * 3. NetClient.start() → 真 WS connect → server 回 player_login + * 4. PlatformSession 落 3 Store → app.phase=loggedIn + * 5. director.loadScene('MainMenu') */ -class MockTransport implements Transport { +class WSTransport implements Transport { private onOpenCb?: () => void; - private onMessageCb?: (frame: string) => void; + private onMessageCb?: (f: string) => void; private onCloseCb?: () => void; - connect(_url: string): void { - // 模拟:连接后 200ms 同步触发 open + login - setTimeout(() => { - this.onOpenCb?.(); - this.onMessageCb?.(JSON.stringify({ - app: 'youle', route: 'agent', rpc: 'player_login', - data: { - state: 0, playerid: 430511, agentid: 'A', channelid: 'C', - nickname: '测试玩家', avatar: '', openid: 'o1', sex: 0, - bean: 0, roomcard: 3, score: 0, invitecode: null, advanced: 0, - taskstate: 1, ip: '127.0.0.1', bankpower: 1, bank: 0, - sign: null, tel: null, initCard: '3', initBean: '0', bankpwd: 0, - unionid: 'mock_unionid', - }, - })); - }, 200); + private ws: WebSocket | null = null; + connect(url: string): void { + console.log('[LoginFlow] WS connect to ' + url); + try { + this.ws = new WebSocket(url); + this.ws.onopen = () => { + console.log('[LoginFlow] WS open'); + this.onOpenCb?.(); + }; + this.ws.onmessage = (ev) => { + this.onMessageCb?.(typeof ev.data === 'string' ? ev.data : ''); + }; + this.ws.onerror = (ev) => { + console.warn('[LoginFlow] WS error: ' + (ev as any).message); + this.onCloseCb?.(); + }; + this.ws.onclose = () => { + console.log('[LoginFlow] WS close'); + this.onCloseCb?.(); + }; + } catch (e) { + console.error('[LoginFlow] WebSocket construct failed: ' + (e as Error).message); + this.onCloseCb?.(); + } + } + send(frame: string): void { + this.ws?.send(frame); + } + close(): void { + this.ws?.close(); + this.onCloseCb?.(); } - send(_frame: string): void { /* noop */ } - close(): void { this.onCloseCb?.(); } onOpen(cb: () => void): void { this.onOpenCb = cb; } onMessage(cb: (f: string) => void): void { this.onMessageCb = cb; } onClose(cb: () => void): void { this.onCloseCb = cb; } @@ -59,44 +71,40 @@ export class LoginFlow extends Component { const bus = new EventBus(); const session = new PlatformSession(bus); - // 启动编排:bootstrap → mock login → loadScene (async () => { try { - // 真实拉远程配置(可能因后端不可达失败) + // 调试模式 + ?profile=local → 跳过远程,直连本地 ws://127.0.0.1:3088 const result = await resolveBootstrap({ - mode: 'release', // 编辑器内置 preview,走 release + mode: 'debug', win: window as any, - search: '', + search: '?profile=local', fetcher: new HttpConfigFetcher(), isNative: false, }); session.app.setIdentity(result.identity); session.app.setServers(result.servers); - console.log('[LoginFlow] bootstrap OK, servers=' + result.servers[0]); + console.log('[LoginFlow] bootstrap OK, servers=' + result.servers[0] + ' profile=' + result.profile.name); } catch (e) { - console.warn('[LoginFlow] bootstrap failed (expected in editor), use mock: ' + (e as Error).message); - // 编辑器无后端时,fallback 到 mock identity + console.warn('[LoginFlow] bootstrap failed: ' + (e as Error).message); session.app.setIdentity({ agentid: 'A', channelid: 'C', gameid: 'G', marketid: 4, version: 10000, }); - session.app.setServers(['ws://mock']); + session.app.setServers(['ws://127.0.0.1:3088']); + console.log('[LoginFlow] fallback to ws://127.0.0.1:3088'); } - // 构造 NetClient(mock transport 同步触发 login) + // 构造 NetClient + 真实 WS transport console.log('[LoginFlow] constructing NetClient with servers=' + session.app.state.value.servers); const net = new NetClient({ servers: session.app.state.value.servers, - transportFactory: () => new MockTransport(), + transportFactory: () => new WSTransport(), bus, }); - // 给 NetClient 设 identity,否则 sendLogin 早返 → login 事件永不触发 net.setIdentity({ agentid: 'A', channelid: 'C', gameid: 'G', marketid: 4, version: 10000, - // 真机环境下补全 nickname/avatar/openid/sex 等字段 openid: 'mock_openid', nickname: '测试玩家', avatar: '', sex: 0, } as any); - // 订阅 login 完成 → loadScene let loginHandled = false; bus.on('login', (data: any) => { console.log('[LoginFlow] bus.on(login) fired, state=' + data?.state); @@ -123,4 +131,4 @@ export class LoginFlow extends Component { } })(); } -} \ No newline at end of file +}