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.
154 lines
5.8 KiB
154 lines
5.8 KiB
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<typeof setTimeout> | 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<void> {
|
|
return new Promise((resolve) => {
|
|
setTimeout(resolve, 0);
|
|
});
|
|
}
|
|
|
|
private static _logDone(task: string): void {
|
|
console.log(`[HomeBattlePreload] 加载完成: ${task}`);
|
|
}
|
|
|
|
private static async _run(chapterId: number): Promise<void> {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|