前言:
适用范围:Unity 中需要查找所有预制体里面的某一个脚本的属性值,或者Lua脚本里面的某一个属性值
本文介绍如何查找预制体和Lua脚本里面调用的本地化id

下面首先介绍改插件的功能以及使用方法,然后对该插件的原理进行说明

使用说明

本插件能够查找到预制体和lua脚本里面那些地方调用了指定的本地化id。操作步骤:首先在LangID输入框中输入要查找的id(使用分号间隔),也可以直接从csv文件导入id。点击【查找】按钮,就可以找到对应的id被哪些预制体和lua代码调用了。
在这里插入图片描述
【打开】按钮会调用默认编辑器打开对应的文件
【更新Lua代码索引】按钮会运行python程序生成lua代码的索引文件
【设置】按钮用于设置本地化函数名


插件原理说明

首先需要确保工程已经安装了Odin Inspector插件,否则无法运行本插件。

因为是要查找指定的本地化id,那么可以按照功能模块将代码分为两部分——查找预制体和查找Lua代码。

查找Lua代码中的本地化id

假设获取本地化id的函数名为lang.Get。
那么,是不是使用正则匹配lang.Get这个字符串,然后就可以获取调用的id了呢?实际项目中情况可能更复杂。

通过总结实际项目中代码的编写格式,可以将函数调用分为一下几种情况

function test()
    print("function test")
    
    --参数为常量
    lang.Get(10000)
    lang.Get(10000 + 10)
    
    --参数包含变量的情况
    local id = 20
    lang.Get(id)
    lang.Get(10000 + id)
    lang.Get(id + 10000)
    
    --参数包含table的情况
    local LANG_ENUM = {
        id1 = 10000,
        id2 = 10001,
        id3 = 10002,
    }
    lang.Get(LANG_ENUM.id1)
    lang.Get(LANG_ENUM.id2)
    lang.Get(LANG_ENUM.id3)
    
    local LANG_ARRAY = {20000, 20001, 20002}
    lang.Get(LANG_ARRAY[1])
    lang.Get(LANG_ARRAY[2])
end

面对这些情况,正则就不够用了。为了实现对以上情况的查找,所以lua代码部分的查找工作使用语法树来完成,这里使用基于python的luaparser(也有基于JS的)。luaparser的官方文档:https://pypi.org/project/luaparser/

这里使用python是为了方便将python程序打包,因为大部分人的电脑中没有python环境,而且我们不可能在插件中内嵌一个python环境,所有最后需要将python代码打包成exe程序。
请添加图片描述

上面是整套python代码的执行流程,简单来说就是首先找出差异文件,然后生成lua代码的语法树,然后找到所有的本地化id,最后将查找的结果进行序列化并以JSON格式保存在本地。C#层会读取该JSON文件,从而查找对应id。

P.S. 原本没有差异文件对比的,后来实际运行发现速度太慢了,构建2000个lua文件的索引大概需要8分钟左右,完全接受不了。后面加入差异化文件对比之后每次构建时间缩短到了1分钟以内,速度大大提高。

下面对python代码进行简单介绍

ast.walk(tree):获取树结构进行遍历
isinstance(node, astnodes.Call) :判断该节点是否是函数调用(.调用lua的函数)
isinstance(node, astnodes.Invoke) :判断该节点是否是函数调用(:调用lua的函数)
isinstance(node.func, astnodes.Name):判断是否是lua的命名表达式

# 查找调用指定函数的Node
def FindFuncNude(tree, funcName = "lang.Get"):
    funcList = []
    funcInfo = funcName.split('.')
    for node in ast.walk(tree):
        if isinstance(node, astnodes.Call) or isinstance(node, astnodes.Invoke):
            if isinstance(node.func, astnodes.Index):
                if isinstance(node.func.value, astnodes.Name) and funcInfo[0] == node.func.value.id:
                    if isinstance(node.func.idx, astnodes.Name) and funcInfo[1] == node.func.idx.id:
                        funcList.append(node)
                        print("lang.Get line->", node.line)
            elif isinstance(node.func, astnodes.Name):
                if node.func.id == funcName :
                    funcList.append(node)
                    print("lang.Get->", node.line)
    return funcList

#获取table里面所有的键值对
def GetTableKeyValuePairs(tableNode):
    '''
    :param tableNode: table 节点
    :return: key:变量名,value:变量的节点
    '''
    keyValueList = {}
    if isinstance(tableNode, astnodes.Table):
        for pair in tableNode.fields :
            if isinstance(pair.key, astnodes.Name) and isinstance(pair.value, astnodes.Number) :          #解析哈希表
                keyValueList[pair.key.id] = pair.value
            elif isinstance(pair.key, astnodes.Number) and isinstance(pair.value, astnodes.Number) :        #解析数组
                keyValueList[str(pair.key.n)] = pair.value
    return keyValueList

#获取文件里面所有的局部变量
def FindAllVariable(tree):
    '''
    :param tree: ast树
    :return: key:变量名,value:{value:变量值,node: 节点}
    '''
    varList = {}
    for node in ast.walk(tree):
        if isinstance(node, astnodes.LocalAssign):
            if len(node.targets) > 0 and len(node.values) > 0 :
                tempVar = node.targets[0]
                tempValue = node.values[0]
                if isinstance(tempVar, astnodes.Name) and isinstance(tempValue, astnodes.Number):    #等号左边是变量  等号右边是字面量
                    varList[tempVar.id] = {"value" : tempValue.n, "node": tempValue}
                elif isinstance(tempVar, astnodes.Name) and isinstance(tempValue, astnodes.Table):   #等号左边是变量  等号右边是table
                    keyValueList = GetTableKeyValuePairs(tempValue)
                    for key in keyValueList :
                        varList[tempVar.id + "." + key] = {"value" : keyValueList[key].n, "node": keyValueList[key]}
    print("---------------------------------")
    for key in varList :
        print(key,"=", varList[key]["value"])
    print("---------------------------------")
    return varList

至此,C#端只需要读取python端生成的json文件就可以获取lua的索引信息了,C#端的代码不做信息介绍。完整代码附在末尾的链接里面。

查找预制体中的本地化id

下面介绍如何查找预制体中的本地化id。首先获取所有预制体的路径,然后依次遍历这些路径,使用AssetDatabase.LoadAssetAtPath实例化预制,然后搜索对应的本地化脚本组件即可。

        public static Dictionary<int ,Dictionary<string, List<string>>> Finder(string prefabPath, HashSet<int> langIDSet)
        {
            List<string> allPrefabDir = Util.GetAllPrefabDir(prefabPath);
            Dictionary<int ,Dictionary<string, List<string>>> resDic = new Dictionary<int ,Dictionary<string, List<string>>>();
            foreach (var dir in allPrefabDir)
            {
                GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(dir);
                if (prefab != null)
                {
                    LocalizationText[] localizeTextList = prefab.GetComponentsInChildren<LocalizationText>(true);
                    foreach (var localizeText in localizeTextList)
                    {
                        int compLangID = localizeText.TextKey;
                        // 如果找到了
                        if (langIDSet.Contains(compLangID))
                        {
                            if (!resDic.ContainsKey(compLangID))
                            {
                                resDic[compLangID] = new Dictionary<string, List<string>>();
                            }

                            if (!resDic[compLangID].ContainsKey(dir))
                            {
                                resDic[compLangID][dir] = new List<string>();
                            }
                            
                            resDic[compLangID][dir].Add(Util.GetRoute(localizeText.transform));
                        }
                    }
                }
            }

            return resDic;
        }

代码自取:

langIDFinder 文件为unity插件的代码,其中的python代码位于main.py中
https://github.com/momohola/Localization-ID-Finder-by-luaparser

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部