杀戮尖塔Mod中RawPatch的探索

杀戮尖塔Mod中RawPatch的探索

本站内容版权属于本人。转载须告知本人,写明出处,并在文首提供指向本站对应文章的链接。
本文链接:杀戮尖塔Mod中RawPatch的探索

在做杀戮尖塔Mod的时候,Patch是个常用工具,用来在原版游戏里面各处插入代码。不过最经常用的都是PrefixPatch、InsertPatch、PostfixPatch这种直接在特定地方插入代码,最多用用InstrumentPatch,像RawPatch几乎不会用到。但如果要做一些复杂的功能,只插入一些代码完成不了的时候,就需要使用RawPatch了。

使用方法

和其他Patch类似,RawPatch也需要用SpirePatch定义需要修改的方法,代码如下:

作为参数传入的CtBehavior是Javassist提供的类,可以直接改这个方法的任意代码。但RawPatch的功能不只如此,通过CtBehavior其实可以拿到任意一个类的任意方法并修改。所以如果你想对不特定的类加Patch,可以用RawPatch作为入口来读取。具体方法是通过method拿到ClassPool,再从ClassPool中取到对应的类:

修改代码

一般来说,你不需要从字节码层面去修改代码。从CtBehavior可以用insertAt、insertAfter、insertBefore来在特定位置插入代码,也可以用instrument来做和InstrumentPatch类似的事情。但如果这些不能满足你,就需要修改字节码了。

要修改字节码,需要以下几个东西:

CodeIterator是用来读写字节码的,ConstPool是常量池,有些指令会引用常量池中的内容。

字节码的功能可以参考以下文档:

以下的代码可以打印出这个方法所有的字节码:

要插入代码,可以用Bytecode对象生成代码,再用CodeIterator插入。Bytecode提供了一系列方法来插入字节码,对于没支持的方法,也可以用addOpcode或者add来直接插入字节码。

注意事项

插入代码后,这个方法最大栈深度和局部变量数可能会不同。需要估算后更新进去,下面只是个示例,没考虑到插入位置对栈深度和局部变量数的影响。

如果你插入了任何跳转指令并产生了新的跳转落点,或者加入了局部变量,则需要更新StackMapTable:

总结

虽说RawPatch提供了强大的功能,不过能不直接改字节码还是别折腾了吧,又费事又容易出bug。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

*

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据