多版本原版资源包
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) 做三步:
new MultiVersionDefaultResourcePack(assetDirector);- 反射读
Minecraft.defaultResourcePacks(SRGfield_110449_ao),add进去; - 若资源管理器是
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 的优先级:
- 用户资源包覆盖 — 若
minecraft命名空间下有非内置资源包提供了同名资源(sounds.json除外),直接返回它的流; - jar 内资源 — 客户端 jar 里存在时返回 jar 条目流;
- 下载的资源对象 —
fetcher.hashExists(hash)为真时返回下载文件流; - 都不满足则
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 时:
- 取整形后的 JSON;
stripUnusedSounds删掉":tmp:requested"键(常量AssetDirector.SOUNDS_JSON_REQUESTED),并移除所有不在 requested 集合里的事件——其他 mod 请求过的事件不会漏掉;- 系统属性
assetDirector.dumpSoundsJson为真时额外导出到<实例>/asset_director/out/sounds-<version>.json(pretty print); - 返回
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"。
相关条目
- AssetDirector - 资源声明与下载
- AssetFetcher - 本类依赖的索引与哈希查询接口
- 反射访问点 - 本类用到的两个 SRG 字段
- SSL 信任库替换 -
MCUtil.getInstanceDir()导出的目标目录