unity-find-fault
Version:
A tool to find fault in unity project.
187 lines • 7.2 kB
JavaScript
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