@cc-component/cc-core 1.8.3 → 1.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,12 +4,18 @@ import { EnvironmentConfig, IConfig } from './IConfig';
4
4
  import { LayerType } from './LayerType';
5
5
  import { Canvas, director } from 'cc';
6
6
  import { ResourceManager } from '../home/ResourceManager';
7
- import { IBundleConfig, IInitConfig } from './CommonEnum';
7
+ import { IBundleConfig, IInitConfig, IWindowParam, SystemMessage } from './CommonEnum';
8
8
  import { ISceneParam } from '../interface/ISceneParam';
9
9
  import { BlockInputEvents } from 'cc';
10
10
  import { BaseLaunchComponent } from '../home/BaseLaunchComponent';
11
11
  import { AssetManager } from 'cc';
12
- import { assetManager } from 'cc';
12
+ import { Component } from 'cc';
13
+ import { Prefab, instantiate, isValid } from 'cc';
14
+ import { sp } from 'cc';
15
+ import { SkeletonAnim } from '../home/BaseSkeleton';
16
+ import { Sprite, SpriteFrame } from 'cc';
17
+ import { Game } from 'cc';
18
+ import { game } from 'cc';
13
19
 
14
20
  const { ccclass, property } = _decorator;
15
21
 
@@ -20,14 +26,24 @@ export class LayerUI {
20
26
  public get current_config(): EnvironmentConfig {
21
27
  return this.config.config[this.config.type]
22
28
  }
23
- /**获取指定ui层 */
24
- public GetLayer(type: LayerType) { return this.ui_map.get(type); }
29
+
30
+ private openWindowLayer: Map<string, string[]> = new Map();
31
+ private openedWindows: Map<string, Component> = new Map();
32
+ private openedWindowsConfig: Map<string, IBundleConfig> = new Map();
33
+
34
+ /** 最上层的UI */
35
+ public topUI(layer: LayerType) { return this.getTopView(layer) }
36
+ /**事件阻挡遮罩 */
37
+ public blockEvents: Node;
38
+ /**事件阻挡遮罩-用户输入事件时间(秒),小于0表示立即停止屏蔽触摸事件 */
39
+ public set blockEventsTime(value: number) {
40
+ this.blockEvents.active = true
41
+ this.launch.scheduleOnce(() => this.blockEvents.active = false, value);
42
+ }
25
43
 
26
44
  /**加载转圈窗口 */
27
- public loadingWindow: Node;
28
45
  public LayerWindow: Node;
29
46
 
30
-
31
47
  private ui_map: Map<string, Node> = new Map();
32
48
  bundleName: string = "";
33
49
 
@@ -36,22 +52,22 @@ export class LayerUI {
36
52
  window: { willOpen: (comp: IBundleConfig, param: any) => void, open: (comp: IBundleConfig) => void, willClose: (comp: IBundleConfig) => void, close: (comp: IBundleConfig) => void }
37
53
  scene: ISceneParam
38
54
  launch: BaseLaunchComponent;
55
+ scenesParm: ISceneParam = { param: undefined, bundleName: "", sceneName: "", };
39
56
 
40
57
  async loadConfig(params: IInitConfig) {
58
+ //创建常驻节点
41
59
  this.launch = await this.LoadLayerWindow(params);
42
60
  const parent = this.launch.node
43
61
  const data = await App.LoadAsset<JsonAsset>(params.bundleName, "config", JsonAsset)
44
62
  this.config = data.json as IConfig;
45
63
  App.ReleaseAssetPath('config', params.bundleName)
46
- //if (App.GetDebug()) Logger.debug(this.config)
47
-
64
+ //创建UI层
48
65
  const config = this.config;
49
66
  config.gui.forEach(element => {
50
67
  const node = LayerUI.CreateNnode(element.name);
51
68
  node.parent = parent
52
69
  this.ui_map.set(element.name, node);
53
70
  });
54
- this.initLog();
55
71
 
56
72
  //事件阻挡层
57
73
  [LayerType.LayerBlockEventsUI, LayerType.LayerBlockEventsNet].forEach(element => {
@@ -69,6 +85,8 @@ export class LayerUI {
69
85
  Promise.all(list).then(() => {
70
86
  this.launch.InitGame();
71
87
  });
88
+ // 👇 设置 FPS(例如 60 帧)
89
+ game.frameRate = this.current_config.frameRate;
72
90
  }
73
91
 
74
92
  public static CreateNnode(name: string) {
@@ -94,27 +112,343 @@ export class LayerUI {
94
112
  });
95
113
  }
96
114
  setBundleName(value: string) { this.bundleName = value; }
97
- initLog() {
98
- // const debug = this.config.debug
99
- // if (debug) {
100
- // if (App.GetDebug()) Logger.debug("是debug模式");
101
- // } else {
102
- // console.log("发布模式");
103
- // console.log = function () { }; // 关闭普通日志输出
104
- // console.warn = function () { }; // 关闭警告输出
105
- // // console.error = function () { }; // 关闭错误输出
106
- // console.info = function () { }
107
- // }
115
+ getTopView(layer: LayerType) {
116
+ const list = this.openWindowLayer.get(layer)
117
+ if (list && list.length > 0) { return this.openedWindows.get(list[list.length - 1]); }
118
+ else return null
108
119
  }
109
120
 
121
+ /**获取指定ui层 */
122
+ public GetLayer(type: LayerType) { return this.ui_map.get(type); }
110
123
  /**重置网络配置 */
111
- ResetHttpServer(config: EnvironmentConfig) {
112
- Object.assign(this.current_config, config);
124
+ public ResetHttpServer(config: EnvironmentConfig) { Object.assign(this.current_config, config); }
125
+
126
+
127
+
128
+ async OpenWindow<T extends Component>(config: IBundleConfig, param?: IWindowParam): Promise<T> {
129
+ return new Promise<T>(async (resolve, reject) => {
130
+ try {
131
+ const className = config.name ?? config.path.split('/').pop();
132
+ config.name = className;
133
+ if (this.IsWindowOpen(className)) {
134
+ const view = this.GetOpenWindow<Component>(config);
135
+ resolve(view as T);
136
+ //延迟100毫秒防止连点
137
+ setTimeout(() => { this.OpenBlockEvents(LayerType.LayerBlockEventsUI, false) }, 100);
138
+ return;
139
+ }
140
+ else if (this.IsWindowOpen(className)) {
141
+ Logger.warn("重复打开窗口-请检查", config.path)
142
+ return;
143
+ }
144
+ if (!param) { param = {} }
145
+ this.window?.willOpen?.(config, param)
146
+ this.OpenBlockEvents(LayerType.LayerBlockEventsUI, true)
147
+
148
+ const view = await this.LoadWindow<T>(config, param);
149
+
150
+ this.GetLayer(config.layer).addChild(view.node);
151
+
152
+ // 添加关闭事件监听
153
+ this.setupCloseListener(view, className);
154
+
155
+ if (config.is_load_sub) {
156
+ (view as any).root.active = false;
157
+ await new Promise<void>((resolve, reject) => { (view as any).finish_sub = resolve; });
158
+ (view as any).root.active = true;
159
+ }
160
+
161
+ view.node.getComponent(Widget)?.updateAlignment();
162
+
163
+ //隐藏底层的UI
164
+ this.ShowLayerUI(config, false)
165
+ //收集打开的窗口
166
+ if (!this.openWindowLayer.has(config.layer)) {
167
+ this.openWindowLayer.set(config.layer, []);//LayerUI层
168
+ }
169
+ const list = this.openWindowLayer.get(config.layer)
170
+ list.push(className);
171
+ const layerUI_list = this.openWindowLayer.get(LayerType.LayerUI)
172
+ if (layerUI_list && layerUI_list.length > 0) this.GetLayer(LayerType.LayerGame).active = false;
173
+ if (App.GetDebug()) Logger.debug('LayerType.LayerUI 打开窗口记录:', className, list);
174
+ App.Emit(SystemMessage.OpenWindow, className)
175
+ this.window?.open?.(config)
176
+
177
+ resolve(view);
178
+ //延迟100毫秒防止连点
179
+ setTimeout(() => { this.OpenBlockEvents(LayerType.LayerBlockEventsUI, false) }, 100);
180
+ } catch (error) {
181
+ console.error("打开窗口失败:", error);
182
+ this.CloseLoading()
183
+ reject(error);
184
+ }
185
+ });
113
186
  }
114
187
 
188
+ async LoadWindow<T extends Component>(config: IBundleConfig, param?: IWindowParam): Promise<T> {
189
+ return new Promise<T>(async (resolve, reject) => {
190
+ try {
191
+ const className = config.name ?? config.path.split('/').pop();
192
+ //@ts-ignore
193
+ config.name = className;
194
+ // 记录打开的窗口--先占位
195
+ if (config.is_record === undefined || config.is_record) {//默认记录
196
+ this.openedWindows.set(className, null);
197
+ this.openedWindowsConfig.set(className, config);
198
+ }
199
+ //await Await(1000)
200
+ const prefab = await ResourceManager.loadAsset<Prefab>(config.bundle, config.path)
201
+ const node = instantiate(prefab);
202
+
203
+ const view = ((node.getComponent(className)) || (node.addComponent(className))) as T;
204
+ if (config.is_record === undefined || config.is_record) {//默认记录
205
+ this.openedWindows.set(className, view);
206
+ this.openedWindowsConfig.set(className, config);
207
+ }
208
+ //@ts-ignore
209
+ view.config = config;
210
+ //@ts-ignore
211
+ if (param) view.param = param;
115
212
 
213
+ resolve(view);
214
+ } catch (error) {
215
+ console.error("加载窗口失败:", config.path, error);
216
+ reject(error);
217
+ }
218
+ });
219
+ }
116
220
 
221
+ async RootWindow<T extends Component>(config: IBundleConfig, param?: IWindowParam): Promise<T> {
222
+ await this.CloseAll([LayerType.LayerUI, LayerType.LayerDialog, LayerType.LayerPopUp])
223
+ return this.OpenWindow(config)
224
+ }
117
225
 
226
+ async CloseAll(layer_list: LayerType[]) {
227
+ const windows = this.GetOpenedWindowNames()
228
+ await new Promise<void>((resolve, reject) => {
229
+ //销毁已有的窗口
230
+ const destroyPromises: Promise<void>[] = []; // 用于存储每个销毁事件的 Promise
231
+ windows.forEach(className => {
232
+ const config = this.openedWindowsConfig.get(className);
233
+ if (layer_list.includes(config.layer)) {
234
+ const view = this.GetOpenWindow<any>(config);
235
+ // 创建一个 Promise 来等待 NODE_DESTROYED 事件完成
236
+ const destroyPromise = new Promise<void>((destroyResolve) => {
237
+ if (view.node && isValid(view.node, true)) {
238
+ view.node.once(Node.EventType.NODE_DESTROYED, () => {
239
+ destroyResolve(); // 当前节点销毁后 resolve
240
+ });
241
+ } else {
242
+ destroyResolve(); // 当前节点销毁后 resolve
243
+ }
244
+ });
245
+ destroyPromises.push(destroyPromise); // 将 Promise 添加到集合中
246
+ if (view && view.node && isValid(view.node, true)) {
247
+ /**关闭事件-当系统级关闭所有打开的界面时。如果关闭界面时需要执行自己的业务逻辑,使用此属性
248
+ * eventName:关闭方法名称
249
+ * param:参数
250
+ */
251
+ const closeEvent: { eventName: string, param?: any } = view.closeEvent?.()
252
+ if (closeEvent) {
253
+ const close: Function = view[closeEvent.eventName]
254
+ if (close) { close.call(view, closeEvent.param) }
255
+ }
256
+ if (view && view.node && view.node.isValid) view.node.destroy(); // 关闭窗口
257
+ }
258
+ }
259
+ })
260
+ // 等待所有销毁事件完成后再 resolve 外层 Promise
261
+ Promise.all(destroyPromises).then(() => resolve());
262
+ });
263
+ }
264
+ OpenBlockEvents(type: LayerType, is_show: boolean) { this.GetLayer(type).active = is_show; }
265
+ async CloseLoading() {
266
+ this.OpenBlockEvents(LayerType.LayerBlockEventsUI, false)
267
+ this.OpenBlockEvents(LayerType.LayerBlockEventsNet, false)
268
+ }
269
+
270
+
271
+ //#region 记录打开的窗口
272
+ // 关闭指定窗口
273
+ CloseWindow(className: string): boolean {
274
+ const instance = this
275
+ const window = instance.openedWindows.get(className);
276
+ if (window) {
277
+ try {
278
+ // 调用窗口的关闭方法(如果存在)
279
+ if (typeof (window as any).onClose === 'function') {
280
+ (window as any).onClose();
281
+ }
282
+ // 销毁节点
283
+ if (window.node && isValid(window.node, true)) {
284
+ window.node.destroy();
285
+ }
286
+ // 清除记录
287
+ instance.openedWindows.delete(className);
288
+ instance.openedWindowsConfig.delete(className);
289
+ return true;
290
+ } catch (error) {
291
+ console.error(`关闭窗口 ${className} 时出错:`, error);
292
+ return false;
293
+ }
294
+ } else {
295
+ Logger.warn(`窗口 ${className} 未找到或未打开`);
296
+ return false;
297
+ }
298
+ }
299
+
300
+ // 设置窗口关闭监听
301
+ private setupCloseListener(view: Component, className: string) {
302
+ const config = this.openedWindowsConfig.get(className);
303
+ const old_destroy = view.node.destroy
304
+ view.node.destroy = () => {
305
+ this.removeWindowRecord(className);
306
+ return old_destroy.call(view.node)
307
+ }
308
+ // 监听节点销毁事件
309
+ // view.node.once(Node.EventType.NODE_DESTROYED, () => {
310
+ // this.removeWindowRecord(className);
311
+ // });
312
+ }
313
+
314
+ ShowLayerUI(config: IBundleConfig, is_show: boolean) {
315
+ if (config.layer === LayerType.LayerUI) {
316
+ const list_layer = this.openWindowLayer.get(config.layer)
317
+ if (list_layer && list_layer.length > 0) {
318
+ const last_name = list_layer[list_layer.length - 1];
319
+ const com = this.openedWindows.get(last_name);
320
+ if (com && com.isValid) {
321
+ com.node.active = is_show;
322
+ }
323
+ } else {
324
+ this.GetLayer(LayerType.LayerGame).active = true;
325
+ }
326
+ }
327
+ }
328
+ // 移除窗口记录
329
+ private removeWindowRecord(className: string) {
330
+ const config = this.openedWindowsConfig.get(className);
331
+ const list_layer = this.openWindowLayer.get(config.layer)
332
+ list_layer.pop();//移除最后一个
333
+ if (config.layer === LayerType.LayerUI) {
334
+ this.ShowLayerUI(config, true)
335
+ }
336
+ if (App.GetDebug()) Logger.debug('LayerType.LayerUI 移除窗口记录:', className, list_layer);
337
+ this.openedWindows.delete(className);
338
+ this.openedWindowsConfig.delete(className);
339
+ App.Emit(SystemMessage.CloseWindow, className)
340
+ this.window?.close?.(config)
341
+ }
342
+
343
+ // 通过配置关闭窗口
344
+ CloseWindowTarget(config: IBundleConfig): boolean { return this.CloseWindow(config.name ?? config.path.split('/').pop()!); }
345
+
346
+ // 关闭所有窗口
347
+ CloseAllWindows(): number {
348
+ const instance = this;
349
+ let closedCount = 0;
350
+ // 创建副本以避免在迭代时修改Map
351
+ const windowsToClose = new Array(...this.openedWindows.entries());
352
+ for (const [className, window] of windowsToClose) {
353
+ if (this.CloseWindow(className)) {
354
+ closedCount++;
355
+ }
356
+ }
357
+ if (App.GetDebug()) Logger.debug(`共关闭 ${closedCount} 个窗口`);
358
+ return closedCount;
359
+ }
360
+
361
+ // 检查窗口是否已打开
362
+ IsWindowOpen(className: string): boolean { return this.openedWindows.has(className); }
363
+ // 获取已打开的窗口实例
364
+ GetOpenWindow<T extends Component>(config: IBundleConfig): T {
365
+ const className = config.name ?? config.path.split('/').pop();
366
+ const window = this.openedWindows.get(className);
367
+ return window ? window as T : null;
368
+ }
369
+ // 获取已打开的窗口实例
370
+ GetOpenWindows<T extends Component>(): T[] { return Array.from(this.openedWindows.values()) as T[]; }
371
+ // 获取已打开的窗口实例
372
+ GetOpenWindowsConfig(): IBundleConfig[] { return Array.from(this.openedWindowsConfig.values()); }
373
+ // 获取所有已打开的窗口名称
374
+ GetOpenedWindowNames(): string[] { return Array.from(this.openedWindows.keys()); }
375
+ OpenLoading(is_show: boolean) {
376
+ if (is_show) this.loading_call.open?.(() => { })
377
+ else this.loading_call.close?.()
378
+ this.OpenBlockEvents(LayerType.LayerBlockEventsUI, is_show)
379
+ }
380
+
381
+ /**播放skpine动画 */
382
+ PlaySpine(skeleton: sp.Skeleton, animations: { name: string, loop?: boolean, call?: (name?: string) => void, event?: (name?: string) => void }[]) { SkeletonAnim.Play(skeleton, animations); }
383
+
384
+ LoadSprite(sp: Sprite, params: { path: string, bundle?: string, callback?: () => void }) {
385
+ const path = params.path + '/spriteFrame'
386
+ const bundleName = params ? (params.bundle ?? 'game') : "game"
387
+ const sprite = App.GetAsset<SpriteFrame>(bundleName, path, SpriteFrame)
388
+ if (sprite) {
389
+ if (isValid(sp, true)) {
390
+ sp.spriteFrame = sprite;
391
+ params?.callback?.()
392
+ }
393
+ else {
394
+ if (App.GetDebug()) Logger.debug("图片已销毁")
395
+ }
396
+ return;
397
+ }
398
+ App.LoadAsset(bundleName, path, SpriteFrame).then((spriteFrame) => {
399
+ if (sp) {
400
+ if (isValid(sp, true)) {
401
+ sp.spriteFrame = spriteFrame;
402
+ params?.callback?.()
403
+ }
404
+ else {
405
+ if (App.GetDebug()) Logger.debug("图片已销毁")
406
+ }
407
+ }
408
+ })
409
+ }
410
+
411
+
412
+ LoadSpine(spine: sp.Skeleton, params: { path: string, bundle?: string, callback?: () => void }) {
413
+ const path = params.path
414
+ const bundleName = params ? (params.bundle ?? 'game') : "game"
415
+ const skeletonData = App.GetAsset<sp.SkeletonData>(bundleName, path, sp.SkeletonData)
416
+ if (skeletonData) {
417
+ if (spine) {
418
+ if (isValid(spine, true)) {
419
+ spine.skeletonData = skeletonData;
420
+ params?.callback?.()
421
+ }
422
+ }
423
+ return;
424
+ }
425
+ App.LoadAsset(bundleName, path, sp.SkeletonData).then((skeletonData) => {
426
+ if (spine) {
427
+ if (isValid(spine, true)) {
428
+ spine.skeletonData = skeletonData;
429
+ params?.callback?.()
430
+ }
431
+ else {
432
+ if (App.GetDebug()) Logger.debug("动画已销毁")
433
+ }
434
+ }
435
+ })
436
+ }
437
+
438
+ async OpenScene(param: ISceneParam) {
439
+ this.scenesParm = param;
440
+ this.OpenBlockEvents(LayerType.LayerBlockEventsUI, true)
441
+ await new Promise<void>(resolve => { this.progess?.open?.(param, () => { resolve() }) })
442
+ //关闭所有窗口
443
+ await this.CloseAll([LayerType.LayerUI, LayerType.LayerDialog, LayerType.LayerPopUp, LayerType.LayerGame])
444
+ let scene = await ResourceManager.loadScene(param.bundleName, param.sceneName, (pro) => { });
445
+ if (scene) {
446
+ ResourceManager.runScene(scene);
447
+ } else {
448
+ param.error?.("加载场景失败");
449
+ }
450
+ this.OpenBlockEvents(LayerType.LayerBlockEventsUI, false)
451
+ }
118
452
  }
119
453
 
120
454
 
@@ -32,7 +32,7 @@ export class App {
32
32
  /**存储层 */
33
33
  static get storage(): StorageManager { return this.instance._storage };
34
34
  /**场景参数 */
35
- static get scenesParm(): ISceneParam { return this.instance._scenesParm };
35
+ static get scenesParm(): ISceneParam { return this.instance._gui.scenesParm };
36
36
  /**时间管理 */
37
37
  static get time(): TimeManager { return this.instance._timeManager };
38
38
  /**多语言模块 */
@@ -69,9 +69,7 @@ export class App {
69
69
 
70
70
  time: number = 0
71
71
  isDebug = false;
72
- private openedWindows: Map<string, Component> = new Map();
73
- private openedWindowsConfig: Map<string, IBundleConfig> = new Map();
74
- private openWindowLayer: Map<string, string[]> = new Map();
72
+
75
73
 
76
74
  static async InitGameConfig(param: IInitConfig) {
77
75
  if (!EDITOR) { if (App.Ins._gui) { return } }
@@ -105,12 +103,6 @@ export class App {
105
103
  console.log("初始化完成")
106
104
  }
107
105
 
108
- static OpenLoading(is_show: boolean) {
109
- if (is_show) App.gui.loading_call.open?.(() => { })
110
- else App.gui.loading_call.close?.()
111
- App.OpenBlockEvents(LayerType.LayerBlockEventsUI, is_show)
112
- }
113
-
114
106
  /**
115
107
  * 加载资源并自动记录
116
108
  * @param bundleName Bundle 名称
@@ -139,395 +131,39 @@ export class App {
139
131
  static OnLoading(param: { open: (finish: () => void) => void, close: () => void }) { App.gui.loading_call = param; }
140
132
  static OnProgess(param: { open: (param: ISceneParam, finish: () => void) => void, close: (param: ISceneParam) => void, progess: (param: ISceneParam, progress: number, time?: number) => void }) { App.gui.progess = param; }
141
133
  static OnWindow(param: { willOpen: (comp: IBundleConfig) => void, open: (comp: IBundleConfig) => void, willClose: (comp: IBundleConfig) => void, close: (comp: IBundleConfig) => void }) { App.gui.window = param; }
142
- static async Requst<T>(config: IHttpConfig, params?: any, ext?: IExtData): Promise<{ code: number, data: T, msg: string }> {
143
- return new Promise<{ code: number, data: T, msg: string }>(async (originalResolve, originalReject) => {
144
- let retries = 0; // 当前重试次数
145
- const maxRetries = 5; // 最大重试次数
146
- // 内部辅助函数,用于执行请求逻辑
147
- const attemptRequest = async () => {
148
- try {
149
- App.OpenBlockEvents(LayerType.LayerBlockEventsNet, true);
150
-
151
- const url = App.gui.current_config.httpServer + config.url
152
- if (App.GetDebug()) Logger.debug(`${config.type === HttpType.GET ? "GET请求" : "POST请求"} url:${url} `, `\n 参数:`, params);
153
- let ret: HttpReturn<any>;
154
- if (config.type === HttpType.GET) {
155
- ret = await App.http.getJson(config.url, params);
156
- } else if (config.type === HttpType.POST) {
157
- ret = await App.http.postJson(config.url, params, ext);
158
- }
159
-
160
- if (App.GetDebug()) Logger.debug(`${config.type === HttpType.GET ? "GET请求" : "POST请求"} 结果 url:${url}\n`, ` 参数:`, params);
161
- if (App.GetDebug()) Logger.debug(`返回结果:`, ret.res);
162
- //Logger.warn(`返回结果:${JSON.stringify(ret.res)}`);
163
-
164
- App.OpenBlockEvents(LayerType.LayerBlockEventsNet, false);
165
- if (ret.isSucc) {
166
- originalResolve(ret.res); // 请求成功,调用原始 resolve
167
- } else {
168
- throw new Error(ret.err); // 请求失败,抛出错误以触发重试逻辑
169
- }
170
- } catch (error) {
171
- console.error(`请求失败: ${error.message}`);
172
- retries++;
173
-
174
- if (retries > maxRetries) {
175
- console.error("达到最大重试次数,请求失败");
176
- originalReject(error); // 达到最大重试次数后调用原始 reject
177
- return;
178
- }
179
-
180
- if (ext && ext.is_show_alert || (ext === undefined || ext.is_show_alert === undefined)) {
181
-
182
- const userChoice = await new Promise<boolean>((resolve) => {
183
- const finish = (isOk: boolean) => { resolve(isOk) }
184
- App.http.param?.open?.(finish)
185
- //param.callBack = (isOk: boolean) => resolve(isOk);
186
- });
187
-
188
- if (!userChoice) {
189
- if (App.GetDebug()) Logger.debug("用户取消请求");
190
- originalReject("取消了"); // 用户取消,调用原始 reject
191
- return;
192
- }
193
- }
194
- App.OpenBlockEvents(LayerType.LayerBlockEventsNet, true);
195
- // 继续重试,但避免直接递归调用
196
- setTimeout(attemptRequest, 100); // 使用 setTimeout 避免栈溢出
197
- }
198
- };
199
- // 开始第一次请求
200
- attemptRequest();
201
- });
202
- }
134
+ static async Requst<T>(config: IHttpConfig, params?: any, ext?: IExtData): Promise<{ code: number, data: T, msg: string }> { return App.http.Requst<T>(config, params, ext); }
203
135
  /**重置网络配置 */
204
136
  static ResetHttpServer(config: EnvironmentConfig) { App.instance._gui.ResetHttpServer(config); }
205
137
 
206
-
207
- static async OpenWindow<T extends Component>(config: IBundleConfig, param?: IWindowParam): Promise<T> {
208
- return new Promise<T>(async (resolve, reject) => {
209
- try {
210
- const className = config.name ?? config.path.split('/').pop();
211
- config.name = className;
212
- if (App.IsWindowOpen(className)) {
213
- const view = App.GetOpenWindow<Component>(config);
214
- resolve(view as T);
215
- //延迟100毫秒防止连点
216
- setTimeout(() => { App.OpenBlockEvents(LayerType.LayerBlockEventsUI, false) }, 100);
217
- return;
218
- }
219
- else if (App.IsWindowOpen(className)) {
220
- Logger.warn("重复打开窗口-请检查", config.path)
221
- return;
222
- }
223
- if (!param) { param = {} }
224
- App.gui.window?.willOpen?.(config, param)
225
- //console.error('打开:', Array.from(App.Instance.openedWindows.keys()), config.path);
226
- App.OpenBlockEvents(LayerType.LayerBlockEventsUI, true)
227
-
228
- const view = await App.LoadWindow<T>(config, param);
229
-
230
- App.gui.GetLayer(config.layer).addChild(view.node);
231
-
232
- // 添加关闭事件监听
233
- App.Ins.setupCloseListener(view, className);
234
-
235
- if (config.is_load_sub) {
236
- (view as any).root.active = false;
237
- await new Promise<void>((resolve, reject) => { (view as any).finish_sub = resolve; });
238
- (view as any).root.active = true;
239
- }
240
-
241
- view.node.getComponent(Widget)?.updateAlignment();
242
-
243
- //隐藏底层的UI
244
- App.instance.ShowLayerUI(config, false)
245
- //收集打开的窗口
246
- if (!App.Ins.openWindowLayer.has(config.layer)) {
247
- App.Ins.openWindowLayer.set(config.layer, []);//LayerUI层
248
- }
249
- const list = App.Ins.openWindowLayer.get(config.layer)
250
- list.push(className);
251
- const layerUI_list = App.Ins.openWindowLayer.get(LayerType.LayerUI)
252
- if (layerUI_list && layerUI_list.length > 0) App.gui.GetLayer(LayerType.LayerGame).active = false;
253
- if (App.GetDebug()) Logger.debug('LayerType.LayerUI 打开窗口记录:', className, list);
254
- App.Emit(SystemMessage.OpenWindow, className)
255
- App.gui.window?.open?.(config)
256
-
257
- resolve(view);
258
- //延迟100毫秒防止连点
259
- setTimeout(() => { App.OpenBlockEvents(LayerType.LayerBlockEventsUI, false) }, 100);
260
- } catch (error) {
261
- console.error("打开窗口失败:", error);
262
- App.CloseLoading()
263
- reject(error);
264
- }
265
- });
266
- }
267
-
268
- static async LoadWindow<T extends Component>(config: IBundleConfig, param?: IWindowParam): Promise<T> {
269
- return new Promise<T>(async (resolve, reject) => {
270
- try {
271
- const className = config.name ?? config.path.split('/').pop();
272
- //@ts-ignore
273
- config.name = className;
274
- // 记录打开的窗口--先占位
275
- if (config.is_record === undefined || config.is_record) {//默认记录
276
- App.Ins.openedWindows.set(className, null);
277
- App.Ins.openedWindowsConfig.set(className, config);
278
- }
279
- //await Await(1000)
280
- const prefab = await ResourceManager.loadAsset<Prefab>(config.bundle, config.path)
281
- const node = instantiate(prefab);
282
-
283
- const view = ((node.getComponent(className)) || (node.addComponent(className))) as T;
284
- if (config.is_record === undefined || config.is_record) {//默认记录
285
- App.Ins.openedWindows.set(className, view);
286
- App.Ins.openedWindowsConfig.set(className, config);
287
- }
288
- //@ts-ignore
289
- view.config = config;
290
- //@ts-ignore
291
- if (param) view.param = param;
292
-
293
- resolve(view);
294
- } catch (error) {
295
- console.error("加载窗口失败:", config.path, error);
296
- reject(error);
297
- }
298
- });
299
- }
300
-
301
- static async RootWindow<T extends Component>(config: IBundleConfig, param?: IWindowParam): Promise<T> {
302
- await App.CloseAll([LayerType.LayerUI, LayerType.LayerDialog, LayerType.LayerPopUp])
303
- return App.OpenWindow(config)
304
- }
305
-
306
- static async CloseAll(layer_list: LayerType[]) {
307
- const windows = App.GetOpenedWindowNames()
308
- await new Promise<void>((resolve, reject) => {
309
- //销毁已有的窗口
310
- const destroyPromises: Promise<void>[] = []; // 用于存储每个销毁事件的 Promise
311
- windows.forEach(className => {
312
- const config = App.Ins.openedWindowsConfig.get(className);
313
- if (layer_list.includes(config.layer)) {
314
- const view = App.GetOpenWindow<any>(config);
315
- // 创建一个 Promise 来等待 NODE_DESTROYED 事件完成
316
- const destroyPromise = new Promise<void>((destroyResolve) => {
317
- if (view.node && isValid(view.node, true)) {
318
- view.node.once(Node.EventType.NODE_DESTROYED, () => {
319
- destroyResolve(); // 当前节点销毁后 resolve
320
- });
321
- } else {
322
- destroyResolve(); // 当前节点销毁后 resolve
323
- }
324
- });
325
- destroyPromises.push(destroyPromise); // 将 Promise 添加到集合中
326
- if (view && view.node && isValid(view.node, true)) {
327
- /**关闭事件-当系统级关闭所有打开的界面时。如果关闭界面时需要执行自己的业务逻辑,使用此属性
328
- * eventName:关闭方法名称
329
- * param:参数
330
- */
331
- const closeEvent: { eventName: string, param?: any } = view.closeEvent?.()
332
- if (closeEvent) {
333
- const close: Function = view[closeEvent.eventName]
334
- if (close) { close.call(view, closeEvent.param) }
335
- }
336
- if (view && view.node && view.node.isValid) view.node.destroy(); // 关闭窗口
337
- }
338
- }
339
- })
340
- // 等待所有销毁事件完成后再 resolve 外层 Promise
341
- Promise.all(destroyPromises).then(() => resolve());
342
- });
343
- }
344
- static OpenBlockEvents(type: LayerType, is_show: boolean) { App.gui.GetLayer(type).active = is_show; }
345
- static async CloseLoading() {
346
- App.OpenBlockEvents(LayerType.LayerBlockEventsUI, false)
347
- App.OpenBlockEvents(LayerType.LayerBlockEventsNet, false)
348
- }
349
-
350
- static async OpenScene(param: ISceneParam) {
351
- App.OpenBlockEvents(LayerType.LayerBlockEventsUI, true)
352
- await new Promise<void>(resolve => { App.gui.progess?.open?.(param, () => { resolve() }) })
353
- //关闭所有窗口
354
- await App.CloseAll([LayerType.LayerUI, LayerType.LayerDialog, LayerType.LayerPopUp, LayerType.LayerGame])
355
- App.Ins._scenesParm = param
356
- let scene = await ResourceManager.loadScene(param.bundleName, param.sceneName, (pro) => { });
357
- if (scene) {
358
- ResourceManager.runScene(scene);
359
- } else {
360
- param.error?.("加载场景失败");
361
- }
362
- App.OpenBlockEvents(LayerType.LayerBlockEventsUI, false)
363
- }
364
-
365
- //#region 记录打开的窗口
366
- // 关闭指定窗口
367
- static CloseWindow(className: string): boolean {
368
- const instance = App.Ins;
369
- const window = instance.openedWindows.get(className);
370
- if (window) {
371
- try {
372
- // 调用窗口的关闭方法(如果存在)
373
- if (typeof (window as any).onClose === 'function') {
374
- (window as any).onClose();
375
- }
376
- // 销毁节点
377
- if (window.node && isValid(window.node, true)) {
378
- window.node.destroy();
379
- }
380
- // 清除记录
381
- instance.openedWindows.delete(className);
382
- instance.openedWindowsConfig.delete(className);
383
- return true;
384
- } catch (error) {
385
- console.error(`关闭窗口 ${className} 时出错:`, error);
386
- return false;
387
- }
388
- } else {
389
- Logger.warn(`窗口 ${className} 未找到或未打开`);
390
- return false;
391
- }
392
- }
393
-
394
- // 设置窗口关闭监听
395
- private setupCloseListener(view: Component, className: string) {
396
- const config = App.Ins.openedWindowsConfig.get(className);
397
- const old_destroy = view.node.destroy
398
- view.node.destroy = () => {
399
- this.removeWindowRecord(className);
400
- return old_destroy.call(view.node)
401
- }
402
- // 监听节点销毁事件
403
- // view.node.once(Node.EventType.NODE_DESTROYED, () => {
404
- // this.removeWindowRecord(className);
405
- // });
406
- }
407
-
408
- ShowLayerUI(config: IBundleConfig, is_show: boolean) {
409
- if (config.layer === LayerType.LayerUI) {
410
- const list_layer = App.Ins.openWindowLayer.get(config.layer)
411
- if (list_layer && list_layer.length > 0) {
412
- const last_name = list_layer[list_layer.length - 1];
413
- const com = this.openedWindows.get(last_name);
414
- if (com && com.isValid) {
415
- com.node.active = is_show;
416
- }
417
- } else {
418
- App.gui.GetLayer(LayerType.LayerGame).active = true;
419
- }
420
- }
421
- }
422
- // 移除窗口记录
423
- private removeWindowRecord(className: string) {
424
- const config = App.Ins.openedWindowsConfig.get(className);
425
- const list_layer = App.Ins.openWindowLayer.get(config.layer)
426
- list_layer.pop();//移除最后一个
427
- if (config.layer === LayerType.LayerUI) {
428
- this.ShowLayerUI(config, true)
429
- }
430
- if (App.GetDebug()) Logger.debug('LayerType.LayerUI 移除窗口记录:', className, list_layer);
431
- this.openedWindows.delete(className);
432
- this.openedWindowsConfig.delete(className);
433
- App.Emit(SystemMessage.CloseWindow, className)
434
- App.gui.window?.close?.(config)
435
- }
436
-
437
- // 通过配置关闭窗口
438
- static CloseWindowTarget(config: IBundleConfig): boolean { return App.CloseWindow(config.name ?? config.path.split('/').pop()!); }
439
-
440
- // 关闭所有窗口
441
- static CloseAllWindows(): number {
442
- const instance = App.Ins;
443
- let closedCount = 0;
444
- // 创建副本以避免在迭代时修改Map
445
- const windowsToClose = new Array(...instance.openedWindows.entries());
446
- for (const [className, window] of windowsToClose) {
447
- if (App.CloseWindow(className)) {
448
- closedCount++;
449
- }
450
- }
451
- if (App.GetDebug()) Logger.debug(`共关闭 ${closedCount} 个窗口`);
452
- return closedCount;
453
- }
454
-
455
- // 检查窗口是否已打开
456
- static IsWindowOpen(className: string): boolean { return App.Ins.openedWindows.has(className); }
457
- // 获取已打开的窗口实例
458
- static GetOpenWindow<T extends Component>(config: IBundleConfig): T {
459
- const className = config.name ?? config.path.split('/').pop();
460
- const window = App.Ins.openedWindows.get(className);
461
- return window ? window as T : null;
462
- }
463
- // 获取已打开的窗口实例
464
- static GetOpenWindows<T extends Component>(): T[] { return Array.from(App.Ins.openedWindows.values()) as T[]; }
465
- // 获取已打开的窗口实例
466
- static GetOpenWindowsConfig(): IBundleConfig[] { return Array.from(App.Ins.openedWindowsConfig.values()); }
467
- // 获取所有已打开的窗口名称
468
- static GetOpenedWindowNames(): string[] { return Array.from(App.Ins.openedWindows.keys()); }
469
-
470
-
471
138
  //#region 常用
472
139
  static Debug(isDebug: boolean) { this.instance.isDebug = isDebug }
473
140
  static GetDebug() { return this.instance.isDebug }
141
+ /**打开场景 */
142
+ static async OpenScene(param: ISceneParam) { await this.gui.OpenScene(param); }
474
143
  /**播放skpine动画 */
475
144
  static PlaySpine(skeleton: sp.Skeleton, animations: { name: string, loop?: boolean, call?: (name?: string) => void, event?: (name?: string) => void }[]) { SkeletonAnim.Play(skeleton, animations); }
476
-
477
- static LoadSprite(sp: Sprite, params: { path: string, bundle?: string, callback?: () => void }) {
478
- const path = params.path + '/spriteFrame'
479
- const bundleName = params ? (params.bundle ?? 'game') : "game"
480
- const sprite = App.GetAsset<SpriteFrame>(bundleName, path, SpriteFrame)
481
- if (sprite) {
482
- if (isValid(sp, true)) {
483
- sp.spriteFrame = sprite;
484
- params?.callback?.()
485
- }
486
- else {
487
- if (App.GetDebug()) Logger.debug("图片已销毁")
488
- }
489
- return;
490
- }
491
- App.LoadAsset(bundleName, path, SpriteFrame).then((spriteFrame) => {
492
- if (sp) {
493
- if (isValid(sp, true)) {
494
- sp.spriteFrame = spriteFrame;
495
- params?.callback?.()
496
- }
497
- else {
498
- if (App.GetDebug()) Logger.debug("图片已销毁")
499
- }
500
- }
501
- })
502
- }
503
-
504
-
505
- static LoadSpine(spine: sp.Skeleton, params: { path: string, bundle?: string, callback?: () => void }) {
506
- const path = params.path
507
- const bundleName = params ? (params.bundle ?? 'game') : "game"
508
- const skeletonData = App.GetAsset<sp.SkeletonData>(bundleName, path, sp.SkeletonData)
509
- if (skeletonData) {
510
- if (spine) {
511
- if (isValid(spine, true)) {
512
- spine.skeletonData = skeletonData;
513
- params?.callback?.()
514
- }
515
- }
516
- return;
517
- }
518
- App.LoadAsset(bundleName, path, sp.SkeletonData).then((skeletonData) => {
519
- if (spine) {
520
- if (isValid(spine, true)) {
521
- spine.skeletonData = skeletonData;
522
- params?.callback?.()
523
- }
524
- else {
525
- if (App.GetDebug()) Logger.debug("动画已销毁")
526
- }
527
- }
528
- })
529
- }
530
-
145
+ static LoadSprite(sp: Sprite, params: { path: string, bundle?: string, callback?: () => void }) { App.gui.LoadSprite(sp, params) }
146
+ static LoadSpine(spine: sp.Skeleton, params: { path: string, bundle?: string, callback?: () => void }) { App.gui.LoadSpine(spine, params) }
147
+ /**打开遮罩 */
148
+ static OpenBlockEvents(type: LayerType, is_show: boolean) { App.gui.OpenBlockEvents(type, is_show) }
149
+ /**加载窗口 */
150
+ static LoadWindow<T extends Component>(config: IBundleConfig, param?: IWindowParam): Promise<T> { return App.gui.LoadWindow(config, param) }
151
+ /**打开窗口 */
152
+ static OpenWindow<T extends Component>(config: IBundleConfig, param?: IWindowParam): Promise<T> { return App.gui.OpenWindow(config, param) }
153
+ /**打开窗口--根窗口 备注移除层: LayerType.LayerUI, LayerType.LayerDialog, LayerType.LayerPopUp 里的窗口*/
154
+ static RootWindow<T extends Component>(config: IBundleConfig, param?: IWindowParam): Promise<T> { return App.gui.RootWindow(config, param) }
155
+ /**通过配置关闭窗口*/
156
+ static CloseWindowTarget(config: IBundleConfig): boolean { return App.gui.CloseWindowTarget(config) }
157
+ /**获取所有已打开的窗口名称 */
158
+ static GetOpenedWindowNames(): string[] { return App.gui.GetOpenedWindowNames() }
159
+ /**获取已打开的窗口实例*/
160
+ static GetOpenWindow<T extends Component>(config: IBundleConfig): T { return App.gui.GetOpenWindow(config) }
161
+ // 获取已打开的窗口实例-对象
162
+ static GetOpenWindows<T extends Component>(): T[] { return App.gui.GetOpenWindows<T>() }
163
+ // 获取已打开的窗口实例-配置
164
+ static GetOpenWindowsConfig(): IBundleConfig[] { return App.gui.GetOpenWindowsConfig() }
165
+ /** 显示加载转圈*/
166
+ static OpenLoading(is_show: boolean) { App.gui.OpenLoading(is_show) }
531
167
  //#region 运行补丁
532
168
  // 默认实现函数
533
169
  static DefaultFunction(param?: any, callBack?: Function) {
@@ -552,6 +188,8 @@ s */
552
188
  }
553
189
 
554
190
  static PromiseQueue<T>(promises: Promise<T>[], onProgress: (completed: number, total: number) => void): Promise<T[]> { return App.Ins._tools.PromiseQueue(promises, onProgress) }
191
+
192
+
555
193
  }
556
194
 
557
195
  window.App = App;
@@ -114,10 +114,6 @@ declare global {
114
114
  function CloseWindowTarget(config: { path: string; bundle: string }): boolean;
115
115
  /**为 target 补全缺失的方法 */
116
116
  function RegisterModule(target: any)
117
- /**✅✅✅监听窗口的打开 */
118
- //App.On(SystemMessage.OpenWindow)
119
- /**✅✅✅监听窗口的关闭 */
120
- //App.On(SystemMessage.CloseWindow)
121
117
  /**获取所有已打开的窗口名称 */
122
118
  function GetOpenedWindowNames(): string[]
123
119
  /**获取已打开的窗口实例*/
@@ -132,8 +128,6 @@ declare global {
132
128
  /**开启打印日志 */
133
129
  function Debug(isDebug: boolean);
134
130
  function GetDebug(): boolean;
135
-
136
-
137
131
  /**=======================================✅✅常用工具======================= */
138
132
  // function TwoBezier(param1, param2, param3, param4);
139
133
  // function CustomEaseOutInWithSpeed(param)
@@ -5,7 +5,9 @@
5
5
  * @LastEditTime: 2022-09-09 18:10:50
6
6
  */
7
7
 
8
- import { IExtData } from "db://assets/cc-core";
8
+ import { HttpType, IExtData, IHttpConfig } from "../../../config/CommonEnum";
9
+ import { LayerType } from "../../../config/LayerType";
10
+
9
11
 
10
12
 
11
13
  /** HTTP请求返回值 */
@@ -304,4 +306,70 @@ export class HttpManager {
304
306
  }
305
307
  return result.substring(0, result.length - 1);
306
308
  }
309
+
310
+
311
+
312
+ /**扩展请求 */
313
+ async Requst<T>(config: IHttpConfig, params?: any, ext?: IExtData): Promise<{ code: number, data: T, msg: string }> {
314
+ return new Promise<{ code: number, data: T, msg: string }>(async (originalResolve, originalReject) => {
315
+ let retries = 0; // 当前重试次数
316
+ const maxRetries = 5; // 最大重试次数
317
+ // 内部辅助函数,用于执行请求逻辑
318
+ const attemptRequest = async () => {
319
+ try {
320
+ App.gui.OpenBlockEvents(LayerType.LayerBlockEventsNet, true);
321
+
322
+ const url = App.gui.current_config.httpServer + config.url
323
+ if (App.GetDebug()) Logger.debug(`${config.type === HttpType.GET ? "GET请求" : "POST请求"} url:${url} `, `\n 参数:`, params);
324
+ let ret: HttpReturn<any>;
325
+ if (config.type === HttpType.GET) {
326
+ ret = await App.http.getJson(config.url, params);
327
+ } else if (config.type === HttpType.POST) {
328
+ ret = await App.http.postJson(config.url, params, ext);
329
+ }
330
+
331
+ if (App.GetDebug()) Logger.debug(`${config.type === HttpType.GET ? "GET请求" : "POST请求"} 结果 url:${url}\n`, ` 参数:`, params);
332
+ if (App.GetDebug()) Logger.debug(`返回结果:`, ret.res);
333
+ //Logger.warn(`返回结果:${JSON.stringify(ret.res)}`);
334
+
335
+ App.gui.OpenBlockEvents(LayerType.LayerBlockEventsNet, false);
336
+ if (ret.isSucc) {
337
+ originalResolve(ret.res); // 请求成功,调用原始 resolve
338
+ } else {
339
+ throw new Error(ret.err); // 请求失败,抛出错误以触发重试逻辑
340
+ }
341
+ } catch (error) {
342
+ console.error(`请求失败: ${error.message}`);
343
+ retries++;
344
+
345
+ if (retries > maxRetries) {
346
+ console.error("达到最大重试次数,请求失败");
347
+ originalReject(error); // 达到最大重试次数后调用原始 reject
348
+ return;
349
+ }
350
+
351
+ if (ext && ext.is_show_alert || (ext === undefined || ext.is_show_alert === undefined)) {
352
+
353
+ const userChoice = await new Promise<boolean>((resolve) => {
354
+ const finish = (isOk: boolean) => { resolve(isOk) }
355
+ App.http.param?.open?.(finish)
356
+ //param.callBack = (isOk: boolean) => resolve(isOk);
357
+ });
358
+
359
+ if (!userChoice) {
360
+ if (App.GetDebug()) Logger.debug("用户取消请求");
361
+ originalReject("取消了"); // 用户取消,调用原始 reject
362
+ return;
363
+ }
364
+ }
365
+ App.gui.OpenBlockEvents(LayerType.LayerBlockEventsNet, true);
366
+ // 继续重试,但避免直接递归调用
367
+ setTimeout(attemptRequest, 100); // 使用 setTimeout 避免栈溢出
368
+ }
369
+ };
370
+ // 开始第一次请求
371
+ attemptRequest();
372
+ });
373
+ }
374
+
307
375
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cc-component/cc-core",
3
- "version": "1.8.3",
3
+ "version": "1.8.5",
4
4
  "engine": ">=3.8.6",
5
5
  "description": "系统组件添加常用扩展方法",
6
6
  "main": "index.ts",