Skip to content

与 Minecraft Mixin 的差异

This content is not available in your language yet.

Copper 使用的 Mixin 是 SpongePowered Mixin 0.8.7 的修改版(仓库:MDTCopper/Mixin),版本号 0.1.x。它删去了与 Minecraft 相关的代码,调整了若干默认值,并扩展了 Java 版本支持。

原版 Mixin 为了适配 Minecraft 的各种加载环境(Forge、Fabric/ModLauncher、旧版启动器),内置了大量平台服务。这些在 Mindustry 场景下全部无用,因此被删除:

被删内容用途对 Copper 的影响
Mojang 服务(service.mojang.*)旧版 Minecraft 启动器(LaunchWrapper)集成无。Mindustry 不使用 LaunchWrapper
ModLauncher 服务(service.modlauncher.*)Fabric/Forge 的类加载服务集成无
Forge/FML 平台代理Forge 专用平台无
RuntimeDecompiler(Fernflower)导出时反编译无(导出仍可用,见下文)
混淆相关(tools.obfuscation.* 的 JSON/Mapping)官方混淆映射Mindustry 不混淆,无需映射
module-info 等Java 模块化无

结论: 面向 Minecraft 的配置项(refmap、混淆映射、MixinPlatformAgent 等)在 Copper 中不存在或无效,不要使用。

原版 Mixin 的所有注解 remap 默认为 true(因为 Minecraft 有混淆)。本项目把全部注解的 remap 默认值改为 false:

@Mixin(value = Vars.class, remap = false) // remap 可省略,默认就是 false
public abstract class MyPatch { ... }

涉及注解:@Mixin、@Overwrite、@Shadow、@Accessor、@Invoker、@At、@Inject、@ModifyArg、@ModifyArgs、@ModifyConstant、@ModifyVariable、@Redirect。

影响:

  • 你不需要(也不应该)写 remap = false,省略即可;
  • 不要把 remap 设为 true——没有映射表可查,会直接报错;
  • refmap 相关配置无需处理。

原版 Mixin 0.8.7 官方支持到 Java 21。本项目扩展支持 Java 22–27(Mixin 环境兼容级别 JAVA_17 ~ JAVA_27)。上限不是”越新越好”,而是由内置 ASM 能解析的类文件版本钉死的:

  • 最低兼容级别 JAVA_17:加载器的 Mixin 服务把下限报成它。低于它,JVM 连加载器与 Mixin 的类文件都加载不了;
  • 上限来自 ASM:Mixin 解析标准库类时读的是运行中 JRE 的 modules——解析 java.lang.Object 拿到的就是这份 JRE 里的那一份,类文件版本随本机 JDK 走。加载器当前带 ASM 9.10.1,认到类文件主版本 71,即 Java 27;在 JDK 28 上读到主版本 72 的标准库类,ASM 直接抛 Unsupported class file major version 72。所以换更新的 JDK 不会把上限抬高,只会踩到 ASM 的上限,不存在无限向上兼容;
  • 兼容级别说的是类文件版本:你的 Mixin 类如果按更高的版本编译,可以在配置里声明 compatibilityLevel(该字段原样透传,见配置 JSON 详解 · 原版字段透传),但它同样不能越过 JAVA_27 与 ASM 的能力。

这条上限同时也是加载器自己声明的 Java 支持范围,即 17 到 27。范围写在 gradle.properties 的 javaVersionRange 里,与同一份文件里的 asmVersion 配套维护:构建时连同版本号一起写进 Jar 内的 version.properties,供启动器与工具判断某个加载器版本该配哪版 Java(见加载器命令行 · 准备,报错现象见启动报错 · Java 版本问题)。

Mixin 配置的 target 字段(@env(...) 目标选择器)在原版中无默认值;本项目默认设为 @env(DEFAULT)。绝大多数情况下你不需要书写 target 字段。

原版的 Mixin 调试导出目录是编译期常量。本项目改为运行时可变,加载器会为每个容器设置独立的子目录:

.mixin.out/<容器id>/

容器 id 示例:mindustry、example-examplemod。配合 --mixin-flag <modId,DEBUG_EXPORT> 使用(见入门教程 · 调试技巧)。

原版 Mixin 通过扫描 classpath 发现服务。本项目实现了一套自有的 Mixin 服务(copper.loader.mixin.MixinEngineService),通过 META-INF/services 注册:

  • 字节码来源:不是文件系统,而是加载器的容器系统(按容器解析目标类的字节码);
  • 配置来源:Mixin 配置在内存中提供(copper://<id>.json),不会去磁盘扫描 mixins.json;
  • 全局属性服务:MixinEngineGlobalPropertyService。

对模组作者的影响:

  • 不要在 Jar 里放原版风格的 mixins.json(不会生效),一切以 copper.mod.json + assets/copper/ 下的配置为准(见配置 JSON 详解);
  • Mixin 引擎按容器独立初始化,不同模组的注入互不干扰;
  • 每个容器一个引擎实例,但共享全局单例的变换器——注入顺序由配置登记顺序决定。

注解处理器被保留,且修复了与 remap 默认值不一致的判定逻辑(AP 侧同样默认 remap = false)。构建时引入:

annotationProcessor "com.github.MDTCopper:Mixin:$mixinVersion:processor"

它在编译期检查注解用法(目标类存在性、签名匹配等),能在开发期发现大部分低级错误,强烈建议配置。

项目Minecraft 原版Copper
配置文件名mixins.json(任意位置)assets/copper/<任意名>.json(由元数据引用)
配置格式纯 Mixin 配置{ "version": 1, "config": {...} }
mixins 字段类名数组版本过滤器 → 类名映射(可多分支合并)
target需显式设置默认 @env(DEFAULT)
混淆映射需要 refmap不需要
加载方式扫描 classpath容器 + 内存 copper://
Java agent需要 -javaagent由加载器自行启动(Launcher-Agent-Class),不用自己配置;仅用于调试模组
  1. 面向版本写注入:游戏版本变化大(正式版/BE 版本号体系不同),尽量用版本过滤拆分注入分支,而不是硬编码某个版本的行为;
  2. 少用 @Overwrite:游戏更新频繁,@Inject 更抗版本变化;
  3. 别写 remap:默认就是正确的;
  4. 调试靠日志、导出与类路径:--mixin-log、--mixin-flag ...DEBUG_EXPORT(见入门教程),以及调试模组(--mod-debug-jar + --mod-debug-classpath)。