JM_KA/assets/Script/Engine/HUDV2/AssetBundleMamagerV2.ts

522 lines
16 KiB
TypeScript
Raw Normal View History

2022-08-26 16:48:17 +08:00
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.02.0.02.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