共享状态与版本仲裁

MCLib 的核心设计:同一个库可能被 shade 进十几个 mod。当多个副本同时存在时,全场只有一个真正执行逻辑,其余副本的调用被重定向到它。状态本身存在 LaunchWrapper 的全局 blackboard 上,因此跨 jar 可见。

基本信息

属性 值
类型 运行时机制 / cglib 代理
触发条件 MCLib 构造时自动 register,共享模块类加载时 shareifyClass
全局键前缀 mclib.sharedstate.

SharedReference

包路径 makamys.mclib.core.sharedstate。泛型帮助类,把对象存进 Launch.blackboard。

方法 说明
get(String namespace, String name, Class<?> clazz) 用 clazz.newInstance() 构造初值
get(String namespace, String name, Supplier<T> constructor) 用 supplier 构造初值
get(String namespace, String name, Class<?> clazz, Supplier<T> constructor)(私有) 实际实现

键名拼装为 "mclib.sharedstate." + namespace + "." + name,查不到就先 put 再返回。

本 mod 实际使用的键:

namespace name 类型 使用者
"TaskQueue" "queuedTasks" Map TaskQueue.queuedTasks
"mclib" "existingLibPackages" ArrayList SharedLibHelper.existingLibPackages
"mclib" "newestLibPackage" MutableObject<String> SharedLibHelper.newestLibPackage
SloppyDepLoader.NS("SloppyDepLoader") "modDeps" HashMap SloppyDepLoaderAPI.modDeps
AssetDirector.NS("AssetDirector") "jsons" HashMap AssetDirectorAPI.jsons

MutableObject 来自 commons-lang3 的可变包装,充当跨副本的 lazy 单例槽位。

SharedLibHelper

包路径 makamys.mclib.core.sharedstate。

方法 说明
register(MCLib mcLib) 取 MCLib 类的 canonical name 去掉最后 2 段作为本副本包名,加入 existingLibPackages
getNewestLibPackage() 遍历所有已注册包名,逐一 Class.forName 读其 VERSION 字段,用 ComparableVersion 取最大值。若版本串以 @ 开头则按 Integer.MAX_VALUE 处理(开发版构建)。必须在 pre-init 之后调用,否则抛 IllegalStateException
isNewestLib(MCLib) 本副本是否就是最新版本
shareifyClass(Class<?> clazz) 转发到最新副本的 shareifyClassImpl
shareifyClassImpl(Class<?> clazz) 遍历 clazz.getFields(),对每个 public static 字段用 cglib Enhancer 生成同类型代理并写回该字段
toRelativeClassName(String className) 剥掉所属 mclib 包前缀,转成相对类名
findNewestLibClass(Class<?> clazz) 拼出最新副本中的对应类并加载

选出的最新包名会 LOGGER.info("Latest version of MCLib present: ...") 打印一次。

注意:shareifyClassImpl 要求字段类型有无参构造,代理才能在最新副本中实例化真实对象。

SharedModuleMethodRedirector

包路径 makamys.mclib.core.sharedstate,实现 cglib 的 MethodInterceptor。

  • 构造时记录字段,并判断 field.getDeclaringClass().getName().startsWith(SharedLibHelper.getNewestLibPackage()) 得到 isNewest。
  • isNewest = true:懒加载真实对象(field.getType().getConstructor().newInstance()),把调用 proxy.invoke 给它。
  • isNewest = false:到最新副本的同名字段上取对象,再按方法名和参数类型反射调用同构方法。

"等价"的定义写在类注释里:字段名相同,且外层类相对 mclib 根包的 canonical name 相同。

@SharedField

包路径 makamys.mclib.core.sharedstate,@Retention(RUNTIME) 的空标记注解。当前 shareifyClassImpl 里对它的检查是被注释掉的——源码里保留着 //if(f.isAnnotationPresent(SharedField.class)) { 与对应的 }// 配对,注解目前不参与任何逻辑,加了也不会被特殊对待。

相关条目