1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
use crate::{
classes::pptr::PPtr,
serialized_file::SerializedFile,
unityfs::{
NodeReader, UnityFS, block_reader::BlockReader, header::NodeInfo, multi_reader::MultiReader,
},
};
use anyhow::{Context, Result, anyhow};
use log::debug;
use std::{
collections::HashMap,
fs::File,
io::{BufReader, Read, Seek},
marker::PhantomData,
path::Path,
sync::{Arc, Mutex},
};
/// High-level wrapper around UnityFS, SerializedFile and all the classes.
pub struct AssetBundle<T> {
pub fs: UnityFS<T>,
pub ser_files:
HashMap<String, Arc<Mutex<SerializedFile<NodeReader<BlockReader<MultiReader<T>>>>>>>,
pub main_file: NodeInfo,
pub default_resources: SerializedFile<BufReader<File>>,
}
impl<T: Read + Seek> AssetBundle<T> {
pub fn open(inner: T, support_dir: impl AsRef<Path>) -> Result<Self> {
let fs = UnityFS::open(inner).context("opening UnityFS")?;
let main_file = fs
.find_main_file()
.ok_or(anyhow!("AssetBundle seems to lack main file"))?
.clone();
debug!("opening default resource file");
let default_resources = SerializedFile::read(
BufReader::new(File::open(
support_dir.as_ref().join("unity default resources"),
)?),
"Library/unity default resources".to_owned(),
)?;
debug!("detected {:?} as main file", main_file.name);
Ok(Self {
fs,
main_file,
default_resources,
ser_files: HashMap::new(),
})
}
pub fn get_fs_file(
&mut self,
node: &NodeInfo,
) -> Result<Arc<Mutex<SerializedFile<NodeReader<BlockReader<MultiReader<T>>>>>>> {
if !self.ser_files.contains_key(&node.name) {
let file =
SerializedFile::read(self.fs.read(node)?, format!("archive:/{}", node.name))?;
self.ser_files
.insert(node.name.clone(), Arc::new(Mutex::new(file)));
}
Ok(self.ser_files.get(&node.name).unwrap().clone())
}
pub fn all_toplevel(&mut self) -> Vec<PPtr> {
let main = self.get_fs_file(&self.main_file.clone()).unwrap();
let main = main.lock().unwrap();
let shared_assets = main.find_fs_shared_assets(&self.fs);
let main_obs = main
.objects
.iter()
.map(|o| (main.ecx.clone(), o.to_owned()))
.collect::<Vec<_>>();
let shared_obs = if let Some(shared_assets) = shared_assets {
let shared = self.get_fs_file(&shared_assets).unwrap();
let shared = shared.lock().unwrap();
shared
.objects
.iter()
.map(|o| (shared.ecx.clone(), o.to_owned()))
.collect()
} else {
Vec::new()
};
main_obs
.into_iter()
.chain(shared_obs)
.map(|(ecx, o)| PPtr {
class: "".to_string(),
ecx,
file_id: 0,
path_id: o.path_id,
_class: PhantomData,
})
.collect()
}
pub fn all_toplevel_of_class(&mut self, class_name: &str) -> Vec<PPtr> {
let main = self.get_fs_file(&self.main_file.clone()).unwrap();
let main = main.lock().unwrap();
let shared_assets = main.find_fs_shared_assets(&self.fs);
let main_obs = main
.all_objects_of_class(class_name)
.map(|o| (main.ecx.clone(), o.to_owned()))
.collect::<Vec<_>>();
let shared_obs = if let Some(shared_assets) = shared_assets {
let shared = self.get_fs_file(&shared_assets).unwrap();
let shared = shared.lock().unwrap();
shared
.all_objects_of_class(class_name)
.map(|o| (shared.ecx.clone(), o.to_owned()))
.collect()
} else {
Vec::new()
};
main_obs
.into_iter()
.chain(shared_obs)
.map(|(ecx, o)| PPtr {
class: "".to_string(),
ecx,
file_id: 0,
path_id: o.path_id,
_class: PhantomData,
})
.collect()
}
}
|