首先请确保你会Java,不然我可以保证你看的一头雾水
对于汉化那些消息都写在class文件里的插件,这些东西还是比较有用的还有这些东西比较难懂,所以尽管问……
首先每个class文件中都有一个常量池,其中会存放不少东西,包括字符串
常量池中的数据分成14种,以下是比较常见的11种和他们之间的引用关系
- Fieldref_info --\ /--> Class_info --\
- Methodref_info ---+===+---> NameAndType_info ---+===> Utf8_info
- InterfaceMethodref_info --/ /
- String_info--------------------------------------------/
- Integer_info
- Float_info
- Long_info
- Double_info
Methodref_info:表示类中的方法
InterfaceMethodref_info:表示接口中的方法
Class_info:表示类和接口
NameAndType_info:表示字段或方法的名称和类型,含有两个对Utf8_info的引用
String_info:表示字符串常量
Utf8_info:实际保存字符串的地方
Integer_info:保存一个32位整数
Float_info:保存一个32位单精度浮点数
Long_info:保存一个64位整数,在这个常量后的一个常量必须是有效的,但是会被忽略(也就是不能使用)
Double_info:保存一个64位双精度浮点数,同上
常量池中的常量从1开始编号,最大为65535
class文件中,所有的数据都是大尾序的(也就是说,0x01020304保存为0x01 0x02 0x03 0x04四个字节,而小尾序是0x04 0x03 0x02 0x01)
对类的引用在class文件中表示为一个Class_info,这个结构中有一个表示相应的Utf8_info的编号的字段,而相应的Utf8_info中会记录实际的类名
类的名字很容易看,比如Java中的类com.example.foo.Bar,记录在class文件中时,把.换成/即可,也就是com/example/foo/Bar
对字段的引用在class文件中表示为一个Fieldref_info,这个结构中有一个表示所属的类的Class_info的编号的字段,还有一个表示字段名称和类型的NameAndType_info
NameAndType_info中有两个Utf8_info的编号,一个是名字,另外一个是类型。
class文件中,类型的信息是有自己的一个表示方式的。byte记为B,char记为C,double记为D,float记为F,int记为I,long记为J,short记为S,boolean记为Z,而某个特定的类记为 L类名; ,数组则是在相应的类型前加上[
比如,byte[]是[B,String[][]是[[Ljava/lang/String;,com.example.foo.Bar类型记为Lcom/example/foo/Bar;
对方法的引用和对字段的引用大体上是一样的,区别在于类型的标记方式。
一个方法可以接受多个参数,并且可以返回一个值(或者void类型,没有返回值)
这些信息一样是记录在NameAndType_info中表示类型的那个Utf8_info里的,记录方法是
- (参数1类型 参数2类型 ...)返回类型
特别的,对于void的返回类型,记作V
举例:java.lang.StringBuilder.append
- Methodref_info ---+---> Class_info -------> Utf8_info "java/lang/StringBuilder"
- \--> NameAndType_info ---+---> Utf8_info "append"
- \--> Utf8_info "(Ljava/lang/String;)Ljava/lang/StringBuilder;"
- Methodref_info ---+---> Class_info -------> Utf8_info "java/lang/Object"
- \--> NameAndType_info ---+---> Utf8_info "toString"
- \--> Utf8_info "()Ljava/lang/String;"
- NameAndType_info ---+---> Utf8_info "foobar"
- \--> Utf8_info "(IDLjava/lang/Thread;)Z"
对于字符串常量,String_info里有一个记录对应Utf8_info的编号的字段。非常简单的东西。
然后我们来考虑插件汉化……
考虑这种情况:你的程序里有一个地方使用了java.lang.StringBuilder.append(字符串之间用+都会用到这个),然后你又有一个字符串常量是"append"
那么在class文件里看起来就是这样的:
- Methodref_info ---+---> Class_info --------> Utf8_info "java/lang/StringBuilder"
- \--> NameAndType_info ---+----> Utf8_info "(Ljava/lang/String;)Ljava/lang/StringBuilder;"
- \
- String_info --------------------------------+--> Utf8_info "append"
正确的做法:单独添加一个Utf8_info常量,内容是“附加”,然后把本来指向“append”的String_info改为指向这个新的常量。
软件的话,http://classeditor.sourceforge.net/
来练个手吧w
这是某个class文件中的常量池的一部分:
#8 Fieldref_info Class_info#137,NameAndType_info#253
#39 String_info Utf8_info#149
#63 Methodref_Info Class_info#137,NameAndType_info#314
#137 Class_info Utf8_info#375
#149 Utf8_Info "compressor"
#150 Utf8_Info "Lnet/jpountz/lz4/LZ4Compressor;"
#204 Utf8_Info "setWorldsAutoSaving"
#205 Utf8_Info "(Z)V"
#253 NameAndType_Info Utf8_info#149 Utf8_info#150
#314 NameAndType_Info Utf8_info#204 Utf8_info#205
#375 Utf8_Info "name/linnaea/mbdelta/cb/BukkitPlugin"
请试着指出Methodref_Info#63表示的方法所在的类,及其原型
请试着指出Fieldref_info#8表示的字段所在的类,以及字段的名称和类型
请试着指出String_info#39表示的字符串
之后我可能会试着自己写个这种东西,方便汉化什么的
不过这些东西放这里的话,我觉得肯定会有人比我先完成,因为……
我懒啊