You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
AdLike2048/assets/mx/module/boot/BootPipeline.ts

179 lines
7.4 KiB

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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
// 先取 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?.();
}
}