parser.js 4.73 KB
Newer Older
liujiangnan's avatar
liujiangnan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
const { print } = require("../eazax/editor-main-util");
const FileUtil = require("../eazax/file-util");
const { containsProperty } = require("./object-util");

/**
 * 解析器
 */
const Parser = {

    /**
     * 节点树缓存
     * @type {{ [key: string]: object }}
     */
    caches: Object.create(null),

    /**
     * 获取节点树
     * @param {string} path 路径
     * @returns {Promise<object>}
     */
    async getNodeTree(path) {
        if (!Parser.caches[path]) {
            const file = await FileUtil.readFile(path);
            let data = null;
            try {
                data = JSON.parse(file);
            } catch (error) {
                print('warn', '文件解析失败', path);
                print('warn', error);
            }
            if (!data) {
                return null;
            }
            Parser.caches[path] = Parser.convert(data);
        }
        return Parser.caches[path];
    },

    /**
     * 更新缓存
     * @param {string} path 路径
     */
    async updateCache(path) {
        Parser.caches[path] = null;
        await Parser.getNodeTree(path);
    },

    /**
     * 将资源解析为节点树
     * @param {object} source 源数据
     * @returns {object}
     */
    convert(source) {
        const tree = Object.create(null),
            type = source[0]['__type__'];
        if (type === 'cc.SceneAsset') {
            // 场景资源
            const sceneId = source[0]['scene']['__id__'],
                children = source[sceneId]['_children'];
            tree.type = 'cc.Scene';  // 类型
            tree.id = sceneId;       // ID
            // 场景下可以有多个一级节点
            tree.children = [];
            for (let i = 0, l = children.length; i < l; i++) {
                const nodeId = children[i]['__id__'];
                Parser.convertNode(source, nodeId, tree);
            }
        } else if (type === 'cc.Prefab') {
            // 预制体资源 
            const uuid = source[source.length - 1]['asset']['__uuid__'];
            tree.type = 'cc.Prefab';  // 类型
            tree.uuid = uuid;         // uuid
            // 预制体本身就是一个节点
            tree.children = [];
            const nodeId = source[0]['data']['__id__'];
            Parser.convertNode(source, nodeId, tree);
        }
        return tree;
    },

    /**
     * 解析节点
     * @param {object} source 源数据
     * @param {number} nodeId 节点 ID
     * @param {object} parent 父节点
     */
    convertNode(source, nodeId, parent) {
        const srcNode = source[nodeId],
            node = Object.create(null);
        // 基本信息
        node.name = srcNode['_name'];
        node.id = nodeId;
        node.type = srcNode['__type__'];

        // 路径
        const parentPath = parent.path || null;
        node.path = parentPath ? `${parentPath}/${node.name}` : node.name;

        // 预制体引用
        const srcPrefab = srcNode['_prefab'];
        if (srcPrefab) {
            const id = srcPrefab['__id__'];
            node.prefab = Parser.extractValidInfo(source[id]);
        }

        // 组件
        node.components = [];
        const srcComponents = srcNode['_components'];
        if (srcComponents && srcComponents.length > 0) {
            for (let i = 0, l = srcComponents.length; i < l; i++) {
                const compId = srcComponents[i]['__id__'],
                    component = Parser.extractValidInfo(source[compId]);
                node.components.push(component);
            }
        }

        // 子节点
        node.children = [];
        const srcChildren = srcNode['_children'];
        if (srcChildren && srcChildren.length > 0) {
            for (let i = 0, l = srcChildren.length; i < l; i++) {
                const nodeId = srcChildren[i]['__id__'];
                Parser.convertNode(source, nodeId, node);
            }
        }

        // 保存到父节点
        parent.children.push(node);
    },

    /**
     * 提取有效信息(含有 uuid)
     * @param {object} source 源数据
     * @returns {{ __type__: string, _name: string, fileId?: string }}
     */
    extractValidInfo(source) {
        const result = Object.create(null);

        // 记录有用的属性
        const keys = ['__type__', '_name', 'fileId'];
        for (let i = 0, l = keys.length; i < l; i++) {
            const key = keys[i];
            if (source[key] !== undefined) {
                result[key] = source[key];
            }
        }

        // 记录包含 uuid 的属性
        for (const key in source) {
            const contains = containsProperty(source[key], '__uuid__');
            if (contains) {
                result[key] = source[key];
            }
        }

        return result;
    },

};

module.exports = Parser;