UNPKG

unity-find-fault

Version:

A tool to find fault in unity project.

187 lines 7.2 kB
import fs from 'fs-extra'; import yaml from 'yaml'; export class PrefabParser { static SectionHeader = /--- !u!(\d+) &(-?\d+)( stripped)?/; unityStruct = {}; /**解析Prefab,获得根GameObject为起点的GameObject树 */ async parse(filePath) { const elements = []; const elemMap = {}; let fileContent = await fs.readFile(filePath, 'utf-8'); fileContent = fileContent.replaceAll(/(\r?\n){2,}(?=')/g, ''); // 去掉text末尾换行的情况 let fileLines = fileContent.split(/[\r\n]+/); // 前两行为tag跳过 let elemContent = ''; let elem; for (let i = 2, len = fileLines.length; i < len; i++) { const line = fileLines[i]; const docMatchRst = line.match(PrefabParser.SectionHeader); if (docMatchRst) { // 匹配到新元素 if (elem != null) { this.parseUnityElement(elem, elemContent, filePath); } elem = {}; elem.yamlID = Number(docMatchRst[1]); elem.fileID = docMatchRst[2]; elem.stripped = Boolean(docMatchRst[3]); elemMap[elem.fileID] = elem; elements.push(elem); elemContent = ''; } else { elemContent += line + '\n'; } } if (elem != null) { this.parseUnityElement(elem, elemContent, filePath); } const childBook = {}; for (const e of elements) { if (e.type == 'GameObject') { e.components = {}; const components = e.object.m_Component; if (components != null) { for (const c of components) { const comp = elemMap[c.component.fileID.toString()]; let key = comp.type; if (comp.type == 'MonoBehaviour') { key += '_' + comp.object.m_Script.guid; } e.components[key] = comp; } } } else if (e.type == 'Transform' || e.type == 'RectTransform') { if (e.object.m_GameObject == null) { if (!e.stripped) { console.error('RectTransform without GameObject:', e.fileID); } continue; } const go = elemMap[e.object.m_GameObject.fileID.toString()]; const children = e.object.m_Children; if (children != null) { e.children = []; for (const c of children) { childBook[c.fileID] = true; let child = elemMap[c.fileID]; if (child.type == 'Transform' || child.type == 'RectTransform') { if (child.object.m_GameObject != null) { child = elemMap[child.object.m_GameObject.fileID.toString()]; } } if (child != null) { if (child.type == 'GameObject') { e.children.push(child); } else { // console.error('child is not GameObject:', child.fileID); } } else { console.error('could not get child:', c.fileID); } } go.children = e.children; } const father = e.object.m_Father; if (father != null) { e.father = elemMap[father.fileID]; go.father = e.father; } } } const prefab = []; for (const e of elements) { if (e.type == 'GameObject' && e.father == null) prefab.push(e); } // 更新unity结构描述 // for(let i = 0, len = elements.length; i < len; i++) { // let elem = elements[i]; // let structMap = this.unityStruct[elem.type]; // if(!structMap) { // this.unityStruct[elem.type] = structMap = {}; // } // // if (elem.type == 'MonoBehaviour' && elem.fileID == '6860625456729184521') { // // this.getDesciption(elem.object, structMap); // // } // } // this.dumpDescribor(); return prefab; } parseUnityElement(elem, elemContent, filePath) { try { let obj = yaml.parse(elemContent, { intAsBigInt: true, toStringDefaults: { singleQuote: true } }); for (const key in obj) { elem.type = key; elem.object = obj[key]; break; } } catch (e) { console.log(elemContent); console.error(e); throw new Error('YAML parse error: ' + filePath); } if (!elem.type) { throw new Error('Prefab parse error!'); } } getDesciption(obj, structMap) { for (let key in obj) { let node = obj[key]; let nodeType = typeof (node); if (!structMap[key]) { if (nodeType == 'object') { if (!structMap[key]) { structMap[key] = {}; } } else { try { structMap[key] = nodeType; } catch (e) { console.error(e); throw new Error('getDesciption error!'); } } } if (nodeType == 'object') { this.getDesciption(node, structMap[key]); } } } dumpDescribor() { for (let type in this.unityStruct) { let lines = this.getDescriptionStr(this.unityStruct[type], ''); fs.writeFileSync('tmp/' + type + '.txt', lines.join('\n'), 'utf-8'); } } getDescriptionStr(structMap, indent) { let lines = []; lines.push('{'); for (let key in structMap) { let structValue = structMap[key]; if (typeof (structValue) == 'object') { let subLines = this.getDescriptionStr(structValue, indent + ' '); lines.push(key + '?: {'); for (let i = 1, len = subLines.length; i < len - 1; i++) { lines.push(subLines[i]); } lines.push('}, '); } else { lines.push(key + '?: ' + structValue + ', '); } } lines.push('}, '); for (let i = 1, len = lines.length; i < len - 1; i++) { lines[i] = ' ' + lines[i]; } return lines; } } //# sourceMappingURL=PrefabParser.js.map