pub struct ModuleFile {
pub header: ModuleHeader,
pub files: Vec<ModuleFileEntry>,
pub resource_indices: Vec<u32>,
blocks: Vec<ModuleBlockEntry>,
file_data_offset: u64,
module_file: Option<BufReader<File>>,
hd1_file: Option<BufReader<File>>,
pub use_hd1: bool,
}
Expand description
Module structure which contains the layout of the entire module file.
Fields§
§header: ModuleHeader
Information relating to how the other fields should be read.
files: Vec<ModuleFileEntry>
Metadata regarding compression and layout of files (tags).
resource_indices: Vec<u32>
Indices of resource files present in the module.
blocks: Vec<ModuleBlockEntry>
Uncompressed/compressed blocks making up a file.
file_data_offset: u64
Offset in BufReader
where file data starts.
module_file: Option<BufReader<File>>
Reference to the module file buffer.
hd1_file: Option<BufReader<File>>
Reference to HD1 buffer if it exists.
use_hd1: bool
Whether to use the HD1 module or not.
Implementations§
Source§impl ModuleFile
impl ModuleFile
Sourcepub fn from_path<T: AsRef<Path>>(file_path: T) -> Result<Self>
pub fn from_path<T: AsRef<Path>>(file_path: T) -> Result<Self>
Instantiates a ModuleFile
object from the given file path.
Examples found in repository?
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
fn load_modules<R: AsRef<Path>>(deploy_path: R) -> Result<Vec<ModuleFile>> {
let mut modules = Vec::new();
for entry in walkdir::WalkDir::new(deploy_path)
.into_iter()
.filter_map(|e| e.ok())
{
if entry.file_type().is_file() {
let file_path = entry.path().to_str().unwrap();
if file_path.ends_with(".module") {
let module = ModuleFile::from_path(file_path)?;
modules.push(module);
}
}
}
Ok(modules)
}
More examples
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
fn load_modules<R: AsRef<Path>>(deploy_path: R) -> Result<Vec<ModuleFile>> {
let mut modules = Vec::new();
for entry in walkdir::WalkDir::new(deploy_path)
.into_iter()
.filter_map(|e| e.ok())
{
if entry.file_type().is_file() {
let file_path = entry.path().to_str().unwrap();
if file_path.ends_with(".module") {
let module = ModuleFile::from_path(file_path)?;
modules.push(module);
}
}
}
Ok(modules)
}
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
fn main() -> Result<()> {
let mut module = ModuleFile::from_path(DEPLOY_PATH)?;
for idx in 0..module.files.len() {
if module.files[idx].tag_group == SCRIPT_GROUP {
let tag = module.read_tag(idx as u32)?;
if let Some(tag) = tag {
let mut source = HsSourceFileTag::default();
tag.read_metadata(&mut source)?;
let size = tag.uncompressed_header_size + 0x2D8;
let mut server_buf = vec![0; source.server.size as usize];
let mut client_buf = vec![0; source.client.size as usize];
if let Some(stream) = tag.data_stream.as_mut() {
stream.seek(SeekFrom::Start(size as u64))?;
stream.read_exact(&mut server_buf)?;
stream.read_exact(&mut client_buf)?;
}
let server_file = File::create(format!("{SAVE_PATH}/{}_server.luac", tag.tag_id))?;
let mut bw = BufWriter::new(server_file);
bw.write_all(&server_buf)?;
let client_file = File::create(format!("{SAVE_PATH}/{}_client.luac", tag.tag_id))?;
let mut bw = BufWriter::new(client_file);
bw.write_all(&client_buf)?;
}
}
}
Ok(())
}
Sourcepub fn read<T: AsRef<Path>>(&mut self, file_path: T) -> Result<()>
pub fn read<T: AsRef<Path>>(&mut self, file_path: T) -> Result<()>
Reads the module file from the given file path. This function reads the entire structure of the module file. It also calculates and stores important offsets within the file.
§Arguments
file_path
- A reference to a type that implementsPath
that holds the path to the module file.
§Errors
- If the reader fails to read the exact number of bytes
ReadError
- If the string table has invalid UTF-8
Utf8ReadingError
Sourcefn open_hd1<T: AsRef<Path>>(&mut self, file_path: T) -> Result<()>
fn open_hd1<T: AsRef<Path>>(&mut self, file_path: T) -> Result<()>
Opens the HD1 file if it exists.
Sourcefn get_tag_path(&self, index: usize, depth: usize) -> Result<String>
fn get_tag_path(&self, index: usize, depth: usize) -> Result<String>
Gets the tag path of a file entry.
This function returns the tag path of a file entry based on the provided index. For file entries that have a parent, the function recursively gets the tag path of the parent and appends the child index to the path.
§Arguments
index
- The index of the file entry to get the tag path from.depth
- The depth of the recursion. This is used to prevent infinite recursion.
§Returns
Returns the tag path of the file entry if the operation is successful.
Sourcepub fn read_tag(&mut self, index: u32) -> Result<Option<&mut ModuleFileEntry>>
pub fn read_tag(&mut self, index: u32) -> Result<Option<&mut ModuleFileEntry>>
Reads a specific tag from the module file.
This function reads a specific tag from the module file based on the provided index.
It also utilizes the HD1 stream if the file entry has the flag set for it and the stream is loaded, and returns None
if the tag offset is invalid.
§Arguments
index
- The index of the file entry to read the tag from. This index corresponds to the position of the file entry in thefiles
vector.
§Returns
Returns a mutable reference to the file if the read operation is successful, or an Error
, a None
if the file was not read (if tag offset is specified as invalid) or the containing the I/O error if any reading operation fails.
Examples found in repository?
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
fn main() -> Result<()> {
let mut modules = load_modules(String::from("C:/XboxGames/Halo Infinite/Content/deploy/"))?;
for module in &mut modules {
for index in 0..module.files.len() {
let tag = module.read_tag(index as u32)?;
if let Some(tag) = tag {
if tag.tag_group == "mat " {
let mut mat = MaterialTag::default();
tag.read_metadata(&mut mat)?;
}
// explicitly drop buffer to free up memory
// normally, can take 50+ GBs of RAM
module.files[index].data_stream = None
}
}
}
Ok(())
}
More examples
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
fn main() -> Result<()> {
let args: InfiniteExtract = argh::from_env();
let mut modules = load_modules(args.deploy_path)?;
for module in &mut modules {
for idx in 0..module.files.len() {
module.read_tag(idx as u32)?;
}
for file in &mut module.files {
let mut buffer = Vec::with_capacity(file.total_uncompressed_size as usize);
if let Some(stream) = file.data_stream.as_mut() {
stream.rewind()?;
stream.read_to_end(&mut buffer)?;
}
let tag_path = file
.tag_name
.replace(" ", "_")
.replace("*", "_")
.replace(r"\", "/")
.replace(":", "_");
let path = PathBuf::from(&args.output_path).join(tag_path);
create_dir_all(path.parent().unwrap())?;
let filee = File::create(path)?;
let mut bw = BufWriter::new(&filee);
bw.write_all(&buffer)?;
}
}
Ok(())
}
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
fn main() -> Result<()> {
let mut module = ModuleFile::from_path(DEPLOY_PATH)?;
for idx in 0..module.files.len() {
if module.files[idx].tag_group == SCRIPT_GROUP {
let tag = module.read_tag(idx as u32)?;
if let Some(tag) = tag {
let mut source = HsSourceFileTag::default();
tag.read_metadata(&mut source)?;
let size = tag.uncompressed_header_size + 0x2D8;
let mut server_buf = vec![0; source.server.size as usize];
let mut client_buf = vec![0; source.client.size as usize];
if let Some(stream) = tag.data_stream.as_mut() {
stream.seek(SeekFrom::Start(size as u64))?;
stream.read_exact(&mut server_buf)?;
stream.read_exact(&mut client_buf)?;
}
let server_file = File::create(format!("{SAVE_PATH}/{}_server.luac", tag.tag_id))?;
let mut bw = BufWriter::new(server_file);
bw.write_all(&server_buf)?;
let client_file = File::create(format!("{SAVE_PATH}/{}_client.luac", tag.tag_id))?;
let mut bw = BufWriter::new(client_file);
bw.write_all(&client_buf)?;
}
}
}
Ok(())
}
Sourcepub fn read_tag_from_id(
&mut self,
global_id: i32,
) -> Result<Option<&mut ModuleFileEntry>>
pub fn read_tag_from_id( &mut self, global_id: i32, ) -> Result<Option<&mut ModuleFileEntry>>
Searches for the index of the tag given the global_id
.
This function searches for the index of a tag in the files
vector using the provided
global_id
. If the tag is found, it reads the tag using the read_tag
function and
stores it in the index.
§Arguments
global_id
- The global tag ID of the file to find. This ID is used to identify the specific tag within the module file.
§Returns
Returns a mutable reference to the file if successful. If the tag is not
found or couldn’t be read, it returns None
. Any I/O error encountered during the operation is also returned
if it occurs.