feat: prepare experiment push package

This commit is contained in:
2026-06-30 00:08:36 +08:00
parent 3c00659691
commit adc1cd5b91
45 changed files with 7858 additions and 65 deletions
+156 -13
View File
@@ -52,9 +52,52 @@ impl AddressablesCatalogDriver {
}
}
fn resources(json: &Value) -> Vec<ResourceEntry> {
let resources = json
.get("m_InternalIds")
fn resource_from_entry(value: &Value, index: usize) -> Option<ResourceEntry> {
let path = value
.get("internal_id")
.or_else(|| value.get("InternalId"))
.or_else(|| value.get("path"))
.or_else(|| value.get("Path"))
.and_then(|value| value.as_str())?;
if path.is_empty() {
return None;
}
let hash = value
.get("hash")
.or_else(|| value.get("Hash"))
.and_then(|value| value.as_str())
.map(ToOwned::to_owned)
.unwrap_or_else(|| format!("addressable_{}", index));
let size = value
.get("size")
.or_else(|| value.get("Size"))
.and_then(|value| value.as_u64())
.unwrap_or_default();
Some(ResourceEntry {
path: path.to_string(),
hash,
size,
resource_type: Self::resource_type_for_path(path),
})
}
fn entry_resources(json: &Value) -> Vec<ResourceEntry> {
json.get("m_Entries")
.or_else(|| json.get("entries"))
.and_then(|value| value.as_array())
.into_iter()
.flatten()
.enumerate()
.filter_map(|(index, value)| Self::resource_from_entry(value, index))
.collect()
}
fn internal_id_resources(json: &Value) -> Vec<ResourceEntry> {
json.get("m_InternalIds")
.and_then(|value| value.as_array())
.into_iter()
.flatten()
@@ -72,8 +115,55 @@ impl AddressablesCatalogDriver {
resource_type: Self::resource_type_for_path(path),
})
})
.collect();
resources
.collect()
}
fn resources(json: &Value) -> Vec<ResourceEntry> {
let entry_resources = Self::entry_resources(json);
if !entry_resources.is_empty() {
return entry_resources;
}
Self::internal_id_resources(json)
}
fn extra_metadata(json: &Value) -> HashMap<String, String> {
let mut extra = HashMap::new();
Self::insert_array_len(&mut extra, json, "m_InternalIds", "internal_id_count");
Self::insert_array_len(&mut extra, json, "m_Entries", "entry_count");
Self::insert_string_len(&mut extra, json, "m_KeyDataString", "key_data_string_len");
Self::insert_string_len(
&mut extra,
json,
"m_EntryDataString",
"entry_data_string_len",
);
extra
}
fn insert_array_len(extra: &mut HashMap<String, String>, json: &Value, field: &str, key: &str) {
if let Some(len) = json
.get(field)
.and_then(|value| value.as_array())
.map(|values| values.len())
{
extra.insert(key.to_string(), len.to_string());
}
}
fn insert_string_len(
extra: &mut HashMap<String, String>,
json: &Value,
field: &str,
key: &str,
) {
if let Some(len) = json
.get(field)
.and_then(|value| value.as_str())
.map(|value| value.len())
{
extra.insert(key.to_string(), len.to_string());
}
}
}
@@ -125,14 +215,10 @@ impl ManifestDriver for AddressablesCatalogDriver {
async fn parse(&self, raw_data: &[u8]) -> Result<GenericManifest, String> {
let json = Self::parse_json(raw_data)?;
// TODO: 解析 m_KeyDataString、m_EntryDataString 等压缩字段
// 这些字段使用了自定义压缩格式,需要实现解压缩算法
// 参考:Unity Addressables 源代码
let metadata = ManifestMetadata {
locator_id: Self::locator_id(&json),
cdn_prefixes: Self::cdn_prefixes(&json),
extra: HashMap::new(),
extra: Self::extra_metadata(&json),
};
Ok(GenericManifest {
@@ -178,9 +264,9 @@ mod tests {
"m_LocatorId": "AddressablesMainContentCatalog",
"m_InternalIdPrefixes": [],
"m_InternalIds": [
"academy.bundle",
"character.bundle",
"catalog.json"
"synthetic/minimal-a.bundle",
"synthetic/minimal-b.bundle",
"synthetic/catalog.json"
]
}"#;
@@ -195,4 +281,61 @@ mod tests {
ResourceType::AssetBundle
);
}
#[tokio::test]
async fn test_parse_entry_catalog_resources_and_metadata() {
let driver = AddressablesCatalogDriver::new();
let catalog_json = r#"{
"m_LocatorId": "AddressablesMainContentCatalog",
"m_InternalIdPrefixes": ["https://synthetic.invalid/bundles/"],
"m_InternalIds": ["synthetic/fallback.bundle"],
"m_KeyDataString": "key-data",
"m_EntryDataString": "entry-data",
"m_Entries": [
{
"internal_id": "synthetic/minimal.bundle",
"hash": "synthetic-entry-hash",
"size": 119
},
{
"internal_id": "synthetic/catalog.json",
"hash": "synthetic-catalog-hash",
"size": 2
}
]
}"#;
let manifest = driver.parse(catalog_json.as_bytes()).await.unwrap();
assert_eq!(manifest.resources.len(), 2);
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);
assert_eq!(
manifest.resources[0].resource_type,
ResourceType::AssetBundle
);
assert_eq!(manifest.resources[1].resource_type, ResourceType::Manifest);
assert_eq!(
manifest.metadata.cdn_prefixes,
vec!["https://synthetic.invalid/bundles/".to_string()]
);
assert_eq!(
manifest.metadata.extra.get("internal_id_count"),
Some(&"1".to_string())
);
assert_eq!(
manifest.metadata.extra.get("entry_count"),
Some(&"2".to_string())
);
assert_eq!(
manifest.metadata.extra.get("key_data_string_len"),
Some(&"8".to_string())
);
assert_eq!(
manifest.metadata.extra.get("entry_data_string_len"),
Some(&"10".to_string())
);
}
}