MCLib 核心与任务队列
[!IMPORTANT] MCLib 不是一个 Forge mod,而是一个被 shade 进其他 mod 的 Java 库。源码里没有任何可发布的
@Mod类(唯一三处@Mod注解在test/包中,project.gradle默认把它们从 jar 里排除)。宿主 mod 必须在构造期调用MCLib.init()来启动它。
基本信息
| 属性 | 值 |
|---|---|
| 类型 | 库入口 / 生命周期引导 |
| 触发条件 | 宿主 mod 的 FMLConstructionEvent(@EventHandler)中调用 MCLib.init() |
Gradle modid |
makamys.mclib(仅用于 archivesBaseName 和 srgExtra 重定位,不是 Forge 注册的 modid) |
| Minecraft | 1.7.10 / Forge 10.13.4.1614-1.7.10 |
| 发布版本 | 0.3.7.7(publish/version.txt) |
MCLib 主类
包路径 makamys.mclib.core。
| 成员 | 签名 / 值 | 说明 |
|---|---|---|
| 版本号 | public static final String VERSION = "@VERSION@" |
构建期由 publish/get_version.py 替换;运行期若仍为 @...@ 会被当作 Integer.MAX_VALUE 参与版本仲裁(见 共享状态与版本仲裁) |
| 资源版本 | public static final String RESOURCES_VERSION = "v0_3_7" |
决定从 classpath 读取哪个版本的证书/HTML 模板目录 |
| 单例 | public static MCLib instance |
由 init() 赋值 |
| 面向宿主 mod 的日志 | public static Logger LOGGER,初始化为 "mclib(<宿主modid>)" |
构造时改名为 mclib(...),方便在多 mod 环境下分辨日志来源 |
| 库自身日志 | public static final Logger GLOGGER = LogManager.getLogger("mclib") |
固定名 |
| FML 母总线 | public static EventBus FML_MASTER |
从 LoadController.masterChannel 反射取出(见 反射访问点) |
| 方法 | 行为 |
|---|---|
MCLib.init() |
首次调用时转发到 init(true) |
MCLib.init(boolean subscribe) |
无条件新建 MCLib 实例并覆盖 instance |
MCLib(boolean subscribe) |
注册到 SharedLibHelper;subscribe = true 时反射拿到 LoadController.masterChannel 并把自己注册进去,以便接收 FML 生命周期事件 |
onPreInit(FMLPreInitializationEvent) |
@Subscribe(Guava EventBus)。若本副本是全场最新版本则调用 InternalModules.sloppyDepLoader.preInit(),随后 TaskQueue.consume(LoaderState.PREINITIALIZATION, instance) |
subscribe = false 的用途:库不需要自动接收 FML 事件时(例如仅使用静态工具类),可以不窃取 masterChannel。此时 onPreInit 必须由宿主 mod 手动调用,否则依赖 TaskQueue 的 AssetDirector 预初始化任务不会执行。
反射失败时 LOGGER.error 提示:“状态变更事件处理器将必须由你的 mod 手动调用”。
TaskQueue
包路径 makamys.mclib.core。让宿主 mod 把工作推迟到某个 LoaderState 执行,且多个 mod 提交同名任务时由版本更高的一方胜出。
存储结构为 LoaderState -> (taskName -> (version, owner, task)),底层 map 通过 共享状态 机制放在 Launch.blackboard 的 "TaskQueue" / "queuedTasks" 键下。
| 方法 | 说明 |
|---|---|
enqueueTask(LoaderState state, String taskName, Runnable task, ComparableVersion version) |
若已存在同名任务,只有当新版本 compareTo 更大时才覆盖;owner 记为 MCLib.instance |
enqueueTask(LoaderState state, String taskName, Runnable runnable) |
便捷重载,版本取 new ComparableVersion(MCLib.VERSION) |
consume(LoaderState state, Object owner)(包私有) |
只运行 owner 为当前 MCLib.instance 的任务,并从 map 中移除。owner 判等用引用相等 |
AssetDirectorAPI 的静态初始化块会往 LoaderState.PREINITIALIZATION 排一个名为 "AssetDirectorPreinit" 的任务。
模块持有者
| 类 | 可见性 | 成员 |
|---|---|---|
MCLibModules |
public |
public static UpdateCheckAPI updateCheckAPI — 唯一面向外部 mod 的共享模块入口 |
InternalModules |
包私有 | public static SloppyDepLoader sloppyDepLoader — 库内部用 |
两者都在 static { SharedLibHelper.shareifyClass(...); } 中把静态字段替换成 cglib 代理,因此旧版本副本的调用会被重定向到最新副本。
初始化契约
宿主 mod 侧的两步(对应仓库内 updatecheck/test/UCLTest.java 的写法):
- 构造事件里
MCLib.init(); - 预初始化事件里通过
MCLibModules.updateCheckAPI提交任务。
静态工具类(SloppyDepLoader 等)无需初始化即可直接调静态方法。
相关条目
- 共享状态与版本仲裁 -
SharedReference/SharedLibHelper/SharedModuleMethodRedirector的实现 - 反射访问点 -
masterChannel的取法 - Forge 事件钩子 - 本类订阅的 FML 事件与所用总线