You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过AspectJ拦截所有Minecraft Forge Mod的IRecipe assemble()方法?

问题解答

可以用AspectJ拦截所有已安装mod中IRecipe.assemble()方法的调用,且不需要修改FML。以下是具体实现方案,结合Forge的ModLauncher类加载机制完成:

核心原理

Forge的ModLauncher本身支持字节码转换扩展,无需修改FML源码,只需要通过自定义Transformer集成AspectJ的加载时织入(LTW)能力,就能在所有mod类加载时自动织入切面逻辑。

具体实现步骤

1. Gradle依赖配置

在你的mod项目build.gradle中添加AspectJ的运行时和织入器依赖:

dependencies {
    // AspectJ运行时库
    implementation 'org.aspectj:aspectjrt:1.9.9.1'
    // AspectJ加载时织入器
    runtimeOnly 'org.aspectj:aspectjweaver:1.9.9.1'
}

注:1.16版本MC基于Java 8,需选择支持Java 8的AspectJ版本(如1.9.x系列)

2. 编写AspectJ切面

创建切面类,拦截所有IRecipe.assemble()方法的调用,实现你的配方验证逻辑:

public aspect RecipeAssembleInterceptor {
    // 定义切点:匹配所有IRecipe接口assemble方法的调用
    pointcut assembleCall(ContainerLevelAccess container, IInventory inventory):
        call(* net.minecraft.world.item.crafting.IRecipe.assemble(..)) && args(container, inventory);

    // 前置通知:在方法调用前执行验证
    before(ContainerLevelAccess container, IInventory inventory): assembleCall(container, inventory) {
        IRecipe<?> targetRecipe = (IRecipe<?>) thisJoinPoint.getTarget();
        // 替换为你的配方解锁验证逻辑
        if (!isRecipeUnlocked(targetRecipe)) {
            throw new IllegalStateException("该配方未解锁,无法合成");
        }
    }

    // 示例:自定义验证方法
    private boolean isRecipeUnlocked(IRecipe<?> recipe) {
        // 这里实现你的配方阶段检查逻辑
        return true;
    }
}

使用call()切点而非execution(),确保拦截所有mod中对该方法的调用,不管调用方来自哪个模块

3. 配置AspectJ LTW规则

在项目resources/META-INF目录下创建aop.xml,声明切面和织入范围:

<aspectj>
    <weaver options="-verbose -showWeaveInfo">
        <!-- 对所有类进行织入,包括其他mod的类 -->
        <include within="*"/>
    </weaver>
    <aspects>
        <!-- 替换为你的切面类全限定名 -->
        <aspect name="com.yourmod.aspect.RecipeAssembleInterceptor"/>
    </aspects>
</aspectj>

4. 集成AspectJ到Forge的类加载流程

创建自定义Transformer,让ModLauncher在加载所有类时调用AspectJ织入器:

import net.minecraftforge.fml.loading.moddiscovery.IModTransformer;
import org.aspectj.weaver.Weaver;

public class AspectJWeaverTransformer implements IModTransformer {
    private final Weaver weaver;

    public AspectJWeaverTransformer() {
        // 初始化织入器,加载aop.xml配置
        this.weaver = new Weaver();
        weaver.setClassLoader(this.getClass().getClassLoader());
        weaver.process();
    }

    @Override
    public byte[] transform(String className, byte[] classBytes, ClassLoader classLoader) {
        // 让AspectJ处理当前类的字节码
        return weaver.weave(className.replace('.', '/'), classBytes, classLoader);
    }
}

然后在resources/META-INF/services目录下创建文件net.minecraftforge.fml.loading.moddiscovery.IModTransformer,写入你的Transformer全限定名:

com.yourmod.transformer.AspectJWeaverTransformer

这样ModLauncher会在加载所有mod类时自动触发AspectJ的织入逻辑。

关键注意事项

  • 类加载器隔离:确保AspectJ织入器使用的类加载器能访问到所有mod的类,避免因类加载器隔离导致织入失败。
  • 混淆兼容:若目标mod开启了代码混淆,只要其类仍实现IRecipe接口,切点依然能匹配到assemble()方法。
  • 调试:开启aop.xml中的-verbose -showWeaveInfo选项,可在控制台查看织入日志,排查未拦截的情况。

内容的提问来源于stack exchange,提问作者user14573544

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 11:35:01