TableUtil.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import { _decorator, AssetManager, assetManager, JsonAsset } from 'cc';
  2. import IndexedDB from './IndexedDB';
  3. type DeepReadonly<T> = { readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P] };
  4. const ids: Map<string, Readonly<number>[]> = new Map();
  5. const tables: Map<string, ReadonlyMap<number, DeepReadonly<any>>> = new Map();
  6. export default class TableUtil {
  7. private static db: IndexedDB;
  8. //
  9. public static local_ver = 0;
  10. //
  11. private static _setData(name: string, json: any) {
  12. let idlist = ids.get(name);
  13. if (!idlist) {
  14. idlist = [];
  15. ids.set(name, idlist);
  16. } else {
  17. idlist.length = 0;
  18. }
  19. let map = new Map<number, any>();
  20. tables.set(name, map);
  21. for (let v in json) {
  22. const id = parseInt(v);
  23. idlist.push(id);
  24. const table = json[v];
  25. table.id = id;
  26. map.set(id, table);
  27. }
  28. }
  29. /**
  30. * 获取一个表集所有id
  31. * @param name 表名
  32. * @returns
  33. */
  34. public static getIds(name: string): Readonly<number[]> | null {
  35. if (ids.has(name)) {
  36. return ids.get(name) as Readonly<number[]>;
  37. }
  38. console.error("没有配置表:" + name);
  39. return null;
  40. }
  41. /**是否有配置*/
  42. public static has(name: string): boolean {
  43. return ids.has(name);
  44. }
  45. /**
  46. * 获取一个表集所有配置
  47. * @param name 表名
  48. * @returns
  49. */
  50. public static getTables(name: string): DeepReadonly<any>[] | null {
  51. if (tables.has(name)) {
  52. return Array.from(tables.get(name).values());
  53. }
  54. console.error("没有配置表:" + name);
  55. return null;
  56. }
  57. /**
  58. * 获取一个表集
  59. * @param name 表名
  60. * @param id 表id
  61. * @returns
  62. */
  63. public static getTable(name: string, id: number): DeepReadonly<any> | null {
  64. if (tables.has(name)) {
  65. return tables.get(name).get(id);
  66. } else {
  67. console.error("没有配置表:" + name);
  68. return null;
  69. }
  70. }
  71. /**加载远程配置
  72. * @param basepath 远程目录路径
  73. * @param key 解密key
  74. */
  75. public static async preloadRemoteConfig(
  76. gid: string,
  77. basepath: string,
  78. key: string
  79. ): Promise<void> {
  80. try {
  81. if (!this.db) this.db = new IndexedDB(gid, 'table');
  82. //1.加载版本文件
  83. const asset = await new Promise<JsonAsset>((resolve, reject) => {
  84. const fullPath = `${basepath}/ver.json?t=${new Date().getTime()}`;
  85. assetManager.loadRemote(fullPath, (err: Error | null, asset: JsonAsset) => {
  86. err ? reject(err) : resolve(asset);
  87. });
  88. });
  89. const { ver, tables, isMerge } = asset.json;
  90. let local_ver: number = await this.db.getData(chsdk.md5HashStr('ver'));
  91. chsdk.log.log(`本地版本:${local_ver},远程版本版本: ${ver}, ${tables},是否合并: ${isMerge}`);
  92. this.local_ver = ver;
  93. if (local_ver && local_ver === Number.parseInt(ver)) {
  94. for (let i = 0; i < tables.length; i++) {
  95. const name = tables[i];
  96. const data: string = await this.db.getData(chsdk.md5HashStr(name));
  97. if (!data) {
  98. local_ver = 0;
  99. break;
  100. }
  101. this._setData(name, JSON.parse(chsdk.base64_xo_decode(data, name)));
  102. }
  103. if (local_ver) {
  104. chsdk.log.log(`本地配置加载完成! 版本: ${local_ver}, 共加载 ${tables.length} 个配置文件`);
  105. return;
  106. }
  107. }
  108. //远程更新
  109. await this.db.clearAll();
  110. if (isMerge) {
  111. //2.加载合并文件
  112. const asset = await new Promise<JsonAsset>((resolve, reject) => {
  113. const fullPath = `${basepath}/merge.json?t=${new Date().getTime()}`;
  114. assetManager.loadRemote(fullPath, (err: Error | null, asset: JsonAsset) => {
  115. err ? reject(err) : resolve(asset);
  116. });
  117. });
  118. const jsonData = asset.json;
  119. tables.map(name => {
  120. const dd = JSON.parse(jsonData[name]);
  121. const ddd = dd.encrypt ? JSON.parse(chsdk.base64_xo_decode(dd.encrypt, key)) : dd;
  122. this._setData(name, ddd);
  123. console.log(chsdk.base64_xo_encode(ddd, key));
  124. this.db.setData(chsdk.md5HashStr(name), chsdk.base64_xo_encode(JSON.stringify(ddd), name));
  125. });
  126. chsdk.log.log(`远程配置加载完成! 加载merge配置文件`);
  127. } else {
  128. // 2. 并行加载所有配置文件
  129. const loadPromises = tables.map(name =>
  130. new Promise<void>((resolve, reject) => {
  131. const fullPath = `${basepath}/${name}.json?t=${new Date().getTime()}`;
  132. assetManager.loadRemote(fullPath, (err: Error | null, asset: JsonAsset) => {
  133. if (err) {
  134. chsdk.log.error(`配置文件加载失败: ${name}`, err);
  135. reject(err);
  136. } else {
  137. const jsonData = asset.json.encrypt ? JSON.parse(chsdk.base64_xo_decode(asset.json.encrypt, key)) : asset.json;
  138. this._setData(name, jsonData);
  139. this.db.setData(chsdk.md5HashStr(name), chsdk.base64_xo_encode(JSON.stringify(jsonData), name));
  140. resolve();
  141. }
  142. });
  143. })
  144. );
  145. await Promise.all(loadPromises);
  146. chsdk.log.log(`远程配置加载完成! 共加载 ${tables.length} 个配置文件`);
  147. }
  148. this.db.setData(chsdk.md5HashStr('ver'), ver);
  149. } catch (err) {
  150. chsdk.log.error(`远程配置加载失败:`, err);
  151. throw err;
  152. }
  153. }
  154. }