> For the complete documentation index, see [llms.txt](https://xfl03.gitbook.io/coremodtutor/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://xfl03.gitbook.io/coremodtutor/5/5.5.md).

# 定位

来源： [Injection Point Reference](https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference)

`@At`注解的`value`属性只有以下的有限取值，这个取值也限定了`args`、`target`、`ordinal`、`opcode`属性的取值：

## [`HEAD`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/points/MethodHead.html)

表示注入到方法的开头，对应的注入方法在目标方法最开始被调用。

* `args`: 无
* `target`: 无
* `ordinal`: 无
* `opcode`: 无

## [`RETURN`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/points/BeforeReturn.html)

表示注入到`RETURN`操作符之前。

* `args`: 无
* `target`: 无
* `ordinal`: 指定注入到哪个`RETURN`操作符，`RETURN`计数从0开始。如果不指定，表示注入到所有`RETURN`操作符之前
* `opcode`: 无

*对于`@Inject`而且，这是注入构造方法时唯一一个允许注入的地方。如果注入到一个带返回值的方法中，则调用`CallbackInfoReturnable::getReturnType()`会得到目标方法即将返回的值，在其他地方注入时调用此方法则会返回`null`*

## [`TAIL`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/points/BeforeFinalReturn.html)

表示注入到最后一个`RETURN`操作符之前。

* `args`: 无
* `target`: 无
* `ordinal`: 无
* `opcode`: 无

*注意，最后一个`RETURN`操作符有时并不等同于Java代码中最后一个`return`关键词，你可能需要用某些查看字节码的IDE插件确认*

## [`INVOKE`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/points/BeforeInvoke.html)

表示注入到一个方法被调用之前。

* `args`: 允许下列参数：
  * `log`: 一个布尔值，填`log=true`则表示会输出相关的日志信息
* `target`: 指定一个带完整限定名的方法签名，如果不指定，则表示匹配所有的方法调用，以下写法是合法的：
  * `org.lwjgl.opengl.Display.setTitle(Ljava/lang/String;)V`
  * `org/lwjgl/opengl/Display.setTitle(Ljava/lang/String;)V`
  * `Lorg/lwjgl/opengl/Display;setTitle(Ljava/lang/String;)V` &#x20;
* `ordinal`: 指定注入到哪个被`target`匹配的目标前，计数从0开始。如果不指定，表示注入到所有匹配的目标之前
* `opcode`: 无

## [`INVOKE_STRING`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/points/BeforeStringInvoke.html)

表示注入到一个**仅有一个`String`类型的参数且无返回类型**的方法被调用之前，且传入的必须是常量字符串。

* `args`: 允许下列参数：
  * `ldc`: 这个参数必须存在，表示匹配指定传入`String`参数的值，例如`ldc=Minecraft 1.12.2`
  * `log`: 同`INVOKE`
* `target`: 同`INVOKE`
* `ordinal`: 指定注入到哪个同时被`target`和`ldc`参数匹配的目标前，计数从0开始
* `opcode`: 无

## [`INVOKE_ASSIGN`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/points/AfterInvoke.html)

表示注入到一个**有返回类型**的方法被调用之**后**，如果这个方法被调用之后的值会立即传入一个局部变量，则会在传入局部变量之后注入（也就是`*STORE`操作符之后）。

* `args`: 同`INVOKE`
* `target`: 同`INVOKE`
* `ordinal`: 指定注入到哪个被`target`匹配的目标后，计数从0开始。如果不指定，表示注入到所有匹配的目标之后
* `opcode`: 无

## [`FIELD`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/points/BeforeFieldAccess.html)

表示注入到一个字段被引用之前。

* `args`: 允许下列参数：
  * `array`: 仅当`target`指向一个数组元素相关操作的目标时可用，有以下取值：
    * `array=get`: 匹配数组元素被引用的时候
    * `array=set`: 匹配数组元素被赋值的时候
    * `array=length`: 匹配数组的`length`属性被引用的时候
  * `log`: 同`INVOKE`
* `target`: 指定一个带完整限定名的字段签名，如果不指定，则匹配所有的符合`opcode`的字段引用，以下写法是合法的：
  * `net.minecraft.client.Minecraft.instance:Lnet/minecraft/client/Minecraft;`
  * `net/minecraft/client/Minecraft.instance:Lnet/minecraft/client/Minecraft;`
  * `Lnet/minecraft/client/Minecraft;instance:Lnet/minecraft/client/Minecraft;`
* `ordinal`: 指定注入到哪个同时被`args.array`、`target`和`opcode`匹配的目标前，计数从0开始。如果不指定，表示注入到所有匹配的目标之前
* `opcode`: 指定匹配的操作符，如果不指定，则匹配所有的符合`args.array`和`target`的字段引用，有以下取值：
  * `178`: 表示匹配`GETSTATIC`操作符（读取静态字段）
  * `179`: 表示匹配`PUTSTATIC`操作符（写入静态字段）
  * `180`: 表示匹配`GETFIELD`操作符（读取实例字段）
  * `181`: 表示匹配`PUTFIELD`操作符（写入实例字段）

*如果`target`和`opcode`都不指定，则表示匹配所有的字段引用*

## [`NEW`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/points/BeforeNew.html)

表示注入到`NEW`操作符之前。

* `args`: 允许下列参数：
  * `class`: 仅当`target`属性未被指定的时候使用，表示匹配指定实例化的类型（例如`class=net/minecraft/client/tutorial/Tutorial`）
* `target`: 仅当`args.class`未被指定时可用，以下写法是合法的：
  * `net/minecraft/client/tutorial/Tutorial`
  * `(Lnet/minecraft/client/Minecraft;)Lnet/minecraft/client/tutorial/Tutorial;` （表示匹配使用指定构造函数实例化的目标）
* `ordinal`: 指定注入到哪个匹配`args.class`或者`target`的目标之前，计数从0开始。如果不指定，表示注入到所有匹配的目标之前
* `opcode`: 无

*以下两种写法还是有差距的：*\
*写法A: `@At(value = "NEW", target = "(Lnet/minecraft/client/Minecraft;)Lnet/minecraft/client/tutorial/Tutorial;")`*\
*写法B: `@At(value = "INVOKE", target = "Lnet/minecraft/client/tutorial/Tutorial;<init>(Lnet/minecraft/client/Minecraft;)V")`*\
*写法A匹配的是`NEW`操作符，而写法B匹配的是`INVOKESPECIAL`操作符，这意味着写法A匹配的地方构造函数的参数还没有被调用，而写法B匹配的地方参数已经调用完毕，即将执行构造函数本身。*

## [`CONSTANT`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/points/BeforeConstant.html)

表示注入到一个常量被引用之前（即常量引用操作符之前）。

* `args`: 允许以下参数：
  * `nullValue`: 匹配`null`引用（填`nullValue=true`）
  * `intValue`: 匹配`int`类型常量引用（例如`intValue=10`），对于像`if (x>0)`的代码，字节码中是没有引用0的操作的，请使用`expandZeroConditions`
  * `floatValue`: 匹配`float`类型常量引用
  * `longValue`: 匹配`long`类型常量引用
  * `doubleValue`: 匹配`double`类型常量引用
  * `stringValue`: 匹配`String`类型常量引用
  * `class`: 匹配`类名.class`这样的引用，填这个类的完整限定名（例如`class=net.minecraft.client.Minecraft`）
  * `log`: 同`INVOKE`
  * `expandZeroConditions`: 参考下面一节 `常量引用特殊情况：与0比较`
* `target`: 无
* `ordinal`: 指定注入到哪个匹配`args`的目标之前，计数从0开始。如果不指定，表示注入到所有匹配的目标之前
* `opcode`: 无

*如果要匹配多个`expandZeroConditions`，请用逗号隔开，如`expandZeroConditions=LESS_THAN_ZERO,GREATER_THAN_ZERO`*

## [`JUMP`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/points/JumpInsnPoint.html)

表示注入到跳转操作符之前。

* `args`: 无
* `target`: 无
* `ordinal`: 指定注入到哪个匹配`opcode`的目标之前，计数从0开始。如果不指定，表示注入到所有匹配的目标之前
* `opcode`: 指定一个匹配操作符，如果不指定，则匹配所有跳转操作符。允许以下取值：
  * `153`: 表示匹配`IFEQ`操作符
  * `154`: 表示匹配`IFNE`操作符
  * `155`: 表示匹配`IFLT`操作符
  * `156`: 表示匹配`IFGE`操作符
  * `157`: 表示匹配`IFGT`操作符
  * `158`: 表示匹配`IFLE`操作符
  * `159`: 表示匹配`IF_ICMPEQ`操作符
  * `160`: 表示匹配`IF_ICMPNE`操作符
  * `161`: 表示匹配`IF_ICMPLT`操作符
  * `162`: 表示匹配`IF_ICMPGE`操作符
  * `163`: 表示匹配`IF_ICMPGT`操作符
  * `164`: 表示匹配`IF_ICMPLE`操作符
  * `165`: 表示匹配`IF_ACMPEQ`操作符
  * `166`: 表示匹配`IF_ACMPNE`操作符
  * `167`: 表示匹配`GOTO`操作符
  * `168`: 表示匹配`JSR`操作符
  * `198`: 表示匹配`IFNULL`操作符
  * `199`: 表示匹配`IFNONNULL`操作符

## [`LOAD`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/modify/BeforeLoadLocal.html)

表示注入到`*LOAD`操作符之前（读取一个局部变量之前），与`@ModifyVariable`注解配套使用。

* `args`: 无
* `target`: 无
* `ordinal`: 指定注入到哪个`*LOAD`操作符之前，计数从0开始，从`@ModifyVariable`注解中的`ordinal`开始数起
* `opcode`: 无

## [`STORE`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/modify/AfterStoreLocal.html)

表示注入到`*STORE`操作符之**后**（写入一个局部变量之后），与`@ModifyVariable`注解配套使用。

* `args`: 无
* `target`: 无
* `ordinal`: 指定注入到哪个`*STORE`操作符之前，计数从0开始，从`@ModifyVariable`注解中的`ordinal`开始数起
* `opcode`: 无

## 常量引用特殊情况：与0比较

在Java中，对于像 `if (x >= 0)` 这样的代码，是不会出现`ICONST_0`来引用0的，而是像类似于 `if (x.isGreaterThanOrEqualToZero())` 这样的引用方式。例如下面这一段代码：

```java
public int foo(int num) {
    if (num > 0)
        return 11;
    return 22;
}
```

它对应的一部分字节码是：

```
   L0
    LINENUMBER 6 L0
    ILOAD 1  // num 入栈
    IFLE L1  // 这里直接跳转，而没有引用0
   L2
    LINENUMBER 7 L2
    BIPUSH 11
    IRETURN
   L1
    LINENUMBER 8 L1
   FRAME SAME
    BIPUSH 22
    IRETURN
   L3
```

因为`IFEQ`、`IFNE`之类的操作符本身就是与0比较并跳转，为了解决这个问题，Mixin引入了[`Constant.Condition`](http://jenkins.liteloader.com/job/Mixin/javadoc/org/spongepowered/asm/mixin/injection/Constant.Condition.html)枚举：

* `LESS_THAN_ZERO`: 表示`<`或者`>=`操作，用于匹配`if(x<0)`
* `LESS_THAN_OR_EQUAL_TO_ZERO`: 表示`<=`或者`>`操作，用于匹配`if(x<=0)`
* `GREATER_THAN_OR_EQUAL_TO_ZERO`: 等同于`LESS_THAN_ZERO`，用于匹配`if(x>=0)`
* `GREATER_THAN_ZERO`: 等同于`LESS_THAN_OR_EQUAL_TO_ZERO`，用于匹配`if(x>0)`
