提示
上期模组开发教程:ModuleManager与配置文件及简易功能实现。
AccessTransformer访问转换器的使用
简绍
AccessorTransformer 被简称为 AT,它能够修改指定字段或方法的访问修饰符以及是否被 final 修饰,它与 mixin 不同的是它可以访问被 protected 修饰符所修饰的变量或函数。
使用
首先需要先在 build.gradle 文件的 minecraft 项中添加以下内容,并在模组资源目录的 META-INF 目录中新建文件 accesstransformer.cfg:
minecraft {
[...]
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
}
最后重新构建项目即可。
注意:当模组在非开发环境中加载时,Forge 只会加载模组文件中的 META-INF/accesstransformer.cfg AT配置文件。
在AT的配置文件中使用的是 srgName,我们可以使用 mixin 的特性来获取 srgName,例如位于 Minecraft 类中的 timer 变量,该变量用于控制游戏每秒执行的操作数量。
package cn.ksmcbrigade.em.mixin;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Timer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Minecraft.class)
public interface MinecraftMixin {
@Accessor("timer")
Timer getTimer();
}
{
"required": true,
"minVersion": "0.8",
"package": "cn.ksmcbrigade.em.mixin",
"compatibilityLevel": "JAVA_8",
"refmap": "em.refmap.json",
"mixins": [
],
"client": [
"MinecraftMixin"
],
"injectors": {
"defaultRequire": 1
}
}
这里使用 Accessor 来注解以获取指定变量,若要执行指定函数需要使用 Invoker 来注解。
然后运行 build 任务来导出模组文件,最后通过解压软件打开模组文件中的 modid.refmap.json 即可查看到指定变量的srgName:
{
"mappings": {
"cn/ksmcbrigade/em/mixin/MinecraftMixin": {
"timer": "f_90991_:Lnet/minecraft/client/Timer;"
}
},
"data": {
"searge": {
"cn/ksmcbrigade/em/mixin/MinecraftMixin": {
"timer": "f_90991_:Lnet/minecraft/client/Timer;"
}
}
}
}
其中的 f_90991_ 即为 srgName,然后将需要被转换成的访问修饰符和类路径和 srgName 填入 AT 配置文件即可。
public-f net.minecraft.client.Minecraft f_90991_
其中的 -f 的意思为去掉 final 修饰符,因为 timer 变量是被 final 所修饰的,若要加上 final 修饰符,将 -f 改为 +f 即可。
提示:该方法对于函数依旧可以使用。
简易功能实现
Timer
该功能可以修改游戏的运算速度,首先在 modules 目录中创建 Timer 类,并继承 Module,然后重写 enabled 和 disabled 函数:
import cn.ksmcbrigade.em.Module;
import java.awt.event.KeyEvent;
public class Timer extends Module {
public Timer() {
super("Timer", KeyEvent.VK_Y); //key v
}
@Override
public void enabled() throws Exception {
super.enabled();
}
@Override
public void disabled() throws Exception {
super.disabled();
}
}
然后再在 enabled 函数和 disabled 函数中修改 timer 变量:
@Override
public void enabled() throws Exception {
Minecraft.getInstance().timer = new net.minecraft.client.Timer(50,0L); //set 50 (2.5)
}
@Override
public void disabled() throws Exception {
Minecraft.getInstance().timer = new net.minecraft.client.Timer(20,0L); //set 20
}
Timer 的构建函数的第二个参数默认填 0L 即可,这里的 50 为 2.5 倍数,20 为默认倍数。
Pegasus
简绍
该功能可以使在马上的玩家飞行,无视是否已穿戴马鞍和是否已被驯服。
灵感来源:BoatFly,AirJump。
实现
首先在 modules 目录中创建 Pegasus 类,并继承 Module,然后重写 uodate 函数:
package cn.ksmcbrigade.em.modules;
import cn.ksmcbrigade.em.Module;
import java.awt.event.KeyEvent;
public class Pegasus extends Module {
public Pegasus() {
super("Pegasus", KeyEvent.VK_I); //key i
}
@Override
public void update() throws Exception {
super.update();
}
}
然后再在 update 函数中判断玩家是否有坐骑和坐骑是否可以被转换为 AbstractHorse 类以及空格键是否被按下,若都符合则设置坐骑的马鞍存在状态和是否正在跳跃为 true,疾跑计数器 为 7 ,然后使坐骑跳跃:
@Override
public void update() throws Exception {
Minecraft MC = Minecraft.getInstance();
Player player = MC.player;
if(player==null){
return;
}
if(player.getVehicle()==null){
return;
}
if(!MC.options.keyJump.isDown()){
return;
}
Entity vehicle = player.getVehicle();
if(vehicle instanceof AbstractHorse horse){
horse.setFlag(4,true);
horse.sprintCounter = 7;
horse.setIsJumping(true);
horse.jumpFromGround();
}
}
其中的 setFlag 函数和 jumpFromGround 函数需要用到访问转换器,他们分别位于 AbstractHorse 和 LivingEntity 类中。
public net.minecraft.world.entity.LivingEntity m_6135_()V
public net.minecraft.world.entity.animal.horse.AbstractHorse m_30597_(IZ)V
注册功能
然后在 ModuleManager.modulesClass 类中注册即可:
public static Module Timer = new Timer(); //key y
public static Module Pegasus = new Pegasus(); //key i
最后运行测试即可。
完整代码
accesstransformer.cfg
public-f net.minecraft.client.Minecraft f_90991_
public net.minecraft.world.entity.LivingEntity m_6135_()V
public net.minecraft.world.entity.animal.horse.AbstractHorse m_30597_(IZ)V
Timer.java
package cn.ksmcbrigade.em.modules;
import cn.ksmcbrigade.em.Module;
import net.minecraft.client.Minecraft;
import java.awt.event.KeyEvent;
public class Timer extends Module {
public Timer() {
super("Timer", KeyEvent.VK_Y);
}
@Override
public void enabled() throws Exception {
Minecraft.getInstance().timer = new net.minecraft.client.Timer(50,0L);
}
@Override
public void disabled() throws Exception {
Minecraft.getInstance().timer = new net.minecraft.client.Timer(20,0L);
}
}
Pegasus.java
package cn.ksmcbrigade.em.modules;
import cn.ksmcbrigade.em.Module;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.animal.horse.AbstractHorse;
import net.minecraft.world.entity.player.Player;
import java.awt.event.KeyEvent;
public class Pegasus extends Module {
public Pegasus() {
super("Pegasus", KeyEvent.VK_I);
}
@Override
public void update() throws Exception {
Minecraft MC = Minecraft.getInstance();
Player player = MC.player;
if(player==null){
return;
}
if(player.getVehicle()==null){
return;
}
if(!MC.options.keyJump.isDown()){
return;
}
Entity vehicle = player.getVehicle();
if(vehicle instanceof AbstractHorse horse){
horse.setFlag(4,true);
horse.sprintCounter = 7;
horse.setIsJumping(true);
horse.jumpFromGround();
}
}
}
ModuleManager.modulesClass
static class modulesClass {
public static Module NoFall = new NoFall("NoFall", KeyEvent.VK_N);
public static Module XYZ = new XYZ("XYZ", KeyEvent.VK_B);
public static Module Timer = new Timer(); //key y
public static Module Pegasus = new Pegasus(); //key i
}