You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

405 lines
16 KiB

(function (global) {
'use strict';
/**
* 资源面板数据源(仅引擎接口):
* assetManager.assets — 全部已加载资源
* assetManager.bundles — 已加载 Bundle(归属用 cache/_map 尽力匹配)
*/
function fmtType(asset) {
var t = (asset && asset.constructor && asset.constructor.name) || 'Other';
return String(t).replace(/^cc\./, '');
}
function memMB(bytes) {
return (bytes || 0) / (1024 * 1024);
}
/** GPU 估算:纹理去重只计一次 */
function texMemMB(tex) {
if (!tex) return 0;
var w = tex.width || 0;
var h = tex.height || 0;
if (!w || !h) {
try {
if (tex.image && tex.image.width) {
w = tex.image.width;
h = tex.image.height;
}
} catch (e) { /* */ }
}
return w && h ? memMB(w * h * 4 * 1.33) : 0;
}
function assetMem(asset, type, seenTex) {
if (type === 'Texture2D' || type === 'Texture') {
var key = String(asset._uuid || asset.uuid || '');
if (key && seenTex[key]) return 0;
if (key) seenTex[key] = 1;
return texMemMB(asset);
}
// SpriteFrame / Image 挂在纹理上,不进总量
if (type === 'SpriteFrame' || type === 'ImageAsset') return 0;
if (type === 'AudioClip' || /Audio/.test(type)) {
try {
var d = asset.duration || (asset._nativeAsset && asset._nativeAsset.duration) || 0;
return d ? memMB(d * 44100 * 2 * 2) : 0.2;
} catch (e) { return 0.2; }
}
try {
if (asset._nativeAsset && asset._nativeAsset.byteLength) {
return memMB(asset._nativeAsset.byteLength);
}
if (asset.data && asset.data.byteLength) {
return memMB(asset.data.byteLength);
}
} catch (e) { /* */ }
return 0;
}
function frameSize(asset) {
var rect = asset.rect || asset._rect;
if (rect && rect.width) return { w: rect.width | 0, h: rect.height | 0 };
return { w: asset.width | 0, h: asset.height | 0 };
}
function gfxTotals() {
var cc = global.cc;
var tex = 0;
var buf = 0;
var heap = 0;
try {
var st = cc && cc.profiler && cc.profiler.stats;
if (st) {
if (st.textureMemory && st.textureMemory.counter) tex = st.textureMemory.counter.value || 0;
if (st.bufferMemory && st.bufferMemory.counter) buf = st.bufferMemory.counter.value || 0;
}
} catch (e) { /* */ }
try {
if (performance.memory && performance.memory.usedJSHeapSize) {
heap = performance.memory.usedJSHeapSize / (1024 * 1024);
}
} catch (e2) { /* */ }
return { gfxTextureMB: tex, gfxBufferMB: buf, jsHeapMB: heap };
}
/**
* 解析资源所属 Bundle。
* 顺序:asset 上的 bundle 字段 → nativeUrl 路径 → bundle.getAssetInfo → cache.has
*/
function resolveBundleName(uuid, asset, bundleObjs, uuidMap) {
try {
if (asset) {
if (asset.bundle && asset.bundle.name) return asset.bundle.name;
if (asset._bundle && asset._bundle.name) return asset._bundle.name;
if (asset.__bundleName) return asset.__bundleName;
}
} catch (e) { /* */ }
if (uuidMap && uuid && uuidMap[uuid]) return uuidMap[uuid];
var url = (asset && (asset.nativeUrl || asset._nativeUrl)) || '';
var m = String(url).match(/\/([A-Za-z0-9_\-]+)\/(?:import|native|js|ohm|chunks)\//i);
if (m && m[1]) return m[1];
if (bundleObjs && bundleObjs.length) {
for (var i = 0; i < bundleObjs.length; i++) {
var b = bundleObjs[i];
if (!b) continue;
var bname = b.__pwName || b.name || '';
try {
if (typeof b.getAssetInfo === 'function' && uuid) {
var info = b.getAssetInfo(uuid);
if (info && (info.uuid || info.redirect || info.path != null || info.ext)) {
return bname;
}
}
} catch (e2) { /* */ }
try {
if (b.cache && typeof b.cache.has === 'function' && uuid && b.cache.has(uuid)) {
return bname;
}
} catch (e3) { /* */ }
try {
if (b.cache && b.cache.get && uuid && b.cache.get(uuid)) {
return bname;
}
} catch (e4) { /* */ }
}
}
return '';
}
/** 遍历已加载 bundles,收集对象与 cache uuid 索引 */
function indexBundles(cc) {
var list = [];
var uuidMap = {};
var bundleObjs = [];
try {
cc.assetManager.bundles.forEach(function (bundle, name) {
var n = name || (bundle && bundle.name) || '';
if (!n) return;
if (bundle) {
bundle.__pwName = n;
bundleObjs.push(bundle);
}
list.push({
name: n,
assetCount: 0,
memMB: 0,
texMB: 0,
audioMB: 0,
otherMB: 0,
status: 'loaded',
});
var add = function (u) {
if (u) uuidMap[String(u)] = n;
};
try {
var cache = bundle.cache || bundle._cache;
if (cache && typeof cache.forEach === 'function') {
cache.forEach(function (asset, uuid) {
add(uuid);
if (asset) add(asset._uuid);
});
}
if (cache && cache._map) {
for (var k in cache._map) {
if (Object.prototype.hasOwnProperty.call(cache._map, k)) add(k);
}
}
} catch (e) { /* */ }
// config.uuids / paths
try {
var cfg = bundle._config;
if (cfg) {
var lists = [cfg.uuids, cfg.uuidList, cfg._uuidList];
for (var li = 0; li < lists.length; li++) {
var arr = lists[li];
if (!arr) continue;
if (Array.isArray(arr)) {
for (var i = 0; i < arr.length; i++) add(arr[i]);
} else if (typeof arr === 'object') {
for (var kk in arr) {
if (Object.prototype.hasOwnProperty.call(arr, kk)) add(kk);
}
}
}
}
} catch (e2) { /* */ }
});
} catch (e3) { /* */ }
return { list: list, uuidMap: uuidMap, bundleObjs: bundleObjs };
}
/**
* @returns {{bundles:Array, rows:Array, totals:Object}}
*/
function collectAssets() {
var cc = global.cc;
if (!cc || !cc.assetManager || !cc.assetManager.assets) {
return { bundles: [], rows: [], totals: gfxTotals() };
}
var bi = indexBundles(cc);
var bundleByName = {};
for (var i = 0; i < bi.list.length; i++) {
bundleByName[bi.list[i].name] = bi.list[i];
}
var seenTex = {};
var rows = [];
// —— 全部已加载资源:assetManager.assets ——
try {
cc.assetManager.assets.forEach(function (asset, uuid) {
if (!asset) return;
var id = String(uuid || asset._uuid || '');
var type = fmtType(asset);
var mem = assetMem(asset, type, seenTex);
var bname = resolveBundleName(id, asset, bi.bundleObjs, bi.uuidMap);
if (!bname) {
var isDefault = /default_|splash|empty|builtin/i.test(String(asset.name || ''));
bname = isDefault ? 'internal' : 'internal';
}
var agg = bundleByName[bname];
if (!agg) {
agg = {
name: bname,
assetCount: 0,
memMB: 0,
texMB: 0,
audioMB: 0,
otherMB: 0,
status: 'loaded',
};
bundleByName[bname] = agg;
bi.list.push(agg);
}
var kind = 'other';
if (type === 'Texture2D' || type === 'Texture') kind = 'tex';
else if (type === 'AudioClip' || /Audio/.test(type)) kind = 'audio';
var w = 0;
var h = 0;
if (type === 'SpriteFrame') {
var sz = frameSize(asset);
w = sz.w;
h = sz.h;
} else {
w = asset.width | 0;
h = asset.height | 0;
}
var display = asset.name || '';
if (!display || /^[0-9a-f-]{8,}$/i.test(display)) {
// 可读名:优先 getAssetInfo.path 最后一段
try {
for (var bi2 = 0; bi2 < bi.bundleObjs.length; bi2++) {
var bb = bi2.bundleObjs[bi2];
if (bb && typeof bb.getAssetInfo === 'function') {
var inf = bb.getAssetInfo(id);
if (inf && inf.path) {
var segs = String(inf.path).split('/');
display = segs[segs.length - 1] || inf.path;
break;
}
}
}
} catch (eName) { /* */ }
if (!display) display = id.slice(0, 8) + '…';
}
rows.push({
uuid: id,
name: display,
type: type,
bundle: bname,
mem: mem,
ref: asset.refCount != null ? asset.refCount : 0,
w: w,
h: h,
kind: kind,
});
agg.assetCount += 1;
agg.memMB += mem;
if (kind === 'tex') agg.texMB += mem;
else if (kind === 'audio') agg.audioMB += mem;
else agg.otherMB += mem;
});
} catch (e) {
console.warn('[Agent] assets.scan', e);
}
var bundles = bi.list;
for (var j = 0; j < bundles.length; j++) {
if (bundles[j].assetCount === 0 && bundles[j].status === 'loaded') {
// cache 里没建到索引,但 assets 已扫到就保持 loaded;全 0 才标空
if (bundles[j].memMB === 0 && bundles[j].assetCount === 0) {
bundles[j].status = 'loaded-empty';
}
}
}
bundles.sort(function (a, b) {
return (b.memMB - a.memMB) || (b.assetCount - a.assetCount) || String(a.name).localeCompare(String(b.name));
});
var totals = gfxTotals();
totals.estimateMB = 0;
totals.texMB = 0;
totals.audioMB = 0;
totals.otherMB = 0;
for (var r = 0; r < rows.length; r++) {
totals.estimateMB += rows[r].mem;
if (rows[r].kind === 'tex') totals.texMB += rows[r].mem;
else if (rows[r].kind === 'audio') totals.audioMB += rows[r].mem;
else totals.otherMB += rows[r].mem;
}
totals.assetCount = rows.length;
totals.bundleCount = bundles.length;
return { bundles: bundles, rows: rows, totals: totals };
}
function buildPreview(asset, type) {
try {
if (type === 'SpriteFrame') {
var tex = asset.texture || (asset.getTexture && asset.getTexture());
var img = tex && tex.image;
var data = img && (img._data || img.data);
var rect = asset.rect || asset._rect || { x: 0, y: 0, width: asset.width, height: asset.height };
if (data && typeof HTMLImageElement !== 'undefined' && data instanceof HTMLImageElement) {
var ih = data.height || img.height || 0;
var sw = Math.max(1, rect.width | 0);
var sh = Math.max(1, rect.height | 0);
var sx = rect.x | 0;
var sy = Math.max(0, ih - (rect.y | 0) - sh) | 0;
var cv = document.createElement('canvas');
cv.width = sw;
cv.height = sh;
cv.getContext('2d').drawImage(data, sx, sy, sw, sh, 0, 0, sw, sh);
return { kind: 'image', w: sw, h: sh, url: cv.toDataURL('image/png') };
}
if (img && img.nativeUrl) {
return { kind: 'url', url: img.nativeUrl, w: (rect.width | 0), h: (rect.height | 0) };
}
return { kind: 'none' };
}
var im = type === 'ImageAsset' ? asset : (asset.image || asset._image);
var d2 = im && (im._data || im.data);
if (d2 && typeof HTMLImageElement !== 'undefined' && d2 instanceof HTMLImageElement) {
return { kind: 'image', w: d2.width, h: d2.height, url: d2.src || '' };
}
if (d2 && d2.data && d2.width && typeof ImageData !== 'undefined') {
var c2 = document.createElement('canvas');
c2.width = d2.width;
c2.height = d2.height;
c2.getContext('2d').putImageData(new ImageData(d2.data, d2.width, d2.height), 0, 0);
return { kind: 'image', w: d2.width, h: d2.height, url: c2.toDataURL('image/png') };
}
if (im && im.nativeUrl) return { kind: 'url', url: im.nativeUrl, w: im.width | 0, h: im.height | 0 };
if (asset.nativeUrl) return { kind: 'url', url: asset.nativeUrl, w: asset.width | 0, h: asset.height | 0 };
} catch (e) { /* */ }
return { kind: 'none' };
}
function previewAsset(uuid) {
var cc = global.cc;
var asset = null;
try {
asset = cc.assetManager.assets.get(uuid);
} catch (e) {
asset = null;
}
if (!asset) return { kind: 'none' };
return buildPreview(asset, fmtType(asset));
}
if (global.PWAgent) {
global.PWAgent.prototype._listAssets = function () {
return collectAssets();
};
global.PWAgent.prototype._listAssetsAsync = function (done) {
try {
done(collectAssets());
} catch (e) {
done({ bundles: [], rows: [], totals: gfxTotals() });
}
};
global.PWAgent.prototype._previewAsset = function (uuid) {
return previewAsset(uuid);
};
}
global.PWAssetsUtil = {
collectAssets: collectAssets,
previewAsset: previewAsset,
buildPreview: buildPreview,
};
})(window);