@At
@At 注解用于指定注入点(Injection Point),它决定了代码注入到目标方法中的确切位置。@At 通常作为 @Inject、@Redirect 等注解的参数使用。
value 属性
value 属性是一个字符串,用于指定注入点的类型。下面是一些常用的注入点类型:
HEAD
HEAD 将代码注入到目标方法的开头。这是最简单和最常用的注入点之一。
示例:
java
@Inject(method = "update", at = @At("HEAD"))
private void onUpdate(CallbackInfo ci) {
// This code runs at the start of the update() method
}TAIL
TAIL 将代码注入到目标方法的末尾,紧接在 RETURN 指令之前。如果方法有多个返回点,TAIL 会在所有返回点之前注入。
示例:
java
@Inject(method = "update", at = @At("TAIL"))
private void afterUpdate(CallbackInfo ci) {
// This code runs just before the update() method returns
}RETURN
RETURN 与 TAIL 类似,但它会在每个 RETURN 指令之前注入。如果方法有返回值,注入方法的最后一个参数应该是 CallbackInfoReturnable。
INVOKE
INVOKE 用于在方法调用指令之前注入代码。你需要使用 target 参数来指定目标方法。
target 参数:
target 参数是一个字符串,用于指定目标方法的签名。签名格式为 Lowner/class;methodName(Larg/type;)Lreturn/type;。
示例:
java
// Target code:
public class Game {
private Logger logger;
public void start() {
this.logger.info("Game starting!"); // We want to inject before this line
}
}
// Mixin:
@Mixin(Game.class)
public class GameMixin {
@Inject(
method = "start",
at = @At(
value = "INVOKE",
target = "Lorg/apache/logging/log4j/Logger;info(Ljava/lang/String;)V"
)
)
private void onLoggerInfo(CallbackInfo ci) {
System.out.println("The logger is about to be used!");
}
}FIELD
FIELD 用于在字段访问(获取或设置)指令之前注入代码。你需要使用 target 参数来指定目标字段。
示例:
java
@Inject(
method = "someMethod",
at = @At(
value = "FIELD",
target = "Lnet/minecraft/world/World;isRemote:Z",
opcode = Opcodes.GETFIELD
)
)NEW
NEW 用于在 new 一个新对象时注入代码。
CONSTANT
CONSTANT 用于在加载一个常量时注入。这对于修改方法中使用的硬编码值很有用。
shift 属性
shift 属性用于微调注入点的位置。它可以是 BY, BEFORE, 或 AFTER。
shift = At.Shift.BY:按指定的字节码指令数量移动注入点。需要by参数。shift = At.Shift.BEFORE:将注入点移动到目标之前。shift = At.Shift.AFTER:将注入点移动到目标之后。
示例:
java
@Inject(
method = "example",
at = @At(
value = "INVOKE",
target = "...",
shift = At.Shift.AFTER
)
)这会将代码注入到方法调用 之后,而不是之前。