JM_KA/assets/Script/Engine/HUDV2/AssetBundleMamagerV2.ts
2022-08-26 16:48:17 +08:00

522 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import BusinessTypeSetting from "../../_BusinessTypeSetting/BusinessTypeSetting";
import { CoroutineV2 } from "../CatanEngine/CoroutineV2/CoroutineV2";
import LocalStorageData from "../Data/LocalStorageData";
import Enum_Loading from "./Enum_Loading";
export default class AssetBundleMamagerV2 {
//#region static 屬性
private static _instance: AssetBundleMamagerV2 = null;
public static get Instance(): AssetBundleMamagerV2 { return AssetBundleMamagerV2._instance; }
//#endregion
//#region public 屬性
/** 本地VerList */
public LocalVerList: Enum_Loading.VerListObj = null;
/** 遠端VerList */
public RemoteVerList: JSON = null;
public DownloadList_Preview: Object = {};
/** 快取資源 */
public CachedFiles: Map<string, cc.Asset> = new Map<string, cc.Asset>();
//#endregion
//#region Lifecycle
constructor() {
AssetBundleMamagerV2._instance = this;
CC_PREVIEW && this._initdownloadList_Preview();
}
//#endregion
//#region 清除資料
/** 判斷更改編譯版號.清除BUNDLE記錄 */
public CheckCompileVersion(): void {
let oldCompileVersion: string = LocalStorageData.Instance.CompileVersion;
let newCompileVersion: string = BusinessTypeSetting.COMPILE_VERSION;
if (oldCompileVersion && oldCompileVersion !== newCompileVersion) {
this.ClearBundleData();
console.log("change compile version.");
}
LocalStorageData.Instance.CompileVersion = BusinessTypeSetting.COMPILE_VERSION;
}
/** 判斷更改PATCH環境.清除BUNDLE記錄 */
public CheckChangePatchUrl(): void {
let oldBundleUrl: string = LocalStorageData.Instance.BundleUrl;
let newBundleUrl: string = BusinessTypeSetting.UsePatch;
if (oldBundleUrl && oldBundleUrl !== newBundleUrl) {
this.ClearBundleData();
console.log("change patch url.");
}
LocalStorageData.Instance.BundleUrl = BusinessTypeSetting.UsePatch;
}
/** 清除Bundle資料 */
public ClearBundleData(): void {
cc.sys.localStorage.removeItem("LocalVerList");
cc.sys.localStorage.removeItem("RemoteVerList");
cc.assetManager.bundles.clear();
if (CC_JSB) {
cc.assetManager.cacheManager.clearCache();
console.log("clear bundle data.");
}
}
/** 清除所有資料重啟 */
public ClearAppDataToRestart(): void {
cc.sys.localStorage.clear();
cc.assetManager.bundles.clear();
if (CC_JSB) {
cc.assetManager.cacheManager.clearCache();
cc.game.restart();
} else {
window.location.reload();
}
}
//#endregion
//#region Custom Function
/**
* 取得Bundle
* @param {string} BundleName Bundle名稱
* @param {string} Version 版號
* @return {cc.AssetManager.Bundle} Bundle
*/
public *GetBundle(BundleName: string): IterableIterator<cc.AssetManager.Bundle> {
let self: this = this;
let bundle: cc.AssetManager.Bundle | boolean = cc.assetManager.getBundle(BundleName);
if (bundle) {
yield* this.GetDepsBundle(bundle.deps);
return bundle;
}
/** 判斷是不是要下載新版本 */
let isNeedUpdate: boolean = this.IsNeedUpdate(BundleName);
if (isNeedUpdate) {
// 下載新版本前需要先清除暫存
console.log(`removeCache: ${BundleName}`);
this.DelBundleCache(BundleName);
this.LocalVerList[BundleName].UseLocal = false;
}
/** Bundle路徑 */
let BundleUrl: string = BusinessTypeSetting.GetRemoteFileUrl(BundleName);
if (CC_DEV) {
// CC_DEVBundle路徑為: BundleName
// if (BundleName.indexOf("Script") != -1) {
BundleUrl = `${BundleName}`;
// } else {
// BundleUrl = "http://192.168.7.57/bj_casino/test/" + BundleName;
// }
} else if (this.LocalVerList[BundleName].UseLocal) {
// 本地Bundle路徑為: assets/assets/${BundleName}
BundleUrl = `assets/${BundleName}`;
}
if (CC_DEV) {
cc.assetManager.loadBundle(BundleUrl, (err: Error, resp: cc.AssetManager.Bundle) => {
if (err) {
console.error(err);
bundle = null;
return;
}
bundle = resp;
});
while (typeof bundle === "undefined") {
yield null;
}
} else if (BundleName.includes("Script")) {
bundle = yield* self.loadScriptBundle(BundleUrl);
} else {
if (CC_JSB && !this.LocalVerList[BundleName].UseLocal) {
let bundlePath: string = `${jsb.fileUtils.getWritablePath()}gamecaches/${BundleName}/`;
if (!jsb.fileUtils.isFileExist(bundlePath)) {
cc.assetManager.cacheManager["makeBundleFolder"](BundleName);
}
}
bundle = yield* self.loadUIBundle(BundleUrl);
}
if (bundle) {
yield* this.GetDepsBundle((<cc.AssetManager.Bundle>bundle).deps);
if (isNeedUpdate) {
// 下載成功後更改本地Bundle版本
self.LocalVerList[BundleName].Version = self.RemoteVerList[BundleName];
LocalStorageData.Instance.LocalVerList = JSON.stringify(self.LocalVerList);
}
}
return bundle;
}
/**
* 從Bundle取得資源
* @param {string} BundleUrl Bundle路徑
*/
public *loadScriptBundle(BundleUrl: string): IterableIterator<any> {
let fileName: string = `index.${CC_DEBUG ? "js" : "jsc"}`;
let fileUrl: string = `${BundleUrl}/${fileName}`;
let run: boolean = true;
let isSuceess: boolean = false;
cc.assetManager.loadScript(fileUrl, (err: Error) => {
if (err) {
console.error(`[Error] ${fileUrl}載入失敗 err: ${err}`);
run = false;
return;
}
isSuceess = true;
run = false;
});
while (run) {
yield null;
}
return isSuceess;
}
/**
* 從Bundle取得資源
* @param {string} BundleUrl Bundle路徑
*/
public *loadUIBundle(BundleUrl: string): IterableIterator<cc.AssetManager.Bundle> {
let fileName: string = "config.json";
let fileUrl: string = `${BundleUrl}/${fileName}`;
let data: any;
let run: boolean = true;
cc.assetManager.loadRemote(fileUrl, (err: Error, res: cc.JsonAsset) => {
if (err) {
console.error(`[Error] ${fileUrl}載入失敗 err: ${err}`);
return;
}
data = res.json;
run = false;
});
while (run) {
yield null;
}
let bundle: cc.AssetManager.Bundle = new cc.AssetManager.Bundle();
data.base = `${BundleUrl}/`;
bundle.init(data);
return bundle;
}
/**
* 取得Bundle
* @param {string} BundleName Bundle名稱
* @param {string} Version 版號
* @return {cc.AssetManager.Bundle} Bundle
*/
public *GetDepsBundle(deps: string[]): IterableIterator<any> {
if (!deps || deps.length <= 2) {
return;
}
let self: this = this;
let GetBundle_F_Arr: IterableIterator<any>[] = [];
for (const bundleName of deps) {
if (!["main", "internal"].includes(bundleName)) {
let GetBundle_F: IterableIterator<any> = function* (): IterableIterator<any> {
yield* self.GetBundle(bundleName);
}();
GetBundle_F_Arr.push(GetBundle_F);
}
}
yield CoroutineV2.Parallel(...GetBundle_F_Arr).Start();
}
/**
* 從Bundle取得資源
* @param {number} slotID slotID
* @param {Function} onFileProgress onFileProgress
*/
public *PreloadBundleScene(slotID: number, onFileProgress?: (finish: number, total: number, item: cc.AssetManager.RequestItem) => void): IterableIterator<any> {
let BundleName: string = `Game_${slotID}`;
let SourceName: string = `Slot${slotID}`;
let run: boolean = true;
let UpdateingData: Enum_Loading.UpdateingDataObj = new Enum_Loading.UpdateingDataObj(false);
let bundle: cc.AssetManager.Bundle = yield* AssetBundleMamagerV2.Instance.GetBundle(BundleName);
if (!bundle) {
console.error(`GetBundleSource Error BundleName: ${BundleName}`);
return UpdateingData;
}
bundle.preloadScene(SourceName, onFileProgress, function (error: Error): void {
if (error) {
console.error(error);
run = false;
return;
}
UpdateingData.IsUpdatecomplete = true;
run = false;
});
while (run) {
yield null;
}
return UpdateingData;
}
/**
* 從Bundle取得資源
* @param {cc.AssetManager.Bundle | string} BundleName Bundle名稱
* @param {string} SourceName 資源名稱
* @param {string} type 資源型別
* @return {any} Source
*/
public *GetBundleSource(BundleName: cc.AssetManager.Bundle | string, SourceName: string, type?: string | Bundle_Source_Type, onFileProgress?: (finish: number, total: number, item: cc.AssetManager.RequestItem) => void): IterableIterator<any> {
let bundle: cc.AssetManager.Bundle;
let source: any;
if (BundleName instanceof cc.AssetManager.Bundle) {
bundle = BundleName;
} else {
bundle = yield* AssetBundleMamagerV2.Instance.GetBundle(BundleName);
if (!bundle) {
cc.error(`GetBundleSource Error BundleName: ${BundleName}`);
return null;
}
}
switch (type) {
case Bundle_Source_Type.Scene: {
bundle.loadScene(SourceName, onFileProgress, function (err: Error, scene: cc.SceneAsset): void {
if (err) {
cc.error(err);
return null;
}
// cc.director.runScene(scene);
source = scene;
});
break;
}
case Bundle_Source_Type.Json: {
bundle.load(SourceName, onFileProgress, function (err: Error, json: cc.JsonAsset): void {
if (err) {
cc.error(err);
return null;
}
// source = JSON.parse(json["_nativeAsset"]);
source = json;
});
break;
}
case Bundle_Source_Type.Prefab: {
bundle.load(SourceName, cc.Prefab, onFileProgress, function (err: Error, prefab: cc.Asset): void {
if (err) {
cc.error(err);
return null;
}
// source = JSON.parse(json["_nativeAsset"]);
source = prefab;
});
break;
}
default:
bundle.load(SourceName, function (err: Error, any: any): void {
if (err) {
cc.error(err);
return null;
}
source = any;
});
break;
}
while (typeof source === "undefined") {
yield null;
}
return source;
}
/**
* 從Bundle取得資源(不卡協成)
* @param {string} bundleName bundleName
* @param {string} sourcePath Bundle資料夾下的路徑
*/
public static GetBundleSourceV2(bundleName: cc.bundleName | string, sourcePath: string): cc.Prefab {
let bundle: cc.AssetManager.Bundle = cc.assetManager.getBundle(bundleName);
if (!bundle) {
cc.error(`GetBundleSourceV2 getBundle error bundleName: ${bundleName}`);
return null;
}
let source: cc.Prefab = bundle.get(sourcePath, cc.Prefab);
if (!source) {
cc.error(`GetBundleSourceV2 bundle.get error bundleName: ${bundleName}, sourcePath: ${sourcePath}`);
return null;
}
return source;
}
/**
* 釋放Bundle
* @param {string} slotID slotID
*/
public *BundleRelease(slotID: number): IterableIterator<any> {
let gameName: string = `Game_${slotID}`;
let sceneName: string = `Slot${slotID}`;
let bundle: cc.AssetManager.Bundle = cc.assetManager.getBundle(gameName);
if (!bundle) {
cc.log(`BundleRelease Error BundleName: ${gameName}`);
return;
}
this.ReleaseSlotCache(slotID);
}
/**
* 從cachedFiles刪除暫存資源
* @param {string} BundleName Bundle名稱
*/
public DelBundleCache(BundleName: string): void {
if (CC_BUILD && cc.sys.isNative) {
let cachedFiles: Object = cc.assetManager.cacheManager.cachedFiles["_map"];
let delcache: string = BusinessTypeSetting.GetRemoteFileUrl(BundleName) + "/";
for (let cached of Object.keys(cachedFiles)) {
if (cached.includes(delcache)) {
cc.assetManager.cacheManager.removeCache(cached);
// console.log(`removeCache: ${cached}`);
}
}
}
}
/**
* 從cachedFiles釋放暫存資源
* @param {number} slotID slotID
*/
public ReleaseSlotCache(slotID: number): void {
if (!CC_JSB) {
return;
}
let delcachedKeys: string[] = [];
let cachedFiles: Map<string, cc.Asset> = this.CachedFiles;
let delcache_group: string[] = [`shared/jsons`, `Slot/Slot${slotID}`, "sounds/Slot/Default", "submit.txt"];
cachedFiles.forEach((cached: cc.Asset, key: string, map: Map<string, cc.Asset>) => {
for (var i: number = 0; i < delcache_group.length; ++i) {
let delcache: string = delcache_group[i];
if (key.includes(delcache)) {
cc.assetManager.releaseAsset(cached);
delcachedKeys.push(key);
break;
}
}
});
for (var i: number = 0; i < delcachedKeys.length; ++i) {
this.CachedFiles.delete(delcachedKeys[i]);
}
}
/**
* 判斷要不要更新
* @param {string} BundleName Bundle名稱
*/
public IsNeedUpdate(BundleName: string): boolean {
let isNeedUpdate: boolean;
// 判斷本地有無Bundle資料
if (this.LocalVerList[BundleName] && !this.LocalVerList[BundleName].HasBundle) {
if (this.RemoteVerList[BundleName]) {
// 改成有包過Bundle了,重新走下面流程
this.LocalVerList[BundleName] = null;
} else {
return true;
}
}
if (!this.LocalVerList[BundleName]) {
// 本地無Bundle資料需要新增
this.LocalVerList[BundleName] = new Enum_Loading.BundleDataObj();
LocalStorageData.Instance.LocalVerList = JSON.stringify(this.LocalVerList);
}
let version: string = this.RemoteVerList[BundleName];
if (!version) {
// !version代表還沒包Bundle
this.LocalVerList[BundleName].HasBundle = false;
LocalStorageData.Instance.LocalVerList = JSON.stringify(this.LocalVerList);
return true;
} else if (version === "0") {
// version === "0" 代表要使用本體Bundle
this.LocalVerList[BundleName].UseLocal = true;
this.LocalVerList[BundleName].Version = "0";
LocalStorageData.Instance.LocalVerList = JSON.stringify(this.LocalVerList);
}
isNeedUpdate = AssetBundleMamagerV2.Instance.versionCompareHandle(this.LocalVerList[BundleName].Version, this.RemoteVerList[BundleName]) !== 0 ? true : false;
return isNeedUpdate;
}
/**
* 比對版號(熱更能從1.0.0更新到2.0.0從2.0.0回退到1.0.0)
* 官方提供的版本比較函數,只有服務端版本>客戶端版本時才會進行更新。所以不能從2.0.0回退到1.0.0版本。
* @param {string} versionA 本地版號
* @param {string} versionB 遠程版號
* @return {number} num = -1 須更新
* @return {number} num = 0 不須更新
*/
public versionCompareHandle(versionA: string, versionB: string): number {
// console.log("Ver A " + versionA + "VerB " + versionB);
var vA: string[] = versionA.split(".");
var vB: string[] = versionB.split(".");
// 長度不相等,則進行更新
if (vA.length !== vB.length) {
return -1;
}
for (var i: number = 0; i < vA.length; ++i) {
var a: number = +vA[i];
var b: number = +vB[i] || 0;
if (a === b) {
// 數字相同,則跳過
continue;
} else {
// 數字不同(且版號比目標低),則進行更新
return a - b;
}
}
// 長度相等且數字相等,則不更新
return 0;
}
//#endregion
//#region DownloadList_Preview
private _initdownloadList_Preview(): void {
this.DownloadList_Preview = JSON.parse(LocalStorageData.Instance.DownloadList_Preview);
this.DownloadList_Preview = this.DownloadList_Preview ? this.DownloadList_Preview : {};
}
public GetIsDownload_Preview(slotID: number): boolean {
if (!this.DownloadList_Preview[slotID]) {
this.SetIsDownload_Preview(slotID, false);
}
return this.DownloadList_Preview[slotID];
}
public SetIsDownload_Preview(slotID: number, isDownload: boolean = true): void {
this.DownloadList_Preview[slotID] = isDownload;
LocalStorageData.Instance.DownloadList_Preview = JSON.stringify(this.DownloadList_Preview);
}
//#endregion
}
//#region enum
/** Bundle資源類型 */
export enum Bundle_Source_Type {
/** Json */
Json = "json",
/** Scene */
Scene = "scene",
/** Prefab */
Prefab = "prefab"
}
//#endregion