panel_ex.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. /*
  2. 面板扩展
  3. 功能: 绑定快捷键事件
  4. */
  5. 'use strict';
  6. const path = require('path');
  7. const fs = require('fs');
  8. const md5 = require('md5');
  9. const fe = Editor.require('packages://simple-code/tools/tools.js');
  10. const AssetCleaner = Editor.require('packages://simple-code/extensions/cc-asset-clean/AssetCleanerForCocosCreator/AssetCleaner');
  11. const prsPath = Editor.Project && Editor.Project.path ? Editor.Project.path : Editor.remote.projectPath;
  12. const FileUtil = require('./utils/file-util');
  13. const ObjectUtil = require('./utils/object-util');
  14. let is_lock = false;
  15. module.exports = {
  16. /** @type import('../../panel/vs-panel/vs-panel-base') */
  17. parent: null,
  18. // 面板初始化
  19. onLoad(parent) {
  20. // index.js 对象
  21. this.parent = parent;
  22. },
  23. // 面板销毁
  24. onDestroy() {
  25. },
  26. loadList(outMap, color) {
  27. let not_select_list = []
  28. let is_swi_mode = true
  29. for (let [type, files] of outMap.entries()) {
  30. if (files.length <= 0) {
  31. continue;
  32. }
  33. for (let i = 0, len = files.length; i < len; i++) {
  34. let info = files[i];
  35. if (!info.uuid) {
  36. info.uuid = Editor.remote.assetdb.fspathToUuid(info.path);
  37. }
  38. if (info.uuid) {
  39. let item = document.getElementById(info.uuid)
  40. if (item) {
  41. if (is_lock) {
  42. item.style.backgroundColor = color; // 紫色高亮
  43. } else {
  44. item.style.backgroundColor = null; // 取消高亮
  45. }
  46. is_swi_mode = false
  47. } else if (Editor.remote.assetdb.existsByUuid(info.uuid)) {
  48. //新版不支持,切换模式
  49. not_select_list.push(info.uuid)
  50. // Editor.log("未发现item",info.path);
  51. // Editor.Selection.select('asset', uuid)
  52. // Editor.Ipc.sendToAll('assets:hint', uuid)
  53. }
  54. }
  55. }
  56. // 新版高亮
  57. if (not_select_list.length && is_swi_mode) {
  58. Editor.Selection.select('asset', not_select_list)
  59. }
  60. }
  61. },
  62. // 选中资源
  63. selectAsset(assetUuid){
  64. Editor.Ipc.sendToAll('assets:hint', assetUuid)
  65. let list = Editor.Selection.curSelection('asset');
  66. list.push(assetUuid)
  67. Editor.Selection.select('asset', list);
  68. },
  69. cleanSelect(){
  70. Editor.Selection.clear('asset');
  71. },
  72. search() {
  73. if (!this.noBindMap) {
  74. let { noBindMap, noLoadMap, outStr } = AssetCleaner.start(prsPath + path.sep + "assets");
  75. this.noBindMap = noBindMap
  76. this.noLoadMap = noLoadMap
  77. Editor.log("搜索完成,请点开资源管理查看");
  78. Editor.log(outStr);
  79. }
  80. this.loadList(this.noBindMap, 'rgba(114, 0, 218, 0.57)');
  81. this.loadList(this.noLoadMap, 'rgba(14, 0, 218, 0.57)');
  82. },
  83. /** 需要刷新creator右键菜单
  84. * @param type = node | asset
  85. * */
  86. onRefreshCreatorMenu(type, uuid) {
  87. this.updateMenu(type, uuid)
  88. },
  89. findAssetsDel() {
  90. this.findAssets(true)
  91. },
  92. findAssets(bl,uuid) {
  93. // if(window.cc && window.cc.ENGINE_VERSION.startsWith('1')){
  94. // return Editor.log("该功能不支持Creator 2.0 以下版本")
  95. // }
  96. this.cleanSelect()
  97. const curUuids = [uuid]//Editor.Selection.curSelection('asset');
  98. let delFileList = [];
  99. if (curUuids.length === 0) {
  100. return;
  101. }
  102. for (let i = 0; i < curUuids.length; i++) {
  103. // 是否为有效 uuid
  104. if (!Editor.Utils.UuidUtils.isUuid(curUuids[i])) {
  105. Editor.log('[🔎]', '该 uuid 无效', curUuids[i]);
  106. continue;
  107. }
  108. const assetInfo = Editor.remote.assetdb.assetInfoByUuid(curUuids[i]);
  109. if (assetInfo) {
  110. // 暂不查找文件夹
  111. if (assetInfo.type === 'folder') {
  112. this.findPng(assetInfo.path, bl,delFileList)
  113. }
  114. }
  115. }
  116. // 删除未引用的文件
  117. if(bl && delFileList.length){
  118. let desc = '确认删除未引用的资源:\n'
  119. for (let i = 0; i < delFileList.length; i++) {
  120. const url = delFileList[i];
  121. desc += url + '\n';
  122. }
  123. if(confirm(desc)){
  124. Editor.remote.assetdb.delete(delFileList, function (err, results) {
  125. results.forEach(function (result) {
  126. if (err) {
  127. Editor.log("删除文件失败!!!");
  128. return;
  129. }
  130. Editor.log("删除文件成功!!!");
  131. Editor.log(urlItems.join('/'))
  132. Editor.log(`${'----'.repeat(36)}`);
  133. });
  134. });
  135. }
  136. }
  137. },
  138. findPng(path, bl, delFileList) {
  139. if (!path) return
  140. let stats = fs.statSync(path);
  141. if (stats.isFile()) {//文件
  142. if (path.endsWith(".png")) {
  143. let meta = fs.readFileSync(path + ".meta", "utf-8");
  144. let r = /"subMetas".|\s*"uuid": "(.*)"/g;
  145. let uuid = r.exec(meta)[1];
  146. let url = this.findViaUuid(uuid, true, bl);
  147. url ? delFileList.push(url) : null;
  148. }
  149. } else {//文件夹
  150. let pathArr = fs.readdirSync(path);
  151. for (let one of pathArr) {
  152. this.findPng(`${path}/${one}`, bl,delFileList);
  153. }
  154. }
  155. },
  156. /**
  157. * 查找当前选中资源引用
  158. */
  159. findCurrentSelection() {
  160. const curUuids = Editor.Selection.curSelection('asset');
  161. if (curUuids.length === 0) {
  162. Editor.log('[🔎]', '请先在资源管理器中选择需要查找引用的资源!');
  163. return;
  164. }
  165. // 根据 uuid 查找
  166. for (let i = 0; i < curUuids.length; i++) {
  167. this.findViaUuid(curUuids[i]);
  168. }
  169. },
  170. /**
  171. * 使用 uuid 进行查找
  172. * @param {string} uuid
  173. */
  174. findViaUuid(uuid, bl, del) {
  175. // 是否为有效 uuid
  176. if (!Editor.Utils.UuidUtils.isUuid(uuid)) {
  177. Editor.log('[🔎]', '该 uuid 无效', uuid);
  178. return;
  179. }
  180. // 获取资源信息
  181. const assetInfo = Editor.remote.assetdb.assetInfoByUuid(uuid);
  182. if (assetInfo) {
  183. // 暂不查找文件夹
  184. if (assetInfo.type === 'folder') {
  185. Editor.log('[🔎]', '暂不支持查找文件夹', assetInfo.url);
  186. return;
  187. }
  188. // 处理文件路径 & 打印头部日志
  189. const urlItems = assetInfo.url.replace('db://', '').split('/');
  190. if (!urlItems[urlItems.length - 1].includes('.')) {
  191. urlItems.splice(urlItems.length - 1);
  192. }
  193. if (bl != true)
  194. Editor.log('[🔎]', '查找资源引用', urlItems.join('/'));
  195. // 记录子资源 uuid
  196. const subUuids = assetInfo ? [] : null;
  197. // 资源类型检查
  198. if (assetInfo.type === 'texture') {
  199. // 纹理子资源
  200. const subAssetInfos = Editor.remote.assetdb.subAssetInfosByUuid(uuid);
  201. if (subAssetInfos) {
  202. for (let i = 0; i < subAssetInfos.length; i++) {
  203. subUuids.push(subAssetInfos[i].uuid);
  204. }
  205. uuid = null;
  206. }
  207. } else if (assetInfo.type === 'typescript' || assetInfo.type === 'javascript') {
  208. // 脚本
  209. uuid = Editor.Utils.UuidUtils.compressUuid(uuid);
  210. }
  211. // 查找
  212. const results = uuid ? this.findReferences(uuid) : [];
  213. if (subUuids && subUuids.length > 0) {
  214. for (let i = 0; i < subUuids.length; i++) {
  215. const subResults = this.findReferences(subUuids[i]);
  216. if (subResults.length > 0) {
  217. results.push(...subResults);
  218. }
  219. }
  220. }
  221. if (bl) {
  222. if (results.length === 0) {
  223. let url = 'db://' + urlItems.join('/');
  224. // if (del) {
  225. // Editor.remote.assetdb.delete([url], function (err, results) {
  226. // results.forEach(function (result) {
  227. // if (err) {
  228. // Editor.log("删除文件失败!!!");
  229. // return;
  230. // }
  231. // Editor.log("删除文件成功!!!");
  232. // Editor.log(urlItems.join('/'))
  233. // Editor.log(`${'----'.repeat(36)}`);
  234. // });
  235. // });
  236. // // Editor.remote.assetdb.delete(['db://' + urlItems.join('/')], function (err, results) {
  237. // // results.forEach(function (result) {
  238. // // if (err) {
  239. // // Editor.log("删除文件失败!!!");
  240. // // return;
  241. // // }
  242. // // Editor.log("删除文件成功!!!");
  243. // // Editor.log(urlItems.join('/'))
  244. // // Editor.log(`${'----'.repeat(36)}`);
  245. // // });
  246. // // });
  247. // }
  248. // Editor.log(ProjectPath+"/"+urlItems.join('/'))
  249. // Editor.remote.assetdb.delete(ProjectPath+"/"+urlItems.join('/'))
  250. // Editor.remote.assetdb.delete(ProjectPath+"/"+urlItems.join('/')+".meta")
  251. Editor.log('[🔎]', '未被引用的资源图片', urlItems.join('/'));
  252. Editor.log(`${'----'.repeat(36)}`);
  253. // 高亮未使用的资源
  254. this.selectAsset(assetInfo.uuid);
  255. // 返回未使用的资源
  256. return url;
  257. }
  258. } else {
  259. this.printResult(results);
  260. }
  261. } else {
  262. // 不存在的资源,直接查找 uuid
  263. Editor.log('[🔎]', '查找资源引用', uuid);
  264. this.printResult(this.findReferences(uuid), bl);
  265. }
  266. },
  267. /**
  268. * 查找引用
  269. * @param {string} uuid
  270. * @returns {object[]}
  271. */
  272. findReferences(uuid) {
  273. const results = [];
  274. const handler = (filePath, stats) => {
  275. const extname = path.extname(filePath);
  276. if (extname === '.fire' || extname === '.prefab' || extname === '.scene') {
  277. // 场景和预制体资源
  278. // 将资源数据转为节点树
  279. const nodeTree = this.getNodeTree(filePath);
  280. /**
  281. * 读取节点数据并查找引用
  282. * @param {object} node 目标节点
  283. * @param {object[]} container 容器
  284. */
  285. const search = (node, container) => {
  286. // 检查节点上的组件是否有引用
  287. const components = node['components'];
  288. if (components && components.length > 0) {
  289. for (let i = 0; i < components.length; i++) {
  290. const info = this.getContainsInfo(components[i], uuid);
  291. if (info.contains) {
  292. let type = components[i]['__type__'];
  293. // 是否为脚本资源
  294. if (Editor.Utils.UuidUtils.isUuid(type)) {
  295. const scriptUuid = Editor.Utils.UuidUtils.decompressUuid(type);
  296. const assetInfo = Editor.remote.assetdb.assetInfoByUuid(scriptUuid);
  297. type = path.basename(assetInfo.url);
  298. }
  299. // 处理属性名称
  300. if (info.property) {
  301. // Label 组件需要特殊处理
  302. if (type === 'cc.Label' && info.property === '_N$file') {
  303. info.property = 'font';
  304. } else {
  305. // 去除属性名的前缀
  306. if (info.property.indexOf('_N$') !== -1) {
  307. info.property = info.property.replace('_N$', '');
  308. } else if (info.property.indexOf('_') === 0) {
  309. info.property = info.property.substring(1);
  310. }
  311. }
  312. }
  313. container.push({ node: node['path'], component: type, property: info.property });
  314. }
  315. }
  316. }
  317. // 检查预制体是否有引用
  318. const prefab = node['prefab'];
  319. if (prefab) {
  320. // 排除预制体自己
  321. if (uuid !== nodeTree['__uuid__']) {
  322. const contains = ObjectUtil.containsValue(prefab, uuid);
  323. if (contains) {
  324. container.push({ node: node['path'] });
  325. }
  326. }
  327. }
  328. // 遍历子节点
  329. const children = node['children'];
  330. if (children && children.length > 0) {
  331. for (let i = 0; i < children.length; i++) {
  332. search(children[i], container);
  333. }
  334. }
  335. }
  336. // 开始遍历节点
  337. const _results = [];
  338. const children = nodeTree['children'];
  339. for (let i = 0; i < children.length; i++) {
  340. search(children[i], _results);
  341. }
  342. // 保存当前文件引用结果
  343. if (_results.length > 0) {
  344. const fileUrl = Editor.remote.assetdb.fspathToUrl(filePath);
  345. results.push({ type: typeMap[extname], fileUrl: fileUrl, refs: _results });
  346. }
  347. } else if (extname === '.anim') {
  348. // 动画资源
  349. const data = JSON.parse(fs.readFileSync(filePath));
  350. const curveData = data['curveData'];
  351. const contains = ObjectUtil.containsValue(curveData, uuid);
  352. if (contains) {
  353. const fileUrl = Editor.remote.assetdb.fspathToUrl(filePath);
  354. results.push({ type: typeMap[extname], fileUrl: fileUrl });
  355. }
  356. } else if (extname === '.mtl' || filePath.indexOf('.fnt.meta') !== -1) {
  357. // 材质和字体资源
  358. const data = JSON.parse(fs.readFileSync(filePath));
  359. const contains = ObjectUtil.containsValue(data, uuid);
  360. if (contains && !(data['uuid'] && data['uuid'] === uuid)) {
  361. const fileUrl = Editor.remote.assetdb.fspathToUrl(filePath);
  362. const type = extname === '.mtl' ? '.mtl' : '.fnt.meta';
  363. results.push({ type: typeMap[type], fileUrl: fileUrl });
  364. }
  365. }
  366. }
  367. // 遍历资源目录下的文件
  368. const rootPath = path.join(prsPath, 'assets');
  369. FileUtil.map(rootPath, handler);
  370. return results;
  371. },
  372. /**
  373. * 打印结果至控制台
  374. * @param {object[]} results
  375. */
  376. printResult(results) {
  377. if (results.length === 0) {
  378. Editor.log('[🔎]', '没有找到该资源的引用!');
  379. Editor.log(`${'----'.repeat(36)}`);
  380. return;
  381. }
  382. // 添加引用
  383. const nodeRefs = [];
  384. let nodeRefsCount = 0;
  385. const assetRefs = [];
  386. let assetRefsCount = 0;
  387. for (let i = 0; i < results.length; i++) {
  388. const result = results[i];
  389. const url = result.fileUrl.replace('db://', '').replace('.meta', '');
  390. if (result.type === '场景' || result.type === '预制体') {
  391. nodeRefs.push(`   · 📺 [${result.type}] ${url}`);
  392. for (let j = 0; j < result.refs.length; j++) {
  393. nodeRefsCount++;
  394. if (this.detail) {
  395. const ref = result.refs[j];
  396. let string = `       💾 [节点] ${ref.node}`;
  397. if (ref.component) {
  398. string += `  →  💿 [组件] ${ref.component}`;
  399. }
  400. if (ref.property) {
  401. string += `  →  🎲 [属性] ${ref.property}`;
  402. }
  403. nodeRefs.push(string);
  404. }
  405. }
  406. } else {
  407. assetRefsCount++;
  408. assetRefs.push(`   · 📦 [${result.type}] ${url}`);
  409. }
  410. }
  411. // 合并
  412. const texts = [`[🔎] 引用查找结果 >>>`];
  413. if (nodeRefs.length > 0) {
  414. nodeRefs.unshift(`   📙 节点引用 x ${nodeRefsCount}`);
  415. texts.push(...nodeRefs);
  416. }
  417. if (assetRefs.length > 0) {
  418. assetRefs.unshift(`   📘 资源引用 x ${assetRefsCount}`);
  419. texts.push(...assetRefs);
  420. }
  421. texts.push(`${'----'.repeat(36)}`);
  422. if (this.expand) {
  423. for (let i = 0; i < texts.length; i++) {
  424. Editor.log(texts[i]);
  425. }
  426. } else {
  427. const content = texts.join('\n');
  428. Editor.log(content);
  429. }
  430. },
  431. /**
  432. * 更新节点树
  433. * @param {string} filePath 文件路径
  434. */
  435. updateNodeTree(filePath) {
  436. if (!this.nodeTrees) {
  437. this.nodeTrees = Object.create(null);
  438. }
  439. const data = JSON.parse(fs.readFileSync(filePath));
  440. this.nodeTrees[filePath] = this.convertToNodeTree(data);
  441. },
  442. /**
  443. * 获取节点树
  444. * @param {string} filePath 文件路径
  445. * @returns {object}
  446. */
  447. getNodeTree(filePath) {
  448. if (!this.nodeTrees) {
  449. this.nodeTrees = Object.create(null);
  450. }
  451. // 将资源数据转为节点树
  452. if (!this.nodeTrees[filePath]) {
  453. const data = JSON.parse(fs.readFileSync(filePath));
  454. this.nodeTrees[filePath] = this.convertToNodeTree(data);
  455. }
  456. return this.nodeTrees[filePath];
  457. },
  458. /**
  459. * 预加载节点树(未使用)
  460. */
  461. preloadNodeTrees() {
  462. const handler = (filePath, stats) => {
  463. const extname = path.extname(filePath);
  464. if (extname === '.fire' || extname === '.scene' || extname === '.prefab') {
  465. this.updateNodeTree(filePath);
  466. }
  467. }
  468. const rootPath = path.join(Editor.Project.path, 'assets');
  469. FileUtil.map(rootPath, handler);
  470. },
  471. /**
  472. * 将资源数据转为节点树
  473. * @param {object} data 元数据
  474. * @returns {object}
  475. */
  476. convertToNodeTree(data) {
  477. /**
  478. * 读取节点
  479. * @param {object} node 节点
  480. * @param {number} id ID
  481. */
  482. const read = (node, id) => {
  483. const nodeData = Object.create(null);
  484. const actualNodeData = data[id];
  485. // 基本信息
  486. nodeData['__id__'] = id;
  487. nodeData['_name'] = actualNodeData['_name'];
  488. nodeData['__type__'] = actualNodeData['__type__'];
  489. // 记录路径
  490. const parentPath = node['path'] ? node['path'] : (node['_name'] ? node['_name'] : null);
  491. nodeData['path'] = (parentPath ? parentPath + '/' : '') + nodeData['_name'];
  492. // 记录组件
  493. const components = actualNodeData['_components'];
  494. if (components && components.length > 0) {
  495. nodeData['components'] = [];
  496. for (let i = 0; i < components.length; i++) {
  497. const actualComponent = data[components[i]['__id__']];
  498. nodeData['components'].push(this.extractValidInfo(actualComponent));
  499. }
  500. }
  501. // 记录预制体引用
  502. const prefab = actualNodeData['_prefab'];
  503. if (prefab) {
  504. const realPrefab = data[prefab['__id__']];
  505. nodeData['prefab'] = this.extractValidInfo(realPrefab);
  506. }
  507. // 记录子节点
  508. const children = actualNodeData['_children'];
  509. if (children && children.length > 0) {
  510. nodeData['children'] = [];
  511. for (let i = 0; i < children.length; i++) {
  512. const nodeId = children[i]['__id__'];
  513. read(nodeData, nodeId);
  514. }
  515. }
  516. // 推入引用容器
  517. node['children'].push(nodeData);
  518. }
  519. // 读取
  520. const tree = Object.create(null);
  521. const type = data[0]['__type__'];
  522. if (type === 'cc.SceneAsset') {
  523. // 场景资源
  524. tree['__type__'] = 'cc.Scene';
  525. tree['children'] = [];
  526. const sceneId = data[0]['scene']['__id__'];
  527. tree['__id__'] = sceneId;
  528. const nodes = data[sceneId]['_children'];
  529. for (let i = 0; i < nodes.length; i++) {
  530. const nodeId = nodes[i]['__id__'];
  531. read(tree, nodeId);
  532. }
  533. } else if (type === 'cc.Prefab' && data[data.length - 1]['asset']) {
  534. // 预制体资源
  535. tree['__type__'] = 'cc.Prefab';
  536. tree['__uuid__'] = data[data.length - 1]['asset']['__uuid__'];
  537. tree['children'] = [];
  538. const rootId = data[0]['data']['__id__'];
  539. read(tree, rootId);
  540. }
  541. return tree;
  542. },
  543. /**
  544. * 提取有效信息(含有 uuid)
  545. * @param {object} data 元数据
  546. * @returns {object}
  547. */
  548. extractValidInfo(data) {
  549. const info = Object.create(null);
  550. // 记录有用的属性
  551. const keys = ['__type__', '_name', 'fileId'];
  552. for (let i = 0; i < keys.length; i++) {
  553. if (data[keys[i]]) {
  554. info[keys[i]] = data[keys[i]];
  555. }
  556. }
  557. // 记录包含 uuid 的属性
  558. for (const key in data) {
  559. if (ObjectUtil.containsProperty(data[key], '__uuid__')) {
  560. info[key] = data[key];
  561. }
  562. }
  563. return info;
  564. },
  565. /**
  566. * 获取对象中是否包含指定值以及相应属性名
  567. * @param {object} object 对象
  568. * @param {any} value 值
  569. * @returns {{contains:boolean, property?:string}}
  570. */
  571. getContainsInfo(object, value) {
  572. const result = {
  573. contains: false,
  574. property: null
  575. }
  576. const search = (_object, parentKey) => {
  577. if (ObjectUtil.isObject(_object)) {
  578. for (const key in _object) {
  579. if (_object[key] === value) {
  580. result.contains = true;
  581. result.property = parentKey;
  582. return;
  583. }
  584. search(_object[key], key);
  585. }
  586. } else if (Array.isArray(_object)) {
  587. for (let i = 0; i < _object.length; i++) {
  588. search(_object[i], parentKey);
  589. }
  590. }
  591. }
  592. search(object, null);
  593. return result;
  594. },
  595. updateMenu(type, uuid) {
  596. // 当前选中的对象
  597. this.currSelectInfo = { type, uuid };
  598. if (type == 'asset') {
  599. // 资源菜单
  600. if (!uuid) {
  601. // 清除菜单
  602. Editor.Ipc.sendToMain('simple-code:setMenuConfig', { id: "cc-assets-clean", menuCfg: undefined })
  603. } else {
  604. // 菜单内容
  605. let menuCfg = {
  606. assetMenu: [
  607. { type: 'separator' },
  608. { label: '搜索 未使用资源', enabled: true, cmd: "findCleanFileByDir" }, // 快速生成拖拽资源
  609. { label: '搜索 未使用资源 与 删除', enabled: true, cmd: "cleanFileByDir" }, // 快速生成拖拽资源
  610. ],
  611. }
  612. Editor.Ipc.sendToMain('simple-code:setMenuConfig', { id: "cc-assets-clean", menuCfg: menuCfg })
  613. }
  614. } else if (type == 'node') {
  615. }
  616. },
  617. messages: {
  618. 'findCleanFileByDir'() {
  619. Editor.info("开始搜索,可能会卡顿几秒,请稍等...");
  620. setTimeout(() => {
  621. if(this.currSelectInfo && this.currSelectInfo.uuid){
  622. this.findAssets(false,this.currSelectInfo.uuid);
  623. }
  624. }, 500);
  625. },
  626. 'cleanFileByDir'() {
  627. Editor.info("开始搜索,可能会卡顿几秒,请稍等...");
  628. setTimeout(() => {
  629. if(this.currSelectInfo && this.currSelectInfo.uuid){
  630. this.findAssets(true,this.currSelectInfo.uuid);
  631. }
  632. }, 500);
  633. },
  634. 'cleanFile'() {
  635. if (!this.noBindMap) Editor.info("初次搜索未使用的资源,期间会卡顿几秒,请稍等...");
  636. setTimeout(() => {
  637. is_lock = !is_lock;
  638. this.search();
  639. }, this.noBindMap ? 1 : 500);
  640. },
  641. },
  642. };
  643. /** 扩展名对应文件类型 */
  644. const typeMap = {
  645. '.fire': '场景',
  646. '.scene': '场景',
  647. '.prefab': '预制体',
  648. '.anim': '动画',
  649. '.mtl': '材质',
  650. '.fnt.meta': '字体',
  651. }