import { _decorator, AssetManager, assetManager, JsonAsset } from 'cc'; import IndexedDB from './IndexedDB'; type DeepReadonly = { readonly [P in keyof T]: T[P] extends object ? DeepReadonly : T[P] }; const ids: Map[]> = new Map(); const tables: Map>> = new Map(); export default class TableUtil { private static db: IndexedDB; // public static local_ver = 0; // private static _setData(name: string, json: any) { let idlist = ids.get(name); if (!idlist) { idlist = []; ids.set(name, idlist); } else { idlist.length = 0; } let map = new Map(); tables.set(name, map); for (let v in json) { const id = parseInt(v); idlist.push(id); const table = json[v]; table.id = id; map.set(id, table); } } /** * 获取一个表集所有id * @param name 表名 * @returns */ public static getIds(name: string): Readonly | null { if (ids.has(name)) { return ids.get(name) as Readonly; } console.error("没有配置表:" + name); return null; } /**是否有配置*/ public static has(name: string): boolean { return ids.has(name); } /** * 获取一个表集所有配置 * @param name 表名 * @returns */ public static getTables(name: string): DeepReadonly[] | null { if (tables.has(name)) { return Array.from(tables.get(name).values()); } console.error("没有配置表:" + name); return null; } /** * 获取一个表集 * @param name 表名 * @param id 表id * @returns */ public static getTable(name: string, id: number): DeepReadonly | null { if (tables.has(name)) { return tables.get(name).get(id); } else { console.error("没有配置表:" + name); return null; } } /**加载远程配置 * @param basepath 远程目录路径 * @param key 解密key */ public static async preloadRemoteConfig( gid: string, basepath: string, key: string ): Promise { try { if (!this.db) this.db = new IndexedDB(gid, 'table'); //1.加载版本文件 const asset = await new Promise((resolve, reject) => { const fullPath = `${basepath}/ver.json?t=${new Date().getTime()}`; assetManager.loadRemote(fullPath, (err: Error | null, asset: JsonAsset) => { err ? reject(err) : resolve(asset); }); }); const { ver, tables, isMerge } = asset.json; let local_ver: number = await this.db.getData(chsdk.md5HashStr('ver')); chsdk.log.log(`本地版本:${local_ver},远程版本版本: ${ver}, ${tables},是否合并: ${isMerge}`); this.local_ver = ver; if (local_ver && local_ver === Number.parseInt(ver)) { for (let i = 0; i < tables.length; i++) { const name = tables[i]; const data: string = await this.db.getData(chsdk.md5HashStr(name)); if (!data) { local_ver = 0; break; } this._setData(name, JSON.parse(chsdk.base64_xo_decode(data, name))); } if (local_ver) { chsdk.log.log(`本地配置加载完成! 版本: ${local_ver}, 共加载 ${tables.length} 个配置文件`); return; } } //远程更新 await this.db.clearAll(); if (isMerge) { //2.加载合并文件 const asset = await new Promise((resolve, reject) => { const fullPath = `${basepath}/merge.json?t=${new Date().getTime()}`; assetManager.loadRemote(fullPath, (err: Error | null, asset: JsonAsset) => { err ? reject(err) : resolve(asset); }); }); const jsonData = asset.json; tables.map(name => { const dd = JSON.parse(jsonData[name]); const ddd = dd.encrypt ? JSON.parse(chsdk.base64_xo_decode(dd.encrypt, key)) : dd; this._setData(name, ddd); console.log(chsdk.base64_xo_encode(ddd, key)); this.db.setData(chsdk.md5HashStr(name), chsdk.base64_xo_encode(JSON.stringify(ddd), name)); }); chsdk.log.log(`远程配置加载完成! 加载merge配置文件`); } else { // 2. 并行加载所有配置文件 const loadPromises = tables.map(name => new Promise((resolve, reject) => { const fullPath = `${basepath}/${name}.json?t=${new Date().getTime()}`; assetManager.loadRemote(fullPath, (err: Error | null, asset: JsonAsset) => { if (err) { chsdk.log.error(`配置文件加载失败: ${name}`, err); reject(err); } else { const jsonData = asset.json.encrypt ? JSON.parse(chsdk.base64_xo_decode(asset.json.encrypt, key)) : asset.json; this._setData(name, jsonData); this.db.setData(chsdk.md5HashStr(name), chsdk.base64_xo_encode(JSON.stringify(jsonData), name)); resolve(); } }); }) ); await Promise.all(loadPromises); chsdk.log.log(`远程配置加载完成! 共加载 ${tables.length} 个配置文件`); } this.db.setData(chsdk.md5HashStr('ver'), ver); } catch (err) { chsdk.log.error(`远程配置加载失败:`, err); throw err; } } }