@xiacg/exia-assets 1.0.0
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 +82 -0
- package/dist/exia-assets.cjs +746 -0
- package/dist/exia-assets.d.ts +165 -0
- package/dist/exia-assets.min.cjs +1 -0
- package/dist/exia-assets.min.mjs +1 -0
- package/dist/exia-assets.mjs +742 -0
- package/package.json +38 -0
|
@@ -0,0 +1,742 @@
|
|
|
1
|
+
import { Asset, resources, assetManager } from 'cc';
|
|
2
|
+
|
|
3
|
+
/** 资源加载的状态类型 */
|
|
4
|
+
var StateType;
|
|
5
|
+
(function (StateType) {
|
|
6
|
+
StateType[StateType["Error"] = 0] = "Error";
|
|
7
|
+
StateType[StateType["Wait"] = 1] = "Wait";
|
|
8
|
+
StateType[StateType["Loading"] = 2] = "Loading";
|
|
9
|
+
StateType[StateType["Finish"] = 3] = "Finish";
|
|
10
|
+
})(StateType || (StateType = {}));
|
|
11
|
+
var ErrorCode;
|
|
12
|
+
(function (ErrorCode) {
|
|
13
|
+
/** 文件加载失败 */
|
|
14
|
+
ErrorCode[ErrorCode["FileLoadFailed"] = 1] = "FileLoadFailed";
|
|
15
|
+
/** 资源包加载失败 */
|
|
16
|
+
ErrorCode[ErrorCode["BundleLoadFailed"] = 2] = "BundleLoadFailed";
|
|
17
|
+
})(ErrorCode || (ErrorCode = {}));
|
|
18
|
+
|
|
19
|
+
class AssetInfo {
|
|
20
|
+
/**
|
|
21
|
+
* @param info IAssetConfig 资源配置
|
|
22
|
+
* @param count number 资源数量
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
constructor(info, bundle, status = StateType.Wait) {
|
|
27
|
+
/** @internal */
|
|
28
|
+
this._type = Asset;
|
|
29
|
+
/** @internal */
|
|
30
|
+
this._path = "";
|
|
31
|
+
/** @internal */
|
|
32
|
+
this._isFile = false;
|
|
33
|
+
/** @internal */
|
|
34
|
+
this._bundle = "resources";
|
|
35
|
+
/** @internal */
|
|
36
|
+
this._assetBundle = resources;
|
|
37
|
+
/** @internal */
|
|
38
|
+
this._status = StateType.Wait;
|
|
39
|
+
this._type = info.type || Asset;
|
|
40
|
+
this._path = info.path;
|
|
41
|
+
this._isFile = info.isFile || false;
|
|
42
|
+
this._bundle = info.bundle || "resources";
|
|
43
|
+
this._assetBundle = bundle;
|
|
44
|
+
this._status = status;
|
|
45
|
+
}
|
|
46
|
+
/** 固定的属性 */
|
|
47
|
+
get type() {
|
|
48
|
+
return this._type;
|
|
49
|
+
}
|
|
50
|
+
get path() {
|
|
51
|
+
return this._path;
|
|
52
|
+
}
|
|
53
|
+
get isFile() {
|
|
54
|
+
return this._isFile;
|
|
55
|
+
}
|
|
56
|
+
get bundle() {
|
|
57
|
+
return this._bundle;
|
|
58
|
+
}
|
|
59
|
+
get assetBundle() {
|
|
60
|
+
return this._assetBundle;
|
|
61
|
+
}
|
|
62
|
+
/** 可变的属性 */
|
|
63
|
+
get status() {
|
|
64
|
+
return this._status;
|
|
65
|
+
}
|
|
66
|
+
set status(status) {
|
|
67
|
+
this._status = status;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
class AssetLoaderAgent {
|
|
72
|
+
constructor() {
|
|
73
|
+
/** @internal */
|
|
74
|
+
this._maxParallel = 10;
|
|
75
|
+
/** @internal */
|
|
76
|
+
this._maxRetry = 0;
|
|
77
|
+
/**
|
|
78
|
+
* 资源加载项
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
81
|
+
this._assetInfos = [];
|
|
82
|
+
/**
|
|
83
|
+
* 加载完成数量
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
this._completeCounts = new Map();
|
|
87
|
+
/** 是否加载完成 @internal */
|
|
88
|
+
this._isComplete = false;
|
|
89
|
+
/********************** 回调相关内容 end **********************/
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 设置最大并行数量
|
|
93
|
+
* @param {number} parallel 最大并行数量
|
|
94
|
+
*/
|
|
95
|
+
set parallel(parallel) {
|
|
96
|
+
this._maxParallel = Math.max(1, parallel);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 设置失败重试次数
|
|
100
|
+
* @param {number} retry 失败重试次数 默认: 0
|
|
101
|
+
*/
|
|
102
|
+
set retry(retry) {
|
|
103
|
+
this._maxRetry = retry;
|
|
104
|
+
}
|
|
105
|
+
/** @internal */
|
|
106
|
+
initialize() {
|
|
107
|
+
this._isComplete = false;
|
|
108
|
+
this._assetInfos.length = 0;
|
|
109
|
+
this._completeCounts.clear();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 设置资源总数量
|
|
113
|
+
* @param bundle bundle名
|
|
114
|
+
* @param path 资源路径
|
|
115
|
+
* @param total 总数量
|
|
116
|
+
* @internal
|
|
117
|
+
*/
|
|
118
|
+
setTotalCount(bundle, path, total) {
|
|
119
|
+
let key = `${bundle}:${path}`;
|
|
120
|
+
this._completeCounts.set(key, { value: 0, total: total });
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 添加加载完成数量
|
|
124
|
+
* @param bundle bundle名
|
|
125
|
+
* @param path 资源路径
|
|
126
|
+
* @param count 完成数量
|
|
127
|
+
* @internal
|
|
128
|
+
*/
|
|
129
|
+
updateCompleteCount(bundle, path, count, total) {
|
|
130
|
+
let key = `${bundle}:${path}`;
|
|
131
|
+
if (this._completeCounts.has(key)) {
|
|
132
|
+
let info = this._completeCounts.get(key);
|
|
133
|
+
info.value = Math.min(count, total);
|
|
134
|
+
info.total = total;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
this._completeCounts.set(key, {
|
|
138
|
+
value: Math.min(count, total),
|
|
139
|
+
total: total,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
this.progressUpdate();
|
|
143
|
+
}
|
|
144
|
+
/** @internal */
|
|
145
|
+
addAssetInfo(info) {
|
|
146
|
+
this._assetInfos.push(info);
|
|
147
|
+
}
|
|
148
|
+
/** 通过索引获取 */
|
|
149
|
+
getAssetInfo(index) {
|
|
150
|
+
return this._assetInfos[index];
|
|
151
|
+
}
|
|
152
|
+
/** @internal */
|
|
153
|
+
getAssetsCount() {
|
|
154
|
+
return this._assetInfos.length;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 找到第一个等待中资源的索引 如果不存在则返回 -1
|
|
158
|
+
* @internal
|
|
159
|
+
*/
|
|
160
|
+
getFirstWaitIndex() {
|
|
161
|
+
return this._assetInfos.findIndex((item) => item.status == StateType.Wait);
|
|
162
|
+
}
|
|
163
|
+
/** @internal */
|
|
164
|
+
isAllFinished() {
|
|
165
|
+
return this._assetInfos.every((item) => item.status == StateType.Finish);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 重置失败资源状态为等待中
|
|
169
|
+
* @internal
|
|
170
|
+
*/
|
|
171
|
+
resetErrorAssets() {
|
|
172
|
+
let count = 0;
|
|
173
|
+
for (const item of this._assetInfos) {
|
|
174
|
+
if (item.status == StateType.Error) {
|
|
175
|
+
item.status = StateType.Wait;
|
|
176
|
+
count++;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return count;
|
|
180
|
+
}
|
|
181
|
+
downloadFaildAnalysis() {
|
|
182
|
+
// 找到所有失败的资源 把路径拼成字符串
|
|
183
|
+
let paths = [];
|
|
184
|
+
for (const item of this._assetInfos) {
|
|
185
|
+
if (item.status == StateType.Error) {
|
|
186
|
+
paths.push(`bundle:${item.bundle} path:${item.path}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
let msg = `加载失败资源:\n${paths.join("\n")}`;
|
|
190
|
+
this.failCallback(ErrorCode.FileLoadFailed, msg);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* @param res 设置回调函数
|
|
194
|
+
* @param {Function} res.complete 加载完成回调
|
|
195
|
+
* @param {Function} res.fail 加载失败回调
|
|
196
|
+
* @param {Function} res.progress 加载进度回调
|
|
197
|
+
*/
|
|
198
|
+
setCallbacks(res) {
|
|
199
|
+
this._complete = res.complete || (() => { });
|
|
200
|
+
this._fail = res.fail || (() => { });
|
|
201
|
+
this._progress = res.progress || (() => { });
|
|
202
|
+
}
|
|
203
|
+
/** @internal */
|
|
204
|
+
progressUpdate() {
|
|
205
|
+
if (!this._progress) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
let count = 0, totalCount = 0;
|
|
209
|
+
for (const { value, total } of this._completeCounts.values()) {
|
|
210
|
+
count += value;
|
|
211
|
+
totalCount += total;
|
|
212
|
+
}
|
|
213
|
+
this._progress(Math.max(Math.min(count / totalCount, 1), 0));
|
|
214
|
+
}
|
|
215
|
+
/** @internal */
|
|
216
|
+
completeAll() {
|
|
217
|
+
var _a;
|
|
218
|
+
if (this._isComplete) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
this._isComplete = true;
|
|
222
|
+
(_a = this._complete) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
223
|
+
}
|
|
224
|
+
/** @internal */
|
|
225
|
+
failCallback(code, msg) {
|
|
226
|
+
var _a;
|
|
227
|
+
(_a = this._fail) === null || _a === void 0 ? void 0 : _a.call(this, code, msg);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
class AssetUtils {
|
|
232
|
+
/** 获取资源数量 */
|
|
233
|
+
static getResourceCount(dir, type, bundle = resources) {
|
|
234
|
+
dir = assetManager.utils.normalize(dir);
|
|
235
|
+
if (dir[dir.length - 1] === "/") {
|
|
236
|
+
dir = dir.slice(0, -1);
|
|
237
|
+
}
|
|
238
|
+
let list = bundle.getDirWithPath(dir, type);
|
|
239
|
+
return list.length;
|
|
240
|
+
}
|
|
241
|
+
/** 获取资源名称 */
|
|
242
|
+
static getUUIDs(dir, type, bundle = resources) {
|
|
243
|
+
let uuids = [];
|
|
244
|
+
let path = assetManager.utils.normalize(dir);
|
|
245
|
+
if (path[path.length - 1] === "/") {
|
|
246
|
+
path = path.slice(0, -1);
|
|
247
|
+
}
|
|
248
|
+
let list = bundle.getDirWithPath(path, type);
|
|
249
|
+
for (const asset of list) {
|
|
250
|
+
uuids.push(asset.uuid);
|
|
251
|
+
}
|
|
252
|
+
return uuids;
|
|
253
|
+
}
|
|
254
|
+
/** 加载 bundle */
|
|
255
|
+
static loadBundle(bundlename) {
|
|
256
|
+
return new Promise((resolve, reject) => {
|
|
257
|
+
let bundle = assetManager.getBundle(bundlename);
|
|
258
|
+
if (bundle) {
|
|
259
|
+
resolve(bundle);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
assetManager.loadBundle(bundlename, (err, bundle) => {
|
|
263
|
+
if (err) {
|
|
264
|
+
reject(err);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
resolve(bundle);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 加载单个资源
|
|
275
|
+
* @param bundle 资源包名或资源包
|
|
276
|
+
* @param path 资源路径
|
|
277
|
+
* @param type 资源类型
|
|
278
|
+
* @param callbacks 回调函数
|
|
279
|
+
*/
|
|
280
|
+
static loadFile(bundle, path, type, callbacks) {
|
|
281
|
+
if (typeof bundle === "string") {
|
|
282
|
+
AssetUtils.loadBundle(bundle)
|
|
283
|
+
.then((bundle) => {
|
|
284
|
+
// 加载单个资源
|
|
285
|
+
bundle.load(path, type, (error, asset) => {
|
|
286
|
+
var _a, _b;
|
|
287
|
+
if (error) {
|
|
288
|
+
(_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.fail) === null || _a === void 0 ? void 0 : _a.call(callbacks, ErrorCode.FileLoadFailed, `加载资源失败【bundle:${bundle} path:${path}】`);
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
(_b = callbacks === null || callbacks === void 0 ? void 0 : callbacks.complete) === null || _b === void 0 ? void 0 : _b.call(callbacks, asset);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
})
|
|
295
|
+
.catch((err) => {
|
|
296
|
+
var _a;
|
|
297
|
+
(_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.fail) === null || _a === void 0 ? void 0 : _a.call(callbacks, ErrorCode.BundleLoadFailed, `加载bundle[${bundle}]失败`);
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
// 加载单个资源
|
|
302
|
+
bundle.load(path, type, (error, asset) => {
|
|
303
|
+
var _a, _b;
|
|
304
|
+
if (error) {
|
|
305
|
+
(_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.fail) === null || _a === void 0 ? void 0 : _a.call(callbacks, ErrorCode.FileLoadFailed, `加载资源失败【bundle:${bundle.name} path:${path}】`);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
(_b = callbacks === null || callbacks === void 0 ? void 0 : callbacks.complete) === null || _b === void 0 ? void 0 : _b.call(callbacks, asset);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* 加载文件夹下的资源
|
|
315
|
+
* @param bundle 资源包名或资源包
|
|
316
|
+
* @param path 资源路径
|
|
317
|
+
* @param type 资源类型
|
|
318
|
+
* @param callbacks 回调函数
|
|
319
|
+
* @param callbacks.progress 进度回调 value: 已完成数量 total: 总数量
|
|
320
|
+
*/
|
|
321
|
+
static loadDir(bundle, path, type, callbacks) {
|
|
322
|
+
if (typeof bundle === "string") {
|
|
323
|
+
AssetUtils.loadBundle(bundle)
|
|
324
|
+
.then((bundle) => {
|
|
325
|
+
bundle.loadDir(path, type,
|
|
326
|
+
// 进度回调
|
|
327
|
+
(finished, total) => {
|
|
328
|
+
var _a;
|
|
329
|
+
(_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.progress) === null || _a === void 0 ? void 0 : _a.call(callbacks, finished, total);
|
|
330
|
+
},
|
|
331
|
+
// 完成回调
|
|
332
|
+
(error, assets) => {
|
|
333
|
+
var _a, _b;
|
|
334
|
+
if (error) {
|
|
335
|
+
(_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.fail) === null || _a === void 0 ? void 0 : _a.call(callbacks, ErrorCode.FileLoadFailed, `加载文件夹失败【bundle:${bundle} path:${path}】`);
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
(_b = callbacks === null || callbacks === void 0 ? void 0 : callbacks.complete) === null || _b === void 0 ? void 0 : _b.call(callbacks, assets);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
})
|
|
342
|
+
.catch((err) => {
|
|
343
|
+
var _a;
|
|
344
|
+
(_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.fail) === null || _a === void 0 ? void 0 : _a.call(callbacks, ErrorCode.BundleLoadFailed, `加载bundle[${bundle}]失败`);
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
bundle.loadDir(path, type,
|
|
349
|
+
// 进度回调
|
|
350
|
+
(finished, total) => {
|
|
351
|
+
var _a;
|
|
352
|
+
(_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.progress) === null || _a === void 0 ? void 0 : _a.call(callbacks, finished, total);
|
|
353
|
+
},
|
|
354
|
+
// 完成回调
|
|
355
|
+
(error, assets) => {
|
|
356
|
+
var _a, _b;
|
|
357
|
+
if (error) {
|
|
358
|
+
(_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.fail) === null || _a === void 0 ? void 0 : _a.call(callbacks, ErrorCode.FileLoadFailed, `加载文件夹失败【bundle:${bundle} path:${path}】`);
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
(_b = callbacks === null || callbacks === void 0 ? void 0 : callbacks.complete) === null || _b === void 0 ? void 0 : _b.call(callbacks, assets);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
class AssetPool {
|
|
369
|
+
/** 添加资源 */
|
|
370
|
+
static add(asset, bundle = resources, batchName = "") {
|
|
371
|
+
if (Array.isArray(asset)) {
|
|
372
|
+
for (const item of asset) {
|
|
373
|
+
this.add(item, bundle, batchName);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
let uuid = asset.uuid || asset._uuid;
|
|
378
|
+
if (this._uuidToName.has(uuid)) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
// 增加引用计数
|
|
382
|
+
asset.addRef();
|
|
383
|
+
let info = bundle.getAssetInfo(uuid);
|
|
384
|
+
//TODO:: 这里使用了私有属性
|
|
385
|
+
/** @ts-ignore */
|
|
386
|
+
let key = this.getKey(info.path, bundle.name);
|
|
387
|
+
// log(`>>>uuid:${uuid}, path:${info.path}`);
|
|
388
|
+
this._uuidToName.set(uuid, key);
|
|
389
|
+
this._assets.set(key, asset);
|
|
390
|
+
// 添加到批次
|
|
391
|
+
this.addToBatch(batchName, key, asset);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
static addToBatch(batchName, key, asset) {
|
|
395
|
+
if (!batchName) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (!this._batchAssetNames.has(batchName)) {
|
|
399
|
+
this._batchAssetNames.set(batchName, new Set());
|
|
400
|
+
}
|
|
401
|
+
this._batchAssetNames.get(batchName).add(key);
|
|
402
|
+
this._assetToBatchName.set(asset, batchName);
|
|
403
|
+
}
|
|
404
|
+
static getAllAssetPaths() {
|
|
405
|
+
return Array.from(this._assets.keys());
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* 检查资源是否存在
|
|
409
|
+
* @param path 资源在bundle下的路径
|
|
410
|
+
* @param bundlename 资源bundle名 默认 resources
|
|
411
|
+
*/
|
|
412
|
+
static has(path, bundlename = "resources") {
|
|
413
|
+
let key = this.getKey(path, bundlename);
|
|
414
|
+
return this._assets.has(key);
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* 获取资源
|
|
418
|
+
* @param path 资源在bundle下的路径
|
|
419
|
+
* @param bundlename 资源bundle名 默认 resources
|
|
420
|
+
*/
|
|
421
|
+
static get(path, bundlename = "resources") {
|
|
422
|
+
let key = this.getKey(path, bundlename);
|
|
423
|
+
if (!this._assets.has(key)) {
|
|
424
|
+
console.warn(`获取资源失败: 资源 bundle:${bundlename}, path:${path} 未加载`);
|
|
425
|
+
}
|
|
426
|
+
return this._assets.get(key);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* 按 uuid 判断资源是否存在
|
|
430
|
+
*/
|
|
431
|
+
static hasUUID(uuid) {
|
|
432
|
+
if (!this._uuidToName.has(uuid)) {
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* 按 uuid 获取资源
|
|
439
|
+
*/
|
|
440
|
+
static getByUUID(uuid) {
|
|
441
|
+
if (!this._uuidToName.has(uuid)) {
|
|
442
|
+
console.warn(`获取资源失败: 资源 uuid:${uuid} 未加载`);
|
|
443
|
+
}
|
|
444
|
+
let key = this._uuidToName.get(uuid);
|
|
445
|
+
return this._assets.get(key);
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* 按资源加载批次释放资源
|
|
449
|
+
* @param batchName 资源加载批次名 对应 AssetLoader 实例化时传入的 name
|
|
450
|
+
*/
|
|
451
|
+
static releaseBatchAssets(batchName) {
|
|
452
|
+
if (!this._batchAssetNames.has(batchName)) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
let names = this._batchAssetNames.get(batchName);
|
|
456
|
+
for (const name of names) {
|
|
457
|
+
this.release(name);
|
|
458
|
+
}
|
|
459
|
+
this._batchAssetNames.delete(batchName);
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* 按资源路径释放资源
|
|
463
|
+
* @param path 资源在bundle下的路径
|
|
464
|
+
* @param bundlename 资源bundle名 默认 resources
|
|
465
|
+
*/
|
|
466
|
+
static releasePath(path, bundlename = "resources") {
|
|
467
|
+
let key = this.getKey(path, bundlename);
|
|
468
|
+
this.release(key);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* 按 bundle、文件夹和资源类型释放资源
|
|
472
|
+
* @param dir 资源在bundle下的路径
|
|
473
|
+
* @param bundlename 资源bundle名 默认 resources
|
|
474
|
+
* @param asset 资源类型 不传表示所有类型的资源
|
|
475
|
+
*/
|
|
476
|
+
static releaseDir(dir, bundlename = "resources", asset) {
|
|
477
|
+
return new Promise((resolve, reject) => {
|
|
478
|
+
if (bundlename == "resources") {
|
|
479
|
+
let uuids = AssetUtils.getUUIDs(dir, asset, resources);
|
|
480
|
+
for (const uuid of uuids) {
|
|
481
|
+
this.releaseUUID(uuid);
|
|
482
|
+
}
|
|
483
|
+
resolve(true);
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
AssetUtils.loadBundle(bundlename)
|
|
487
|
+
.then((bundle) => {
|
|
488
|
+
let uuids = AssetUtils.getUUIDs(dir, asset, bundle);
|
|
489
|
+
for (const uuid of uuids) {
|
|
490
|
+
this.releaseUUID(uuid);
|
|
491
|
+
}
|
|
492
|
+
resolve(true);
|
|
493
|
+
})
|
|
494
|
+
.catch((err) => {
|
|
495
|
+
reject(false);
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* 按 uuid 释放资源
|
|
502
|
+
*/
|
|
503
|
+
static releaseUUID(uuid) {
|
|
504
|
+
if (this._uuidToName.has(uuid)) {
|
|
505
|
+
let key = this._uuidToName.get(uuid);
|
|
506
|
+
this.release(key);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* 释放所有加载的资源
|
|
511
|
+
*/
|
|
512
|
+
static releaseAll() {
|
|
513
|
+
this._assets.forEach((asset, key) => {
|
|
514
|
+
asset.decRef();
|
|
515
|
+
});
|
|
516
|
+
this._assets.clear();
|
|
517
|
+
this._uuidToName.clear();
|
|
518
|
+
this._batchAssetNames.clear();
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* 按key释放资源
|
|
522
|
+
* @internal
|
|
523
|
+
*/
|
|
524
|
+
static release(key) {
|
|
525
|
+
if (this._assets.has(key)) {
|
|
526
|
+
let asset = this._assets.get(key);
|
|
527
|
+
if (this._assetToBatchName.has(asset)) {
|
|
528
|
+
let batchName = this._assetToBatchName.get(asset);
|
|
529
|
+
this._batchAssetNames.get(batchName).delete(key);
|
|
530
|
+
this._assetToBatchName.delete(asset);
|
|
531
|
+
}
|
|
532
|
+
this._uuidToName.delete(asset.uuid);
|
|
533
|
+
asset.decRef();
|
|
534
|
+
this._assets.delete(key);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
console.warn(`释放资源失败: 资源【${key}】未加载`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* 获取资源 key
|
|
542
|
+
* @internal
|
|
543
|
+
*/
|
|
544
|
+
static getKey(path, bundlename = "resources") {
|
|
545
|
+
return `${bundlename}:${path}`;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* 资源名对应的资源
|
|
550
|
+
* @internal
|
|
551
|
+
*/
|
|
552
|
+
AssetPool._assets = new Map();
|
|
553
|
+
/**
|
|
554
|
+
* uuid 对应的资源名
|
|
555
|
+
* @internal
|
|
556
|
+
*/
|
|
557
|
+
AssetPool._uuidToName = new Map();
|
|
558
|
+
/** @internal */
|
|
559
|
+
AssetPool._batchAssetNames = new Map();
|
|
560
|
+
/** @internal */
|
|
561
|
+
AssetPool._assetToBatchName = new WeakMap();
|
|
562
|
+
|
|
563
|
+
class AssetLoader extends AssetLoaderAgent {
|
|
564
|
+
constructor(batchName) {
|
|
565
|
+
super();
|
|
566
|
+
/** @internal */
|
|
567
|
+
this._name = "";
|
|
568
|
+
/**
|
|
569
|
+
* 当前并行加载数量
|
|
570
|
+
* @internal
|
|
571
|
+
*/
|
|
572
|
+
this._parallel = 0;
|
|
573
|
+
/**
|
|
574
|
+
* 失败重试次数
|
|
575
|
+
* @internal
|
|
576
|
+
*/
|
|
577
|
+
this._retry = 0;
|
|
578
|
+
/**
|
|
579
|
+
* 获取资源数量是否成功
|
|
580
|
+
* @internal
|
|
581
|
+
*/
|
|
582
|
+
this._initSuccess = false;
|
|
583
|
+
/** @internal */
|
|
584
|
+
this._configs = [];
|
|
585
|
+
this._name = batchName || "";
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* 开始加载资源
|
|
589
|
+
* @param {IAssetConfig[]} res.configs 资源配置
|
|
590
|
+
*/
|
|
591
|
+
start(assetConfigs) {
|
|
592
|
+
this._configs = assetConfigs;
|
|
593
|
+
this.onStart();
|
|
594
|
+
}
|
|
595
|
+
onStart() {
|
|
596
|
+
this.initialize();
|
|
597
|
+
this._initSuccess = false;
|
|
598
|
+
let initCount = this._configs.length;
|
|
599
|
+
for (const info of this._configs) {
|
|
600
|
+
let bundlename = info.bundle || "resources";
|
|
601
|
+
if (bundlename == "resources") {
|
|
602
|
+
let count = AssetUtils.getResourceCount(info.path, info.type, resources);
|
|
603
|
+
this.setTotalCount(bundlename, info.path, count);
|
|
604
|
+
this.addAssetInfo(new AssetInfo(info, resources));
|
|
605
|
+
initCount--;
|
|
606
|
+
initCount <= 0 && this.initSuccess();
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
AssetUtils.loadBundle(bundlename)
|
|
610
|
+
.then((bundle) => {
|
|
611
|
+
let count = AssetUtils.getResourceCount(info.path, info.type, bundle);
|
|
612
|
+
this.setTotalCount(bundlename, info.path, count);
|
|
613
|
+
this.addAssetInfo(new AssetInfo(info, bundle));
|
|
614
|
+
initCount--;
|
|
615
|
+
initCount <= 0 && this.initSuccess();
|
|
616
|
+
})
|
|
617
|
+
.catch((err) => {
|
|
618
|
+
if (this._retry < this._maxRetry) {
|
|
619
|
+
this._retry++;
|
|
620
|
+
this.onStart();
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
this.failCallback(ErrorCode.BundleLoadFailed, `加载bundle【${bundlename}】失败`);
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* 初始化成功后,开始批量加载资源
|
|
631
|
+
* @internal
|
|
632
|
+
*/
|
|
633
|
+
initSuccess() {
|
|
634
|
+
this._initSuccess = true;
|
|
635
|
+
this._parallel = 0;
|
|
636
|
+
let maxLoad = Math.min(this.getAssetsCount(), this._maxParallel);
|
|
637
|
+
for (let i = 0; i < maxLoad; i++) {
|
|
638
|
+
this.loadNext();
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* 加载下一个资源
|
|
643
|
+
* @internal
|
|
644
|
+
*/
|
|
645
|
+
loadNext() {
|
|
646
|
+
// 存在等待中的资源,则加载等待中的资源
|
|
647
|
+
let index = this.getFirstWaitIndex();
|
|
648
|
+
if (index > -1) {
|
|
649
|
+
this.loadItem(index);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
// 所有资源全部完成了,则完成
|
|
653
|
+
if (this.isAllFinished()) {
|
|
654
|
+
this.completeAll();
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
// 如果当前并行数量 > 0 则跳过
|
|
658
|
+
if (this._parallel > 0) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
// 重试次数小于最大次数 则开始重试
|
|
662
|
+
if (this._retry < this._maxRetry) {
|
|
663
|
+
this.retryLoad();
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
// 最终资源加载失败了
|
|
667
|
+
this.downloadFaildAnalysis();
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* 加载资源
|
|
671
|
+
* @internal
|
|
672
|
+
*/
|
|
673
|
+
loadItem(index) {
|
|
674
|
+
let item = this.getAssetInfo(index);
|
|
675
|
+
item.status = StateType.Loading;
|
|
676
|
+
this._parallel++;
|
|
677
|
+
if (item.isFile) {
|
|
678
|
+
// 加载单个资源文件
|
|
679
|
+
AssetUtils.loadFile(item.assetBundle, item.path, item.type, {
|
|
680
|
+
complete: (asset) => {
|
|
681
|
+
this._parallel--;
|
|
682
|
+
item.status = StateType.Finish;
|
|
683
|
+
AssetPool.add(asset, item.assetBundle, this._name);
|
|
684
|
+
this.updateCompleteCount(item.bundle, item.path, 1, 1);
|
|
685
|
+
this.loadNext();
|
|
686
|
+
},
|
|
687
|
+
fail: () => {
|
|
688
|
+
this._parallel--;
|
|
689
|
+
item.status = StateType.Error;
|
|
690
|
+
this.loadNext();
|
|
691
|
+
},
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
else {
|
|
695
|
+
// 加载文件夹
|
|
696
|
+
AssetUtils.loadDir(item.assetBundle, item.path, item.type, {
|
|
697
|
+
complete: (assets) => {
|
|
698
|
+
this._parallel--;
|
|
699
|
+
item.status = StateType.Finish;
|
|
700
|
+
AssetPool.add(assets, item.assetBundle, this._name);
|
|
701
|
+
this.loadNext();
|
|
702
|
+
},
|
|
703
|
+
fail: () => {
|
|
704
|
+
this._parallel--;
|
|
705
|
+
item.status = StateType.Error;
|
|
706
|
+
this.loadNext();
|
|
707
|
+
},
|
|
708
|
+
progress: (value, total) => {
|
|
709
|
+
value > 0 &&
|
|
710
|
+
total > 0 &&
|
|
711
|
+
this.updateCompleteCount(item.bundle, item.path, value, total);
|
|
712
|
+
},
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
/** 重新加载失败的资源 */
|
|
717
|
+
retryDownLoadFailedAssets() {
|
|
718
|
+
this._parallel = 0;
|
|
719
|
+
this._retry = 0;
|
|
720
|
+
if (!this._initSuccess) {
|
|
721
|
+
this._retry++;
|
|
722
|
+
this.onStart();
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
this.retryLoad();
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* 重试加载资源
|
|
730
|
+
* @internal
|
|
731
|
+
*/
|
|
732
|
+
retryLoad() {
|
|
733
|
+
this._retry++;
|
|
734
|
+
let count = this.resetErrorAssets();
|
|
735
|
+
let maxLoad = Math.min(count, this._maxParallel);
|
|
736
|
+
for (let i = 0; i < maxLoad; i++) {
|
|
737
|
+
this.loadNext();
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
export { AssetLoader, AssetPool, AssetUtils, ErrorCode };
|