UNPKG

unity-find-fault

Version:

A tool to find fault in unity project.

169 lines 7.89 kB
import fs from 'fs-extra'; import fg from 'fast-glob'; import { toolchain } from "../toolchain.js"; import { UnityHelper } from './UnityHelper.js'; import { Record } from './Record.js'; import path from 'path'; import { Project } from 'ts-morph'; import { UIRelations } from './UIRelations.js'; export class Handyman { async executeDelete(r) { if (!toolchain.opts.input) { console.error('no input file!'); return false; } const content = await fs.readFileSync(toolchain.opts.input, 'utf-8'); const toBeDeleteds = content.split(/\r?\n/).map(d => d.split(' ')[0]); for (const d of toBeDeleteds) { if (!fs.existsSync(d)) continue; await r.collect(d); const guid = await UnityHelper.readGUID(d + '.meta'); await fs.unlink(d); await fs.unlink(d + '.meta'); await Record.Instance.recordGUID(guid, d); } return toBeDeleteds.find(d => d.endsWith('.prefab')) != null; } async replaceFile() { const guidA = await UnityHelper.readGUID(path.join(toolchain.opts.projectRoot, toolchain.opts.input + '.meta')); const guidB = await UnityHelper.readGUID(path.join(toolchain.opts.projectRoot, toolchain.opts.target + '.meta')); const targets = await fg(UnityHelper.CompositeFileTypes.map((v) => `**/*${v}`), { cwd: toolchain.opts.projectRoot }); for (const tgt of targets) { const tgtf = path.join(toolchain.opts.projectRoot, tgt); const content = await fs.readFile(tgtf, 'utf-8'); const newContent = content.replaceAll(guidA, guidB); if (newContent != content) { await fs.writeFile(tgtf, newContent, 'utf-8'); } } } async anyway() { await this.findPotentialBugs(); } async fixWindowAnim() { const windowAnimController = path.join(toolchain.opts.projectRoot, 'Assets/AssetSources/ui/animation/windowOpen/windowAnim.controller'); const waguid = await UnityHelper.readGUID(windowAnimController + '.meta'); const root = path.join(toolchain.opts.projectRoot, 'Assets/AssetSources/ui'); const tsRoot = path.join(toolchain.opts.projectRoot, 'TsScripts'); const prefabs = await fg('**/*.prefab', { cwd: root }); for (const p of prefabs) { const file = path.join(root, p); const content = await fs.readFile(file, 'utf-8'); if (content.includes(waguid) && !content.includes('CanvasGroup:')) { const pn = path.basename(p, '.prefab'); const tsfs = await fg(pn + '.ts', { cwd: tsRoot, caseSensitiveMatch: false }); let useAlpha = undefined; if (tsfs.length > 0) { const tsf = path.join(tsRoot, tsfs[0]); const tsContent = await fs.readFile(tsf, 'utf-8'); const wpan = tsContent.matchAll(/this\._windowOpenAnimName\s=\s("|')(\w+)\1/g); const wcan = tsContent.matchAll(/this\._windowCloseAnimName\s=\s("|')(\w+)\1/g); for (const n of wpan) { if (n[2] == 'windowOpen') { useAlpha = true; } else { useAlpha = false; } } for (const n of wcan) { if (n[2] == 'windowClose') { useAlpha = true; } else { useAlpha = false; } } } if (useAlpha != false) { console.error(pn); } } } } async fixMonster() { const matRoot = path.join(toolchain.opts.projectRoot, 'Assets/AssetSources/modelSource/monster'); const files = await fg('**/*.mat', { cwd: matRoot }); for (const f of files) { const matf = path.join(matRoot, f); const content = await fs.readFile(matf, 'utf-8'); if (content.includes('7746c211250e33a419416482fc37989c')) { let newContent = content.replace('_EdgeWidth: 0.1', '_EdgeWidth: 0.05'); // .replace('_EdgeColor: {r: 1, g: 1, b: 1, a: 1}', '_EdgeColor: {r: 0.23137252, g: 0.34346527, b: 0.9607843, a: 1}'); // if (!newContent.includes('_EdgeColor')) { // const lines = newContent.split(/\r?\n/); // const idx = lines.findIndex(v => v.includes('_CurvedWorldBendSettings')); // if (idx >= 0) { // lines.splice(idx + 1, 0, ' - _EdgeColor: {r: 0.23137252, g: 0.34346527, b: 0.9607843, a: 1}'); // } // newContent = lines.join('\n'); // } await fs.writeFile(matf, newContent, 'utf-8'); } } } async findMissCfg() { const a = 'D:/works/dp_minigame/trunk/Assets/AssetSources/data'; const aCfgs = await fg('*.json', { cwd: a }); const b = 'D:/works/dpxyx/trunk/project/Assets/AssetSources/data'; const bCfgs = await fg('*.json', { cwd: b }); for (const c of aCfgs) { if (!bCfgs.includes(c)) { console.error(c); } } } async findPotentialBugs() { await UIRelations.build(); const allForms = UIRelations.getAllForms(); const tsRoot = path.join(toolchain.opts.projectRoot, 'TsScripts'); const project = new Project({ tsConfigFilePath: path.join(tsRoot, 'tsconfig.json') }); for (const f of allForms) { const src = project.getSourceFile(f.tsClass.sourceFile); if (!src) { console.error('SourceFile not exists:', f.tsClass.sourceFile); continue; } const classes = src.getClasses(); for (const cls of classes) { if (cls.getName() != f.tsClass.className) continue; if (cls.getConstructors()[0]?.getText().includes('this._cacheForm = true')) continue; const mthds = cls.getMethods(); for (const mthd of mthds) { const body = mthd.getBody(); if (body == null) continue; const startLine = body.getStartLineNumber(); const lines = body.getText().split(/\r?\n/); let closeLine = -1, lineCnt = lines.length; for (let i = 0; i < lineCnt; i++) { const line = lines[i]; if (!line.match(/^\s*\/\//) && (line.includes('.doClose()') || line.includes('.close()'))) { closeLine = i; break; } } if (closeLine >= 0 && closeLine < lineCnt - 1) { const nextLine = lines[closeLine + 1]; if (nextLine.includes('return')) continue; for (let i = closeLine + 1; i < lineCnt; i++) { const line = lines[i]; if (line.includes('this.')) { console.error(`try to access properties after dispose: ${f.tsClass.sourceFile}:${startLine + i}`); console.error(line); break; } } } } } } } } //# sourceMappingURL=Handyman.js.map