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/res/AssetService.ts

120 lines
4.5 KiB

import { Asset, instantiate, Node, Prefab } from 'cc';
import { GEvent } from '../event/GEvent';
import { Singleton } from '../../tools/Singleton';
import { ResourcesManager, ResPakage } from './ResourcesManager';
import { LoadScheduler } from './LoadScheduler';
import { AssetDesc, LoadOptions, LoadPriority, mergeLoadOptions } from './LoadPolicy';
/**
* 统一资源门面:同步 getRes/getNode 仅命中已晋升资源;异步 ensure* 负责加载并晋升。
*/
export class AssetService extends Singleton {
private _loadingShown = false;
get res(): ResourcesManager {
return ResourcesManager.getInstance();
}
get scheduler(): LoadScheduler {
return LoadScheduler.getInstance();
}
ensureBundle(bundleName: string, priority: LoadPriority = 'interactive'): Promise<void> {
return this.scheduler.enqueue(priority, () => new Promise<void>((resolve) => {
this.res.loadBundle(bundleName, () => resolve());
}));
}
ensureAsset(desc: AssetDesc, opts?: LoadOptions): Promise<Asset | null> {
const options = mergeLoadOptions(opts);
const existing = this.res.getRes(desc.name, desc.path, desc.bundle, desc.type);
if (existing) return Promise.resolve(existing as Asset);
return new Promise<Asset | null>((resolve) => {
void this.scheduler.enqueue(options.priority, () => new Promise<void>((done) => {
this.res.loadAsset(desc.bundle, desc.path, desc.name, desc.type, (asset) => {
resolve(asset);
done();
});
}));
});
}
ensurePackage(pkg: ResPakage, opts?: LoadOptions): Promise<void> {
const options = mergeLoadOptions(opts);
if (pkg.ress.length <= 0) return Promise.resolve();
this.res.clearResPkg(pkg.name);
const showLoading = this._maybeShowLoading(options);
let done = 0;
const total = pkg.ress.length;
let chain = Promise.resolve();
for (const conf of pkg.ress) {
chain = chain.then(() => this.ensureAsset(
{ name: conf.name, path: conf.path, bundle: conf.bundle, type: conf.type },
options,
).then(() => {
done++;
options.onProgress?.(done, total);
}));
}
return chain.then(() => {
this._hideLoadingIfNeeded(showLoading);
this._registerPackageCache(pkg);
}).catch((e) => {
this._hideLoadingIfNeeded(showLoading);
throw e;
});
}
loadResPakg(pkg: ResPakage, opts?: LoadOptions): Promise<void> {
return this.ensurePackage(pkg, { ...mergeLoadOptions(opts), priority: opts?.priority ?? 'interactive' });
}
preLoadResPakg(pkg: ResPakage, onProgress?: (c: number, t: number) => void, onComplete?: (result: { ok: boolean; failed: string[] }) => void): void {
this.res.preLoadResPakg(pkg, onProgress, onComplete);
}
ensureNode(path: string, name: string, bundle: string, opts?: LoadOptions): Promise<Node | null> {
return this.ensureAsset(
{ name, path, bundle, type: Prefab },
opts,
).then(() => this.res.getNode(path, name, bundle));
}
private _registerPackageCache(pkg: ResPakage): void {
const cache = (this.res as any)._resCache as Map<string, ResPakage>;
if (cache.get(pkg.name)) return;
for (const conf of pkg.ress) {
const res = this.res.getRes(conf.name, conf.path, conf.bundle, conf.type);
if (res) conf.res = res as Asset;
}
cache.set(pkg.name, pkg);
}
private _maybeShowLoading(options: ReturnType<typeof mergeLoadOptions>): boolean {
// Boot(critical) / 静默预载(silent) 不走运行时 loadingUI,进度由 BootPipeline / GameLaunch 负责
if (options.priority === 'critical' || options.priority === 'silent' || options.priority === 'background') {
return false;
}
if (options.policy === 'network') {
GEvent.Ins.emit(GEvent.SHOW_LOADING, 1);
this._loadingShown = true;
return true;
}
if (options.showLoadingAfterMs <= 0) return false;
GEvent.Ins.emit(GEvent.SHOW_LOADING, 1);
this._loadingShown = true;
return true;
}
private _hideLoadingIfNeeded(immediateShown: boolean): void {
if (immediateShown || this._loadingShown) {
GEvent.Ins.emit(GEvent.HIDE_LOADING);
this._loadingShown = false;
}
}
}