之前 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) <noreply@anthropic.com>
135 lines
5.0 KiB
TypeScript
135 lines
5.0 KiB
TypeScript
import { _decorator, Component, director } from 'cc';
|
|
import { PlatformSession } from '../framework/platform/session.ts';
|
|
import { NetClient, type NetClientEvents } from '../framework/net/net-client.ts';
|
|
import { resolveBootstrap } from '../framework/config/bootstrap.ts';
|
|
import { HttpConfigFetcher } from '../framework/config/remote-config-fetcher.ts';
|
|
import { RoomRPCBus } from '../framework/platform/room-rpc-bus.ts';
|
|
import { EventBus } from '../framework/core/events.ts';
|
|
import type { Transport } from '../framework/net/transport.ts';
|
|
|
|
const { ccclass } = _decorator;
|
|
|
|
/**
|
|
* LoginFlow: 登录场景编排器(真机版,接入 PlatformSession 真实流)。
|
|
*
|
|
* 调试期间:
|
|
* - mode='debug' + ?profile=local → 跳过远程配置,直连本地服务器
|
|
* - 真实 WebSocket 传输(用浏览器原生 WebSocket API)
|
|
*
|
|
* 流程:
|
|
* 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 WSTransport implements Transport {
|
|
private onOpenCb?: () => void;
|
|
private onMessageCb?: (f: string) => void;
|
|
private onCloseCb?: () => void;
|
|
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?.();
|
|
}
|
|
onOpen(cb: () => void): void { this.onOpenCb = cb; }
|
|
onMessage(cb: (f: string) => void): void { this.onMessageCb = cb; }
|
|
onClose(cb: () => void): void { this.onCloseCb = cb; }
|
|
}
|
|
|
|
@ccclass('LoginFlow')
|
|
export class LoginFlow extends Component {
|
|
start(): void {
|
|
const bus = new EventBus<NetClientEvents>();
|
|
const session = new PlatformSession(bus);
|
|
|
|
(async () => {
|
|
try {
|
|
// 调试模式 + ?profile=local → 跳过远程,直连本地 ws://127.0.0.1:3088
|
|
const result = await resolveBootstrap({
|
|
mode: 'debug',
|
|
win: window as any,
|
|
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] + ' profile=' + result.profile.name);
|
|
} catch (e) {
|
|
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://127.0.0.1:3088']);
|
|
console.log('[LoginFlow] fallback to ws://127.0.0.1:3088');
|
|
}
|
|
|
|
// 构造 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 WSTransport(),
|
|
bus,
|
|
});
|
|
net.setIdentity({
|
|
agentid: 'A', channelid: 'C', gameid: 'G', marketid: 4, version: 10000,
|
|
openid: 'mock_openid', nickname: '测试玩家', avatar: '', sex: 0,
|
|
} as any);
|
|
|
|
let loginHandled = false;
|
|
bus.on('login', (data: any) => {
|
|
console.log('[LoginFlow] bus.on(login) fired, state=' + data?.state);
|
|
if (loginHandled) return;
|
|
loginHandled = true;
|
|
console.log('[LoginFlow] login success, phase=' + session.app.state.value.phase);
|
|
if (session.app.state.value.phase === 'loggedIn') {
|
|
new RoomRPCBus(bus, session).start();
|
|
console.log('[LoginFlow] RoomRPCBus started');
|
|
this.scheduleOnce(() => director.loadScene('MainMenu'), 0.5);
|
|
} else {
|
|
console.warn('[LoginFlow] phase is not loggedIn: ' + session.app.state.value.phase);
|
|
}
|
|
});
|
|
|
|
bus.on('open', () => console.log('[LoginFlow] bus.on(open) fired'));
|
|
bus.on('reconnecting', (s) => console.log('[LoginFlow] bus.on(reconnecting) to ' + s));
|
|
|
|
try {
|
|
net.start();
|
|
console.log('[LoginFlow] net.start() called');
|
|
} catch (e) {
|
|
console.error('[LoginFlow] net.start() failed: ' + (e as Error).message);
|
|
}
|
|
})();
|
|
}
|
|
}
|