杂项
循环执行逻辑
在《灭》中,我们需要监测世界上新增的火焰,如果没有对应的自动消防水炮能够立即处理,则将新增的火焰存入缓存中,在之后重复检查,直至火焰熄灭或者被自动消防水炮处理;
在R6MS中,我们需要常常检测正在等待匹配的玩家,通过一定的算法选择合适的玩家,建立一局新的对战。
这些需要一直重复做的事情,我们当然应该放在tick
中去执行。
在TickEvent
类下,有五种不同的子类可供选择:
TODO
两个不同的类的实例要是各自注册了一个一模一样的事件监听器,事件响应的时候会报ClassCastException
重复继承问题
这种情况在造轮子时更容易遇到。你的mod在开发环境下一切正常,但却在生产环境下崩溃,错误报告中有这样一行:
Caused by: java.lang.AbstractMethodError: Receiver class cn.ussshenzhou.t88.gui.widegt.TButton does not define or inherit an implementation of the resolved method 'abstract int getX()' of interface cn.ussshenzhou.t88.gui.widegt.TWidget.
这是典型的重复继承后混淆产生的问题,它的大体原理是这样:
你出于某种目的让YourClass
继承了一个原版类VanillaClass
,又实现了一个新接口IYourInterface
,但是恰好这个新接口内的foo()
方法在VanillaClass
中也有一个同名的方法。
在开发环境下不会有任何问题,yourClass.foo()
调用的就是YourClass#foo()
,不会有任何毛病;在生产环境可就不一样了:在你构建mod时,所有的原版方法都会被重混淆——很不幸的是,混淆工具并不知道此foo()
非彼foo()
。
假如VanillaClass#foo()
的SRG名是bar()
,那你的YourClass#foo()
就会被混淆成为YourClass#bar()
(因为看起来是从原版父类那里继承来的),但是yourClass.foo()
却不会被改变(因为看起来是从新接口实现的)。然后等到生产环境运行yourClass.foo()
的时候——找不到foo()
了。
一种简单而高效的补救措施是把你的新方法改个名,就像T88里的tickT()
、isVisibleT()
、getXT()
、getYT()
一样:
另一种比较沙雕的办法是反向改名:
显然,由于SRG名没有可读性而不推荐。
你应该可以感觉到,这种错误在编写阶段很难发现——开发环境完成测试不代表生产环境就万事大吉了。