import { sdkConfig } from 'db://assets/script/sdk/sdkConfig'; import { GBundle, getBootResPakage } from 'db://assets/script/game/ConfigRes'; import { LoadScheduler } from '../res/LoadScheduler'; import { BundleLifecycle } from '../res/BundleLifecycle'; import { PreloadPredictor } from '../res/PreloadPredictor'; import { BattleBackgroundLoadGate } from '../res/BattleBackgroundLoadGate'; import { ResourcePhase, ResourcePhaseGate } from '../res/ResourcePhaseGate'; import { MemoryProfile } from 'db://assets/script/game/MemoryProfile'; import { DeviceCapability } from 'db://assets/script/game/DeviceCapability'; import { ThermalGovernor } from 'db://assets/script/game/ThermalGovernor'; import { AppLifecycle } from 'db://assets/script/game/AppLifecycle'; import { PerfReport } from 'db://assets/script/game/PerfReport'; import { fetchHotUpdateTables } from 'db://assets/script/game/ConfigHotUpdate'; export interface BootPipelineCallbacks { /** 进度增量(Boot 各阶段累加到 GameLaunch 进度条) */ onProgress?: (delta: number, weight?: number) => void; /** Boot 标题文案 */ onTitle?: (text: string) => void; /** Boot 分包资源加载完成(允许部分失败,见日志) */ onBootAssetsReady?: () => void; /** SDK 与 gg.data.init 完成 */ onSdkAndDataReady?: () => void; } /** * 启动编排:核心表 / 最小 Boot 资源 / SDK 网络初始化三路并行; * gg.data.init 在「核心表 + SDK」均就绪后执行(存档合并依赖双方结果)。 * Boot 只拉 first/comm/home;icons 在三分包落地后静默开下;BootRes 完成后并行点火战斗分包。 */ export class BootPipeline { /** Boot 分包资源是否已就绪 */ private _bootAssetsReady = false; /** SDK 与存档是否已就绪 */ private _sdkAndDataReady = false; private _bootStartTime = 0; /** SDK init 返回的远端用户数据 */ private _sdkUserData: unknown = null; /** Boot 分包资源是否已就绪 */ get bootAssetsReady(): boolean { return this._bootAssetsReady; } /** SDK 与存档是否已就绪 */ get sdkAndDataReady(): boolean { return this._sdkAndDataReady; } /** * 启动主阶段:并行加载核心表、Boot 资源、SDK;数据 init 在表+SDK 后执行。 * @param callbacks Boot 进度与就绪回调 */ async start(callbacks?: BootPipelineCallbacks): Promise { this._bootStartTime = Date.now(); LoadScheduler.getInstance().start(); AppLifecycle.install(); callbacks?.onTitle?.('正在更新资源...'); const tablesPromise = this._loadBootTables(callbacks); const assetsPromise = this._loadBootPhase(callbacks); const sdkPromise = this._initSdkNetwork(); await Promise.all([tablesPromise, sdkPromise]); await this._finishDataInit(callbacks); await assetsPromise; sdkConfig.resLoadFinishTime = Date.now() - this._bootStartTime; } /** 进游戏后延迟阶段:机型探测、内存档位、预载预测等 */ startDeferredPhase(): void { void this._startDeferredPhaseAsync(); } private async _startDeferredPhaseAsync(): Promise { await DeviceCapability.ensurePlatformProbe(); MemoryProfile.resolve(); MemoryProfile.applyLoadPolicy(); ThermalGovernor.install(); PerfReport.reportBootTier(); BattleBackgroundLoadGate.install(); ResourcePhaseGate.getInstance().setPhase(ResourcePhase.Boot); void this._loadDeferredTables(); PreloadPredictor.getInstance().start(); } /** 战斗/大厅核心表 + 弹窗依赖表 */ private _loadBootTables(callbacks?: BootPipelineCallbacks): Promise { return new Promise((resolve) => { gg.data.table.loadBootTables((c, t) => { callbacks?.onProgress?.(c / t * 0.25, 0.25); }, () => { resolve(); }); }); } private _loadDeferredTables(): void { gg.data.table.loadDeferredTables(null, () => { }); } /** Boot 分包剩余数 */ private _bootBundleLeft = 0; /** Boot 阶段 resolve */ private _bootPhaseResolve: (() => void) | null = null; /** Boot 阶段回调 */ private _bootPhaseCallbacks: BootPipelineCallbacks | undefined; private _loadBootPhase(callbacks?: BootPipelineCallbacks): Promise { return new Promise((resolve) => { this._bootPhaseResolve = resolve; this._bootPhaseCallbacks = callbacks; const names = [GBundle.First, GBundle.Comm, GBundle.Home]; this._bootBundleLeft = names.length; for (let i = 0; i < names.length; i++) { this._loadOneBootBundle(names[i]); } }); } /** 加载单个 Boot 分包(经 BundleLifecycle,避免与 ensureLoaded 同名双飞) */ private _loadOneBootBundle(name: string): void { void BundleLifecycle.getInstance().ensureLoaded(name).then((bundle) => { if (!bundle) { console.error('[BootPipeline] boot bundle', name); } this._onOneBootBundle(); }); } private _onOneBootBundle = (): void => { this._bootBundleLeft--; if (this._bootBundleLeft > 0) return; this._bootPhaseCallbacks?.onProgress?.(0.1, 0.1); PreloadPredictor.getInstance().startEarlyIconsDownload(); gg.res.loadResPakg(getBootResPakage(), this._onBootResProgress, this._onBootResComplete); }; private _onBootResProgress = (c: number, t: number): void => { this._bootPhaseCallbacks?.onProgress?.(c / t * 0.4, 0.4); }; private _onBootResComplete = (result: { ok: boolean; failed: string[] }): void => { if (!result.ok) { PerfReport.reportLoadFail('boot', result.failed.length); console.error('[BootPipeline] Boot 资源部分失败', result.failed); } this._bootAssetsReady = true; PreloadPredictor.getInstance().startEarlyBattleBundleDownload(); this._bootPhaseCallbacks?.onBootAssetsReady?.(); const resolve = this._bootPhaseResolve; this._bootPhaseResolve = null; this._bootPhaseCallbacks = undefined; resolve?.(); }; /** SDK 网络/平台初始化(不依赖配表与 Boot 资源,可与加载并行) */ private async _initSdkNetwork(): Promise { const startTime2 = Date.now(); this._sdkUserData = await gg.sdk.init(); const uid = await ZYSDK.ZYSDK.getUserId(); gg.data.doc.uid = uid; gg.sdk.sdk30r?.setOpenId(uid); sdkConfig.sdkLoadFinishTime = Date.now() - startTime2; } /** 核心表与 SDK 均就绪后合并存档并标记数据层可进游戏 */ private async _finishDataInit(callbacks?: BootPipelineCallbacks): Promise { // 先取 SDK uid,init 重建 Doc 后回填,避免被 initDoc 清空 const uid = await ZYSDK.ZYSDK.getUserId(); gg.data.init(sdkConfig.config.pointData.gid, this._sdkUserData); if (!gg.data.doc.uid && uid != null && uid !== '') { gg.data.doc.uid = String(uid); } // 不阻塞进游戏:本地表已就绪,远端成功后再 applyHotUpdateTables 覆盖 void fetchHotUpdateTables(); callbacks?.onProgress?.(0.25, 0.25); this._sdkAndDataReady = true; callbacks?.onSdkAndDataReady?.(); } }