package com.example.mixins;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.Display;
import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(Minecraft.class)
public abstract class MixinMinecraft {
// @Redirect 要求 @At.value 只能是 INVOKE 或 FIELD
// 对方法参数和返回值的要求详见下面的例子:
// 如果定位的是调用静态方法或者构造方法(构造方法返回被构造的类型):
// private <重定向方法的返回类型> function(<重定向方法的所有参数>)
// 特别地,当重定向的是构造方法内的父类构造方法传入参数中的方法或字段引用(不是重定向父类构造方法本身),那么注入方法必须是静态的
// 重定向父类构造方法本身参见 @ModifyArgs 注解, @At 注解的用法参见下一章-定位
// 和 @Inject 类似,下面所有情况,如果有必要,都可以在参数后追加目标方法的参数
@Redirect(
method = "createDisplay",
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/Display;setTitle(Ljava/lang/String;)V", remap = false)
)
private void redirect_createDisplay(String title) { Display.setTitle("MyCustomTitle"); }
// 如果定位的是调用实例方法、接口方法或父类方法:
// private <重定向方法的返回类型> function(<重定向方法所在类实例类型>, <重定向方法的所有参数>)
@Redirect(
method = "createDisplay",
at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;error(Ljava/lang/String;Ljava/lang/Throwable;)V", remap = false)
)
private void redirect_createDisplay(Logger logger, String message, Throwable t) {}
// 如果定位的是读取静态字段:
// private <字段类型> function()
@Redirect(
method = "createDisplay",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/Minecraft;LOGGER:Lorg/apache/logging/log4j/Logger;", opcode = Opcodes.GETSTATIC)
)
private Logger redirect_createDisplay() { return null; }
// 如果定位的是写入静态字段:
// private void function(<字段类型>)
@Redirect(
method = "freeMemory",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/Minecraft;memoryReserve:[B", opcode = Opcodes.PUTSTATIC)
)
private void redirect_freeMemory(byte[] memoryReserve) {}
// 如果定位的是读取实例字段:
// private <字段类型> function(<字段所在类实例类型>)
@Redirect(
method = "createDisplay",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/Minecraft;fullscreen:Z", opcode = Opcodes.GETFIELD)
)
private boolean redirect_createDisplay(Minecraft mc) { return false; }
// 如果定位的是写入实例字段:
// private void function(<字段所在类实例类型>, <字段类型>)
@Redirect(
method = "run",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/Minecraft;running:Z", opcode = Opcodes.PUTFIELD)
)
private void redirect_run(Minecraft mc, boolean running) {}
// 特别地,如果定位的是数组元素相关的读写的话
// 读取数组元素:
// private <数组元素类型> function(<数组类型>, int index)
@Redirect(
method = "processKeyBinds",
at = @At(value = "FIELD", args = "array=get", target = "Lnet/minecraft/client/settings/GameSettings;keyBindsHotbar:[Lnet/minecraft/client/settings/KeyBinding;")
)
private KeyBinding redirect_processKeyBinds(KeyBinding[] keyBindsHotbar, int index) { return null; }
// 写入数组元素:(因为整个 Minecraft 类中没有写入数组元素的操作,所以没有可用的例子)
// private void function(<数组类型>, int index, <数组元素类型>)
//@Redirect(
// method = "someMethod",
// at = @At(value = "FIELD", args = "array=set", target = "LSomeClass1;someArray:[LSomeClass2;")
//)
//private void redirect_someMethod(SomeClass2[] someArray, int index, SomeClass2 value) {}
// 获取一维数组 length 属性:
// private int function(<数组类型>)
//@Redirect(
// method = "someMethod",
// at = @At(value = "FIELD", args = "array=length", target = "LSomeClass1;someArray:[LSomeClass2;")
//)
//private int redirect_someMethod(SomeClass2[] someArray) { return 0; }
// 获取多维数组中的某一维的 length 属性:
// private int function(<数组类型>, int baseDim1, int baseDim2, int baseDim3, ...) <-- 后面 int 参数的数量等于数组维度数量-1
//@Redirect(
// method = "someMethod",
// at = @At(value = "FIELD", args = "array=length", target = "LSomeClass1;someArray:[[[LSomeClass2;")
//)
//private int redirect_someMethod(SomeClass2[][][] someArray, int baseDim1, int baseDim2) { return 0; }
}