Unity本地化id查找器,luaparser函数参数查找

news2024/9/23 11:24:04

前言:
适用范围: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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2094018.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SOMEIP_ETS_075: Wrong_Message_Type

测试目的&#xff1a; 验证当设备&#xff08;DUT&#xff09;接收到一个包含错误消息类型的SOME/IP请求时&#xff0c;是否能够返回错误消息或忽略该请求。 描述 本测试用例旨在检查DUT在处理一个echoUINT8方法的SOME/IP消息时&#xff0c;如果消息中包含的消息类型不正确&…

【超详细】Linux开发环境搭建指南 | Ubuntu

文章目录 虚拟机安装对比Virtual Box 下载ubuntu 操作系统下载Virtual Box 安装安装ubuntu设置中文语言共享文件夹设置添加输入法安装步骤&#xff0c;参考官方教程 安装 vscode解决主机不能通过ssh连接宿主机网络连接几种网络连接区别主机和宿主机相互 ping通 网络代理 虚拟机…

为k8s准备docker 私有仓库 harbor

目录 一、 环境准备 二、部署docker 二、为Registry提加密传输 三、为仓库建立登陆认证 四、构建harbor 五、上传镜像 然后就是在200上面进行配置了 一、 环境准备 我是用两台虚拟机(红帽9)的&#xff0c;一台172.25.254.10用来部署加密认证仓库&#xff0c;另一台172.2…

从零上手CV竞赛:YOLO方案 # Datawhale AI夏令营

文章目录 平台参赛平台云平台 Task 1 从零上手CV竞赛下载baseline相关文件一键运行baseline&#xff01;&#xff08;大约需要25分钟&#xff09;赛题解析数据集提交结果违法标准注意事项 下载生成的文件结果如图最后要记得关机 不然一直消耗算力 Task 2 建模方案解读与进阶物体…

【大数据算法】时间亚线性算法之:串相等判定算法。

串相等判定算法 1、引言2、串相等判定算法2.1 定义2.2 核心原理2.3 应用场景2.4 算法公式2.4.1 Rabin-Karp算法2.4.2 哈希函数 2.5 代码示例 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c; 啥是串相等判定算法啊 小鱼&#xff1a;这个… en…en… 小屌丝&#xff1a;咋…

ai免费生成ppt软件有哪些?我推荐秒出PPT

现在市面上的ai生成PPT软件非常的多。有收费的&#xff0c;也有不收费的&#xff0c;生成的效果也各不相同。要选择一个性价比高的确实难度不小。 我在使用了不少的产品之后&#xff0c;说一说我的心得。 首先就是&#xff0c;大部分免费的ai生成ppt产品并不好用。我怕不排除…

解决Selenium已安装,在pycharm导入时报错

搭建设selenium环境时&#xff0c;selenium已安装&#xff0c;但是在pycharm中使用“from selenium import webdriver”语句时红线报错 解决方案&#xff1a; 1.file->settings进入设置 2.点击加号&#xff0c;搜索‘selenium’安装 3&#xff0c;等待安装完成&#xff0…

windows 上安装 Anaconda

下载 立即下载 |蟒蛇 (anaconda.com) 安装

Nginx: 高可用和与虚拟路由冗余协议VRRP原理以及KeepAlived软件架构

Nginx 服务的高可用 1 &#xff09;服务可用 假定是这样一个最传统的一个CS模式的一个客户服务器模式 这里有用户和一台服务器服务器可能是mysql, 也可能是webserver, 或其他服务器 想实现服务可用的一个三要素 1.1 ) server 需要公网的ip地址以及申请一个域名1.2 ) 需要服务软…

MIG IP核详解

1.MIG IP核简介 MIG(Memory Interface Generators) IP 核是Xilinx公司针对DDR存储器开发的 IP&#xff0c;里面集成存储器控制模块&#xff0c;实现DDR读写操作的控制流程&#xff0c;下图是7系列的 MIG IP 核结构框图。MIG IP 核对外分出了两组接口。左侧是用户接口&#xff…

自制实战吃鸡手柄原理

在前面的讨论中&#xff0c;通过类似物理点击的方式来实现了声控触发射击键的点击 【Arduino】自制声控点击器&#xff08;吼叫吃鸡助手&#xff09;_辅助机械臂物理物理键盘点击器神器-CSDN博客 为了更有实战效果&#xff0c;我们可以把玩具枪改造为一个手柄&#xff0c;这样…

2024年Java最新面试题总结(三年经验)

目录 第一章、基础技术栈1.1&#xff09;集合&#xff0c;string等基础问题1、arraylist &#xff0c;linkedlist的区别&#xff0c;为啥集合有的快有的慢2、字符串倒叙输出2.1、字符串常用方法2.2、字符串号拼接的底层原理3、讲一下Java的集合框架4、定义线程安全的map&#x…

进制数基础知识 与 位运算(基础版)

目录 1. 计算机常用进制类别 2. 10进制转各种进制&#xff08;取余倒置法&#xff09; 3. 二进制转8进制、16进制 3.1 二进制转8进制 3.2 二进制转16进制 4. 原码、反码、补码 5. 整型提升 与 算术转换 5.1 整型提升 5.2 算术转换 6. 移位操作符 6.1 左移操作符( &l…

【spring】学习笔记2:sample、boot功能和组件设计

Spring自带了一个强大的Web框架,名为Spring MVC。Spring MVC的核心 是控制器(controller)的理念。控制器是处理请求并以某种方式进行信息 响应的类。在面向浏览器的应用中,控制器会填充可选的数据模型并将请求 传递给一个视图,以便于生成返回给浏览器的HTML。在pom.xml文件…

前端开发——熟悉WebSocket(包含示例)

最近在开发中需要调用第三方API&#xff0c;现在大家的API基本上都是使用WebSocket来进行的&#xff0c;前端也必须来学一手了 什么是WebSocket 参考&#xff1a;https://blog.csdn.net/L2043524156/article/details/139271715 有如下四个好处&#xff1a; 双向通信&#x…

C# .Net 条码批量自动打印框架 基于Bartender 10.1 V1.0

调用Bartender打印模板&#xff0c;批量打印条码。 需要有一定的C#开发能力。 非常适合工厂中从ERP拿取信息后&#xff0c;批量打印出货条码。 提供全部源代码&#xff0c;毫无保留。 Winform程序&#xff0c;使用了依赖注入(微软DI)&#xff0c;数据库访问的ORM为Dapper。…

位图 —— 哈希思想的产物

目录 1.学习位图的前置知识 计算机中数据存储的单位 C中数据类型的大小 2.位图的讲解 位图的引出 位图的使用 位图的实现 位图完整代码 3.位图的总结 位图的优缺点 优点 缺点 1.学习位图的前置知识 计算机中数据存储的单位 想要学习位图&#xff0c;首先要明白什…

在Windows10系统快速启用telnet功能

打开Windows控制面板 → 程序 → 启用或关闭Windows功能 勾选Telnet客户端 然后确定 启用后windowR 打开运行&#xff0c;输入cmd回车 使用telnet命令回车 可以直接使用telnet命令&#xff08;如果提示telnet是外部命令需要重启电脑&#xff09; 输入 ?/help 可查看帮助 到…

排序算法:

冒泡排序&#xff1a; 从列表的第一个数字开始进行比较&#xff0c;判断该数和下一个数之间的大小关系&#xff0c;如果该数比右边的数大&#xff0c;则交换位置&#xff1b;否则不变。一般一轮可以确定最大的数字&#xff0c;在列表的最后一位。 代码&#xff1a; 注意&…

开源 AI 智能名片 S2B2C 商城小程序在现代商业中的创新与启示

摘要&#xff1a;本文通过分析一种以 9.9 元裙子为代表的独特商业模式&#xff0c;探讨了其背后的现金流、产品和渠道组合策略&#xff0c;以及开源 AI 智能名片 S2B2C 商城小程序在其中可能发挥的作用和带来的启示。 一、引言 在当今竞争激烈的商业环境中&#xff0c;企业不断…