# 定位

来源： [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`: 无

*以下两种写法还是有差距的：*\
\&#xNAN;*写法A: `@At(value = "NEW", target = "(Lnet/minecraft/client/Minecraft;)Lnet/minecraft/client/tutorial/Tutorial;")`*\
\&#xNAN;*写法B: `@At(value = "INVOKE", target = "Lnet/minecraft/client/tutorial/Tutorial;<init>(Lnet/minecraft/client/Minecraft;)V")`*\
\&#xNAN;*写法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)`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xfl03.gitbook.io/coremodtutor/5/5.5.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
