mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 01:15:14 +08:00
feat(addressables): 提取 m_Crc 并提供 size/CRC 校验 API(issue #2)
Addressables catalog 里的 m_Crc(bundle IEEE CRC-32)此前从未解析;
声明的 size 也只作元数据、无校验能力。本次:
- ResourceEntry 新增 crc: Option<u32>(serde default 向后兼容),
compact 与 expanded 两种 catalog 形态均解析 m_Crc/m_Crc→crc
- core 新增 crc32_ieee(IEEE CRC-32,等价 zlib/Unity m_Crc)与
ResourceEntry::{declared_crc, verify_downloaded_bytes}:按声明的
size/crc 校验字节,0 视为「无 CRC」跳过
- SqliteResourceRepository 持久化 crc 列,旧库经幂等 ensure_column
迁移补列(pragma_table_info 判断后 ALTER)
- golden 投影与 fixture 补 crc 字段,验证真实形态 catalog 提取贯通
校验 API 暂不接入 import 覆盖路径(该路径按 CAS id 重写 hash/size 是
既定语义,且合成测试的声明值不匹配实际字节);接入下载/导入校验留
待 G-011。
验证:core crc32 标准向量 + verify 分支单测、expanded 形态非零 crc
提取单测、golden 端到端;core/adapters/infrastructure 全测试 + fmt +
clippy --all-targets -D warnings 全绿。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -272,6 +272,12 @@ impl AddressablesCatalogDriver {
|
||||
.unwrap_or_default();
|
||||
|
||||
let dependencies = Self::dependencies_from_entry(value);
|
||||
let crc = value
|
||||
.get("crc")
|
||||
.or_else(|| value.get("Crc"))
|
||||
.or_else(|| value.get("m_Crc"))
|
||||
.and_then(|value| value.as_u64())
|
||||
.and_then(|value| u32::try_from(value).ok());
|
||||
|
||||
Some(ResourceEntry {
|
||||
path: path.to_string(),
|
||||
@@ -280,6 +286,7 @@ impl AddressablesCatalogDriver {
|
||||
resource_type: Self::resource_type_for_path(path),
|
||||
address,
|
||||
dependencies,
|
||||
crc,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -376,6 +383,7 @@ impl AddressablesCatalogDriver {
|
||||
resource_type: Self::resource_type_for_path(path),
|
||||
address: None,
|
||||
dependencies: Vec::new(),
|
||||
crc: None,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@@ -413,6 +421,7 @@ impl AddressablesCatalogDriver {
|
||||
resource_type,
|
||||
address: None,
|
||||
dependencies: Vec::new(),
|
||||
crc: None,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -483,6 +492,7 @@ impl AddressablesCatalogDriver {
|
||||
Some(primary_key)
|
||||
},
|
||||
dependencies,
|
||||
crc: extra.crc,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@@ -619,6 +629,11 @@ impl AddressablesCatalogDriver {
|
||||
.and_then(|value| value.as_str())
|
||||
.map(ToOwned::to_owned),
|
||||
bundle_size: json.get("m_BundleSize").and_then(|value| value.as_u64()),
|
||||
// m_Crc 是 bundle 的 IEEE CRC-32;0 表示不做 CRC 校验,忠实保留原值。
|
||||
crc: json
|
||||
.get("m_Crc")
|
||||
.and_then(|value| value.as_u64())
|
||||
.and_then(|value| u32::try_from(value).ok()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,6 +836,7 @@ struct AddressablesExtraData {
|
||||
hash: Option<String>,
|
||||
bundle_name: Option<String>,
|
||||
bundle_size: Option<u64>,
|
||||
crc: Option<u32>,
|
||||
}
|
||||
|
||||
impl Default for AddressablesCatalogDriver {
|
||||
@@ -954,6 +970,7 @@ mod tests {
|
||||
"internal_id": "synthetic/minimal.bundle",
|
||||
"hash": "synthetic-entry-hash",
|
||||
"size": 119,
|
||||
"crc": 3735928559,
|
||||
"address": "Character_001",
|
||||
"dependencies": ["synthetic/shared.bundle"]
|
||||
},
|
||||
@@ -971,6 +988,9 @@ mod tests {
|
||||
assert_eq!(manifest.resources[0].path, "synthetic/minimal.bundle");
|
||||
assert_eq!(manifest.resources[0].hash, "synthetic-entry-hash");
|
||||
assert_eq!(manifest.resources[0].size, 119);
|
||||
// m_Crc(此处 0xDEADBEEF)应被提取;缺该字段的条目为 None。
|
||||
assert_eq!(manifest.resources[0].crc, Some(0xDEAD_BEEF));
|
||||
assert_eq!(manifest.resources[1].crc, None);
|
||||
assert_eq!(
|
||||
manifest.resources[0].address.as_deref(),
|
||||
Some("Character_001")
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
"address": "academy-_mxload-prefabs-2025-07-02_assets_all_638981069.bundle",
|
||||
"dependencies": [
|
||||
"shared_assets_all_123.bundle"
|
||||
]
|
||||
],
|
||||
"crc": 0
|
||||
},
|
||||
{
|
||||
"path": "academy-_mxload-prefabs-2025-08-26_assets_all_1581352935.bundle",
|
||||
@@ -20,7 +21,8 @@
|
||||
"size": 162134,
|
||||
"resource_type": "AssetBundle",
|
||||
"address": "academy-_mxload-prefabs-2025-08-26_assets_all_1581352935.bundle",
|
||||
"dependencies": []
|
||||
"dependencies": [],
|
||||
"crc": 0
|
||||
},
|
||||
{
|
||||
"path": "shared_assets_all_123.bundle",
|
||||
@@ -28,7 +30,8 @@
|
||||
"size": 153480,
|
||||
"resource_type": "AssetBundle",
|
||||
"address": "shared_assets_all_123.bundle",
|
||||
"dependencies": []
|
||||
"dependencies": [],
|
||||
"crc": 0
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -22,6 +22,7 @@ async fn parses_real_shape_addressables_catalog_against_golden() {
|
||||
"resource_type": format!("{:?}", resource.resource_type),
|
||||
"address": resource.address,
|
||||
"dependencies": resource.dependencies,
|
||||
"crc": resource.crc,
|
||||
})
|
||||
}).collect::<Vec<_>>(),
|
||||
"metadata": manifest.metadata.extra,
|
||||
|
||||
Reference in New Issue
Block a user