Skip to content

注入 DSL 与 Mixin ​

当需要修改 Minecraft 内部未暴露的逻辑时,用 OML 的注入 DSL 替代 Mixin。规则是纯静态声明,启动期 逐条自检(处理器存在性 / 签名 / 命中数),写错的规则在启动时失败而不是在游戏里静默失效。

规则集骨架 ​

kotlin
@RuleSource("my_mod")
object MyRules : RuleSetProvider {
    override fun rules(): RuleSet = injection {
        classTarget("net/minecraft/client/Minecraft") {
            method("runTick") {
                atHead { call("com/example/MyRules", "onGameTick", "()V") }
                require(1)
            }
        }
    }
}
  • classTarget 的参数是目标类的内部名(net/minecraft/...,斜杠分隔);
  • 处理器(onGameTick)是 mod 自己的类里的静态方法,注入后由游戏直接调用;
  • require(1) 声明命中数下限:不满足时启动失败并打印原因。 必须命中的规则一定要声明, 否则目标漂移时规则会静默失效。

锚点 ​

锚点语义对应 Mixin
atHead方法头HEAD
atConstructorHead构造器 super() 之后(此刻 this 才可用)–
atReturn(ordinal)每条返回指令前;atReturn() 全部RETURN
atTail最后一条返回前TAIL
beforeCall / afterCall方法调用指令前 / 后INVOKE / INVOKE_ASSIGN
beforeField / afterField字段读写指令前 / 后–
beforeNewnew 指令前–
beforeConstant / afterConstant常量加载前 / 后CONSTANT
afterStore / beforeLoad局部变量写入后 / 读取前Store / Load
within(from, to)把搜索窗口限定在两个锚点之间(可嵌套,取交集)@Slice

锚点支持按 owner / desc / ordinal 过滤(如 atReturn(0) 只命中第一条返回)。

载荷 ​

每个锚点块内声明注入什么:

载荷语义对应 Mixin
call(owner, method, desc)在锚点处调用一个静态方法(参数可注入局部变量等)@Inject
redirectCall(...)重定向一处方法调用@Redirect
modifyArg(...) / modifyArgs(...)改写调用参数@ModifyArg / @ModifyArgs
modifyConstant(...)改写常量@ModifyConstant
modifyExpressionValue(...)改写表达式求值结果@ModifyExpressionValue
modifyVariable(...)改写局部变量@ModifyVariable

命中数策略 ​

声明语义
require(n)至少命中 n 次,否则启动失败(下限)
allow(n)至多命中 n 次,超出即失败(防规则过宽)
expect(n)预期命中 n 次,偏差只告警
optional()允许零命中,压制"未命中"警告

访问改写与类合并 ​

kotlin
classTarget("net/minecraft/client/Minecraft") {
    field("proxy", desc = "Ljava/net/Proxy;") {
        makePublic()
        removeFinal()
    }
    methodAccess("runTick") { makePublic() }

    // 类合并:把 mod 里的一个类"真合并"进目标类,处理器可以 this = 目标实例运行
    merge("com/example/MyHooks")
}

merge 的源类里用 @Shadow(声明"目标类已有此成员")、@Unique(新增成员)、@Overwrite(替换方法体)、 @Accessor / @Invoker(合成字段访问器 / 私有方法调用器)标记成员——语义与 Mixin 一致,但发生在 字节码层,由引擎合成。

Mixin 注解 ​

习惯 Mixin 的开发者可以直接写注解,@Mixin / @Inject / @Redirect / @ModifyArg / @ModifyArgs / @ModifyConstant / @ModifyVariable / @ModifyReturnValue / @ModifyExpressionValue 都支持, 配合 @At 与 @Slice。注解在启动期被前端翻译成上面同一套注入规则,走同一条管线、享受同一套自检。 不支持的 Mixin 特性(Shift.BY、动态 targets、@Pseudo、refmap)会启动期报错,不会静默失效。

自检 ​

所有规则在控制权交给游戏主线程之前重新验证:处理器存在性、静态性、签名一致性、命中数。默认模式 fail 逐条打印问题并中止启动;-Doml.injection.verify=warn 只告警;off 关闭。要拿到改写耗时与 规模统计,加上 -Doml.diagnostics=1——这个开关是布尔的(任何非空且非 false 的值即启用,取值本身 没有含义)。

基于 AGPL-3.0 许可证发布