更新
This commit is contained in:
@@ -71,56 +71,15 @@ export class GameConfig {
|
||||
private static levelLoadRequest = 0;
|
||||
private static sceneLoadRequest = 0;
|
||||
private static cancelBlockLoading: () => void = null;
|
||||
private static preparedBlocks: any[] = null;
|
||||
private static preparedNextLevel = 0;
|
||||
private static nextBlocksLoading: Promise<any[]> = null;
|
||||
|
||||
/** 只读取下一关配置,不调用 LEVEL_INFO_init,也不改玩家进度。 */
|
||||
/** 只准备当前关图片,不预读或加载下一关图片。 */
|
||||
static prepareBlockWindow(onRemoteRequired?: () => void, stage = "进关"): Promise<boolean> {
|
||||
const blocks = this.BLOCK_INFO && this.BLOCK_INFO[0];
|
||||
if (!blocks || !this.loadedLevelNumber) return Promise.reject(new Error("关卡配置尚未就绪"));
|
||||
const currentLevel = this.loadedLevelNumber;
|
||||
let nextLevel = currentLevel + 1;
|
||||
if (!this.GM_INFO.otherLevel && (this.GM_INFO.GameplayType === 1
|
||||
|| this.loadedLevelNumber >= GameTool.MAX_NORMAL_LEVEL)) {
|
||||
// 预选无尽模式本地随机的下一关,通关时 getNextLevel 复用同一个结果。
|
||||
if (!this.nextEndlessLevel) {
|
||||
this.nextEndlessLevel = GameTool.getPurelyRandom(GameTool.MAX_NORMAL_LEVEL);
|
||||
}
|
||||
nextLevel = this.nextEndlessLevel;
|
||||
} else {
|
||||
this.nextEndlessLevel = 0;
|
||||
}
|
||||
if (this.preparedBlocks !== blocks || this.preparedNextLevel !== nextLevel || !this.nextBlocksLoading) {
|
||||
this.preparedBlocks = blocks;
|
||||
this.preparedNextLevel = nextLevel;
|
||||
const loadNext = new Promise<any[]>((resolve, reject) => {
|
||||
cc.assetManager.loadBundle("custom", (err, bundle) => {
|
||||
if (err) return reject(err);
|
||||
const path = "Json/level" + nextLevel;
|
||||
if (!bundle.getInfoWithPath(path, cc.JsonAsset)) return resolve([]);
|
||||
bundle.load(path, cc.JsonAsset, (error, asset: cc.JsonAsset) => {
|
||||
if (error) return reject(error);
|
||||
if (!asset || !asset.json || !Array.isArray(asset.json.BLOCK_INFO)
|
||||
|| !Array.isArray(asset.json.BLOCK_INFO[0])) {
|
||||
return reject(new Error("下一关配置无效: " + path));
|
||||
}
|
||||
resolve(asset.json.BLOCK_INFO[0]);
|
||||
});
|
||||
});
|
||||
}).catch(error => {
|
||||
if (this.nextBlocksLoading === loadNext) this.nextBlocksLoading = null;
|
||||
throw error;
|
||||
});
|
||||
this.nextBlocksLoading = loadNext;
|
||||
}
|
||||
// 只复用下一关 JSON;每次进关都检查图片来源,不能复用已完成 Promise 跳过日志/重试通知。
|
||||
return this.nextBlocksLoading.then(next => {
|
||||
if (this.BLOCK_INFO[0] !== blocks) return false;
|
||||
return BlockAssetManager.instance.prepareWindow(blocks, next,
|
||||
{ onRemoteRequired, currentLevel, nextLevel, stage }).then(ready =>
|
||||
ready && this.BLOCK_INFO[0] === blocks);
|
||||
});
|
||||
return BlockAssetManager.instance.prepareWindow(blocks,
|
||||
{ onRemoteRequired, currentLevel, stage }).then(ready =>
|
||||
ready && this.BLOCK_INFO[0] === blocks);
|
||||
}
|
||||
|
||||
/** 创建时不显示;仅远程图片调用 open。失效请求不能打开或关闭后续请求的 Loading。 */
|
||||
@@ -150,7 +109,7 @@ export class GameConfig {
|
||||
};
|
||||
}
|
||||
|
||||
/** 所有正式进关入口都在两关图片就绪后才切换 GameScene。 */
|
||||
/** 所有正式进关入口都在当前关图片就绪后才切换 GameScene。 */
|
||||
static enterGameSceneWhenReady(time = 0): void {
|
||||
const id = ++this.sceneLoadRequest;
|
||||
const scene = cc.director.getScene();
|
||||
|
||||
@@ -8,7 +8,6 @@ type ImageSource = "内存复用" | "本地缓存" | "临时缓存" | "远程下
|
||||
interface BlockWindowOptions {
|
||||
onRemoteRequired?: () => void;
|
||||
currentLevel?: number;
|
||||
nextLevel?: number;
|
||||
stage?: string;
|
||||
}
|
||||
|
||||
@@ -53,6 +52,9 @@ export default class BlockAssetManager {
|
||||
private committedPaths = new Set<string>();
|
||||
private activePaths = new Set<string>();
|
||||
private requestId = 0;
|
||||
private windowRequestId = 0;
|
||||
private committedRequestId = 0;
|
||||
private activeRequestId = 0;
|
||||
private foregroundLoads = 0;
|
||||
private backgroundRunning = false;
|
||||
private backgroundTimer: any = null;
|
||||
@@ -144,31 +146,28 @@ export default class BlockAssetManager {
|
||||
} catch (error) { return {}; }
|
||||
}
|
||||
|
||||
/** 当前场景还在显示时保留它的图片,切场景销毁后再释放旧关独占资源。 */
|
||||
async prepareWindow(current: any[], next: any[], options: BlockWindowOptions = {}): Promise<boolean> {
|
||||
/** 只准备当前关;当前场景仍在显示时保留它的图片。 */
|
||||
async prepareWindow(current: any[], options: BlockWindowOptions = {}): Promise<boolean> {
|
||||
const currentPaths = collectBlockTexturePaths(current);
|
||||
const nextPaths = collectBlockTexturePaths(next);
|
||||
const paths = new Set(currentPaths.concat(nextPaths));
|
||||
const paths = new Set(currentPaths);
|
||||
const id = ++this.requestId;
|
||||
const stage = options.stage || "进关";
|
||||
const currentLabel = "当前关" + (options.currentLevel || "");
|
||||
const nextLabel = "下一关" + (options.nextLevel || "");
|
||||
// 同时存在多个进关请求时,只通知最新窗口;共享加载失败后的远程重试也走这里。
|
||||
this.reportSource = (path, source) => {
|
||||
if (id !== this.requestId || !paths.has(path)) return;
|
||||
const levels = [currentPaths.indexOf(path) >= 0 ? currentLabel : "",
|
||||
nextPaths.indexOf(path) >= 0 ? nextLabel : ""].filter(Boolean).join(" / ");
|
||||
// console.log(`[Block图片][${stage}来源] ${levels} ${path}.png -> ${source},版本=${this.version}`);
|
||||
// console.log(`[Block图片][${stage}来源] ${currentLabel} ${path}.png -> ${source},版本=${this.version}`);
|
||||
if (source === "远程下载" && options.onRemoteRequired) options.onRemoteRequired();
|
||||
};
|
||||
this.windowPaths = paths;
|
||||
this.windowRequestId = id;
|
||||
this.foregroundLoads++;
|
||||
this.releaseUnused();
|
||||
try {
|
||||
await this.initialize();
|
||||
if (id !== this.requestId) return false;
|
||||
this.ensureUserCacheFolder();
|
||||
// console.log(`[Block图片][${stage}检查] ${currentLabel} / ${nextLabel},版本=${this.version},共${paths.size}张`);
|
||||
// console.log(`[Block图片][${stage}检查] ${currentLabel},版本=${this.version},共${paths.size}张`);
|
||||
const names = Array.from(paths);
|
||||
// 限制前台并发,后台队列在此期间让出下载机会。
|
||||
for (let i = 0; i < names.length; i += 4) {
|
||||
@@ -180,10 +179,12 @@ export default class BlockAssetManager {
|
||||
}
|
||||
if (id !== this.requestId) return false;
|
||||
this.committedPaths = paths;
|
||||
this.committedRequestId = id;
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (id !== this.requestId) return false;
|
||||
this.windowPaths = this.committedPaths;
|
||||
this.windowRequestId = this.committedRequestId;
|
||||
throw error;
|
||||
} finally {
|
||||
if (id === this.requestId) this.reportSource = null;
|
||||
@@ -197,11 +198,23 @@ export default class BlockAssetManager {
|
||||
const paths = collectBlockTexturePaths(blocks);
|
||||
paths.forEach(path => this.getFrame(path));
|
||||
this.activePaths = new Set(paths);
|
||||
this.activeRequestId = this.committedRequestId;
|
||||
this.releaseUnused();
|
||||
}
|
||||
|
||||
releaseScene(): void {
|
||||
const releasedRequestId = this.activeRequestId;
|
||||
this.activePaths.clear();
|
||||
this.activeRequestId = 0;
|
||||
// 若下一关或重开关卡已准备完成,即使图片集合相同,也不能被旧场景销毁流程释放。
|
||||
if (releasedRequestId && this.windowRequestId === releasedRequestId) {
|
||||
this.windowPaths = new Set<string>();
|
||||
this.windowRequestId = 0;
|
||||
}
|
||||
if (releasedRequestId && this.committedRequestId === releasedRequestId) {
|
||||
this.committedPaths = new Set<string>();
|
||||
this.committedRequestId = 0;
|
||||
}
|
||||
this.releaseUnused();
|
||||
}
|
||||
|
||||
@@ -211,7 +224,7 @@ export default class BlockAssetManager {
|
||||
return frame;
|
||||
}
|
||||
|
||||
/** 调试时可核对是否只有当前关、下一关,以及尚未销毁的旧场景资源。 */
|
||||
/** 调试时可核对是否只有当前关,以及转场期间尚未销毁的旧场景资源。 */
|
||||
getLoadedPaths(): string[] {
|
||||
return Array.from(this.frames.keys()).sort();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user