2025-04-24 17:03:28 +08:00

248 lines
10 KiB
JavaScript

const Fs = require('fire-fs');
const FsExtra = require('fs-extra');
const Path = require('fire-path');
let vueInst = null;
Editor.Panel.extend({
style: Fs.readFileSync(Editor.url('packages://res-remove/pannel/index.css'), 'utf-8'),
template: Fs.readFileSync(Editor.url('packages://res-remove/pannel/index.html'), 'utf-8'),
$: {
logText: "#logTextArea"
},
ready() {
// 显示日志用.
let logCtrl = this.$logText;
let logListScrollToBottom = () => {
setTimeout(function () {
logCtrl.scrollTop = logCtrl.scrollHeight;
}, 10);
};
vueInst = new window.Vue({
el: this.shadowRoot,
created() {
Fs.readFile(Editor.url('packages://res-remove/.setting.json'), 'utf-8', (err, res) => {
if (err) {
return;
}
const settingObj = res ? JSON.parse(res) : {};
this.settings = settingObj;
this.filters = settingObj.filters || "";
this.moveNumber = settingObj.moveNumber || 3;
this.moveSwitch = settingObj.moveSwitch || true;
this.onConfirmFilter();
});
},
data: {
logView: "",
checkProgress: 0,
fileGroups: {},
savedFiles: {},
depend0s: [],
filters: "/res/",
settings: {},
taskState: "空闲中",
moveSwitch: true,
moveNumber: 3,
},
methods: {
_addLog(str) {
let time = new Date();
this.logView += `[${time.toLocaleString()}]: ${str}\n`;
logListScrollToBottom();
Editor.log(str);
},
_setProgress(p) {
this.checkProgress = p;
},
_saveSetting() {
Fs.writeFile(Editor.url('packages://res-remove/.setting.json'), JSON.stringify(this.settings), 'utf-8');
},
onFilterChange(ev) {
this.filters = ev.target.value;
},
onMoveNumberChanged(ev) {
this.moveNumber = ev.target.value;
},
onMoveSwitchChanged(ev) {
this.moveSwitch = ev.target.checked;
},
onConfirmFilter() {
this.settings.filters = this.filters;
this.settings.moveNumber = this.moveNumber || 3;
this.settings.moveSwitch = this.moveSwitch;
this._saveSetting();
Editor.Ipc.sendToMain("res-remove:setting-changed", this.settings);
},
onMakCache() {
this.fileGroups = {};
this.savedFiles = {};
this.depend0s = [];
this.checkProgress = 0;
// 开始重建缓存数据.
Editor.log("开始重建资源索引数据...");
this.taskState = "正在重建资源索引数据中";
Editor.Ipc.sendToMain("res-remove:make-cache", (error, answer) => {
if (error && error.code === 'ETIMEOUT') {
//check the error code to confirm a timeout
Editor.error('Timeout for ipc message foobar:greeting');
return;
}
Editor.success("资源索引构建完成!");
this.taskState = "重建索引完成"
});
},
async showDumpRes(res) {
this.fileGroups = res;
},
checkDefaultSaves(res) {
// 检测可以默认选中的资源: 包含db://assets/Texture/, db://assets/resources/,且总引用数大于0.
const SAVE_DIR = ["db://assets/Texture/", "db://assets/resources/"];
for (let crc in res) {
const files = res[crc];
let deps = 0;
let saveFile = null;
let saveFile2 = null;// 虽然不在texture/下, 但存在引用计数.
for (const f of files) {
deps += (f.depends || 0)
const inTexture = SAVE_DIR.filter(v => {
return f.url.startsWith(v)
});
if (inTexture.length > 0) {
saveFile = f;
} else if (f.depends && !saveFile2) {
saveFile2 = f;
}
}
if (deps > 0) {
if (saveFile) {
this.savedFiles[saveFile.uuid] = saveFile;
} else if (saveFile2) {
this.savedFiles[saveFile2.uuid] = saveFile2;
}
}
}
},
updateDepends0(depend0List) {
this.depend0s = depend0List;
// 存储无引用资源.
},
async onConfirmAll() {
const files = this.files;
const length = files.length;
if (length <= 0) {
this._addLog("没有发现重复资源,无需处理!!!")
return;
}
this.taskState = "正在替换重复资源中"
const p = 100 / length;
let count = 0;
this.checkProgress = 0;
const savedFiles = this.savedFiles;
for (const group of files) {
const dropped = []; // 如果所有资源都未勾选,则如果有引用时会被忽略删除.
const saved = [];// 原则上,每一组相同资源,只应该保留其中一个,若选择了多个,则会用第一个选项进行资源替换,其他勾选项不做处理,也不删除.
for (let f of group) {
if (savedFiles.hasOwnProperty(f.uuid)) {
saved.push(f)
} else {
dropped.push(f)
}
}
// 查找待移除的uuid资源,将其引用预制体修改掉,saved[0]有可能为空,则都不保留.全部删掉.
Editor.Ipc.sendToMain("res-remove:exchange-uuid", saved[0], dropped, (err, resp) => {
this.checkProgress += p;
count += 1;
if (count == length) {
Editor.Ipc.sendToMain("res-remove:exchange-uuid-finish", (err) => {
this.startRemoveUnused();
}, 30000);
}
}, 20000);
}
},
startRemoveUnused() {
this._addLog("准备清理无用资源...")
this.taskState = "正在清理无引用资源"
this.checkProgress = 0;
const unusedFiles = this.depend0s.filter(v => {
return !this.savedFiles.hasOwnProperty(v.uuid);
}).map(v => {
return v.url;
});
// 移除未引用资源.
if (unusedFiles && unusedFiles.length > 0) {
Editor.Ipc.sendToMain("res-remove:remove-unused", unusedFiles, (err) => {
// 确认所有待清理资源已发送完成.
this._addLog("资源清理完成!");
this.taskState = "资源清理完成";
this.onMakCache()
}, 30000);
} else {
this._addLog("未用资源数量为0,无需清理.资源清理完成!");
this.onMakCache()
}
},
onItemChecked(ele, v) {
if (ele.target.checked) {
window.Vue.set(this.savedFiles, v.uuid, v);
} else {
window.Vue.delete(this.savedFiles, v.uuid);
}
},
onPrintDepends(item) {
// 打印显示某资源的依赖资源列表
Editor.Ipc.sendToMain("res-remove:print-depends", item.subMetas[0].uuid);
},
onUnusedSelect(ele) {
if (ele.target.checked) {
// 全选
this.depend0s.forEach(v => {
window.Vue.set(this.savedFiles, v.uuid, v);
});
} else {
this.depend0s.forEach(v => {
window.Vue.delete(this.savedFiles, v.uuid);
});
}
}
},
computed: {
files: function () {
const values = Object.values(this.fileGroups);
return values;
}
}
});
},
messages: {
'update-progress'(event, args) {
if (args) {
vueInst._setProgress(args);
}
if (event.reply) {
event.reply(null, "");
}
},
'addLog'(event, args) {
if (args) {
vueInst._addLog(args);
}
if (event.reply) {
event.reply(null, "");
}
},
'res-search-finished'(event, fileGroups, depend0s) {
Editor.log("资源检索完成");
if (event.reply) {
event.reply(null, "");
}
if (fileGroups) {
vueInst.checkDefaultSaves(fileGroups);
vueInst.showDumpRes(fileGroups);
}
if (depend0s) {
vueInst.updateDepends0(depend0s);
}
}
}
});