@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/LICENSE +21 -0
- package/README.md +175 -56
- package/dist/bit-core.cjs +2215 -223
- package/dist/bit-core.d.ts +579 -20
- package/dist/bit-core.min.cjs +1 -1
- package/dist/bit-core.min.mjs +1 -1
- package/dist/bit-core.mjs +2203 -225
- package/package.json +33 -51
package/dist/bit-core.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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-
|
|
322
|
-
* @Description:
|
|
195
|
+
* @Date: 2024-12-07
|
|
196
|
+
* @Description: 二叉堆(默认最小堆) 支持最大堆和最小堆
|
|
323
197
|
*/
|
|
324
|
-
class
|
|
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
|
-
|
|
331
|
-
|
|
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
|
-
* @
|
|
339
|
-
* @internal
|
|
213
|
+
* 获取节点
|
|
214
|
+
* @param index 节点索引
|
|
340
215
|
*/
|
|
341
|
-
|
|
342
|
-
|
|
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
|
-
|
|
351
|
-
|
|
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
|
-
* @
|
|
226
|
+
* 是否包含节点
|
|
227
|
+
* @param node 节点
|
|
381
228
|
*/
|
|
382
|
-
|
|
383
|
-
this.
|
|
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("
|
|
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("
|
|
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
|
-
|
|
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 };
|