mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 09:15:15 +08:00
chore: establish development baseline
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
//! Unity Adapter 接口定义
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// Unity 版本范围
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VersionRange {
|
||||
/// 最小版本(包含)
|
||||
pub min: String,
|
||||
/// 最大版本(包含)
|
||||
pub max: String,
|
||||
}
|
||||
|
||||
impl VersionRange {
|
||||
/// 创建新的版本范围
|
||||
pub fn new(min: impl Into<String>, max: impl Into<String>) -> Self {
|
||||
Self {
|
||||
min: min.into(),
|
||||
max: max.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查版本是否在范围内
|
||||
pub fn contains(&self, version: &str) -> bool {
|
||||
version >= self.min.as_str() && version <= self.max.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
/// 原始 AssetBundle 数据
|
||||
#[derive(Debug)]
|
||||
pub struct RawAssetBundle {
|
||||
/// 文件数据
|
||||
pub data: Vec<u8>,
|
||||
/// 文件路径(可选)
|
||||
pub path: Option<String>,
|
||||
}
|
||||
|
||||
/// 解析后的 AssetBundle
|
||||
#[derive(Debug)]
|
||||
pub struct ParsedAssetBundle {
|
||||
/// Unity 版本
|
||||
pub unity_version: String,
|
||||
/// 资源列表(简化表示)
|
||||
pub assets: Vec<String>,
|
||||
/// 原始数据(保留用于序列化)
|
||||
pub raw_data: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Unity Adapter 接口
|
||||
///
|
||||
/// 用于解析不同 Unity 版本的 AssetBundle
|
||||
#[async_trait]
|
||||
pub trait UnityAdapter: Send + Sync {
|
||||
/// 适配器名称(例如 "Unity-2021.3")
|
||||
fn name(&self) -> &str;
|
||||
|
||||
/// 支持的 Unity 版本范围
|
||||
fn supported_versions(&self) -> VersionRange;
|
||||
|
||||
/// 检测是否可以处理这个 AssetBundle
|
||||
///
|
||||
/// # 参数
|
||||
/// - `bundle`: 原始 AssetBundle
|
||||
///
|
||||
/// # 返回
|
||||
/// - true: 可以处理
|
||||
/// - false: 不能处理
|
||||
fn can_handle(&self, bundle: &RawAssetBundle) -> bool;
|
||||
|
||||
/// 解析 AssetBundle
|
||||
///
|
||||
/// # 参数
|
||||
/// - `bundle`: 原始 AssetBundle
|
||||
///
|
||||
/// # 返回
|
||||
/// - 成功:返回解析后的 AssetBundle
|
||||
/// - 失败:返回错误
|
||||
///
|
||||
/// # 注意
|
||||
/// Phase 1 中标记为 TODO,Phase 2 实现
|
||||
async fn parse(&self, bundle: &RawAssetBundle) -> Result<ParsedAssetBundle, String>;
|
||||
|
||||
/// 序列化 AssetBundle
|
||||
///
|
||||
/// # 参数
|
||||
/// - `parsed`: 解析后的 AssetBundle
|
||||
///
|
||||
/// # 返回
|
||||
/// - 成功:返回序列化后的数据
|
||||
/// - 失败:返回错误
|
||||
///
|
||||
/// # 注意
|
||||
/// Phase 1 中标记为 TODO,Phase 2 实现
|
||||
async fn serialize(&self, parsed: &ParsedAssetBundle) -> Result<Vec<u8>, String>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_version_range() {
|
||||
let range = VersionRange::new("2021.3.0", "2021.3.99");
|
||||
|
||||
assert!(range.contains("2021.3.0"));
|
||||
assert!(range.contains("2021.3.56"));
|
||||
assert!(range.contains("2021.3.99"));
|
||||
assert!(!range.contains("2021.2.0"));
|
||||
assert!(!range.contains("2021.4.0"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_assetbundle() {
|
||||
let bundle = RawAssetBundle {
|
||||
data: vec![0x55, 0x6e, 0x69, 0x74, 0x79, 0x46, 0x53], // "UnityFS"
|
||||
path: Some("test.bundle".to_string()),
|
||||
};
|
||||
|
||||
assert_eq!(bundle.data.len(), 7);
|
||||
assert_eq!(bundle.path, Some("test.bundle".to_string()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
//! Unity Adapter 注册表
|
||||
//!
|
||||
//! 管理所有 Unity Adapter 并自动选择合适的适配器
|
||||
|
||||
use super::adapter::{RawAssetBundle, UnityAdapter};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Unity Adapter 注册表
|
||||
pub struct UnityAdapterRegistry {
|
||||
adapters: Vec<Arc<dyn UnityAdapter>>,
|
||||
}
|
||||
|
||||
impl UnityAdapterRegistry {
|
||||
/// 创建新的注册表
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
adapters: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 注册一个适配器
|
||||
pub fn register(&mut self, adapter: Arc<dyn UnityAdapter>) {
|
||||
self.adapters.push(adapter);
|
||||
}
|
||||
|
||||
/// 自动选择合适的适配器
|
||||
///
|
||||
/// # 参数
|
||||
/// - `bundle`: 原始 AssetBundle
|
||||
///
|
||||
/// # 返回
|
||||
/// - 成功:返回合适的适配器
|
||||
/// - 失败:如果没有合适的适配器,返回错误
|
||||
pub fn select_adapter(&self, bundle: &RawAssetBundle) -> Result<Arc<dyn UnityAdapter>, String> {
|
||||
for adapter in &self.adapters {
|
||||
if adapter.can_handle(bundle) {
|
||||
return Ok(Arc::clone(adapter));
|
||||
}
|
||||
}
|
||||
|
||||
Err("No suitable adapter found for this AssetBundle".to_string())
|
||||
}
|
||||
|
||||
/// 获取所有已注册的适配器
|
||||
pub fn all_adapters(&self) -> &[Arc<dyn UnityAdapter>] {
|
||||
&self.adapters
|
||||
}
|
||||
|
||||
/// 获取适配器数量
|
||||
pub fn count(&self) -> usize {
|
||||
self.adapters.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UnityAdapterRegistry {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::unity::Unity2021_3Adapter;
|
||||
|
||||
#[test]
|
||||
fn test_registry_new() {
|
||||
let registry = UnityAdapterRegistry::new();
|
||||
assert_eq!(registry.count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_register_adapter() {
|
||||
let mut registry = UnityAdapterRegistry::new();
|
||||
let adapter = Arc::new(Unity2021_3Adapter::new());
|
||||
|
||||
registry.register(adapter);
|
||||
assert_eq!(registry.count(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_select_adapter() {
|
||||
let mut registry = UnityAdapterRegistry::new();
|
||||
registry.register(Arc::new(Unity2021_3Adapter::new()));
|
||||
|
||||
// 创建一个 Unity 2021.3 的 bundle
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(b"UnityFS\0");
|
||||
data.extend_from_slice(&[0, 0, 0, 8]);
|
||||
data.extend_from_slice(b"5.x.x\x002021.3.56f2\0");
|
||||
|
||||
let bundle = RawAssetBundle {
|
||||
data,
|
||||
path: Some("test.bundle".to_string()),
|
||||
};
|
||||
|
||||
let result = registry.select_adapter(&bundle);
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap().name(), "Unity-2021.3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_select_adapter_not_found() {
|
||||
let registry = UnityAdapterRegistry::new();
|
||||
|
||||
let bundle = RawAssetBundle {
|
||||
data: vec![0, 1, 2, 3],
|
||||
path: None,
|
||||
};
|
||||
|
||||
let result = registry.select_adapter(&bundle);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
//! Unity 2021.3 Adapter
|
||||
//!
|
||||
//! 支持 Unity 2021.3.x 版本的 AssetBundle
|
||||
|
||||
use super::adapter::{ParsedAssetBundle, RawAssetBundle, UnityAdapter, VersionRange};
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// Unity 2021.3 Adapter
|
||||
pub struct Unity2021_3Adapter;
|
||||
|
||||
impl Unity2021_3Adapter {
|
||||
/// 创建新的适配器实例
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
/// 检测 Unity 版本(从文件头)
|
||||
fn detect_unity_version(data: &[u8]) -> Option<String> {
|
||||
// UnityFS 文件头结构:
|
||||
// 0x00-0x06: "UnityFS\0"
|
||||
// 0x08-0x0B: format version
|
||||
// 0x0C-...: Unity version string
|
||||
|
||||
if data.len() < 20 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// 检查签名
|
||||
if &data[0..7] != b"UnityFS" {
|
||||
return None;
|
||||
}
|
||||
|
||||
// 读取 Unity 版本字符串
|
||||
// 版本字符串从偏移 0x14 开始(可能因格式版本不同而变化)
|
||||
if let Some(version_start) = data.windows(7).position(|w| w.starts_with(b"2021.3.")) {
|
||||
// 读取版本字符串直到 null 或非 ASCII
|
||||
let version_bytes = &data[version_start..];
|
||||
if let Some(end) = version_bytes.iter().position(|&b| b == 0 || !b.is_ascii()) {
|
||||
if let Ok(version) = std::str::from_utf8(&version_bytes[..end]) {
|
||||
return Some(version.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Unity2021_3Adapter {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UnityAdapter for Unity2021_3Adapter {
|
||||
fn name(&self) -> &str {
|
||||
"Unity-2021.3"
|
||||
}
|
||||
|
||||
fn supported_versions(&self) -> VersionRange {
|
||||
VersionRange::new("2021.3.0", "2021.3.99")
|
||||
}
|
||||
|
||||
fn can_handle(&self, bundle: &RawAssetBundle) -> bool {
|
||||
// 检测 Unity 版本
|
||||
if let Some(version) = Self::detect_unity_version(&bundle.data) {
|
||||
self.supported_versions().contains(&version)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
async fn parse(&self, _bundle: &RawAssetBundle) -> Result<ParsedAssetBundle, String> {
|
||||
// TODO: Phase 2 实现
|
||||
// 需要:
|
||||
// 1. 解析 UnityFS 文件头
|
||||
// 2. 解压缩数据块
|
||||
// 3. 解析 TypeTree
|
||||
// 4. 提取 Asset 对象
|
||||
Err("parse() 将在 Phase 2 实现".to_string())
|
||||
}
|
||||
|
||||
async fn serialize(&self, _parsed: &ParsedAssetBundle) -> Result<Vec<u8>, String> {
|
||||
// TODO: Phase 2 实现
|
||||
// 需要:
|
||||
// 1. 序列化 Asset 对象
|
||||
// 2. 重新构建 TypeTree
|
||||
// 3. 压缩数据块
|
||||
// 4. 写入 UnityFS 文件头
|
||||
Err("serialize() 将在 Phase 2 实现".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_adapter_name() {
|
||||
let adapter = Unity2021_3Adapter::new();
|
||||
assert_eq!(adapter.name(), "Unity-2021.3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_supported_versions() {
|
||||
let adapter = Unity2021_3Adapter::new();
|
||||
let range = adapter.supported_versions();
|
||||
|
||||
assert!(range.contains("2021.3.0"));
|
||||
assert!(range.contains("2021.3.56"));
|
||||
assert!(!range.contains("2021.2.0"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_can_handle_valid_bundle() {
|
||||
let adapter = Unity2021_3Adapter::new();
|
||||
|
||||
// 模拟 UnityFS 文件头
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(b"UnityFS\0");
|
||||
data.extend_from_slice(&[0, 0, 0, 8]); // format version
|
||||
data.extend_from_slice(b"5.x.x\x002021.3.56f2\0");
|
||||
|
||||
let bundle = RawAssetBundle {
|
||||
data,
|
||||
path: Some("test.bundle".to_string()),
|
||||
};
|
||||
|
||||
assert!(adapter.can_handle(&bundle));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_can_handle_invalid_bundle() {
|
||||
let adapter = Unity2021_3Adapter::new();
|
||||
|
||||
let bundle = RawAssetBundle {
|
||||
data: vec![0, 1, 2, 3],
|
||||
path: None,
|
||||
};
|
||||
|
||||
assert!(!adapter.can_handle(&bundle));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_parse_not_implemented() {
|
||||
let adapter = Unity2021_3Adapter::new();
|
||||
|
||||
let bundle = RawAssetBundle {
|
||||
data: vec![],
|
||||
path: None,
|
||||
};
|
||||
|
||||
let result = adapter.parse(&bundle).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Phase 2"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user