Unity手游汉化笔记①:UABE+AssetStudio修改MonoBehavior

本秂侑毒 提交于 2020-03-17 08:04:49

总的笔记:https://www.cnblogs.com/guobaoxu/p/12055930.html


目录

一、使用工具

二、脚本在序列化文件中的表现形式

三、对MonoBehavior的参数进行修改

(1)寻找和定位

(2)修改之文本形式

(3)修改之二进制形式


MonoBehavior是开发过程中绑定在物体上的脚本被序列化后得到的,在汉化过程中,修改文字经常会需要修改这种类型的资源,字体的修改过程也会涉及到。

一、使用工具:

  Unity版本:2018.4.5f1

  AssetStudio(地址:https://www.perfare.net/tag/assetstudio

  UABE(地址:https://7daystodie.com/forums/showthread.php?22675-Unity-Assets-Bundle-Extractor

  il2cppdumper(地址:https://www.perfare.net/tag/il2cppdumper

二、脚本在序列化文件中的表现形式

  正向开发中,类中的public字段会放进检查器Inspector中(不考虑属性的控制的话),而在序列化的时候,首先会将类的信息序列化为一个MonoScript,绑定在场景物体上的具体对象则是序列化为MonoBehavior,一个类可以多次实例化,所以一个MonoScript会被多个MonoBehavior引用。

  给一个具体的例子,写一个简单的类,代码如下

namespace MyNamespace
{
    public class MyScript : MonoBehaviour
    {
        public bool myBool;
        public string myStr;
        public int myInt;
    }
}

在检查器Inspector中会对应出现下面三个参数:

然后我们编译一下,再用Asset Studio预览,会找到下面这个

  在右侧预览中,第一个指针指向的是这个MonoBehavior所绑定的场景对象,然后是Enabled,也就是检查器Inspector中名字左侧的勾,第二个指针指向的就是描述了类信息的MonoScript,值得注意的是,在MonoScript中,只描述了类的所属DLL、命名空间、类名等,并没有字段的信息,然后就是字段区域了,他的具体二进制形式也可以关注一下,用UABE导出一下二进制,内容如下

拆解一下,对应关系如下:

00 00 00 00 02 00 00 00 00 00 00 00             指向GameObject的指针
01 00 00 00                                     Enabled
01 00 00 00 67 00 00 00 00 00 00 00             指向MonoScript
00 00 00 00                                     这个MonoBehavior的名字
01 00 00 00                                     字段myBool,布尔值占4byte
09 00 00 00 E5 AD 97 E7 AC A6 E4 B8 B2 00 00 00 字段myStr,先长度,然后UTF-8编码,最后向4Byte对齐
39 30 00 00                                     字段myInt

可以看到在MonoScript的指针之后就是参数区域了,实际上如果把父类和非基本类型一并考虑进来,参数区域的序列化规则如下:

(1)先放父类的变量,再放入一个String(跟类有关系),再放入当前类内的字段;字段按照类内定义的顺序放

(2)基本类型会直接放,其中布尔值会用占4byte,可参考上面的例子

(3)String是先一个Int表示实际长度,再放入UTF-8编码的内容,最后补0,使得最后占据的总长度和4byte对齐

(4)Unity定义的资源会用PPtr来指向

(5)其他类的字段需要先有serializable属性才会进行序列化,规则类似(这还是个递归的过程)

  如果想要深入理解,建议自己多做几个类看看

三、对MonoBehavior的参数进行修改

  既然知道了在检查器Inspector中设置的字段会被序列化进资源文件,那么我们就可以从这里入手给他做修改。先对样例做点修改,把脚本绑到一个Text上,再在脚本里加一段代码:

void Start()
{
    Text text = gameObject.GetComponent<Text>();
    text.text = myStr;
}

这样运行起来之后效果如下:

接下来是修改的全过程,遇到的问题我尽可能记下来了,所以比较长

(1)寻找和定位

  寻找主要利用AssetStudio,直接用AssetStudio加载Data文件夹,菜单栏-Filter Type-MonoBehaviour,筛选只看MonoBehavior类型,如果没有其他信息,就只能直接一个一个看了,第一次点击的时候会弹窗“Select Assembly Folder”,这里是要求选择DLL所在的文件夹。

【问题1】关于类的信息

  前面说过了,类的信息会放在MonoScript中,但是MonoScript中只有类名,没有字段信息,所以要解析参数区域,还需要DLL,这很好理解。

  但是涉及到DLL,又出现新的问题,Mono脚本后端的DLL就直接放在assets\bin\Data\Managed文件夹下,而il2cpp脚本后端则是编译成了so文件,所以针对il2cpp脚本后端,还需要另一个工具的帮助,il2cppdumper,他的具体操作建议看官网,利用il2cppdumper,可以得到DummyDLL,这里面没有实际的代码逻辑,但是有字段信息,足够使用了。

找到我们需要的MonoBehavior之后,右键Show original File,可以看到他在level0文件。

  然后要用UABE找到具体的这个MonoBehavior,用UABE打开level0,有几个信息可以帮助我们定位到该MonoBehavior,首先是Type列,里面有完整的类名,而AssetStudio中也会有这个名字(AS左侧列表中的Name列,有名字就显示名字,没名字就显示类名);其次是Size列,大小肯定是不会变的。找到该MonoBehavior所在的行如下

(2)修改之文本形式

  修改靠的是UABE,因为UABE中有两种导入导出的方式,二进制RAW和文本形式,所以这里也分两种来说。

  先用UABE导出文本,点击右侧的Export Dump,会弹窗提示:

  这跟【问题1】是同一个问题,UABE会自动现在Data/Manager文件夹下找DLL,如果有DLL找不到,在第一次导出文本的时候就会提示这个框,要你给他找那些找不到的DLL。点击“是”,然后给他找缺少的DLL,然后就会发现一个新的问题,很多DLL根本没有,这很正常,因为Unity有很多的默认资源,这些资源里引用的类又不一定会编译进来,所以一般来说在Manager文件夹下有的、或者il2cppdumper导出来的给他选上就够了。导出来的文本如下:

0 MonoBehaviour Base
 0 PPtr<GameObject> m_GameObject
  0 int m_FileID = 0
  0 SInt64 m_PathID = 2
 1 UInt8 m_Enabled = 1
 0 PPtr<MonoScript> m_Script
  0 int m_FileID = 1
  0 SInt64 m_PathID = 103
 1 string m_Name = ""
 1 UInt8 myBool = 1
 1 string myStr = "字符串"
 0 int myInt = 12345

可以看到和AssetStudio中的基本一样,如果你的中文字符串是乱码,说明你没有采用UTF-8编码

【问题2】编码问题

  Unity序列化文件中的字符串用的是UTF-8编码

  改一下参数,再回到UABE,点击Import Dump,选择修改后的文本,可以看到Modified列中出现了星号。接下来就是保存了,点击OK,这里有个小问题,UABE只能另存为,而不能直接写回源文件,所以要保存到别的地方,再手动复制替换。

  替换后,如果没有其他安全措施,那就可以直接运行,效果如下:

(3)修改之二进制形式

  二进制形式其实很少用,能直接改文本根本不想写十六进制,但是以防万一还是测试了。

  还是先用UABE打开level0并定位到要改的MonoBehavior,这次点击右侧的Export Raw,用010 Editor打开,工具其实随意,只要能进行十六进制的编辑就可以了。关于参数区域,前面(二、脚本在序列化文件中的表现形式)已经说过了,但是那是已知类的字段的情况,再不知道的情况怎么做呢?其实也不难,直接调成UTF-8编码,虽然都是乱码,但是字符串部分是没有乱的!用010Editor的话效果如下:

这里有两种方式回到十六进制:

  ① 010 Editor的话,选中字符串,再切回十六进制显示,选中是保持着的

  ② 在百度找个在线编码转换,(注意【问题2】编码问题)得到这串的编码“%e6%96%b0%e7%9a%84%e5%ad%97%e7%ac%a6%e4%b8%b2”,只保留十六进制数“e696b0e79a84e5ad97e7aca6e4b8b2”,然后利用编辑器搜索功能搜索一下,一样可以定位到

  确定了字符串的位置,接下来就是修改,回顾一下前面的规则,字符串是“先长度、再Byte数组、最后补0对齐4byte”的规则,所以前面的“0F 00 00 00”是长度,还是那个在线编码转换,得到“更新的字符串”的编码“%e6%9b%b4%e6%96%b0%e7%9a%84%e5%ad%97%e7%ac%a6%e4%b8%b2”,只保留十六进制数“e69bb4e696b0e79a84e5ad97e7aca6e4b8b2”,长度为18个Byte(十六进制就是0x12),按照规则写进去:

注意,字符串后面的参数应该向后移动,不能被覆盖。

  改完了就是写回,回到UABE,右侧Import Raw,选中已经修改完的dat文件,保存,覆盖,再运行。效果如下:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!