ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Ely Prism Launcher如何判定依赖库:Library、Rule与GradleSpecifier详解

Ely Prism Launcher如何判定依赖库:Library、Rule与GradleSpecifier详解

【免费下载链接】Launcher

This fork of Prism Launcher adds integrated support for Ely.by accounts.

项目地址:https://gitcode.com/GitHub_Trending/ely/Launcher
点击查看免费下载

Ely Prism Launcher 是一款集成 Ely.by 账号登录的 Minecraft 启动器(Prism Launcher 分支)。启动游戏前,它需要自动解析版本清单,判定每个依赖库该不该下载、该不该加载。本文带你搞懂它背后的三个核心组件:Library、Rule与GradleSpecifier,看懂依赖库判定的完整链路。

为什么启动器要"判定"依赖库?

Minecraft 每个版本的version.json中都带有一段libraries列表,声明了运行游戏所需的一堆 jar 包和原生库。但这些库并非每台电脑都要加载:

  • 有的库只在 Windows 上用,Linux 下必须跳过;
  • 有的库是"原生库"(natives),不同系统、不同 CPU 架构对应不同的文件;
  • 有的库需要解压出.dll/.so文件,而不是放进 classpath。

所以 Ely Prism Launcher 对每个库都会做一道判定:"在我这台电脑上,这个库是否激活?该下载哪个文件?存到哪里?"这套判定逻辑的核心代码就在 launcher/minecraft/Library.cpp 中。

第一步:GradleSpecifier 解析"依赖坐标"

每个依赖库在清单里都长这样:

org.lwjgl.lwjgl:lwjgl-platform:2.9.4-nightly-20150209

这是一种借鉴 Gradle / Maven 生态的"坐标"格式。Ely Prism Launcher 用 GradleSpecifier 结构体把它拆成标准字段:

字段示例含义
groupIdorg.lwjgl.lwjgl组织/包名
artifactIdlwjgl-platform构件名
version2.9.4-nightly-20150209版本号
classifiernatives-linux(可选)平台/变体标识
extensionjar(可选,@后)文件扩展名

GradleSpecifier 还能把坐标还原成存储路径(见 toPath()):groupId 中的.换成/,就得到类似org/lwjgl/lwjgl/lwjgl-platform/2.9.4-.../lwjgl-platform-2.9.4-....jar的相对路径。这也是本地libraries/目录里"按组织名分层建文件夹"的原因。

单元测试文件 tests/GradleSpecifier_test.cpp 里用id.software:doom:1.666:demons@wad这种案例验证了非 jar 扩展名(如.wad)也能被正确解析,非常直观。

第二步:Library 对象统一管理库元数据

解析好坐标后,每个依赖库被封装成一个Library对象(定义见 launcher/minecraft/Library.h),它集中保存了判定所需的全部信息:

  • m_name:GradleSpecifier 依赖坐标;
  • m_rules:加载规则列表(Rule);
  • m_nativeClassifiers:各系统对应的原生库 classifier 映射;
  • m_mojangDownloads:Mojang 提供的下载地址与 sha1 校验值;
  • m_hint/m_storagePrefix:Prism 系的扩展字段,决定库是"本地库"还是"共享库"。

其中最有用的判定入口就是 isActive():传入当前运行环境,返回true表示"这个库在当前系统上应该被加载"。

第三步:Rule 规则决定"在什么系统上加载"

Rule(launcher/minecraft/Rule.h)是清单里rules数组的单个条目,形如:

{ "action": "disallow", "os": { "name": "osx" } }

一条 Rule 只有两种动作:allow(允许加载)和disallow(禁止加载),还可以附加os.name限定只针对某个操作系统(如windows、osx、linux)。

判定逻辑在 Rule::apply():

  1. 如果 Rule 指定了os,但当前系统不匹配 → 返回Defer("与本条规则无关,跳过");
  2. 否则直接返回它的action(allow 或 disallow)。

多条规则叠加时,isActive() 会按顺序遍历,让最后一条"不 Defer"的规则生效——即后面的规则可以覆盖前面的规则。如果整个库没有rules字段,则默认激活(result = true)。

拿 tests/testdata/Libraries/lib-native.json 这个真实样本看:allow全平台生效,随后又有一条disallow osx,最终效果就是"除了 macOS,其他系统都加载这个库"——这正是 Mojang 给 LWJGL 配置的经典写法。

第四步:RuntimeContext 描述"我现在的运行环境"

Rule 和原生库匹配都依赖RuntimeContext(launcher/RuntimeContext.h),它由启动器根据当前系统自动填充:

  • system:操作系统(windows / osx / linux);
  • javaRealArchitecture:Java 实际架构(amd64、aarch64 等),会被映射成x86_64、arm64等标准名;
  • getClassifier():拼出形如linux-x86_64的"精确分类器"。

匹配时采取先精确、后宽松的策略(见 classifierMatches()):先尝试匹配os-arch(如linux-x86_64);如果没匹配上、且当前是 x86/x86_64 这类"传统架构",再退回去只匹配操作系统名(如linux)。这样既能支持新平台,也兼容老版本清单里只写了系统名的情况。

原生库 natives:为每个平台选对文件

原生库(如 LWJGL)会带一个natives映射,声明各系统对应的 classifier:

"natives": { "linux": "natives-linux", "osx": "natives-osx", "windows": "natives-windows" }

getCompatibleNative() 会按"先系统-架构、后系统名"的顺序从这份映射里查出当前环境该用哪个 classifier(如natives-linux),进而确定要下载的文件是lwjgl-platform-...-natives-linux.jar。如果查不到(比如某个系统没有对应版本),该库会被判定为不激活。

判定结果:下载与存储

判定通过后,Library::getDownloads()会结合 Mojang 的下载地址和 sha1 校验值发起下载,文件默认存放到共享目录的libraries/前缀下(defaultStoragePrefix()),路径规则就是前面 GradleSpecifier 的toPath()结果。hint: local的库则会被复制进实例目录,alwaysStale: true的库每次都会重新校验更新。整个下载调度由 launcher/minecraft/update/LibrariesTask.cpp 任务驱动。

一图流:完整判定链路

  1. 解析:GradleSpecifier把坐标拆成 groupId / artifactId / version / classifier;
  2. 封装:Library持有坐标、rules、natives 映射、下载信息;
  3. 环境:RuntimeContext提供当前系统 + Java 架构;
  4. 判定:Rule按顺序求值,后者覆盖前者;natives 按 classifier 精确/宽松匹配;
  5. 执行:isActive()为 true 的库进入下载队列,存到libraries/对应路径。

常见问题 FAQ

问:为什么我的 Linux 实例下载了 Windows 的原生库?答:不会。getCompatibleNative()只会为当前系统匹配的 classifier 生成下载请求,不匹配的平台文件根本不会被请求。

问:rules为空和不写rules有区别吗?答:功能上等价——两者都表示"默认允许加载"。代码里m_rules为空时直接返回激活(见 isActive())。

问:在哪里能验证这套解析逻辑?答:单元测试 tests/GradleSpecifier_test.cpp 与 tests/Library_test.cpp 覆盖了坐标解析、路径生成和规则判定的典型场景,测试数据在 tests/testdata/Libraries/ 目录中,是很好的学习材料。


至此你就完全理解了 Ely Prism Launcher 判定依赖库的原理:GradleSpecifier 负责"读懂坐标",Rule 负责"决定去留",Library 负责"统筹执行"。下次遇到"某个库为什么没被下载"的问题,顺着isActive()的判定链路查一遍 rules 和 natives 配置,答案基本就出来了。

【免费下载链接】Launcher

This fork of Prism Launcher adds integrated support for Ely.by accounts.

项目地址:https://gitcode.com/GitHub_Trending/ely/Launcher
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进