Skip to content

@Shadow

@Shadow 注解用于在 Mixin 类中声明一个对目标类中成员(字段或方法)的引用。这允许你从 Mixin 的方法中访问目标类的私有(private)或保护(protected)成员。

用法

访问字段

要访问目标类中的一个字段,你可以在 Mixin 中声明一个带有 @Shadow 注解的同名同类型的字段。

示例:

目标类:

java
public class Player {
    private boolean onGround;
}

Mixin:

java
@Mixin(Player.class)
public abstract class PlayerMixin {
    @Shadow private boolean onGround;

    @Inject(method = "jump", at = @At("HEAD"))
    private void onJump(CallbackInfo ci) {
        if (this.onGround) {
            // ...
        }
    }
}

现在你可以在 onJump 方法中访问 onGround 字段了。

访问方法

同样地,你也可以用 @Shadow 来访问目标类中的方法。

示例:

目标类:

java
public class Block {
    protected void dropItems() {
        // ...
    }
}

Mixin:

java
@Mixin(Block.class)
public abstract class BlockMixin {
    @Shadow protected abstract void dropItems();

    @Inject(method = "destroy", at = @At("TAIL"))
    private void onDestroy(CallbackInfo ci) {
        this.dropItems();
    }
}

注意,@Shadow 方法必须是 abstract 的。

prefix 属性

有时,你的 Mixin 类可能需要一个与目标类中字段或方法同名的成员。为了避免命名冲突,你可以使用 prefix 属性。Mixin 会自动为你添加上前缀。

示例:

java
@Mixin(Example.class)
public class ExampleMixin {
    @Shadow(prefix = "shadow$")
    private int value; // This will shadow the 'value' field in Example.class

    private int value; // This is a new field specific to the mixin

    public void someMethod() {
        this.value = 1; // Accesses the mixin's own 'value' field
        this.shadow$value = 2; // Accesses the shadowed 'value' field from the target class
    }
}

final 字段

如果目标字段是 final 的,你需要在 @Shadow 注解的字段上也加上 final 修饰符。

java
@Shadow final private int score;

如果你想修改一个 final 字段,你需要使用 @Mutable 注解和 @Shadow 一起。

java
@Mixin(Example.class)
public abstract class ExampleMixin {
    @Mutable
    @Shadow
    private final int score;

    // constructor or other methods to modify score
}

现在你就可以在你的 Mixin 方法中修改 score 的值了。

匿名内部类

@Shadow 也可以用于匿名内部类,但这通常比较复杂,因为匿名类没有名字。你需要使用特殊的语法来定位它们。