AssetFetcher

AssetFetcher 负责 AssetDirector 的实现细节:与 Mojang 接口交互、维护版本索引与资源索引、按 SHA-1 校验下载物。类注释写明"最核心的是与 Mojang 的 API 打交道"。

基本信息

属性 值
类型 内部实现 / HTTP 下载器
所属 AssetDirector 的字段 fetcher
存放根目录 MCUtil.getMCAssetsDir()(读)+ AssetDirector.AD_DIR(写)

端点与路径

常量 值 覆盖方式
MANIFEST_ENDPOINT https://launchermeta.mojang.com/mc/game/version_manifest.json 系统属性 assetDirector.manifestEndpoint
RESOURCES_ENDPOINT https://resources.download.minecraft.net 系统属性 assetDirector.resourcesEndpoint
ASSET_INDEX_PATH assets/indexes/%s.json(参数为 assetsId) —
CLIENT_JAR_PATH versions/%s/%s.jar(版本号,版本号) —
VERSION_INDEX_PATH versions/%s/%s.json —
DOWNLOAD_TIMEOUT 10000 ms 系统属性 assetDirector.downloadTimeout
DOWNLOAD_ATTEMPTS 3 系统属性 assetDirector.downloadAttempts

资源对象路径为 /<hash 前两位>/<hash>,对应 Mojang 的 object store 布局。

公共方法

方法 说明
init() 打印数据目录;删除所有 .part 结尾的残留文件(清理上次中断的下载);调用 SSLHacker.hack()
loadVersionDeps(String version) 依次准备:版本 JSON(必要时从 manifest 找 URL 下载)→ 构造 VersionIndex;若其 assetsId 未缓存则下载 assets/indexes/<assetsId>.json 并构造 AssetIndex
fetchAsset(String version, String asset) 准备版本依赖 → 查哈希 → 下载
fetchAssetByHash(String assetHash) 已知哈希时直接下载;哈希为 null 时静默返回
fetchForAllVersions(String asset) 对所有已加载 assetsId 的版本各下载一次
needsFetchResource(String version, String asset) needsFetchAsset(version, asset, false)
needsFetchAsset(String version, String asset, boolean printErrors) 查哈希后判断文件是否存在
needsFetchAssetByHash(String assetHash) 哈希非 null 且文件不存在时返回 true
getAssetHash(String version, String asset[, boolean printErrors]) 从资源索引查名字到哈希的映射;printErrors 为真时查不到会报错
fileIsPresent(String hash) 读路径不等于哨兵 NULL_FILE 即视为存在
fetchJar(String version) / loadJar(String version) / needsFetchJar(String version) 客户端 jar 的下载、打开、存在性判断
getAssetFileForRead(String hash) 先查内存 fileMap;未命中则依次试写目录 assets/objects/xx/<hash> 与原 assets 目录 objects/xx/<hash>,都不存在返回 NULL_FILE
getAssetFileForWrite(String hash) 恒为写目录 assets/objects/xx/<hash>
getAssetInputStream(String hash) / getAssetInputStream(String version, String path) 读流;后者先经 versionToAssetsId 换算
hashExists(String hash) 内存缓存判断,哈希为 null 返回 false
versionToAssetsId(String version) 必要时先 loadVersionDeps
getSha1(File file)(静态) Guava Files.hash(file, Hashing.sha1())

下载与校验

downloadAssetByHash 的流程:

  1. 下载到 <写目录>/<hash>.part;
  2. 比对 SHA-1;
  3. 匹配则建父目录、renameTo 正式文件、写入 fileMap、break;
  4. 不匹配则 LOGGER.warn("Got invalid hash when downloading <hash>. Attempt <i>/<DOWNLOAD_ATTEMPTS>") 继续重试。

版本索引下载用 FileUtils.copyURLToFile(url, destination, DOWNLOAD_TIMEOUT, DOWNLOAD_TIMEOUT);manifest 按 versions[].id 匹配目标版本,取其 url 下载,版本不存在则 LOGGER.error("Game version <version> could not be found in manifest json.")。

内部数据结构

类型 字段 / 说明
AssetFetcher.AssetIndex(public static) public JsonObject json、public Map<String, String> nameToHash;构造时遍历 json.objects 读每项的 hash
AssetFetcher.VersionIndex(public 内部类) public JsonObject json、public String assetsId(取 json.assets)、JarFile jar、public Set<String> jarContents、public Version version(取 json.id);方法 fetchJar、loadJar、jarContainsFile(String)、getJarFileStream(String)
ManifestVersionJSON(private static) 字段 id、url

getJarFileStream 在 jar 未加载时会对 null jar 抛 NPE——调用方需保证先 loadJar。

并发

无。整个 AssetDirector 流程在 pre-init 阶段单线程同步执行,靠 FML 的 ProgressManager.ProgressBar 显示进度(封装见 SSL 信任库替换 中的 MCUtil.ProgressBar)。

相关条目