Mixins
備註
此页适用于 SpongeCommon、 SpongeForge 和 SpongeVanilla。这三个仓库利用 Mixin 挂钩到底层进行实现 (原版 Minecraft 服务器和 Forge 服)。
Mixins是一种在运行时修改Java代码的方式,它向类中添加额外的行为。这可以将我们需要的功能加入到原版的Minecraft中去。Mixins对于Sponge的运行来说是必须的。
Mixin Wiki 上对一些关于Mixin使用的核心概念进行了基本的介绍。
上面的Wiki相当基础,如果你是一位有经验的Java开发者,你可以跳过第4节,其中讨论了mixins本身。
如果你是刚开始写 Mixin,我们强烈建议将 SpongeCommon 代码仓库中所有的范例 全部仔细阅读一遍。这些范例覆盖了大多数复杂的使用情景,同时也带有详尽的文档。同时你也应当查阅 Mixin 仓库本身的 Javadoc,大多数 Mixin 的功能的文档都可以在那里找到。
備註
不仅是 Sponge,还有很多项目也在使用 Mixin。所以 Mixin 有其自己的文档。
Mixin 与内部类
尽管可以使用 lambda 表达式,你不能在 Mixin 的(匿名)内部类中使用非静态的(匿名)内部类。
这意味着像后面的一些代码会搞坏mixin,同时也会把Sponge搞到万劫不复的境地。
return new Collection<ItemStack>() {
@Override
public Iterator<ItemStack> iterator() {
return new Iterator<ItemStack>() {
// THIS WILL NOT WORK!
@Override
public boolean hasNext() {
// Code skipped
}
@Override
public ItemStack next() {
// Code skipped
}
};
}
// Other methods skipped
};
这一规则适用于所有带有 @Mixin
注解的类。不经过 Mixin 处理的类完全可以使用这些语言特性。有两种规避此规则的方法。
一种方法是使用单独的工具类,因为工具类并不会被 Mixin 处理然后合并入目标类中。因此,下面的代码可以正常工作。
public class SampleCollection implements Collection<ItemStack> {
private final TargetClass target;
public SampleCollection(TargetClass target) {
this.target = target;
}
@Override
public Iterator<ItemStack> iterator() {
return new Iterator<ItemStack>() {
@Override
public boolean hasNext() {
// Code skipped
}
@Override
public ItemStack next() {
// Code skipped
}
};
}
// Other methods skipped
}
@Mixin(TargetClass.class)
public abstract class SomeMixin {
public Collection<ItemStack> someFunction() {
return new SampleCollection((TargetClass) (Object) this);
}
}
另一种方法是将所有内部类直接写为 Mixin 类的内部类或者某个方法的局部类,而非互相嵌套。例如:
@Mixin(TargetClass.class)
public abstract class SomeMixin {
private final class SampleIterator implements Iterator<ItemStack> {
@Override
public boolean hasNext() {
// Code skipped
}
@Override
public ItemStack next() {
// Code skipped
}
}
public Collection<ItemStack> someFunction() {
return new Collection<ItemStack>() {
@Override
public Iterator<ItemStack> iterator() {
return new SampleIterator();
}
// Other methods skipped
};
}
}