import { BattleResLoader } from './BattleResLoader'; import { GBundle, getBattleMapResItemByChapter, ResPkgName } from './ConfigRes'; /** * Home 页后台预加载战斗资源: * - 当前选中关卡地图 * - 局内相关 bundle(tetriGame/Map/Cards/Weapon + battleGameWeapon + 弹窗包) * - weapon1 子弹 + hitEffect 爆炸 * 其它资源进局后再按需加载。 * * 切到商城/角色/武器/副本时 pause;切回 Home 延迟 2s 再 resume。 * 分包之间 yield 一帧,避免连续 loadBundle 造成卡帧尖刺。 */ export class HomeBattlePreload { private static readonly RESUME_DELAY_MS = 2000; /** 战斗结束回大厅后错峰预载(与 releaseBundle 错开,减轻卡顿) */ private static readonly POST_BATTLE_RESUME_MS = 1500; /** Home 相关局内分包(只拉 bundle 索引,具体 prefab 再 ensure) */ private static readonly BATTLE_BUNDLES: string[] = [ GBundle.tetriGame, GBundle.tetriMap, GBundle.tetriCards, GBundle.tetriWeapon, GBundle.BattleGameWeapon, GBundle.BattleGameResult, GBundle.SkillSelect, GBundle.TurnTable, GBundle.tetriDoc, ]; private static _paused = false; private static _gen = 0; private static _chapterId = 0; private static _resumeTimer: ReturnType | null = null; private static _running = false; /** Home 创建完成 / 切章节:立即开始(取消延迟) */ static startNow(chapterId: number): void { if (!chapterId || chapterId <= 0) return; this._clearResumeTimer(); this._paused = false; this._chapterId = chapterId; void this._run(chapterId); } /** 切走 Home:暂停,丢弃进行中的预载代际 */ static pause(): void { this._clearResumeTimer(); this._paused = true; this._gen++; } /** * 战斗结束回大厅:延迟预载,避免与 releaseBundle 同帧争抢主线程。 */ static resumeAfterBattle(chapterId?: number): void { const id = chapterId > 0 ? chapterId : (this._chapterId || gg?.game?.CurentSelectChapterId || gg?.data?.doc?.chapter || 0); if (!id) return; this.scheduleResume(id, HomeBattlePreload.POST_BATTLE_RESUME_MS); } /** 切回 Home:等待 delayMs 后再开(默认 2s) */ static scheduleResume(chapterId?: number, delayMs: number = HomeBattlePreload.RESUME_DELAY_MS): void { const id = chapterId > 0 ? chapterId : (this._chapterId || gg?.game?.CurentSelectChapterId || 0); this.pause(); if (!id) return; this._chapterId = id; this._resumeTimer = setTimeout(() => { this._resumeTimer = null; if (gg?.game?.CurentBattle) return; this._paused = false; void this._run(this._chapterId); }, delayMs); } private static _clearResumeTimer(): void { if (this._resumeTimer != null) { clearTimeout(this._resumeTimer); this._resumeTimer = null; } } private static _alive(gen: number): boolean { return !this._paused && this._gen === gen && !gg?.game?.CurentBattle; } /** 让出主线程一帧,避免连续 loadBundle 造成卡顿尖刺 */ private static _yieldFrame(): Promise { return new Promise((resolve) => { setTimeout(resolve, 0); }); } private static _logDone(task: string): void { console.log(`[HomeBattlePreload] 加载完成: ${task}`); } private static async _run(chapterId: number): Promise { const gen = ++this._gen; this._chapterId = chapterId; this._running = true; console.log(`[HomeBattlePreload] 开始预载 chapter=${chapterId}`); try { if (!this._alive(gen)) return; await BattleResLoader.ensureBattleEntry(); if (!this._alive(gen)) return; this._logDone('ensureBattleEntry(home/audio)'); await this._yieldFrame(); for (let i = 0; i < this.BATTLE_BUNDLES.length; i++) { const bundleName = this.BATTLE_BUNDLES[i]; await BattleResLoader.loadBundle(bundleName); if (!this._alive(gen)) return; this._logDone(`bundle/${bundleName}`); await this._yieldFrame(); } const mapItem = getBattleMapResItemByChapter(chapterId); if (mapItem && gg?.res) { await gg.res.ensurePrefab(mapItem.name, mapItem.path, mapItem.bundle); if (!this._alive(gen)) return; gg.res.appendToResPkg(ResPkgName.BattleRes, [mapItem]); this._logDone(`地图 ${mapItem.bundle}/${mapItem.path}${mapItem.name}`); await this._yieldFrame(); } else { console.warn(`[HomeBattlePreload] 章节${chapterId} 无地图配置,跳过地图预载`); } if (gg?.res) { await gg.res.ensurePrefab('tetriGame', 'prefab/', GBundle.tetriGame); if (!this._alive(gen)) return; this._logDone(`界面 ${GBundle.tetriGame}/prefab/tetriGame`); await this._yieldFrame(); } await BattleResLoader.preloadWeapon1Bullet(); if (!this._alive(gen)) return; const hit = gg?.data?.project?.getWeaponData?.(1)?.hitEffect ?? ''; this._logDone(`weapon1 子弹 + hitEffect(${hit || '无'})`); this._logDone(`章节${chapterId} 全部预载任务结束`); } catch (e) { console.warn('[HomeBattlePreload] run failed', chapterId, e); } finally { if (this._gen === gen) { this._running = false; } } } }