多版本原版资源包

MultiVersionDefaultResourcePack 把下载到本地的新版原版资源以 minecraft_<版本号> 域的形式挂进 1.7.10 的资源管理器,并处理 1.7.10 与 1.13+ 之间的资源重命名和用户覆盖。

基本信息

属性 值
类型 资源包注入 / 资源定位
实现接口 net.minecraft.client.resources.IResourcePack
注入点 AssetDirector.preInit() 末尾调用 MultiVersionDefaultResourcePack.inject(this)
运行端 仅客户端
硬编码版本 1.7.10(v1_7_10)、1.13(v1_13)

注入过程

inject(AssetDirector assetDirector) 做三步:

  1. new MultiVersionDefaultResourcePack(assetDirector);
  2. 反射读 Minecraft.defaultResourcePacks(SRG field_110449_ao),add 进去;
  3. 若资源管理器是 SimpleReloadableResourceManager,再调一次 reloadResourcePack(multiDefaultPack) 强制重载。

资源域命名

getResourceDomains() 返回所有已加载版本号派生的 minecraft_<version> 字符串集合。

parseName 的解析规则:

步骤 行为
域校验 resLoc.getResourceDomain().startsWith("minecraft_"),否则 isValid = false 直接返回
拆分 第一个下划线之前是 namespace,之后是 version
定位 用 version 查 fetcher.versionIndexes 得到 VersionIndex
路径换算 convertPath(resLoc.getResourcePath(), scratch.vi.version)
判定来源 若 vi.jarContainsFile("assets/minecraft/" + name) 则走 jar 流(isInJar = true),否则查 assetIndexes.get(vi.assetsId).nameToHash 拿哈希

解析结果缓存在私有静态类 NameParserScratch 中,重复请求同一 ResourceLocation 直接复用。

1.7.10 与 1.13+ 的路径差异

convertPath(String path, Version version):当版本 >= 1.13 时做两处重写。

1.7.10 及以下 1.13 及以上
textures/blocks/... textures/block/...
textures/items/... textures/item/...

用 replaceFirst 实现,只替换开头一次。

查找顺序

getInputStream 的优先级:

  1. 用户资源包覆盖 — 若 minecraft 命名空间下有非内置资源包提供了同名资源(sounds.json 除外),直接返回它的流;
  2. jar 内资源 — 客户端 jar 里存在时返回 jar 条目流;
  3. 下载的资源对象 — fetcher.hashExists(hash) 为真时返回下载文件流;
  4. 都不满足则 throw new IOException("Resource does not exist: " + resLoc)。

resourceExists 判定:isValid 且(isInJar 为真 或 哈希存在 或 找到了用户覆盖包)。

用户覆盖的查找方式

对非 sounds.json 的请求,会同时构造 1.7.10 和 1.13 两个路径变体的 ResourceLocation(域固定为 "minecraft"),然后从后往前遍历 ResourcePackUtil.getMinecraftResourcePackList(),跳过内置包,第一个能提供资源的包即为覆盖者。sounds.json 跳过这一步。

sounds.json 的特殊处理

请求 minecraft 域的 sounds.json 且 assetDirector.getMassagedSoundJson(version) 非 null 时:

  1. 取整形后的 JSON;
  2. stripUnusedSounds 删掉 ":tmp:requested" 键(常量 AssetDirector.SOUNDS_JSON_REQUESTED),并移除所有不在 requested 集合里的事件——其他 mod 请求过的事件不会漏掉;
  3. 系统属性 assetDirector.dumpSoundsJson 为真时额外导出到 <实例>/asset_director/out/sounds-<version>.json(pretty print);
  4. 返回 IOUtils.toInputStream(new Gson().toJson(obj))。

ResourcePackUtil

方法 说明
getMinecraftResourcePackList() 反射 SimpleReloadableResourceManager.domainResourceManagers(SRG field_110548_a)取 "minecraft" 域;若是 FallbackResourceManager 再反射其 resourcePacks(SRG field_110540_a)。带一层缓存:若资源管理器实例没变就直接复用上次的结果
isBuiltIn(IResourcePack) 返回 true 当资源包是 DefaultResourcePack 实例,或包名为 "FMLFileResourcePack:Forge Mod Loader" 或 "FMLFileResourcePack:Minecraft Forge"

未实现的方法

getPackMetadata(IMetadataSerializer, String) 和 getPackImage() 都直接 return null(源码里带 TODO Auto-generated method stub 注释)。getPackName() 返回 "AssetDirector"。

相关条目