coremod 补丁

OpenModsLib 通过 FML coremod 机制在类加载阶段改写原版 Minecraft 类,为 OpenBlocks 系列提供底层能力。这是本 mod 最核心也最不可见的部分:6 个 ASM 补丁全部作用于 net.minecraft.* 类,玩家在游戏内看不到任何提示,但关掉任何一个都会让特定功能静默失效或崩溃。

类生成机制见类注入与 include,配置属性见OpenModsLib 配置。

基本信息

属性 值
coremod 入口 openmods.core.OpenModsCorePlugin(@SortingIndex(16))
核心 mod 容器 openmods.core.OpenModsCore(继承 DummyModContainer,非 @Mod)
ASM 变换器 openmods.core.OpenModsClassTransformer
配置文件 <游戏目录>/config/OpenModsLibCore.json
补丁数 6(全部作用于 net.minecraft.*)
黑板标记 OpenModsCoreLoaded(OpenModsCorePlugin.java:20)
@MCVersion "1.7.10"(OpenModsCorePlugin.java:16)

功能

coremod 入口

OpenModsCorePlugin(src/main/java/openmods/core/OpenModsCorePlugin.java:15)实现 IFMLLoadingPlugin:

回调 返回 行
getASMTransformerClass() ["openmods.core.OpenModsClassTransformer"] :29-32
getModContainerClass() "openmods.core.OpenModsCore" :34-37
getSetupClass() null :39-42
getAccessTransformerClass() null :48-51
injectData(Map) 转发给 Bootstrap.injectData(data) :44-47

@SortingIndex(16)(:16)保证本 coremod 的排序值低于所有依赖它的 coremod(源码注释 // must be lower than all dependent ones)。

@TransformerExclusions(:17)声明 5 个前缀下的类不参与变换,避免自我递归:

openmods.asm.  openmods.include.  openmods.core.  openmods.injector.  openmods.Log

构造函数(:19-23)把版本号写入 LaunchWrapper 黑板,键 OpenModsCoreLoaded,供其它 coremod 检测 OpenModsLib 是否已加载。

核心 mod 容器

OpenModsCore(src/main/java/openmods/core/OpenModsCore.java:16)继承 DummyModContainer 而非使用 @Mod 注解 —— 这是 FML 提供给 coremod 的标准容器。构造时手工填充 ModMetadata(:21-29):

字段 值
modId / name "OpenModsCore"
version Mods.OPEN_MODS_LIB_VERSION(Gradle 令牌,编译期替换)
authorList Mikee、NeverCast、boq
url https://openmods.info/
parent "OpenMods"
description "This is where the magic happens"

modConstruction 事件(:37)中调用 OpenModsClassTransformer.instance().injectAsmData(evt.getASMHarvestedData()) 把 FML 扫描到的 @IncludeInterface / @IncludeOverride 标注类名注入变换器(OpenModsClassTransformer.java:230-235)。

同一事件还注册 2 个崩溃报告条目(:41,54):"OpenModsLib class transformers"(输出各补丁的 DISABLED/ENABLED/ACTIVATED/FINISHED/FAILED 状态,:70-72 的 listStates)与 InjectorSanityChecker(检测失效的注入类)。

6 个原版类补丁

OpenModsClassTransformer.addConfigValues(src/main/java/openmods/core/OpenModsClassTransformer.java:96)为每个补丁注册一个 ConfigProcessor 条目,配置值默认为 "true"。激活时把 ClassVisitor 工厂放入 vanillaPatches 映射。

# 配置项 目标类 注入的 Visitor 声明行 用途 已知使用方
1 activate_movement_callback net.minecraft.client.entity.EntityPlayerSP openmods.movement.MovementPatcher :98-124 给玩家移动控制加回调钩子 OpenBlocks 电梯
2 activate_map_gen_fix net.minecraft.world.gen.structure.MapGenStructure openmods.world.MapGenStructureVisitor :125-146 修复原版查找附近结构的 bug OpenBlocks 金眼
3 activate_player_render_hook net.minecraft.client.renderer.entity.RenderPlayer openmods.renderer.PlayerRendererHookVisitor :147-169 给玩家渲染代码加钩子 OpenBlocks 滑翔翼
4 activate_stencil_patches net.minecraft.client.shader.Framebuffer openmods.stencil.FramebufferInjector :170-192 为 FBO 重新启用模板缓冲 OpenBlocks 天空方块
5 activate_gl_capabilities_hook net.minecraft.client.renderer.OpenGlHelper openmods.stencil.CapabilitiesHookInjector :193-215 钩取额外 OpenGL 能力检测 OpenBlocks 天空方块
6 activate_player_damage_hook net.minecraft.entity.player.EntityPlayer openmods.entity.PlayerDamageEventInjector :216-238 捕获护甲与药水结算后的玩家伤害 Last Stand 附魔

每个条目的 activate_* 开关默认 "true",配置说明中明确写出了「已知使用方」(Known users)与「关闭后的后果」(When disabled)。其中:

  • 关闭 activate_map_gen_fix → 「features may not work (either silently fail or cause crash)」
  • 关闭 activate_player_damage_hook → 「Last Stand enchantment will not work」
  • 关闭 activate_stencil_patches / activate_gl_capabilities_hook → 「no stencil buffer available unless unlocked with Forge flag」

6 个补丁中有 4 个是纯客户端补丁(#1、#3、#4、#5 均在 net.minecraft.client.*),仅 #2(世界生成)和 #6(伤害事件)作用于服务端逻辑。

变换器状态机

每个补丁通过 StateTracker<TransformerState>(OpenModsClassTransformer.java:56)维护 5 态生命周期:

状态 含义
DISABLED 初始态(StateTracker.create(TransformerState.DISABLED),:56)
ENABLED 配置值读到 "true",vanillaPatches 已填入
ACTIVATED transform() 命中该类,Visitor 已创建
FINISHED 变换成功(IResultListener.onSuccess)
FAILED 变换失败(IResultListener.onFailure)

listStates()(:70)把所有补丁状态用逗号连接,供崩溃报告定位问题。ConfigOption.valueSet(:66-71)只接受大小写不敏感的 "true",其它值保持 DISABLED。

变换器的类过滤

transform(:245)的判定顺序:

  1. bytes == null → 交给 InjectedClassesManager.instance.tryGetBytecode(name),这是动态生成类的入口(见类注入)
  2. transformedName 以 net.minecraft. 开头 → 查 vanillaPatches,命中才变换,否则原样返回
  3. 其它类 → 走 applyIncludes 走 include 机制

IGNORED_PREFIXES(:44-52)列出 8 个永不 include 的前缀:cpw.mods.fml.、net.minecraftforge.、io.netty.、gnu.trove.、com.google.、com.mojang.、joptsimple.、tv.twitch.。

但一旦 injectAsmData 已执行(shouldTryIncluding,:239-241),白名单模式生效 —— 只处理 FML 扫描到的带 @IncludeInterface / @IncludeOverride 的类,上面的前缀黑名单不再起作用。

数值

数值名 值
coremod 入口类数 1(OpenModsCorePlugin)
IFMLLoadingPlugin 实现数 1
DummyModContainer 子类数 1(OpenModsCore,非 @Mod)
原版类补丁数 6
其中客户端专用补丁数 4(#1 #3 #4 #5)
@TransformerExclusions 前缀数 5
IGNORED_PREFIXES 前缀数 8
崩溃报告条目数 3(2 个在此类,1 个在客户端代理)
变换器状态数 5(DISABLED/ENABLED/ACTIVATED/FINISHED/FAILED)

交互

coremod 本身无玩家可见交互。玩家的唯一感知途径是崩溃报告中的 "OpenModsLib class transformers" 条目,可据此判断某个补丁是否成功应用。

配置文件 OpenModsLibCore.json 由 Bootstrap.injectData(src/main/java/openmods/core/Bootstrap.java:14)在 coremod 阶段创建:若 <游戏目录>/config/ 不存在则 mkdir(:18-19),随后用 ConfigProcessor 读取(:21-25)。读取失败会直接抛 RuntimeException 阻止游戏启动(:24),而非静默降级。

相关条目