@gongxh/bit-core 0.0.3 → 0.0.6

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.
package/dist/bit-core.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { sys, view, ResolutionPolicy, screen, Component, _decorator, game, director } from 'cc';
1
+ import { view, ResolutionPolicy, game, screen, Component, sys, _decorator, director, macro } from 'cc';
2
2
 
3
3
  /**
4
4
  * @Author: Gongxh
@@ -58,142 +58,6 @@ function error(...args) {
58
58
  KUNPO_DEBUG && console.error("bit-framework:", ...args);
59
59
  }
60
60
 
61
- /**
62
- * @Author: Gongxh
63
- * @Date: 2024-12-07
64
- * @Description: 平台相关
65
- */
66
- var PlatformType;
67
- (function (PlatformType) {
68
- PlatformType[PlatformType["Android"] = 1] = "Android";
69
- PlatformType[PlatformType["IOS"] = 2] = "IOS";
70
- PlatformType[PlatformType["HarmonyOS"] = 3] = "HarmonyOS";
71
- /** 微信小游戏 */
72
- PlatformType[PlatformType["WX"] = 4] = "WX";
73
- /** 支付宝小游戏 */
74
- PlatformType[PlatformType["Alipay"] = 5] = "Alipay";
75
- /** 字节小游戏 */
76
- PlatformType[PlatformType["Bytedance"] = 6] = "Bytedance";
77
- /** 华为快游戏 */
78
- PlatformType[PlatformType["HuaweiQuick"] = 7] = "HuaweiQuick";
79
- /** 其他都为Browser */
80
- PlatformType[PlatformType["Browser"] = 1001] = "Browser";
81
- })(PlatformType || (PlatformType = {}));
82
- class Platform {
83
- }
84
- /**
85
- * 是否为原生平台
86
- * @type {boolean}
87
- */
88
- Platform.isNative = false;
89
- /**
90
- * 是否为移动平台
91
- * @type {boolean}
92
- */
93
- Platform.isMobile = false;
94
- /**
95
- * 是否为原生移动平台
96
- * @type {boolean}
97
- */
98
- Platform.isNativeMobile = false;
99
- /**
100
- * 是否为安卓平台
101
- * @type {boolean}
102
- */
103
- Platform.isAndroid = false;
104
- /**
105
- * 是否为IOS平台
106
- * @type {boolean}
107
- */
108
- Platform.isIOS = false;
109
- /**
110
- * 是否为HarmonyOS平台
111
- * @type {boolean}
112
- */
113
- Platform.isHarmonyOS = false;
114
- /**
115
- * 是否为微信小游戏
116
- * @type {boolean}
117
- */
118
- Platform.isWX = false;
119
- /**
120
- * 是否为支付宝小游戏
121
- * @type {boolean}
122
- */
123
- Platform.isAlipay = false;
124
- /**
125
- * 是否为字节小游戏
126
- * @type {boolean}
127
- */
128
- Platform.isBytedance = false;
129
- /**
130
- * 是否是华为快游戏
131
- * @type {boolean}
132
- */
133
- Platform.isHuaweiQuick = false;
134
- /**
135
- * 是否为浏览器
136
- * @type {boolean}
137
- */
138
- Platform.isBrowser = false;
139
- /**
140
- * 平台初始化器
141
- * @internal
142
- */
143
- class PlatformInitializer {
144
- constructor() {
145
- this.initPlatform();
146
- }
147
- /**
148
- * 初始化平台
149
- * @internal
150
- */
151
- initPlatform() {
152
- // 处理平台判断
153
- Platform.isNative = sys.isNative;
154
- Platform.isMobile = sys.isMobile;
155
- Platform.isNativeMobile = sys.isNative && sys.isMobile;
156
- switch (sys.os) {
157
- case sys.OS.ANDROID:
158
- Platform.isAndroid = true;
159
- debug("系统类型 Android");
160
- break;
161
- case sys.OS.IOS:
162
- Platform.isIOS = true;
163
- debug("系统类型 IOS");
164
- break;
165
- case sys.OS.OPENHARMONY:
166
- Platform.isHarmonyOS = true;
167
- debug("系统类型 HarmonyOS");
168
- break;
169
- }
170
- switch (sys.platform) {
171
- case sys.Platform.WECHAT_GAME:
172
- Platform.isWX = true;
173
- Platform.platform = PlatformType.WX;
174
- break;
175
- case sys.Platform.ALIPAY_MINI_GAME:
176
- Platform.isAlipay = true;
177
- Platform.platform = PlatformType.Alipay;
178
- break;
179
- case sys.Platform.BYTEDANCE_MINI_GAME:
180
- Platform.isBytedance = true;
181
- Platform.platform = PlatformType.Bytedance;
182
- break;
183
- case sys.Platform.HUAWEI_QUICK_GAME:
184
- Platform.isHuaweiQuick = true;
185
- Platform.platform = PlatformType.HuaweiQuick;
186
- break;
187
- default:
188
- // 其他都设置为浏览器
189
- Platform.isBrowser = true;
190
- Platform.platform = PlatformType.Browser;
191
- break;
192
- }
193
- debug(`platform: ${PlatformType[Platform.platform]}`);
194
- }
195
- }
196
-
197
61
  /**
198
62
  * @Author: Gongxh
199
63
  * @Date: 2024-12-08
@@ -202,35 +66,6 @@ class PlatformInitializer {
202
66
  class Screen {
203
67
  }
204
68
 
205
- /******************************************************************************
206
- Copyright (c) Microsoft Corporation.
207
-
208
- Permission to use, copy, modify, and/or distribute this software for any
209
- purpose with or without fee is hereby granted.
210
-
211
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
212
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
213
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
214
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
215
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
216
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
217
- PERFORMANCE OF THIS SOFTWARE.
218
- ***************************************************************************** */
219
- /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
220
-
221
-
222
- function __decorate(decorators, target, key, desc) {
223
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
224
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
225
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
226
- return c > 3 && r && Object.defineProperty(target, key, r), r;
227
- }
228
-
229
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
230
- var e = new Error(message);
231
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
232
- };
233
-
234
69
  /**
235
70
  * @Author: Gongxh
236
71
  * @Date: 2024-12-07
@@ -238,16 +73,26 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
238
73
  */
239
74
  class Adapter {
240
75
  constructor() {
76
+ /**
77
+ * 监听器
78
+ * @internal
79
+ */
241
80
  this.listeners = [];
242
81
  }
243
82
  /**
244
- * 外部监听屏幕尺寸发生变化
83
+ * 添加屏幕尺寸发生变化的监听
245
84
  * @param listener 监听器
246
- * @internal
247
85
  */
248
86
  addResizeListener(listener) {
249
87
  this.listeners.push(listener);
250
88
  }
89
+ /**
90
+ * 移除屏幕尺寸发生变化的监听
91
+ * @param listener 监听器
92
+ */
93
+ removeResizeListener(listener) {
94
+ this.listeners = this.listeners.filter(l => l !== listener);
95
+ }
251
96
  /**
252
97
  * 初始化适配器
253
98
  * @internal
@@ -316,75 +161,1252 @@ class Adapter {
316
161
  }
317
162
  }
318
163
 
164
+ /******************************************************************************
165
+ Copyright (c) Microsoft Corporation.
166
+
167
+ Permission to use, copy, modify, and/or distribute this software for any
168
+ purpose with or without fee is hereby granted.
169
+
170
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
171
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
172
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
173
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
174
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
175
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
176
+ PERFORMANCE OF THIS SOFTWARE.
177
+ ***************************************************************************** */
178
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
179
+
180
+
181
+ function __decorate(decorators, target, key, desc) {
182
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
183
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
184
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
185
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
186
+ }
187
+
188
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
189
+ var e = new Error(message);
190
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
191
+ };
192
+
319
193
  /**
320
194
  * @Author: Gongxh
321
- * @Date: 2024-12-08
322
- * @Description:
195
+ * @Date: 2024-12-07
196
+ * @Description: 二叉堆(默认最小堆) 支持最大堆和最小堆
323
197
  */
324
- class CocosAdapter extends Adapter {
198
+ class HeapNode {
199
+ }
200
+ class BinaryHeap {
201
+ constructor(capacity) {
202
+ this._size = 0;
203
+ this._capacity = capacity <= 0 ? 4 : capacity;
204
+ this._nodes = new Array(this._capacity);
205
+ }
325
206
  /**
326
- * 获取屏幕像素尺寸
327
- * @returns {Size}
328
- * @internal
207
+ * 清空
329
208
  */
330
- getScreenSize() {
331
- let windowSize = screen.windowSize;
332
- let width = Math.ceil(windowSize.width / view.getScaleX());
333
- let height = Math.ceil(windowSize.height / view.getScaleY());
334
- return { width, height };
209
+ clear() {
210
+ this._size = 0;
335
211
  }
336
212
  /**
337
- * 获取设计尺寸
338
- * @returns {Size}
339
- * @internal
213
+ * 获取节点
214
+ * @param index 节点索引
340
215
  */
341
- getDesignSize() {
342
- let designSize = view.getDesignResolutionSize();
343
- return { width: designSize.width, height: designSize.height };
216
+ get(index) {
217
+ return this._nodes[index];
344
218
  }
345
219
  /**
346
- * 设置尺寸发生变化的监听
347
- * @param callback 回调
348
- * @internal
220
+ * 获取顶部节点
349
221
  */
350
- registerListener(listener) {
351
- if (screen && screen.on) {
352
- screen.on("window-resize", (...args) => {
353
- debug("window-resize");
354
- listener(...args);
355
- }, this);
356
- screen.on("orientation-change", (...args) => {
357
- debug("orientation-change");
358
- listener(...args);
359
- }, this);
360
- screen.on("fullscreen-change", (...args) => {
361
- debug("fullscreen-change");
362
- listener(...args);
363
- }, this);
364
- }
365
- else {
366
- // 3.8.0之前的版本
367
- view.setResizeCallback(listener);
368
- }
222
+ top() {
223
+ return this._nodes[0];
369
224
  }
370
- }
371
-
372
- /**
373
- * @Author: Gongxh
374
- * @Date: 2024-12-07
375
- * @Description: cocos UI模块
376
- */
377
- class Module extends Component {
378
225
  /**
379
- * 模块初始化 (内部使用)
380
- * @internal
226
+ * 是否包含节点
227
+ * @param node 节点
381
228
  */
382
- init() {
383
- this.onInit();
229
+ contains(node) {
230
+ return node.index >= 0 && node.index < this._size;
384
231
  }
385
- }
386
-
387
- /**
232
+ /**
233
+ * Push节点
234
+ * @param node 节点
235
+ */
236
+ push(node) {
237
+ const size = ++this._size;
238
+ if (size > this._capacity) {
239
+ this._capacity = this._nodes.length *= 2;
240
+ }
241
+ this._sortUp(node, size - 1);
242
+ }
243
+ /**
244
+ * Pop节点
245
+ * @returns
246
+ */
247
+ pop() {
248
+ if (this._size == 0) {
249
+ return null;
250
+ }
251
+ const nodes = this._nodes;
252
+ const node = nodes[0];
253
+ node.index = -1;
254
+ nodes[0] = null;
255
+ const size = --this._size;
256
+ if (size > 0) {
257
+ const finalNode = nodes[size];
258
+ nodes[size] = null;
259
+ this._sortDown(finalNode, 0);
260
+ }
261
+ return node;
262
+ }
263
+ /**
264
+ * 移除节点
265
+ * @param node 要移除的节点
266
+ */
267
+ remove(node) {
268
+ if (!this.contains(node)) {
269
+ return;
270
+ }
271
+ const size = --this._size;
272
+ const nodes = this._nodes;
273
+ // 如果删除的不是最后一个元素,需要调整堆
274
+ if (node.index < size) {
275
+ const newNode = (nodes[node.index] = nodes[size]);
276
+ newNode.index = node.index;
277
+ nodes[size] = null;
278
+ this.update(newNode);
279
+ }
280
+ else {
281
+ nodes[size] = null;
282
+ }
283
+ node.index = -1;
284
+ }
285
+ /**
286
+ * 更新节点
287
+ * @param node 要更新的节点
288
+ */
289
+ update(node) {
290
+ if (!this.contains(node)) {
291
+ return false;
292
+ }
293
+ const index = node.index;
294
+ const nodes = this._nodes;
295
+ if (index > 0 && nodes[index].lessThan(nodes[this._parent(index)])) {
296
+ this._sortUp(nodes[index], index);
297
+ }
298
+ else {
299
+ this._sortDown(nodes[index], index);
300
+ }
301
+ return true;
302
+ }
303
+ /** @internal */
304
+ _parent(index) {
305
+ return (index - 1) >> 1;
306
+ }
307
+ get count() {
308
+ return this._size;
309
+ }
310
+ get empty() {
311
+ return this._size == 0;
312
+ }
313
+ /** @internal */
314
+ _sortUp(node, index) {
315
+ let parentIndex = this._parent(index);
316
+ const nodes = this._nodes;
317
+ while (index > 0 && node.lessThan(nodes[parentIndex])) {
318
+ nodes[parentIndex].index = index;
319
+ nodes[index] = nodes[parentIndex];
320
+ index = parentIndex;
321
+ parentIndex = this._parent(parentIndex);
322
+ }
323
+ node.index = index;
324
+ nodes[index] = node;
325
+ }
326
+ /** @internal */
327
+ _sortDown(node, index) {
328
+ let childIndex = (index << 1) + 1;
329
+ const nodes = this._nodes;
330
+ const size = this._size;
331
+ while (childIndex < size) {
332
+ let newParent = node;
333
+ // left
334
+ if (nodes[childIndex].lessThan(newParent)) {
335
+ newParent = nodes[childIndex];
336
+ }
337
+ // right
338
+ if (childIndex + 1 < size && nodes[childIndex + 1].lessThan(newParent)) {
339
+ ++childIndex;
340
+ newParent = nodes[childIndex];
341
+ }
342
+ if (node == newParent) {
343
+ break;
344
+ }
345
+ // swap down
346
+ newParent.index = index;
347
+ nodes[index] = newParent;
348
+ index = childIndex;
349
+ childIndex = (childIndex << 1) + 1;
350
+ }
351
+ node.index = index;
352
+ nodes[index] = node;
353
+ }
354
+ }
355
+
356
+ /**
357
+ * @Author: Gongxh
358
+ * @Date: 2024-12-07
359
+ * @Description: 计时器节点
360
+ */
361
+ /** @internal */
362
+ class TimerNode extends HeapNode {
363
+ constructor(id) {
364
+ super();
365
+ /** 重复次数 */
366
+ this.loop = 0;
367
+ this.id = id;
368
+ }
369
+ /**
370
+ * 是否比其他定时节点小
371
+ * @param {HeapNode} other 其他定时节点
372
+ * @returns {boolean}
373
+ */
374
+ lessThan(other) {
375
+ const otherTimerNode = other;
376
+ if (Math.abs(this.expireTime - otherTimerNode.expireTime) <= 1e-5) {
377
+ return this.orderIndex < otherTimerNode.orderIndex;
378
+ }
379
+ return this.expireTime < otherTimerNode.expireTime;
380
+ }
381
+ }
382
+
383
+ /**
384
+ * @Author: Gongxh
385
+ * @Date: 2024-12-07
386
+ * @Description: 计时器节点回收池
387
+ */
388
+ const TimerIdBit = 19;
389
+ const TimerCount = 1 << (32 - TimerIdBit);
390
+ const TimerVersionMask = (1 << TimerIdBit) - 1;
391
+ const TimerMaxVersion = TimerVersionMask;
392
+ class TimerNodePool {
393
+ /**
394
+ * 定时器池
395
+ * @param {number} capacity 初始容量
396
+ * @internal
397
+ */
398
+ constructor(capacity) {
399
+ /** @internal */
400
+ this._pool = new Array();
401
+ /** @internal */
402
+ this._freeIndices = new Array();
403
+ for (let i = 0; i < capacity; ++i) {
404
+ const timerNode = new TimerNode(i << TimerIdBit);
405
+ timerNode.recycled = true;
406
+ this._pool.push(timerNode);
407
+ this._freeIndices.push(i);
408
+ }
409
+ }
410
+ /**
411
+ * 分配定时器节点
412
+ * @returns {TimerNode} 定时器节点
413
+ * @internal
414
+ */
415
+ allocate() {
416
+ let timerNode;
417
+ const pools = this._pool;
418
+ if (this._freeIndices.length == 0) {
419
+ if (pools.length == TimerCount) {
420
+ throw new Error("超出时钟个数: " + TimerCount);
421
+ }
422
+ timerNode = new TimerNode(pools.length << TimerIdBit);
423
+ pools.push(timerNode);
424
+ }
425
+ else {
426
+ const index = this._freeIndices.pop();
427
+ timerNode = pools[index];
428
+ timerNode.recycled = false;
429
+ if ((timerNode.id & TimerVersionMask) == TimerMaxVersion) {
430
+ throw new Error("时钟版本号过高: " + TimerMaxVersion);
431
+ }
432
+ ++timerNode.id;
433
+ }
434
+ return timerNode;
435
+ }
436
+ /**
437
+ * 回收定时器节点
438
+ * @param {number} timerId 定时器ID
439
+ * @internal
440
+ */
441
+ recycle(timerId) {
442
+ const index = timerId >>> TimerIdBit;
443
+ if (index < 0 || index >= this._pool.length) {
444
+ throw new Error("定时器不存在");
445
+ }
446
+ const timerNode = this._pool[index];
447
+ if (timerNode.recycled) {
448
+ throw new Error("定时器已经被回收");
449
+ }
450
+ timerNode.recycled = true;
451
+ timerNode.callback = null;
452
+ this._freeIndices.push(index);
453
+ }
454
+ /**
455
+ * 根据TimerID获取定时器节点
456
+ * @param {number} timerId 定时器ID
457
+ * @returns {TimerNode}
458
+ * @internal
459
+ */
460
+ get(timerId) {
461
+ const index = timerId >>> TimerIdBit;
462
+ const version = timerId & TimerVersionMask;
463
+ if (index < 0 || index >= this._pool.length) {
464
+ return null;
465
+ }
466
+ const timerNode = this._pool[index];
467
+ if (timerNode.recycled) {
468
+ return null;
469
+ }
470
+ const timerNodeVersion = timerNode.id & TimerVersionMask;
471
+ if (timerNodeVersion != version) {
472
+ return null;
473
+ }
474
+ return timerNode;
475
+ }
476
+ /**
477
+ * 清空正在使用的Timer
478
+ * @internal
479
+ */
480
+ clear() {
481
+ const pools = this._pool;
482
+ const timerNodeCount = pools.length;
483
+ const freeIndices = this._freeIndices;
484
+ freeIndices.length = 0;
485
+ for (let i = 0; i < timerNodeCount; ++i) {
486
+ pools[i].recycled = true;
487
+ pools[i].callback = null;
488
+ freeIndices.push(i);
489
+ }
490
+ }
491
+ }
492
+
493
+ /**
494
+ * @Author: Gongxh
495
+ * @Date: 2024-12-07
496
+ * @Description: 定时器管理类
497
+ */
498
+ class Timer {
499
+ /**
500
+ * 定时器数量
501
+ * @readonly
502
+ * @type {number}
503
+ */
504
+ get timerCount() {
505
+ return this._heap.count;
506
+ }
507
+ /**
508
+ * 定时器管理类
509
+ * @param {number} initTimerCapacity 初始定时器容量
510
+ */
511
+ constructor(initTimerCapacity) {
512
+ /** @internal */
513
+ this._timerNodeOrder = 0;
514
+ /** 经过的时间 @internal */
515
+ this._elapsedTime = 0;
516
+ this._heap = new BinaryHeap(initTimerCapacity);
517
+ this._pool = new TimerNodePool(initTimerCapacity);
518
+ this._pausedTimers = new Map();
519
+ }
520
+ /**
521
+ * 启动一个计时器
522
+ * @param { Function } callback 回调方法
523
+ * @param {number} interval 回调间隔 (秒)
524
+ * @param {number} [loop=0] 重复次数:0:回调一次,1~n:回调n次,-1:无限重复
525
+ * @returns {number} 返回计时器id
526
+ */
527
+ start(callback, interval, loop = 0) {
528
+ const timerNode = this._getTimerNode(callback, interval, loop);
529
+ this._heap.push(timerNode);
530
+ return timerNode.id;
531
+ }
532
+ /**
533
+ * 删除指定计时器
534
+ * @param {number} timerId 定时器ID
535
+ * @memberof Timer
536
+ */
537
+ stop(timerId) {
538
+ const timerNode = this._pool.get(timerId);
539
+ if (timerNode) {
540
+ if (timerNode.pause) {
541
+ this._pausedTimers.delete(timerId);
542
+ }
543
+ this._heap.remove(timerNode);
544
+ this._pool.recycle(timerId);
545
+ }
546
+ }
547
+ /**
548
+ * 暂停定时器
549
+ *
550
+ * @param {number} timerId 定时器ID
551
+ * @memberof Timer
552
+ */
553
+ pause(timerId) {
554
+ const timerNode = this._pool.get(timerId);
555
+ if (timerNode) {
556
+ timerNode.pause = true;
557
+ timerNode.pauseRemainTime = timerNode.expireTime - this._elapsedTime;
558
+ this._heap.remove(timerNode);
559
+ this._pausedTimers.set(timerId, timerNode);
560
+ }
561
+ }
562
+ /**
563
+ * 继续定时器
564
+ *
565
+ * @param {number} timerId 定时器ID
566
+ * @memberof Timer
567
+ */
568
+ resume(timerId) {
569
+ const timerNode = this._pausedTimers.get(timerId);
570
+ if (timerNode) {
571
+ timerNode.pause = false;
572
+ timerNode.expireTime = this._elapsedTime + timerNode.pauseRemainTime;
573
+ this._pausedTimers.delete(timerId);
574
+ this._heap.push(timerNode);
575
+ }
576
+ }
577
+ /**
578
+ * 更新时钟
579
+ * @param {number} deltaTime 更新间隔
580
+ * @internal
581
+ */
582
+ update(deltaTime) {
583
+ const elapsedTime = (this._elapsedTime += deltaTime);
584
+ const heap = this._heap;
585
+ let timerNode = heap.top();
586
+ while (timerNode && timerNode.expireTime <= elapsedTime) {
587
+ const callback = timerNode.callback;
588
+ if (timerNode.loop == 0) {
589
+ heap.pop();
590
+ this._recycle(timerNode);
591
+ }
592
+ else if (timerNode.loop > 0) {
593
+ // 处理多次回调定时器
594
+ if (--timerNode.loop == 0) {
595
+ heap.pop();
596
+ this._recycle(timerNode);
597
+ }
598
+ else {
599
+ // 更新下一次回调
600
+ timerNode.expireTime = timerNode.expireTime + timerNode.interval;
601
+ heap.update(timerNode);
602
+ }
603
+ }
604
+ else {
605
+ // 无限次数回调
606
+ // 更新下一次回调
607
+ timerNode.expireTime = timerNode.expireTime + timerNode.interval;
608
+ heap.update(timerNode);
609
+ }
610
+ callback();
611
+ timerNode = heap.top();
612
+ }
613
+ }
614
+ /**
615
+ * 清空所有定时器
616
+ */
617
+ clear() {
618
+ this._heap.clear();
619
+ this._pool.clear();
620
+ this._pausedTimers.clear();
621
+ this._timerNodeOrder = 0;
622
+ }
623
+ /** @internal */
624
+ _getTimerNode(callback, interval, loop) {
625
+ const timerNode = this._pool.allocate();
626
+ timerNode.orderIndex = ++this._timerNodeOrder;
627
+ timerNode.callback = callback;
628
+ timerNode.interval = interval;
629
+ timerNode.expireTime = this._elapsedTime + interval;
630
+ timerNode.loop = loop;
631
+ timerNode.pause = false;
632
+ return timerNode;
633
+ }
634
+ /** @internal */
635
+ _recycle(timerNode) {
636
+ this._pool.recycle(timerNode.id);
637
+ }
638
+ }
639
+
640
+ /**
641
+ * @Author: Gongxh
642
+ * @Date: 2024-12-07
643
+ * @Description:
644
+ */
645
+ class GlobalTimer {
646
+ /**
647
+ * 初始化全局定时器,设置定时器间隔为16毫秒。
648
+ * 此方法用于启动一个定时器实例,以便在整个应用程序中跟踪时间相关的操作。
649
+ * @internal
650
+ */
651
+ static initTimer() {
652
+ this._timer = new Timer(16);
653
+ }
654
+ /**
655
+ * 获取全局定时器实例。如果定时器尚未初始化,则进行初始化。
656
+ * @returns {Timer} 全局定时器实例
657
+ * @internal
658
+ */
659
+ static get Timer() {
660
+ if (this._timer) {
661
+ return this._timer;
662
+ }
663
+ this.initTimer();
664
+ return this._timer;
665
+ }
666
+ /**
667
+ * 启动一个定时器,执行指定的回调函数。
668
+ * @param callback - 要定时执行的回调函数。
669
+ * @param interval - 定时器的时间间隔(秒)。
670
+ * @param loop - [loop=0] 重复次数:0:回调一次,1~n:回调n次,-1:无限重复
671
+ * @returns 返回定时器的ID。
672
+ */
673
+ static startTimer(callback, interval, loop = 0) {
674
+ return this.Timer.start(callback, interval, loop);
675
+ }
676
+ /**
677
+ * 停止指定ID的计时器。
678
+ * @param timerId - 要停止的计时器的唯一标识符。
679
+ */
680
+ static stopTimer(timerId) {
681
+ this.Timer.stop(timerId);
682
+ }
683
+ /**
684
+ * 暂停指定ID的计时器。
685
+ * @param timerId - 要暂停的计时器的唯一标识符。
686
+ */
687
+ static pauseTimer(timerId) {
688
+ this.Timer.pause(timerId);
689
+ }
690
+ /**
691
+ * 恢复指定ID的计时器。
692
+ * @param timerId - 要恢复的计时器的唯一标识符。
693
+ */
694
+ static resumeTimer(timerId) {
695
+ this.Timer.resume(timerId);
696
+ }
697
+ /**
698
+ * 清除所有定时器。
699
+ */
700
+ static clearAllTimer() {
701
+ this.Timer.clear();
702
+ }
703
+ /**
704
+ * 更新定时器
705
+ * @param dt - 时间间隔
706
+ * @internal
707
+ */
708
+ static update(dt) {
709
+ var _a;
710
+ (_a = this._timer) === null || _a === void 0 ? void 0 : _a.update(dt);
711
+ }
712
+ }
713
+ /** @internal */
714
+ GlobalTimer._timer = null;
715
+
716
+ /**
717
+ * @Author: Gongxh
718
+ * @Date: 2025-02-14
719
+ * @Description: 内部使用的全局定时器
720
+ */
721
+ class InnerTimer {
722
+ /**
723
+ * 初始化全局定时器,设置定时器间隔为16毫秒。
724
+ * 此方法用于启动一个定时器实例,以便在整个应用程序中跟踪时间相关的操作。
725
+ */
726
+ static initTimer() {
727
+ this._timer = new Timer(16);
728
+ }
729
+ /**
730
+ * 启动一个定时器,执行指定的回调函数。
731
+ * @param callback - 要定时执行的回调函数。
732
+ * @param interval - 定时器的时间间隔(秒)。
733
+ * @param loop - [loop=0] 重复次数:0:回调一次,1~n:回调n次,-1:无限重复
734
+ * @returns 返回定时器的ID。
735
+ */
736
+ static startTimer(callback, interval, loop = 0) {
737
+ return this._timer.start(callback, interval, loop);
738
+ }
739
+ /**
740
+ * 停止指定ID的计时器。
741
+ * @param timerId - 要停止的计时器的唯一标识符。
742
+ */
743
+ static stopTimer(timerId) {
744
+ this._timer.stop(timerId);
745
+ }
746
+ static update(dt) {
747
+ var _a;
748
+ (_a = this._timer) === null || _a === void 0 ? void 0 : _a.update(dt);
749
+ }
750
+ }
751
+ InnerTimer._timer = null;
752
+
753
+ /**
754
+ * @Author: Gongxh
755
+ * @Date: 2025-03-06
756
+ * @Description: 时间工具
757
+ */
758
+ /** 时间对象缓存 */
759
+ let TimeCache = null;
760
+ class Time {
761
+ /** 获取游戏系统启动时间戳 */
762
+ static get osBootTime() { return this._osBootTime; }
763
+ /** 获取主动设置的网络时间 单位ms */
764
+ static get netTime() { return this._netTime; }
765
+ /** 获取本地时间与网路时间的偏移量 单位ms */
766
+ static get netTimeDiff() { return this._netTimeDiff; }
767
+ /** 获取系统运行时间 */
768
+ static get runTime() { return Math.floor(game.totalTime); }
769
+ /**
770
+ * 配置系统启动时间
771
+ * @internal
772
+ */
773
+ static _configBoot() {
774
+ this._osBootTime = Math.floor(Date.now());
775
+ TimeCache = new Date();
776
+ this._nowTimestamp = () => {
777
+ return this._osBootTime + this.runTime;
778
+ };
779
+ debug("系统启动时间", this.formatTime(this._osBootTime));
780
+ }
781
+ /**
782
+ * 设置网络时间, 单位ms
783
+ * @param netTime 网络时间
784
+ */
785
+ static setNetTime(netTime) {
786
+ if (netTime == 0) {
787
+ return;
788
+ }
789
+ this._netTime = netTime;
790
+ const localTime = this._nowTimestamp();
791
+ this._netTimeDiff = Math.floor(this.netTime - localTime);
792
+ debug(`设置网络时间: net(${this.formatTime(this.netTime)}), boot(${this.formatTime(this.osBootTime)}), diff(${Math.abs(this.netTimeDiff / 1000)}秒)`);
793
+ }
794
+ /**
795
+ * 获取当前时间 单位ms
796
+ */
797
+ static now() {
798
+ return this._nowTimestamp() + this.netTimeDiff;
799
+ }
800
+ /**
801
+ * 将毫秒转换为秒
802
+ * @param ms 毫秒
803
+ */
804
+ static msTos(ms) {
805
+ return Math.floor((ms || 0) / 1000);
806
+ }
807
+ /**
808
+ * 将秒转换为毫秒
809
+ */
810
+ static sToMs(s) {
811
+ return (s || 0) * 1000;
812
+ }
813
+ /**
814
+ * 获取年份
815
+ * @param timestamp 时间戳 (ms)
816
+ * @returns 年份
817
+ */
818
+ static getYear(timestamp) {
819
+ TimeCache.setTime(timestamp || this.now());
820
+ return TimeCache.getFullYear();
821
+ }
822
+ /**
823
+ * 获取月份
824
+ * @param timestamp 时间戳 (ms)
825
+ * @returns 月份
826
+ */
827
+ static getMonth(timestamp) {
828
+ TimeCache.setTime(timestamp || this.now());
829
+ return TimeCache.getMonth() + 1;
830
+ }
831
+ /**
832
+ * 获取日期
833
+ * @param timestamp 时间戳 (ms)
834
+ * @returns 日期
835
+ */
836
+ static getDay(timestamp) {
837
+ TimeCache.setTime(timestamp || this.now());
838
+ return TimeCache.getDate();
839
+ }
840
+ /**
841
+ * 获取小时
842
+ * @param timestamp 时间戳 (ms)
843
+ * @returns 小时
844
+ */
845
+ static getHour(timestamp) {
846
+ TimeCache.setTime(timestamp || this.now());
847
+ return TimeCache.getHours();
848
+ }
849
+ /**
850
+ * 获取分钟
851
+ * @param timestamp 时间戳 (ms)
852
+ * @returns 分钟
853
+ */
854
+ static getMinute(timestamp) {
855
+ TimeCache.setTime(timestamp || this.now());
856
+ return TimeCache.getMinutes();
857
+ }
858
+ /**
859
+ * 获取秒
860
+ * @param timestamp 时间戳 (ms)
861
+ * @returns 秒
862
+ */
863
+ static getSecond(timestamp) {
864
+ TimeCache.setTime(timestamp || this.now());
865
+ return TimeCache.getSeconds();
866
+ }
867
+ /**
868
+ * 获取当天开始时间
869
+ * @param timestamp 时间戳 (ms)
870
+ * @returns 时间戳 (ms)
871
+ */
872
+ static getDayStartTime(timestamp) {
873
+ TimeCache.setTime(timestamp || this.now());
874
+ TimeCache.setHours(0, 0, 0, 0);
875
+ return TimeCache.getTime();
876
+ }
877
+ /**
878
+ * 获取当天的结束时间
879
+ * @param timestamp 时间戳 (ms)
880
+ * @returns 时间戳 (ms)
881
+ */
882
+ static getDayEndTime(timestamp) {
883
+ return this.getDayStartTime(timestamp) + 86400000;
884
+ }
885
+ /**
886
+ * 获取传入时间是周几
887
+ * @param {number} [time] (ms)
888
+ * @returns {number}
889
+ */
890
+ static getWeekDay(time) {
891
+ TimeCache.setTime(time || Time.now());
892
+ return TimeCache.getDay() || 7;
893
+ }
894
+ /**
895
+ * 获取当前周的开始时间
896
+ * @param timestamp 时间戳 (ms)
897
+ * @returns 时间戳 (ms)
898
+ */
899
+ static getWeekStartTime(timestamp) {
900
+ return this.getDayStartTime(timestamp - this.getWeekDay(timestamp) * 86400000);
901
+ }
902
+ static getWeekEndTime(timestamp) {
903
+ return this.getWeekStartTime(timestamp) + 86400000 * 7;
904
+ }
905
+ /**
906
+ * 获取当前月开始时间
907
+ * @param timestamp 时间戳 (ms)
908
+ * @returns 时间戳 (ms)
909
+ */
910
+ static getMonthStartTime(timestamp) {
911
+ TimeCache.setTime(timestamp || this.now());
912
+ TimeCache.setDate(1);
913
+ TimeCache.setHours(0, 0, 0, 0);
914
+ return TimeCache.getTime();
915
+ }
916
+ /**
917
+ * 获取当前月结束时间
918
+ * @param timestamp 时间戳 (ms)
919
+ * @returns 时间戳 (ms)
920
+ */
921
+ static getMonthEndTime(timestamp) {
922
+ TimeCache.setTime(timestamp || this.now());
923
+ TimeCache.setDate(1);
924
+ TimeCache.setHours(0, 0, 0, 0);
925
+ TimeCache.setMonth(TimeCache.getMonth() + 1);
926
+ return TimeCache.getTime();
927
+ }
928
+ /**
929
+ * 获取当前年份开始时间
930
+ * @param timestamp 时间戳 (ms)
931
+ * @returns 时间戳 (ms)
932
+ */
933
+ static getYearStartTime(timestamp) {
934
+ TimeCache.setTime(timestamp || this.now());
935
+ TimeCache.setMonth(0);
936
+ TimeCache.setDate(1);
937
+ TimeCache.setHours(0, 0, 0, 0);
938
+ return TimeCache.getTime();
939
+ }
940
+ /**
941
+ * 获取当前年份结束时间
942
+ * @param timestamp 时间戳 (ms)
943
+ * @returns 时间戳 (ms)
944
+ */
945
+ static getYearEndTime(timestamp) {
946
+ TimeCache.setTime(timestamp || this.now());
947
+ TimeCache.setMonth(0);
948
+ TimeCache.setDate(1);
949
+ TimeCache.setHours(0, 0, 0, 0);
950
+ TimeCache.setFullYear(TimeCache.getFullYear() + 1);
951
+ return TimeCache.getTime();
952
+ }
953
+ /**
954
+ * 获取当前月的天数
955
+ * @param timestamp 时间戳 (ms)
956
+ * @returns 天数
957
+ */
958
+ static getMonthDays(timestamp) {
959
+ const monthEndTime = this.getMonthEndTime(timestamp);
960
+ const monthStartTime = this.getMonthStartTime(timestamp);
961
+ return Math.round((monthEndTime - monthStartTime) / 86400000);
962
+ }
963
+ /**
964
+ * 是否是同一天
965
+ * @param timestamp1 时间戳1 (ms)
966
+ * @param now 时间戳2 (ms) 如果不传,则和当前时间比较
967
+ * @returns 是否是同一天
968
+ */
969
+ static isSameDay(timestamp1, now) {
970
+ now = now || this.now();
971
+ if (now - timestamp1 > 86400000) {
972
+ return false;
973
+ }
974
+ return this.getDayStartTime(timestamp1) === this.getDayStartTime(now);
975
+ }
976
+ /**
977
+ * 是否是同一周
978
+ * @param timestamp1 时间戳1 (ms)
979
+ * @param now 时间戳2 (ms) 如果不传,则和当前时间比较
980
+ * @returns 是否是同一周
981
+ */
982
+ static isSameWeek(timestamp1, now) {
983
+ now = now || this.now();
984
+ if (now - timestamp1 > 86400000 * 7) {
985
+ return false;
986
+ }
987
+ return this.getWeekStartTime(timestamp1) === this.getWeekStartTime(now);
988
+ }
989
+ /**
990
+ * 是否是同一月
991
+ * @param timestamp1 时间戳1 (ms)
992
+ * @param now 时间戳2 (ms) 如果不传,则和当前时间比较
993
+ * @returns 是否是同一月
994
+ */
995
+ static isSameMonth(timestamp1, now) {
996
+ now = now || this.now();
997
+ TimeCache.setTime(timestamp1);
998
+ const month1 = TimeCache.getMonth();
999
+ const year1 = TimeCache.getFullYear();
1000
+ TimeCache.setTime(now);
1001
+ const month2 = TimeCache.getMonth();
1002
+ const year2 = TimeCache.getFullYear();
1003
+ return month1 === month2 && year1 === year2;
1004
+ }
1005
+ /**
1006
+ * 是否是同一年
1007
+ * @param timestamp1 时间戳1 (ms)
1008
+ * @param now 时间戳2 (ms) 如果不传,则和当前时间比较
1009
+ * @returns 是否是同一年
1010
+ */
1011
+ static isSameYear(timestamp1, now) {
1012
+ now = now || this.now();
1013
+ // 直接比较年份,避免使用天数计算可能出现的边界错误
1014
+ TimeCache.setTime(timestamp1);
1015
+ const year1 = TimeCache.getFullYear();
1016
+ TimeCache.setTime(now);
1017
+ const year2 = TimeCache.getFullYear();
1018
+ return year1 === year2;
1019
+ }
1020
+ /**
1021
+ * 通用时间格式化方法
1022
+ * @param timestamp 时间戳 (ms)
1023
+ * @param pattern 格式化模板
1024
+ *
1025
+ * 支持的占位符(大写补零,小写不补零):
1026
+ * - YYYY: 四位年份 (2025) | YY: 两位年份 (25)
1027
+ * - MM: 两位月份 (01-12) | M: 月份 (1-12)
1028
+ * - DD: 两位日期 (01-31) | D: 日期 (1-31)
1029
+ * - hh: 两位小时 (00-23) | h: 小时 (0-23)
1030
+ * - mm: 两位分钟 (00-59) | m: 分钟 (0-59)
1031
+ * - ss: 两位秒 (00-59) | s: 秒 (0-59)
1032
+ *
1033
+ * @example
1034
+ * Time.format(timestamp, 'YYYY-MM-DD hh:mm:ss') // "2025-01-05 14:30:45"
1035
+ * Time.format(timestamp, 'YYYY年MM月DD日 hh:mm') // "2025年01月05日 14:30"
1036
+ * Time.format(timestamp, 'M月D日 h时m分') // "1月5日 14时30分"
1037
+ */
1038
+ static format(timestamp, pattern) {
1039
+ TimeCache.setTime(timestamp);
1040
+ const year = TimeCache.getFullYear();
1041
+ const month = TimeCache.getMonth() + 1;
1042
+ const day = TimeCache.getDate();
1043
+ const hour = TimeCache.getHours();
1044
+ const minute = TimeCache.getMinutes();
1045
+ const second = TimeCache.getSeconds();
1046
+ const pad = (n) => n < 10 ? `0${n}` : `${n}`;
1047
+ return pattern
1048
+ .replace(/YYYY/g, `${year}`)
1049
+ .replace(/YY/g, pad(year % 100))
1050
+ .replace(/MM/g, pad(month))
1051
+ .replace(/M/g, `${month}`)
1052
+ .replace(/DD/g, pad(day))
1053
+ .replace(/D/g, `${day}`)
1054
+ .replace(/hh/g, pad(hour))
1055
+ .replace(/h/g, `${hour}`)
1056
+ .replace(/mm/g, pad(minute))
1057
+ .replace(/m/g, `${minute}`)
1058
+ .replace(/ss/g, pad(second))
1059
+ .replace(/s/g, `${second}`);
1060
+ }
1061
+ /**
1062
+ * 格式化时间 格式: xxxx-xx-xx hh:mm:ss
1063
+ * @param timestamp 时间戳 (ms)
1064
+ */
1065
+ static formatTime(timestamp) {
1066
+ return this.format(timestamp, 'YYYY-MM-DD hh:mm:ss');
1067
+ }
1068
+ /**
1069
+ * 格式化时间 格式: xxxx年xx月xx日 hh:mm:ss
1070
+ * @param timestamp 时间戳 (ms)
1071
+ */
1072
+ static formatTimeChinese(timestamp) {
1073
+ return this.format(timestamp, 'YYYY年MM月DD日 hh:mm:ss');
1074
+ }
1075
+ /**
1076
+ * 通用时长格式化方法
1077
+ * @param seconds 时长(秒)
1078
+ * @param pattern 格式化模板
1079
+ * @param options 格式化选项
1080
+ *
1081
+ * 支持的占位符(大写补零,小写不补零):
1082
+ * - DD/D: 天数
1083
+ * - HH/H: 总小时数(可超过24)
1084
+ * - hh/h: 小时数(0-23范围)
1085
+ * - MM/M: 总分钟数(可超过60)
1086
+ * - mm/m: 分钟数(0-59范围)
1087
+ * - ss/s: 秒数(0-59范围)
1088
+ *
1089
+ * options.autoHide: 自动隐藏为0的高位单位(默认false)
1090
+ *
1091
+ * @example
1092
+ * Time.formatDuration(3661, 'HH:mm:ss') // "01:01:01"
1093
+ * Time.formatDuration(3661, 'MM:ss') // "61:01"
1094
+ * Time.formatDuration(3661, 'H小时m分s秒') // "1小时1分1秒"
1095
+ * Time.formatDuration(90061, 'DD天hh:mm:ss') // "1天01:01:01"
1096
+ * Time.formatDuration(125, 'HH:mm:ss', { autoHide: true }) // "02:05"
1097
+ * Time.formatDuration(3661, 'DD天HH时mm分ss秒', { autoHide: true }) // "1时1分1秒"
1098
+ */
1099
+ static formatDuration(seconds, pattern, options) {
1100
+ const time = Math.floor(seconds < 0 ? 0 : seconds);
1101
+ const day = Math.floor(time / 86400);
1102
+ const totalHours = Math.floor(time / 3600);
1103
+ const totalMinutes = Math.floor(time / 60);
1104
+ const hour = Math.floor((time % 86400) / 3600);
1105
+ const minute = Math.floor((time % 3600) / 60);
1106
+ const second = time % 60;
1107
+ const pad = (n) => n < 10 ? `0${n}` : `${n}`;
1108
+ // 如果启用自动隐藏,移除值为0的高位单位
1109
+ let result = pattern;
1110
+ if (options === null || options === void 0 ? void 0 : options.autoHide) {
1111
+ // 检测天数
1112
+ if (day === 0) {
1113
+ result = result.replace(/DD天?|D天?/g, '');
1114
+ }
1115
+ // 检测小时(需要天数为0时才隐藏)
1116
+ if (day === 0 && hour === 0 && totalHours === 0) {
1117
+ result = result.replace(/HH[时:]?|H[时:]?|hh[时:]?|h[时:]?/g, '');
1118
+ }
1119
+ // 检测分钟(需要天数和小时都为0时才隐藏)
1120
+ if (day === 0 && hour === 0 && totalHours === 0 && minute === 0 && totalMinutes === 0) {
1121
+ result = result.replace(/MM[分:]?|M[分:]?|mm[分:]?|m[分:]?/g, '');
1122
+ }
1123
+ // 清理多余的分隔符
1124
+ result = result.replace(/^[:\s]+|[:\s]+$/g, '').replace(/\s{2,}/g, ' ');
1125
+ }
1126
+ return result
1127
+ .replace(/DD/g, pad(day))
1128
+ .replace(/D/g, `${day}`)
1129
+ .replace(/HH/g, pad(totalHours))
1130
+ .replace(/H/g, `${totalHours}`)
1131
+ .replace(/hh/g, pad(hour))
1132
+ .replace(/h/g, `${hour}`)
1133
+ .replace(/MM/g, pad(totalMinutes))
1134
+ .replace(/M/g, `${totalMinutes}`)
1135
+ .replace(/mm/g, pad(minute))
1136
+ .replace(/m/g, `${minute}`)
1137
+ .replace(/ss/g, pad(second))
1138
+ .replace(/s/g, `${second}`);
1139
+ }
1140
+ /**
1141
+ * 智能格式化时长 - 自动隐藏为0的高位单位
1142
+ * @param time 时间 (s)
1143
+ * @param pattern 格式化模板,默认 'D天h小时m分s秒'
1144
+ *
1145
+ * @example
1146
+ * Time.formatSmart(86461) // "1天1小时1分1秒"
1147
+ * Time.formatSmart(3661) // "1小时1分1秒"
1148
+ * Time.formatSmart(61) // "1分1秒"
1149
+ * Time.formatSmart(1) // "1秒"
1150
+ */
1151
+ static formatSmart(time, pattern = 'D天h小时m分s秒') {
1152
+ return this.formatDuration(time, pattern, { autoHide: true });
1153
+ }
1154
+ /**
1155
+ * 智能格式化时长(简化版) - 只显示最大的两个单位,较小单位向上取整
1156
+ * @param time 时间 (s)
1157
+ * @param pattern 格式化模板,默认 'D天h小时|h小时m分|m分s秒',用 | 分隔不同级别
1158
+ *
1159
+ * @example
1160
+ * Time.formatSmartSimple(90061) // "1天2小时" (1.04小时向上取整为2)
1161
+ * Time.formatSmartSimple(3661) // "1小时2分" (1.02分钟向上取整为2)
1162
+ * Time.formatSmartSimple(61) // "1分2秒" (1.02秒向上取整为2)
1163
+ * Time.formatSmartSimple(1) // "1秒"
1164
+ * Time.formatSmartSimple(90061, 'D天h时|h时m分|m分s秒') // "1天2时"
1165
+ */
1166
+ static formatSmartSimple(time, pattern = 'D天h小时|h小时m分|m分s秒') {
1167
+ const curTime = Math.floor(time < 0 ? 0 : time);
1168
+ const [dayPattern = 'D天h小时', hourPattern = 'h小时m分', minutePattern = 'm分s秒', secondPattern = 's秒'] = pattern.split('|');
1169
+ if (curTime >= 86400) {
1170
+ const day = Math.floor(curTime / 86400);
1171
+ const hour = Math.ceil((curTime % 86400) / 3600);
1172
+ return this.formatDuration(day * 86400 + hour * 3600, dayPattern);
1173
+ }
1174
+ else if (curTime >= 3600) {
1175
+ const hour = Math.floor(curTime / 3600);
1176
+ const minute = Math.ceil((curTime % 3600) / 60);
1177
+ return this.formatDuration(hour * 3600 + minute * 60, hourPattern);
1178
+ }
1179
+ else if (curTime >= 60) {
1180
+ const minute = Math.floor(curTime / 60);
1181
+ const second = Math.ceil(curTime % 60);
1182
+ return this.formatDuration(minute * 60 + second, minutePattern);
1183
+ }
1184
+ else {
1185
+ return this.formatDuration(curTime, secondPattern);
1186
+ }
1187
+ }
1188
+ }
1189
+ /**
1190
+ * 游戏系统启动时间戳
1191
+ * @internal
1192
+ */
1193
+ Time._osBootTime = 0;
1194
+ /**
1195
+ * 主动设置的网络时间 单位ms
1196
+ * @internal
1197
+ */
1198
+ Time._netTime = 0;
1199
+ /**
1200
+ * 本地时间与网路时间的偏移量 单位ms
1201
+ * @internal
1202
+ */
1203
+ Time._netTimeDiff = 0;
1204
+
1205
+ /**
1206
+ * @Author: Gongxh
1207
+ * @Date: 2024-12-08
1208
+ * @Description:
1209
+ */
1210
+ class CocosAdapter extends Adapter {
1211
+ /**
1212
+ * 获取屏幕像素尺寸
1213
+ * @returns {Size}
1214
+ * @internal
1215
+ */
1216
+ getScreenSize() {
1217
+ let windowSize = screen.windowSize;
1218
+ let width = Math.ceil(windowSize.width / view.getScaleX());
1219
+ let height = Math.ceil(windowSize.height / view.getScaleY());
1220
+ return { width, height };
1221
+ }
1222
+ /**
1223
+ * 获取设计尺寸
1224
+ * @returns {Size}
1225
+ * @internal
1226
+ */
1227
+ getDesignSize() {
1228
+ let designSize = view.getDesignResolutionSize();
1229
+ return { width: designSize.width, height: designSize.height };
1230
+ }
1231
+ /**
1232
+ * 设置尺寸发生变化的监听
1233
+ * @param callback 回调
1234
+ * @internal
1235
+ */
1236
+ registerListener(listener) {
1237
+ if (screen && screen.on) {
1238
+ screen.on("window-resize", (...args) => {
1239
+ debug("window-resize");
1240
+ listener(...args);
1241
+ }, this);
1242
+ screen.on("orientation-change", (...args) => {
1243
+ debug("orientation-change");
1244
+ listener(...args);
1245
+ }, this);
1246
+ screen.on("fullscreen-change", (...args) => {
1247
+ debug("fullscreen-change");
1248
+ listener(...args);
1249
+ }, this);
1250
+ }
1251
+ else {
1252
+ // 3.8.0之前的版本
1253
+ view.setResizeCallback(listener);
1254
+ }
1255
+ }
1256
+ }
1257
+
1258
+ /**
1259
+ * @Author: Gongxh
1260
+ * @Date: 2024-12-07
1261
+ * @Description: cocos UI模块
1262
+ */
1263
+ class Module extends Component {
1264
+ /**
1265
+ * 模块初始化 (内部使用)
1266
+ * @internal
1267
+ */
1268
+ init() {
1269
+ this.onInit();
1270
+ }
1271
+ }
1272
+
1273
+ /**
1274
+ * @Author: Gongxh
1275
+ * @Date: 2024-12-07
1276
+ * @Description: 平台相关
1277
+ */
1278
+ var PlatformType;
1279
+ (function (PlatformType) {
1280
+ PlatformType[PlatformType["Android"] = 1] = "Android";
1281
+ PlatformType[PlatformType["IOS"] = 2] = "IOS";
1282
+ PlatformType[PlatformType["HarmonyOS"] = 3] = "HarmonyOS";
1283
+ /** 微信小游戏 */
1284
+ PlatformType[PlatformType["WX"] = 4] = "WX";
1285
+ /** 支付宝小游戏 */
1286
+ PlatformType[PlatformType["Alipay"] = 5] = "Alipay";
1287
+ /** 字节小游戏 */
1288
+ PlatformType[PlatformType["Bytedance"] = 6] = "Bytedance";
1289
+ /** 华为快游戏 */
1290
+ PlatformType[PlatformType["HuaweiQuick"] = 7] = "HuaweiQuick";
1291
+ /** 其他都为Browser */
1292
+ PlatformType[PlatformType["Browser"] = 1001] = "Browser";
1293
+ })(PlatformType || (PlatformType = {}));
1294
+ class Platform {
1295
+ }
1296
+ /**
1297
+ * 是否为原生平台
1298
+ * @type {boolean}
1299
+ */
1300
+ Platform.isNative = false;
1301
+ /**
1302
+ * 是否为移动平台
1303
+ * @type {boolean}
1304
+ */
1305
+ Platform.isMobile = false;
1306
+ /**
1307
+ * 是否为原生移动平台
1308
+ * @type {boolean}
1309
+ */
1310
+ Platform.isNativeMobile = false;
1311
+ /**
1312
+ * 是否为安卓平台
1313
+ * @type {boolean}
1314
+ */
1315
+ Platform.isAndroid = false;
1316
+ /**
1317
+ * 是否为IOS平台
1318
+ * @type {boolean}
1319
+ */
1320
+ Platform.isIOS = false;
1321
+ /**
1322
+ * 是否为HarmonyOS平台
1323
+ * @type {boolean}
1324
+ */
1325
+ Platform.isHarmonyOS = false;
1326
+ /**
1327
+ * 是否为微信小游戏
1328
+ * @type {boolean}
1329
+ */
1330
+ Platform.isWX = false;
1331
+ /**
1332
+ * 是否为支付宝小游戏
1333
+ * @type {boolean}
1334
+ */
1335
+ Platform.isAlipay = false;
1336
+ /**
1337
+ * 是否为字节小游戏
1338
+ * @type {boolean}
1339
+ */
1340
+ Platform.isBytedance = false;
1341
+ /**
1342
+ * 是否是华为快游戏
1343
+ * @type {boolean}
1344
+ */
1345
+ Platform.isHuaweiQuick = false;
1346
+ /**
1347
+ * 是否为浏览器
1348
+ * @type {boolean}
1349
+ */
1350
+ Platform.isBrowser = false;
1351
+ /**
1352
+ * 平台初始化器
1353
+ * @internal
1354
+ */
1355
+ class PlatformInitializer {
1356
+ constructor() {
1357
+ this.initPlatform();
1358
+ }
1359
+ /**
1360
+ * 初始化平台
1361
+ * @internal
1362
+ */
1363
+ initPlatform() {
1364
+ // 处理平台判断
1365
+ Platform.isNative = sys.isNative;
1366
+ Platform.isMobile = sys.isMobile;
1367
+ Platform.isNativeMobile = sys.isNative && sys.isMobile;
1368
+ switch (sys.os) {
1369
+ case sys.OS.ANDROID:
1370
+ Platform.isAndroid = true;
1371
+ debug("系统类型 Android");
1372
+ break;
1373
+ case sys.OS.IOS:
1374
+ Platform.isIOS = true;
1375
+ debug("系统类型 IOS");
1376
+ break;
1377
+ case sys.OS.OPENHARMONY:
1378
+ Platform.isHarmonyOS = true;
1379
+ debug("系统类型 HarmonyOS");
1380
+ break;
1381
+ }
1382
+ switch (sys.platform) {
1383
+ case sys.Platform.WECHAT_GAME:
1384
+ Platform.isWX = true;
1385
+ Platform.platform = PlatformType.WX;
1386
+ break;
1387
+ case sys.Platform.ALIPAY_MINI_GAME:
1388
+ Platform.isAlipay = true;
1389
+ Platform.platform = PlatformType.Alipay;
1390
+ break;
1391
+ case sys.Platform.BYTEDANCE_MINI_GAME:
1392
+ Platform.isBytedance = true;
1393
+ Platform.platform = PlatformType.Bytedance;
1394
+ break;
1395
+ case sys.Platform.HUAWEI_QUICK_GAME:
1396
+ Platform.isHuaweiQuick = true;
1397
+ Platform.platform = PlatformType.HuaweiQuick;
1398
+ break;
1399
+ default:
1400
+ // 其他都设置为浏览器
1401
+ Platform.isBrowser = true;
1402
+ Platform.platform = PlatformType.Browser;
1403
+ break;
1404
+ }
1405
+ debug(`platform: ${PlatformType[Platform.platform]}`);
1406
+ }
1407
+ }
1408
+
1409
+ /**
388
1410
  * @Author: Gongxh
389
1411
  * @Date: 2024-12-07
390
1412
  * @Description:cocos游戏入口 定义了游戏启动时的基本配置和初始化流程。
@@ -403,7 +1425,7 @@ class CocosEntry extends Component {
403
1425
  start() {
404
1426
  // 是否开启调试输出
405
1427
  this.enableDebug && enableDebugMode(true);
406
- debug("开始初始化【bit-framework】");
1428
+ debug("====================开始初始化=====================");
407
1429
  // 设置游戏真帧率
408
1430
  game.frameRate = this.fps;
409
1431
  director.addPersistRootNode(this.node);
@@ -412,10 +1434,22 @@ class CocosEntry extends Component {
412
1434
  new PlatformInitializer();
413
1435
  // 适配器
414
1436
  new CocosAdapter().init();
1437
+ // 时间相关
1438
+ this.initTime();
1439
+ // 初始化模块
415
1440
  this.initModule();
416
- debug("【bit-framework】初始化完成");
1441
+ debug("=====================初始化完成=====================");
417
1442
  this.onInit();
418
1443
  }
1444
+ /**
1445
+ * 时间相关
1446
+ */
1447
+ initTime() {
1448
+ Time._configBoot();
1449
+ InnerTimer.initTimer();
1450
+ GlobalTimer.initTimer();
1451
+ this.schedule(this.tick.bind(this), 0, macro.REPEAT_FOREVER);
1452
+ }
419
1453
  /**
420
1454
  * 初始化模块
421
1455
  * @internal
@@ -426,6 +1460,15 @@ class CocosEntry extends Component {
426
1460
  module.init();
427
1461
  }
428
1462
  }
1463
+ /**
1464
+ * 更新
1465
+ * @param dt 时间间隔
1466
+ * @internal
1467
+ */
1468
+ tick(dt) {
1469
+ InnerTimer.update(dt);
1470
+ GlobalTimer.update(dt);
1471
+ }
429
1472
  }
430
1473
  __decorate([
431
1474
  property({ displayName: "游戏帧率" })
@@ -434,4 +1477,939 @@ __decorate([
434
1477
  property({ displayName: "开启调试输出" })
435
1478
  ], CocosEntry.prototype, "enableDebug", void 0);
436
1479
 
437
- export { CocosEntry, Module, Platform, PlatformType, Screen, debug, enableDebugMode, error, info, log, warn };
1480
+ /**
1481
+ * @Author: Gongxh
1482
+ * @Date: 2025-03-04
1483
+ * @Description: 二进制工具类 - 使用 JavaScript 标准库实现
1484
+ */
1485
+ class Binary {
1486
+ /**
1487
+ * 将对象转换为二进制数据
1488
+ */
1489
+ static toBinary(obj) {
1490
+ // console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
1491
+ // console.log("原始数据", JSON.stringify(obj));
1492
+ const chunks = [];
1493
+ this.writeValue(obj, chunks);
1494
+ // 计算总长度
1495
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
1496
+ const result = new Uint8Array(totalLength);
1497
+ // 合并所有数据块
1498
+ let offset = 0;
1499
+ for (const chunk of chunks) {
1500
+ result.set(chunk, offset);
1501
+ offset += chunk.length;
1502
+ }
1503
+ // console.log("二进制数据", result);
1504
+ // console.log("还原数据", JSON.stringify(this.toJson(result)));
1505
+ return result;
1506
+ }
1507
+ /**
1508
+ * 将二进制数据转换JSON数据
1509
+ * @param binary 二进制数据
1510
+ * @returns
1511
+ */
1512
+ static toJson(binary) {
1513
+ // 如果是 ArrayBuffer, 转换为 Uint8Array
1514
+ const uint8Array = binary instanceof ArrayBuffer ? new Uint8Array(binary) : binary;
1515
+ // 检查是否为二进制格式
1516
+ if (!this.isBinaryFormat(uint8Array)) {
1517
+ // 如果不是二进制格式, 直接返回
1518
+ return binary;
1519
+ }
1520
+ const view = new DataView(uint8Array.buffer);
1521
+ let offset = 0;
1522
+ return this.readValue(view, offset);
1523
+ }
1524
+ /**
1525
+ * 检查数据是否为二进制格式
1526
+ * @param data 要检查的数据
1527
+ * @returns 是否为二进制格式
1528
+ */
1529
+ static isBinaryFormat(data) {
1530
+ if (!data || !data.length || data.length < 1) {
1531
+ return false;
1532
+ }
1533
+ // 检查第一个字节是否为有效的类型标记(0-5)
1534
+ const firstByte = data[0];
1535
+ if (firstByte < 0 || firstByte > 5) {
1536
+ return false;
1537
+ }
1538
+ // 检查数据格式是否符合我们的二进制格式规范
1539
+ try {
1540
+ const view = new DataView(data.buffer);
1541
+ let offset = 0;
1542
+ // 递归检查数据格式
1543
+ this.validateBinaryFormat(view, offset);
1544
+ return true;
1545
+ }
1546
+ catch (error) {
1547
+ return false;
1548
+ }
1549
+ }
1550
+ /**
1551
+ * 验证二进制数据格式
1552
+ * @param view DataView对象
1553
+ * @param offset 当前偏移量
1554
+ * @returns 下一个数据的偏移量
1555
+ * @internal
1556
+ */
1557
+ static validateBinaryFormat(view, offset) {
1558
+ const type = view.getUint8(offset);
1559
+ switch (type) {
1560
+ case 0: // null
1561
+ return 1;
1562
+ case 1: // number
1563
+ return 9;
1564
+ case 2: { // string
1565
+ const strLen = view.getUint32(offset + 1, true);
1566
+ return 5 + strLen;
1567
+ }
1568
+ case 3: // boolean
1569
+ return 2;
1570
+ case 4: { // array
1571
+ const arrLen = view.getUint32(offset + 1, true);
1572
+ let size = 5;
1573
+ for (let i = 0; i < arrLen; i++) {
1574
+ size += this.validateBinaryFormat(view, offset + size);
1575
+ }
1576
+ return size;
1577
+ }
1578
+ case 5: { // object
1579
+ const objLen = view.getUint32(offset + 1, true);
1580
+ let size = 5;
1581
+ for (let i = 0; i < objLen; i++) {
1582
+ const keyLen = view.getUint32(offset + size, true);
1583
+ size += 4 + keyLen;
1584
+ size += this.validateBinaryFormat(view, offset + size);
1585
+ }
1586
+ return size;
1587
+ }
1588
+ default:
1589
+ throw new Error('无效的类型标记');
1590
+ }
1591
+ }
1592
+ /** @internal */
1593
+ static readValue(view, offset) {
1594
+ const type = view.getUint8(offset++);
1595
+ switch (type) {
1596
+ case 0: // null
1597
+ return null;
1598
+ case 1: // number
1599
+ const num = view.getFloat64(offset, true);
1600
+ return num;
1601
+ case 2: { // string
1602
+ const strLen = view.getUint32(offset, true);
1603
+ offset += 4;
1604
+ const strBytes = new Uint8Array(view.buffer, offset, strLen);
1605
+ return this.utf8ArrayToString(strBytes);
1606
+ }
1607
+ case 3: // boolean
1608
+ return view.getUint8(offset) === 1;
1609
+ case 4: // array
1610
+ const arrLen = view.getUint32(offset, true);
1611
+ offset += 4;
1612
+ const arr = [];
1613
+ for (let i = 0; i < arrLen; i++) {
1614
+ arr.push(this.readValue(view, offset));
1615
+ offset += this.getNextOffset(view, offset);
1616
+ }
1617
+ return arr;
1618
+ case 5: { // object
1619
+ const objLen = view.getUint32(offset, true);
1620
+ offset += 4;
1621
+ const obj = {};
1622
+ for (let i = 0; i < objLen; i++) {
1623
+ const keyLen = view.getUint32(offset, true);
1624
+ offset += 4;
1625
+ let key = '';
1626
+ for (let j = 0; j < keyLen; j++) {
1627
+ key += String.fromCharCode(view.getUint8(offset + j));
1628
+ }
1629
+ offset += keyLen;
1630
+ obj[key] = this.readValue(view, offset);
1631
+ offset += this.getNextOffset(view, offset);
1632
+ }
1633
+ return obj;
1634
+ }
1635
+ default:
1636
+ throw new Error(`未知的类型: ${type}`);
1637
+ }
1638
+ }
1639
+ /** @internal */
1640
+ static writeValue(value, chunks) {
1641
+ if (value === null) {
1642
+ chunks.push(new Uint8Array([0]));
1643
+ return;
1644
+ }
1645
+ switch (typeof value) {
1646
+ case 'number': {
1647
+ const numBuf = new Uint8Array(9);
1648
+ numBuf[0] = 1;
1649
+ const view = new DataView(numBuf.buffer);
1650
+ view.setFloat64(1, value, true);
1651
+ chunks.push(numBuf);
1652
+ break;
1653
+ }
1654
+ case 'string': {
1655
+ const strBytes = this.stringToUtf8Array(value);
1656
+ const strLen = strBytes.length;
1657
+ const strBuf = new Uint8Array(5 + strLen);
1658
+ strBuf[0] = 2;
1659
+ const view = new DataView(strBuf.buffer);
1660
+ view.setUint32(1, strLen, true);
1661
+ strBuf.set(strBytes, 5);
1662
+ chunks.push(strBuf);
1663
+ break;
1664
+ }
1665
+ case 'boolean': {
1666
+ const boolBuf = new Uint8Array(2);
1667
+ boolBuf[0] = 3;
1668
+ boolBuf[1] = value ? 1 : 0;
1669
+ chunks.push(boolBuf);
1670
+ break;
1671
+ }
1672
+ case 'object': {
1673
+ if (Array.isArray(value)) {
1674
+ const arrBuf = new Uint8Array(5);
1675
+ arrBuf[0] = 4;
1676
+ const view = new DataView(arrBuf.buffer);
1677
+ view.setUint32(1, value.length, true);
1678
+ chunks.push(arrBuf);
1679
+ for (const item of value) {
1680
+ this.writeValue(item, chunks);
1681
+ }
1682
+ }
1683
+ else {
1684
+ const keys = Object.keys(value);
1685
+ const objBuf = new Uint8Array(5);
1686
+ objBuf[0] = 5;
1687
+ const view = new DataView(objBuf.buffer);
1688
+ view.setUint32(1, keys.length, true);
1689
+ chunks.push(objBuf);
1690
+ for (const key of keys) {
1691
+ const keyLen = key.length;
1692
+ const keyBuf = new Uint8Array(4 + keyLen);
1693
+ const keyView = new DataView(keyBuf.buffer);
1694
+ keyView.setUint32(0, keyLen, true);
1695
+ const keyBytes = new TextEncoder().encode(key);
1696
+ keyBuf.set(keyBytes, 4);
1697
+ chunks.push(keyBuf);
1698
+ this.writeValue(value[key], chunks);
1699
+ }
1700
+ }
1701
+ break;
1702
+ }
1703
+ default:
1704
+ throw new Error(`不支持的类型: ${typeof value}`);
1705
+ }
1706
+ }
1707
+ /** @internal */
1708
+ static getNextOffset(view, offset) {
1709
+ const type = view.getUint8(offset);
1710
+ switch (type) {
1711
+ case 0: return 1; // null
1712
+ case 1: return 9; // number
1713
+ case 2: return 5 + view.getUint32(offset + 1, true); // string
1714
+ case 3: return 2; // boolean
1715
+ case 4: { // array
1716
+ const arrLen = view.getUint32(offset + 1, true);
1717
+ let currentSize = 5;
1718
+ for (let i = 0; i < arrLen; i++) {
1719
+ currentSize += this.getNextOffset(view, offset + currentSize);
1720
+ }
1721
+ return currentSize;
1722
+ }
1723
+ case 5: { // object
1724
+ const objLen = view.getUint32(offset + 1, true);
1725
+ let currentSize = 5;
1726
+ for (let i = 0; i < objLen; i++) {
1727
+ const keyLen = view.getUint32(offset + currentSize, true);
1728
+ currentSize += 4 + keyLen;
1729
+ currentSize += this.getNextOffset(view, offset + currentSize);
1730
+ }
1731
+ return currentSize;
1732
+ }
1733
+ default:
1734
+ throw new Error(`未知的类型: ${type}`);
1735
+ }
1736
+ }
1737
+ /** @internal */
1738
+ static utf8ArrayToString(array) {
1739
+ if (!array || array.length === 0) {
1740
+ return '';
1741
+ }
1742
+ let out = '';
1743
+ let i = 0;
1744
+ try {
1745
+ while (i < array.length) {
1746
+ let c = array[i++];
1747
+ if (c > 127) {
1748
+ if (c > 191 && c < 224) {
1749
+ if (i >= array.length)
1750
+ break;
1751
+ c = ((c & 31) << 6) | (array[i++] & 63);
1752
+ }
1753
+ else if (c > 223 && c < 240) {
1754
+ if (i + 1 >= array.length)
1755
+ break;
1756
+ c = ((c & 15) << 12) | ((array[i++] & 63) << 6) | (array[i++] & 63);
1757
+ }
1758
+ else if (c > 239 && c < 248) {
1759
+ if (i + 2 >= array.length)
1760
+ break;
1761
+ c = ((c & 7) << 18) | ((array[i++] & 63) << 12) | ((array[i++] & 63) << 6) | (array[i++] & 63);
1762
+ }
1763
+ else {
1764
+ // 无效的 UTF-8 序列
1765
+ continue;
1766
+ }
1767
+ }
1768
+ if (c <= 0xffff) {
1769
+ out += String.fromCharCode(c);
1770
+ }
1771
+ else if (c <= 0x10ffff) {
1772
+ c -= 0x10000;
1773
+ out += String.fromCharCode((c >> 10) | 0xd800);
1774
+ out += String.fromCharCode((c & 0x3FF) | 0xdc00);
1775
+ }
1776
+ }
1777
+ }
1778
+ catch (error) {
1779
+ console.error('UTF-8 解码错误:', error);
1780
+ return '';
1781
+ }
1782
+ return out;
1783
+ }
1784
+ /** @internal */
1785
+ static stringToUtf8Array(str) {
1786
+ if (!str || str.length === 0) {
1787
+ return new Uint8Array(0);
1788
+ }
1789
+ const arr = [];
1790
+ try {
1791
+ for (let i = 0; i < str.length; i++) {
1792
+ let charcode = str.charCodeAt(i);
1793
+ if (charcode < 0x80) {
1794
+ arr.push(charcode);
1795
+ }
1796
+ else if (charcode < 0x800) {
1797
+ arr.push(0xc0 | (charcode >> 6));
1798
+ arr.push(0x80 | (charcode & 0x3f));
1799
+ }
1800
+ else if (charcode < 0xd800 || charcode >= 0xe000) {
1801
+ arr.push(0xe0 | (charcode >> 12));
1802
+ arr.push(0x80 | ((charcode >> 6) & 0x3f));
1803
+ arr.push(0x80 | (charcode & 0x3f));
1804
+ }
1805
+ else {
1806
+ // surrogate pair
1807
+ if (i + 1 >= str.length) {
1808
+ // 不完整的代理对
1809
+ break;
1810
+ }
1811
+ i++;
1812
+ charcode = ((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff);
1813
+ charcode += 0x10000;
1814
+ arr.push(0xf0 | (charcode >> 18));
1815
+ arr.push(0x80 | ((charcode >> 12) & 0x3f));
1816
+ arr.push(0x80 | ((charcode >> 6) & 0x3f));
1817
+ arr.push(0x80 | (charcode & 0x3f));
1818
+ }
1819
+ }
1820
+ }
1821
+ catch (error) {
1822
+ console.error('UTF-8 编码错误:', error);
1823
+ return new Uint8Array(0);
1824
+ }
1825
+ return new Uint8Array(arr);
1826
+ }
1827
+ }
1828
+
1829
+ // const base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1830
+ class Crypt {
1831
+ // Bit-wise rotation left
1832
+ static rotl(n, b) {
1833
+ return (n << b) | (n >>> (32 - b));
1834
+ }
1835
+ // Bit-wise rotation right
1836
+ static rotr(n, b) {
1837
+ return (n << (32 - b)) | (n >>> b);
1838
+ }
1839
+ // Swap big-endian to little-endian and vice versa
1840
+ static endianNumber(n) {
1841
+ return (Crypt.rotl(n, 8) & 0x00ff00ff) | (Crypt.rotl(n, 24) & 0xff00ff00);
1842
+ }
1843
+ // Swap big-endian to little-endian and vice versa
1844
+ static endianArray(n) {
1845
+ for (let i = 0, l = n.length; i < l; i++) {
1846
+ n[i] = Crypt.endianNumber(n[i]);
1847
+ }
1848
+ return n;
1849
+ }
1850
+ // Generate an array of any length of random bytes
1851
+ static randomBytes(n) {
1852
+ const bytes = [];
1853
+ for (; n > 0; n--) {
1854
+ bytes.push(Math.floor(Math.random() * 256));
1855
+ }
1856
+ return bytes;
1857
+ }
1858
+ // Convert a byte array to big-endian 32-bit words
1859
+ static bytesToWords(bytes) {
1860
+ const words = [];
1861
+ for (let i = 0, b = 0, l = bytes.length; i < l; i++, b += 8) {
1862
+ words[b >>> 5] |= bytes[i] << (24 - (b % 32));
1863
+ }
1864
+ return words;
1865
+ }
1866
+ // Convert big-endian 32-bit words to a byte array
1867
+ static wordsToBytes(words) {
1868
+ const bytes = [];
1869
+ for (let b = 0, l = words.length * 32; b < l; b += 8) {
1870
+ bytes.push((words[b >>> 5] >>> (24 - (b % 32))) & 0xff);
1871
+ }
1872
+ return bytes;
1873
+ }
1874
+ // Convert a byte array to a hex string
1875
+ static bytesToHex(bytes) {
1876
+ const hex = [];
1877
+ for (let i = 0, l = bytes.length; i < l; i++) {
1878
+ hex.push((bytes[i] >>> 4).toString(16));
1879
+ hex.push((bytes[i] & 0xf).toString(16));
1880
+ }
1881
+ return hex.join("");
1882
+ }
1883
+ // Convert a hex string to a byte array
1884
+ static hexToBytes(hex) {
1885
+ const bytes = [];
1886
+ for (let c = 0, l = hex.length; c < l; c += 2) {
1887
+ bytes.push(parseInt(hex.substr(c, 2), 16));
1888
+ }
1889
+ return bytes;
1890
+ }
1891
+ }
1892
+ // Convert a string to a byte array
1893
+ function stringToBytes(str) {
1894
+ str = unescape(encodeURIComponent(str));
1895
+ const bytes = [];
1896
+ for (let i = 0, l = str.length; i < l; i++) {
1897
+ bytes.push(str.charCodeAt(i) & 0xff);
1898
+ }
1899
+ return bytes;
1900
+ }
1901
+ // The core
1902
+ const md5Lib = function (message) {
1903
+ const bytes = stringToBytes(message);
1904
+ const m = Crypt.bytesToWords(bytes), l = bytes.length * 8;
1905
+ let ml = m.length;
1906
+ let a = 1732584193, b = -271733879, c = -1732584194, d = 271733878;
1907
+ // Swap endian
1908
+ for (let i = 0; i < ml; i++) {
1909
+ m[i] = (((m[i] << 8) | (m[i] >>> 24)) & 0x00ff00ff) | (((m[i] << 24) | (m[i] >>> 8)) & 0xff00ff00);
1910
+ }
1911
+ // Padding
1912
+ m[l >>> 5] |= 0x80 << l % 32;
1913
+ m[(((l + 64) >>> 9) << 4) + 14] = l;
1914
+ // Method shortcuts
1915
+ const FF = md5Lib._ff, GG = md5Lib._gg, HH = md5Lib._hh, II = md5Lib._ii;
1916
+ ml = m.length;
1917
+ for (let i = 0; i < ml; i += 16) {
1918
+ const aa = a, bb = b, cc = c, dd = d;
1919
+ a = FF(a, b, c, d, m[i + 0], 7, -680876936);
1920
+ d = FF(d, a, b, c, m[i + 1], 12, -389564586);
1921
+ c = FF(c, d, a, b, m[i + 2], 17, 606105819);
1922
+ b = FF(b, c, d, a, m[i + 3], 22, -1044525330);
1923
+ a = FF(a, b, c, d, m[i + 4], 7, -176418897);
1924
+ d = FF(d, a, b, c, m[i + 5], 12, 1200080426);
1925
+ c = FF(c, d, a, b, m[i + 6], 17, -1473231341);
1926
+ b = FF(b, c, d, a, m[i + 7], 22, -45705983);
1927
+ a = FF(a, b, c, d, m[i + 8], 7, 1770035416);
1928
+ d = FF(d, a, b, c, m[i + 9], 12, -1958414417);
1929
+ c = FF(c, d, a, b, m[i + 10], 17, -42063);
1930
+ b = FF(b, c, d, a, m[i + 11], 22, -1990404162);
1931
+ a = FF(a, b, c, d, m[i + 12], 7, 1804603682);
1932
+ d = FF(d, a, b, c, m[i + 13], 12, -40341101);
1933
+ c = FF(c, d, a, b, m[i + 14], 17, -1502002290);
1934
+ b = FF(b, c, d, a, m[i + 15], 22, 1236535329);
1935
+ a = GG(a, b, c, d, m[i + 1], 5, -165796510);
1936
+ d = GG(d, a, b, c, m[i + 6], 9, -1069501632);
1937
+ c = GG(c, d, a, b, m[i + 11], 14, 643717713);
1938
+ b = GG(b, c, d, a, m[i + 0], 20, -373897302);
1939
+ a = GG(a, b, c, d, m[i + 5], 5, -701558691);
1940
+ d = GG(d, a, b, c, m[i + 10], 9, 38016083);
1941
+ c = GG(c, d, a, b, m[i + 15], 14, -660478335);
1942
+ b = GG(b, c, d, a, m[i + 4], 20, -405537848);
1943
+ a = GG(a, b, c, d, m[i + 9], 5, 568446438);
1944
+ d = GG(d, a, b, c, m[i + 14], 9, -1019803690);
1945
+ c = GG(c, d, a, b, m[i + 3], 14, -187363961);
1946
+ b = GG(b, c, d, a, m[i + 8], 20, 1163531501);
1947
+ a = GG(a, b, c, d, m[i + 13], 5, -1444681467);
1948
+ d = GG(d, a, b, c, m[i + 2], 9, -51403784);
1949
+ c = GG(c, d, a, b, m[i + 7], 14, 1735328473);
1950
+ b = GG(b, c, d, a, m[i + 12], 20, -1926607734);
1951
+ a = HH(a, b, c, d, m[i + 5], 4, -378558);
1952
+ d = HH(d, a, b, c, m[i + 8], 11, -2022574463);
1953
+ c = HH(c, d, a, b, m[i + 11], 16, 1839030562);
1954
+ b = HH(b, c, d, a, m[i + 14], 23, -35309556);
1955
+ a = HH(a, b, c, d, m[i + 1], 4, -1530992060);
1956
+ d = HH(d, a, b, c, m[i + 4], 11, 1272893353);
1957
+ c = HH(c, d, a, b, m[i + 7], 16, -155497632);
1958
+ b = HH(b, c, d, a, m[i + 10], 23, -1094730640);
1959
+ a = HH(a, b, c, d, m[i + 13], 4, 681279174);
1960
+ d = HH(d, a, b, c, m[i + 0], 11, -358537222);
1961
+ c = HH(c, d, a, b, m[i + 3], 16, -722521979);
1962
+ b = HH(b, c, d, a, m[i + 6], 23, 76029189);
1963
+ a = HH(a, b, c, d, m[i + 9], 4, -640364487);
1964
+ d = HH(d, a, b, c, m[i + 12], 11, -421815835);
1965
+ c = HH(c, d, a, b, m[i + 15], 16, 530742520);
1966
+ b = HH(b, c, d, a, m[i + 2], 23, -995338651);
1967
+ a = II(a, b, c, d, m[i + 0], 6, -198630844);
1968
+ d = II(d, a, b, c, m[i + 7], 10, 1126891415);
1969
+ c = II(c, d, a, b, m[i + 14], 15, -1416354905);
1970
+ b = II(b, c, d, a, m[i + 5], 21, -57434055);
1971
+ a = II(a, b, c, d, m[i + 12], 6, 1700485571);
1972
+ d = II(d, a, b, c, m[i + 3], 10, -1894986606);
1973
+ c = II(c, d, a, b, m[i + 10], 15, -1051523);
1974
+ b = II(b, c, d, a, m[i + 1], 21, -2054922799);
1975
+ a = II(a, b, c, d, m[i + 8], 6, 1873313359);
1976
+ d = II(d, a, b, c, m[i + 15], 10, -30611744);
1977
+ c = II(c, d, a, b, m[i + 6], 15, -1560198380);
1978
+ b = II(b, c, d, a, m[i + 13], 21, 1309151649);
1979
+ a = II(a, b, c, d, m[i + 4], 6, -145523070);
1980
+ d = II(d, a, b, c, m[i + 11], 10, -1120210379);
1981
+ c = II(c, d, a, b, m[i + 2], 15, 718787259);
1982
+ b = II(b, c, d, a, m[i + 9], 21, -343485551);
1983
+ a = (a + aa) >>> 0;
1984
+ b = (b + bb) >>> 0;
1985
+ c = (c + cc) >>> 0;
1986
+ d = (d + dd) >>> 0;
1987
+ }
1988
+ return Crypt.endianArray([a, b, c, d]);
1989
+ };
1990
+ // Auxiliary functions
1991
+ // eslint-disable-next-line max-params
1992
+ md5Lib._ff = function (a, b, c, d, x, s, t) {
1993
+ const n = a + ((b & c) | (~b & d)) + (x >>> 0) + t;
1994
+ return ((n << s) | (n >>> (32 - s))) + b;
1995
+ };
1996
+ // eslint-disable-next-line max-params
1997
+ md5Lib._gg = function (a, b, c, d, x, s, t) {
1998
+ const n = a + ((b & d) | (c & ~d)) + (x >>> 0) + t;
1999
+ return ((n << s) | (n >>> (32 - s))) + b;
2000
+ };
2001
+ // eslint-disable-next-line max-params
2002
+ md5Lib._hh = function (a, b, c, d, x, s, t) {
2003
+ const n = a + (b ^ c ^ d) + (x >>> 0) + t;
2004
+ return ((n << s) | (n >>> (32 - s))) + b;
2005
+ };
2006
+ // eslint-disable-next-line max-params
2007
+ md5Lib._ii = function (a, b, c, d, x, s, t) {
2008
+ const n = a + (c ^ (b | ~d)) + (x >>> 0) + t;
2009
+ return ((n << s) | (n >>> (32 - s))) + b;
2010
+ };
2011
+ /**
2012
+ * 对字符串执行md5处理
2013
+ *
2014
+ * @export
2015
+ * @param {string} message 要处理的字符串
2016
+ * @returns {string} md5
2017
+ */
2018
+ function md5(message) {
2019
+ if (message === undefined || message === null) {
2020
+ throw new Error("Illegal argument " + message);
2021
+ }
2022
+ return Crypt.bytesToHex(Crypt.wordsToBytes(md5Lib(message)));
2023
+ }
2024
+
2025
+ /**
2026
+ * @Author: Gongxh
2027
+ * @Date: 2025-04-11
2028
+ * @Description:
2029
+ */
2030
+ class Utils {
2031
+ /**
2032
+ * 版本号比较
2033
+ * @param version1 本地版本号
2034
+ * @param version2 远程版本号
2035
+ * 如果返回值大于0,则version1大于version2
2036
+ * 如果返回值等于0,则version1等于version2
2037
+ * 如果返回值小于0,则version1小于version2
2038
+ */
2039
+ static compareVersion(version1, version2) {
2040
+ let v1 = version1.split('.');
2041
+ let v2 = version2.split('.');
2042
+ const len = Math.max(v1.length, v2.length);
2043
+ while (v1.length < len) {
2044
+ v1.push('0');
2045
+ }
2046
+ while (v2.length < len) {
2047
+ v2.push('0');
2048
+ }
2049
+ for (let i = 0; i < len; ++i) {
2050
+ let num1 = parseInt(v1[i]);
2051
+ let num2 = parseInt(v2[i]);
2052
+ if (num1 > num2) {
2053
+ return 1;
2054
+ }
2055
+ else if (num1 < num2) {
2056
+ return -1;
2057
+ }
2058
+ }
2059
+ return 0;
2060
+ }
2061
+ /**
2062
+ * 判断传入的字符串是否是json格式的字符串
2063
+ */
2064
+ static isJsonString(str) {
2065
+ try {
2066
+ JSON.parse(str);
2067
+ return true;
2068
+ }
2069
+ catch (e) {
2070
+ return false;
2071
+ }
2072
+ }
2073
+ /**
2074
+ * 获取url参数
2075
+ * @param url
2076
+ */
2077
+ static getUrlParam(url) {
2078
+ let result = { url: "", params: {} };
2079
+ let urlArr = url.split('?');
2080
+ result.url = urlArr[0];
2081
+ if (urlArr.length > 1) {
2082
+ let paramsArr = urlArr[1].split("&");
2083
+ for (let i = 0; i < paramsArr.length; i++) {
2084
+ let item = paramsArr[i];
2085
+ let [key, value] = item.split("=");
2086
+ result.params[key] = value;
2087
+ }
2088
+ }
2089
+ return result;
2090
+ }
2091
+ /**
2092
+ * 给url添加参数
2093
+ * @param url
2094
+ * @returns 新的url
2095
+ */
2096
+ static addUrlParam(url, key, value) {
2097
+ let urlData = this.getUrlParam(url);
2098
+ urlData.params[key] = value;
2099
+ return urlData.url + "?" + Object.entries(urlData.params).map(([key, value]) => `${key}=${value}`).join("&");
2100
+ }
2101
+ }
2102
+
2103
+ function defaultEquals(a, b) {
2104
+ return a === b;
2105
+ }
2106
+ /** 单链表结结构节点 */
2107
+ class LinkedNode {
2108
+ constructor(element) {
2109
+ this.element = element;
2110
+ this.next = undefined;
2111
+ }
2112
+ }
2113
+ /** 双向链表结结构节点 */
2114
+ class DoublyNode extends LinkedNode {
2115
+ constructor(element) {
2116
+ super(element);
2117
+ this.prev = undefined;
2118
+ }
2119
+ }
2120
+ /** 单向链表 */
2121
+ class LinkedList {
2122
+ /**
2123
+ * create
2124
+ * @param equalsFn 比较是否相等(支持自定义)
2125
+ */
2126
+ constructor(equalsFn) {
2127
+ this._equalsFn = equalsFn || defaultEquals;
2128
+ this._count = 0;
2129
+ this._head = undefined;
2130
+ }
2131
+ /** 向链表尾部添加元素 */
2132
+ push(element) {
2133
+ const node = new LinkedNode(element);
2134
+ let current;
2135
+ if (this._head === undefined) {
2136
+ this._head = node;
2137
+ }
2138
+ else {
2139
+ current = this._head;
2140
+ while (current.next !== undefined) {
2141
+ current = current.next;
2142
+ }
2143
+ current.next = node;
2144
+ }
2145
+ this._count++;
2146
+ }
2147
+ /**
2148
+ * 在链表的指定位置插入一个元素。
2149
+ * @param element 要插入的元素。
2150
+ * @param index 插入位置的索引,从0开始计数。
2151
+ * @returns 如果插入成功返回true,否则返回false。
2152
+ */
2153
+ insert(element, index) {
2154
+ if (index >= 0 && index <= this._count) {
2155
+ const node = new LinkedNode(element);
2156
+ if (index === 0) {
2157
+ const current = this._head;
2158
+ node.next = current;
2159
+ this._head = node;
2160
+ }
2161
+ else {
2162
+ const previous = this.getElementAt(index - 1);
2163
+ const current = previous.next;
2164
+ node.next = current;
2165
+ previous.next = node;
2166
+ }
2167
+ this._count++;
2168
+ return true;
2169
+ }
2170
+ return false;
2171
+ }
2172
+ /**
2173
+ * 获取链表中指定位置的元素,如果不存在返回 underfined
2174
+ * @param index
2175
+ */
2176
+ getElementAt(index) {
2177
+ if (index >= 0 && index <= this._count) {
2178
+ let node = this._head;
2179
+ for (let i = 0; i < index && node !== undefined; i++) {
2180
+ node = node.next;
2181
+ }
2182
+ return node;
2183
+ }
2184
+ return undefined;
2185
+ }
2186
+ /**
2187
+ * 从链表中移除一个元素
2188
+ * @param element
2189
+ */
2190
+ remove(element) {
2191
+ return this.removeAt(this.indexOf(element));
2192
+ }
2193
+ /**
2194
+ * 从链表的特定位置移除一个元素
2195
+ * @param index
2196
+ */
2197
+ removeAt(index) {
2198
+ if (index >= 0 && index < this._count) {
2199
+ let current = this._head;
2200
+ if (index === 0) {
2201
+ this._head = current.next;
2202
+ }
2203
+ else {
2204
+ const previous = this.getElementAt(index - 1);
2205
+ current = previous.next;
2206
+ previous.next = current.next;
2207
+ }
2208
+ this._count--;
2209
+ current.next = undefined;
2210
+ return current.element;
2211
+ }
2212
+ return undefined;
2213
+ }
2214
+ /**
2215
+ * 返回元素在链表中的索引,如果没有则返回-1
2216
+ * @param element
2217
+ */
2218
+ indexOf(element) {
2219
+ let current = this._head;
2220
+ for (let i = 0; i < this._count && current !== undefined; i++) {
2221
+ if (this._equalsFn(element, current.element)) {
2222
+ return i;
2223
+ }
2224
+ current = current.next;
2225
+ }
2226
+ return -1;
2227
+ }
2228
+ clear() {
2229
+ this._head = undefined;
2230
+ this._count = 0;
2231
+ }
2232
+ getHead() {
2233
+ return this._head;
2234
+ }
2235
+ isEmpty() {
2236
+ return this.size() === 0;
2237
+ }
2238
+ size() {
2239
+ return this._count;
2240
+ }
2241
+ toString() {
2242
+ if (this._head === undefined) {
2243
+ return "";
2244
+ }
2245
+ let objString = `${this._head.element}`;
2246
+ let current = this._head.next;
2247
+ for (let i = 0; i < this.size() && current !== undefined; i++) {
2248
+ objString = `${objString},${current.element}`;
2249
+ current = current.next;
2250
+ }
2251
+ return objString;
2252
+ }
2253
+ }
2254
+ /** 双向链表 */
2255
+ class DoublyLinkedList extends LinkedList {
2256
+ /**
2257
+ * create
2258
+ * @param equalsFn 比较是否相等(支持自定义)
2259
+ */
2260
+ constructor(equalsFn) {
2261
+ super(equalsFn);
2262
+ this._tail = undefined;
2263
+ }
2264
+ /**
2265
+ * 向链表尾部添加元素
2266
+ * @param element
2267
+ */
2268
+ push(element) {
2269
+ this.insert(element, this._count);
2270
+ }
2271
+ /**
2272
+ * 向链表指定位置添加元素
2273
+ * @param element
2274
+ * @param index
2275
+ */
2276
+ insert(element, index) {
2277
+ if (index >= 0 && index <= this._count) {
2278
+ const node = new DoublyNode(element);
2279
+ let current = this._head;
2280
+ if (index === 0) {
2281
+ if (this._head === undefined) {
2282
+ this._head = node;
2283
+ this._tail = node;
2284
+ }
2285
+ else {
2286
+ node.next = current;
2287
+ current.prev = node;
2288
+ this._head = node;
2289
+ }
2290
+ }
2291
+ else if (index === this._count) {
2292
+ current = this._tail;
2293
+ current.next = node;
2294
+ node.prev = current;
2295
+ this._tail = node;
2296
+ }
2297
+ else {
2298
+ const previous = this.getElementAt(index - 1);
2299
+ current = previous.next;
2300
+ node.next = current;
2301
+ previous.next = node;
2302
+ current.prev = node;
2303
+ node.prev = previous;
2304
+ }
2305
+ this._count++;
2306
+ return true;
2307
+ }
2308
+ return false;
2309
+ }
2310
+ /**
2311
+ * 从链表的特定位置移除一个元素
2312
+ * @param index
2313
+ */
2314
+ removeAt(index) {
2315
+ if (index >= 0 && index < this._count) {
2316
+ let current = this._head;
2317
+ if (index === 0) {
2318
+ this._head = current.next;
2319
+ if (this._count === 1) {
2320
+ this._tail = undefined;
2321
+ }
2322
+ else {
2323
+ this._head.prev = undefined;
2324
+ }
2325
+ }
2326
+ else if (index === this._count - 1) {
2327
+ current = this._tail;
2328
+ this._tail = current.prev;
2329
+ this._tail.next = undefined;
2330
+ }
2331
+ else {
2332
+ current = this.getElementAt(index);
2333
+ const previous = current.prev;
2334
+ previous.next = current.next;
2335
+ current.next.prev = previous;
2336
+ }
2337
+ this._count--;
2338
+ current.next = undefined;
2339
+ current.prev = undefined;
2340
+ return current.element;
2341
+ }
2342
+ return null;
2343
+ }
2344
+ /**
2345
+ * 获取链表中指定位置的元素,如果不存在返回 null
2346
+ * @param index
2347
+ */
2348
+ getElementAt(index) {
2349
+ if (index >= 0 && index <= this._count) {
2350
+ if (index > this._count * 0.5) {
2351
+ // 从后向前找
2352
+ let node = this._tail;
2353
+ for (let i = this._count - 1; i > index && node !== undefined; i--) {
2354
+ node = node.prev;
2355
+ }
2356
+ return node;
2357
+ }
2358
+ else {
2359
+ // 从前向后找
2360
+ let node = this._head;
2361
+ for (let i = 0; i < index && node !== undefined; i++) {
2362
+ node = node.next;
2363
+ }
2364
+ return node;
2365
+ }
2366
+ }
2367
+ return undefined;
2368
+ }
2369
+ getHead() {
2370
+ return this._head;
2371
+ }
2372
+ getTail() {
2373
+ return this._tail;
2374
+ }
2375
+ clear() {
2376
+ this._head = undefined;
2377
+ this._tail = undefined;
2378
+ this._count = 0;
2379
+ }
2380
+ }
2381
+
2382
+ class Stack {
2383
+ constructor(equalsFn) {
2384
+ this._items = new DoublyLinkedList(equalsFn);
2385
+ }
2386
+ push(element) {
2387
+ this._items.push(element);
2388
+ }
2389
+ pop() {
2390
+ if (this.isEmpty()) {
2391
+ return undefined;
2392
+ }
2393
+ return this._items.removeAt(this.size() - 1);
2394
+ }
2395
+ peek() {
2396
+ if (this.isEmpty()) {
2397
+ return undefined;
2398
+ }
2399
+ return this._items.getTail().element;
2400
+ }
2401
+ size() {
2402
+ return this._items.size();
2403
+ }
2404
+ isEmpty() {
2405
+ return this._items.isEmpty();
2406
+ }
2407
+ clear() {
2408
+ this._items.clear();
2409
+ }
2410
+ toString() {
2411
+ return this._items.toString();
2412
+ }
2413
+ }
2414
+
2415
+ export { Adapter, Binary, BinaryHeap, CocosEntry, DoublyLinkedList, DoublyNode, GlobalTimer, HeapNode, InnerTimer, LinkedList, LinkedNode, Module, Platform, PlatformType, Screen, Stack, Time, Utils, debug, enableDebugMode, error, info, log, md5, warn };