### Auto-detect game installation and query asset database Source: https://docs.rs/maclarian/latest/maclarian/merged/index.html Demonstrates how to use GameDataResolver to automatically detect the game installation and retrieve asset information by visual name. ```rust use maclarian::merged::GameDataResolver; // Auto-detect game installation and query the database let resolver = GameDataResolver::auto_detect()?; if let Some(asset) = resolver.get_by_visual_name("HUM_M_ARM_Leather_A_Body") { println!("GR2: {}", asset.gr2_path); println!("Textures: {:?}", asset.textures); } ``` -------------------------------- ### Virtual texture module documentation with extraction and creation examples Source: https://docs.rs/maclarian/latest/src/maclarian/virtual_texture/mod.rs.html Module-level documentation for the virtual texture module, including extraction and creation examples. The extraction example uses VirtualTextureExtractor::extract to convert a GTP file to DDS textures. The creation example uses VirtualTextureBuilder to build a virtual texture from source DDS files. ```rust //! Virtual texture format handlers (GTS/GTP) //! //! //! //! This module provides support for BG3's virtual texture system: //! - GTS (Game Texture Set) - metadata files describing texture layouts //! - GTP (Game Texture Page) - tile data files with compressed textures //! //! # Extraction Example //! //! ```no_run //! use maclarian::virtual_texture::VirtualTextureExtractor; //! //! // Extract a GTP file to DDS textures //! VirtualTextureExtractor::extract( //! "path/to/texture.gtp", //! "output/directory", //! ).unwrap(); //! ``` //! //! # Creation Example //! //! ```no_run //! use maclarian::virtual_texture::builder::{VirtualTextureBuilder, SourceTexture}; //! //! // Create a virtual texture from source DDS files //! let result = VirtualTextureBuilder::new() //! .add_texture( //! SourceTexture::new("MyTexture") //! .with_base_map("base.dds") //! .with_normal_map("normal.dds") //! ) //! .build("output/")?; //! # Ok::<(), maclarian::error::Error>(()) //! ``` ``` -------------------------------- ### expect recommended message style example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Shows the recommended message style for `expect`, describing the reason you expect the `Result` to be `Ok`. The example reads an environment variable and panics with a message that includes the word 'should'. ```rust let path = std::env::var("IMPORTANT_PATH") .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); ``` -------------------------------- ### Get visuals for a GR2 file example Source: https://docs.rs/maclarian/latest/src/maclarian/merged/game_data.rs.html Example usage of GameDataResolver::get_visuals_for_gr2. Uses auto_detect to create a resolver and prints the count of visuals using the specified GR2 file. Returns an error if auto_detect fails. ```rust use maclarian::merged::GameDataResolver; let resolver = GameDataResolver::auto_detect()?; let visuals = resolver.get_visuals_for_gr2("HUM_M_ARM_Leather_A_Body.GR2"); println!("Found {} visuals using this GR2", visuals.len()); # Ok::<(), maclarian::error::Error>(()) ``` -------------------------------- ### map example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Shows how to apply a function to the Ok value of a Result, leaving Err untouched. The example parses each line of a string and prints the doubled number. ```rust let line = "1\n2\n3\n4\n"; for num in line.lines() { match num.parse::().map(|i| i * 2) { Ok(n) => println!("{n}"), Err(..) => {} } } ``` -------------------------------- ### Auto-detect and print game data path Source: https://docs.rs/maclarian/latest/src/maclarian/merged/game_data.rs.html Auto-detects the game installation path and prints the resolved data directory. Returns an error if no valid game installation is found. ```rust use maclarian::merged::GameDataResolver; let resolver = GameDataResolver::auto_detect()?; println!("Found game at: {}", resolver.game_data_path().display()); # Ok::<(), maclarian::error::Error>(()) ``` -------------------------------- ### Default BG3 installation paths Source: https://docs.rs/maclarian/latest/src/maclarian/cli/commands/gr2.rs.html A constant array containing common file system paths for Baldur's Gate 3 installations across macOS, Windows, and Linux. ```rust const BG3_PATHS: &[&str] = &[ // macOS "~/Library/Application Support/Steam/steamapps/common/Baldurs Gate 3/Baldur's Gate 3.app/Contents/Data", // Windows "C:/Program Files (x86)/Steam/steamapps/common/Baldurs Gate 3/Data", // Linux "~/.steam/steam/steamapps/common/Baldurs Gate 3/Data", ]; ``` -------------------------------- ### is_err_and example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Shows how to use is_err_and to check if a Result is Err and the contained error matches a predicate. Includes examples with ErrorKind and String errors. ```rust use std::io::{Error, ErrorKind}; let x: Result = Err(Error::new(ErrorKind::NotFound, "!")); assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), true); let x: Result = Err(Error::new(ErrorKind::PermissionDenied, "!")); assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false); let x: Result = Ok(123); assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false); let x: Result = Err("ownership".to_string()); assert_eq!(x.as_ref().is_err_and(|x| x.len() > 1), true); println!("still alive {:?}", x); ``` -------------------------------- ### Find BG3 installation path Source: https://docs.rs/maclarian/latest/src/maclarian/cli/commands/gr2.rs.html Iterates through predefined paths to locate a valid Baldur's Gate 3 installation directory. ```rust fn find_bg3_path() -> Option { for path in BG3_PATHS { let expanded = shellexpand::tilde(path); let path = std::path::Path::new(expanded.as_ref()); if path.exists() { return Some(path.to_path_buf()); } } None } ``` -------------------------------- ### expect panic example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Demonstrates `expect` which returns the contained `Ok` value or panics with the given message and the error content if `Err`. This example is marked with ⓘ to indicate it will panic. ```rust let x: Result = Err("emergency failure"); x.expect("Testing expect"); // panics with `Testing expect: emergency failure` ``` -------------------------------- ### Example for Result::is_ok Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Demonstrates checking if a Result is Ok. ```rust let x: Result = Ok(-3); assert_eq!(x.is_ok(), true); let x: Result = Err("Some error message"); assert_eq!(x.is_ok(), false); ``` -------------------------------- ### Get visual asset by exact name example Source: https://docs.rs/maclarian/latest/src/maclarian/merged/game_data.rs.html Example usage of GameDataResolver::get_by_visual_name. Uses auto_detect to create a resolver and prints the gr2_path of the found asset. Returns an error if auto_detect fails. ```rust use maclarian::merged::GameDataResolver; let resolver = GameDataResolver::auto_detect()?; if let Some(asset) = resolver.get_by_visual_name("HUM_M_ARM_Leather_A_Body") { println!("Found: {}", asset.gr2_path); } # Ok::<(), maclarian::error::Error>(()) ``` -------------------------------- ### Result Product Implementation Example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Shows how to calculate the product of parsed strings, returning an Err if any parsing fails. ```rust let nums = vec!["5", "10", "1", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert_eq!(total, Ok(100)); let nums = vec!["5", "10", "one", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert!(total.is_err()); ``` -------------------------------- ### ok example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Demonstrates converting a Result to an Option, returning Some(value) for Ok and None for Err. ```rust let x: Result = Ok(2); assert_eq!(x.ok(), Some(2)); let x: Result = Err("Nothing here"); assert_eq!(x.ok(), None); ``` -------------------------------- ### Merged LSX asset database module documentation Source: https://docs.rs/maclarian/latest/src/maclarian/merged/mod.rs.html Module-level documentation for the merged LSX asset database. It explains the purpose of extracting and caching GR2-to-texture mappings from BG3's `_merged.lsf` files and lists the key bank types involved. The included usage example shows how to auto-detect the game installation and query the database for a visual asset by name. ```rust //! Merged LSX asset database //! //! This module provides tools for extracting and caching GR2-to-texture mappings //! from BG3's `_merged.lsf` files. //! //! # Overview //! //! BG3 stores asset metadata in `_merged.lsf` files which contain mappings between: //! - **`VisualBank`**: GR2 mesh files with `MaterialID` references //! - **`MaterialBank`**: Materials with `Texture2DParameters` referencing textures //! - **`TextureBank`**: DDS texture file paths //! - **`VirtualTextureBank`**: `GTex` streaming texture references //! //! # Usage //! //! ```no_run //! use maclarian::merged::GameDataResolver; //! //! // Auto-detect game installation and query the database //! let resolver = GameDataResolver::auto_detect()?; //! if let Some(asset) = resolver.get_by_visual_name("HUM_M_ARM_Leather_A_Body") { //! println!("GR2: {}", asset.gr2_path); //! println!("Textures: {:?}", asset.textures); //! } //! # Ok::<(), maclarian::error::Error>(()) //! ``` ``` -------------------------------- ### Example for Result::is_ok_and Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Demonstrates checking if a Result is Ok and the value matches a predicate. ```rust let x: Result = Ok(2); assert_eq!(x.is_ok_and(|x| x > 1), true); let x: Result = Ok(0); assert_eq!(x.is_ok_and(|x| x > 1), false); let x: Result = Err("hey"); assert_eq!(x.is_ok_and(|x| x > 1), false); let x: Result = Ok("ownership".to_string()); assert_eq!(x.as_ref().is_ok_and(|x| x.len() > 1), true); println!("still alive {:?}", x); ``` -------------------------------- ### GameDataResolver::auto_detect Source: https://docs.rs/maclarian/latest/maclarian/merged/struct.GameDataResolver.html Auto-detects the game installation path by searching platform-specific Steam installation paths. Returns an error if no valid game installation is found. ```APIDOC ## GameDataResolver::auto_detect ### Description Auto-detects the game installation path by searching platform-specific Steam installation paths. ### Method `auto_detect` ### Signature ```rust pub fn auto_detect() -> Result ``` ### Platform Paths - macOS: `~/Library/Application Support/Steam/steamapps/common/Baldurs Gate 3/Baldur's Gate 3.app/Contents/Data` - Windows: `C:\Program Files (x86)\Steam\steamapps\common\Baldurs Gate 3\Data` - Linux: `~/.steam/steam/steamapps/common/Baldurs Gate 3/Data` ### Errors Returns an error if no valid game installation is found. ### Example ```rust use maclarian::merged::GameDataResolver; let resolver = GameDataResolver::auto_detect()?; println!("Found game at: {}", resolver.game_data_path().display()); ``` ``` -------------------------------- ### Auto-detect game installation path Source: https://docs.rs/maclarian/latest/maclarian/merged/struct.GameDataResolver.html Automatically locates the game installation directory based on platform-specific Steam paths. Returns an error if no valid installation is found. ```rust use maclarian::merged::GameDataResolver; let resolver = GameDataResolver::auto_detect()?; println!("Found game at: {}", resolver.game_data_path().display()); ``` -------------------------------- ### as_ref example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Shows how to convert a Result to a Result of references, allowing inspection without consuming the original. ```rust let x: Result = Ok(2); assert_eq!(x.as_ref(), Ok(&2)); let x: Result = Err("Error"); assert_eq!(x.as_ref(), Err(&"Error")); ``` -------------------------------- ### FourCCNode::guid Source: https://docs.rs/maclarian/latest/src/maclarian/virtual_texture/writer/fourcc.rs.html Creates a new GUID node with the given FourCC code and 16-byte GUID. ```APIDOC ## FourCCNode::guid ### Description Creates a new GUID node with the given FourCC code and 16-byte GUID. ### Method `pub fn guid(fourcc: [u8; 4], guid: [u8; 16]) -> Self` n ### Parameters - **fourcc** (`[ u8; 4]`) - Required - The FourCC code for the GUID node. - **guid** (`[ u8; 16]`) - Required - The 16-byte GUID value. ### Returns - `FourCCNode` - A new GUID node. ### Example ```rust let node = FourCCNode::guid(*b"GUID", [0; 16]); n``` ``` -------------------------------- ### Rust: Example of from_pak_with_progress and related methods (source excerpt) Source: https://docs.rs/maclarian/latest/src/maclarian/merged/resolver.rs.html This snippet contains a larger excerpt that includes from_pak and from_pak_with_progress as shown in the source. It also shows the internal parse_lsx_file method. ```rust pub fn from_pak>(pak_path: P) -> Result { Self::from_pak_with_progress(pak_path, &|_| {}) } ``` ```rust pub fn from_pak_with_progress>( pak_path: P, progress: MergedProgressCallback, ) -> Result { let pak_path = pak_path.as_ref(); tracing::info!("Building merged database from pak: {}", pak_path.display()); progress(&MergedProgress::with_file( MergedPhase::ScanningFiles, 0, 1, "Listing PAK contents", )); let all_files = PakOperations::list(pak_path)?; let merged_paths: Vec<_> = all_files .iter() .filter(|p| p.ends_with("_merged.lsf")) .collect(); if merged_paths.is_empty() { return Err(Error::FileNotFoundInPak( "No _merged.lsf files found in pak".to_string(), )); } let total = merged_paths.len(); tracing::info!("Found {} _merged.lsf files in pak", total); progress(&MergedProgress::with_file( MergedPhase::ExtractingFiles, 0, total, "Extracting files from PAK", )); let temp_dir = TempDir::new()?; let merged_strs: Vec<&str> = merged_paths.iter().map(|s| s.as_str()).collect(); PakOperations::extract_files(pak_path, temp_dir.path(), &merged_strs)?; let mut combined_db = MergedDatabase::new(pak_path.to_string_lossy()); for (i, merged_rel_path) in merged_paths.iter().enumerate() { let filename = std::path::Path::new(merged_rel_path) .file_name() .unwrap_or_default() .to_string_lossy() .to_string(); progress(&MergedProgress::with_file( MergedPhase::ParsingLsf, i + 1, total, &filename, )); let lsf_path = temp_dir.path().join(merged_rel_path); if !lsf_path.exists() { tracing::warn!("Extracted file not found: {}", lsf_path.display()); continue; } let lsx_path = lsf_path.with_extension("lsx"); tracing::debug!( "Converting {} -> {}", lsf_path.display(), lsx_path.display() ); convert_lsf_to_lsx(&lsf_path, &lsx_path)?; let db = Self::parse_lsx_file(&lsx_path)?; merge_databases(&mut combined_db, db); } progress(&MergedProgress::with_file( MergedPhase::ResolvingReferences, total, total, "Resolving texture references", )); resolve_references(&mut combined_db); log_stats(&combined_db); progress(&MergedProgress::new(MergedPhase::Complete, total, total)); Ok(Self { database: combined_db, }) } ``` ```rust pub fn from_lsx>(lsx_path: P) -> Result { let lsx_path = lsx_path.as_ref(); tracing::info!("Building merged database from LSX: {}", lsx_path.display()); let mut database = Self::parse_lsx_file(lsx_path)?; resolve_references(&mut database); log_stats(&database); Ok(Self { database }) } ``` -------------------------------- ### create_with_compression_and_progress Source: https://docs.rs/maclarian/latest/maclarian/pak/pak_tools/struct.PakOperations.html Creates a PAK file from a directory with compression and a progress callback. Returns an error if the source directory cannot be read, the output file cannot be written, directory traversal fails, or file compression fails. ```APIDOC ## create_with_compression_and_progress ### Description Creates a PAK file from a directory with compression and progress callback. ### Method pub fn create_with_compression_and_progress>(source_dir: P, output_pak: P, compression: CompressionMethod, progress: ProgressCallback<'_>) -> Result<()> ### Parameters - **source_dir** (P) - Required - Directory containing files to pack. - **output_pak** (P) - Required - Path to the output PAK file. - **compression** (CompressionMethod) - Required - Compression method to use. - **progress** (ProgressCallback<'_>) - Required - Callback for progress updates. ### Errors - Returns `Error::Io` if the source directory cannot be read or output file cannot be written. - Returns `Error::WalkDirError` if directory traversal fails. - Returns `Error::CompressionError` if file compression fails. ``` -------------------------------- ### TileSetConfiguration::new Source: https://docs.rs/maclarian/latest/maclarian/virtual_texture/builder/config/struct.TileSetConfiguration.html Creates a new TileSetConfiguration with default BG3 settings. ```APIDOC ## TileSetConfiguration::new ### Description Creates a new TileSetConfiguration with default BG3 settings. ### Method pub fn new() -> Self ### Parameters None ### Returns - Self - A new TileSetConfiguration instance with default values. ``` -------------------------------- ### Create output directory and convert GR2 to GLB Source: https://docs.rs/maclarian/latest/src/maclarian/gr2_extraction/mod.rs.html Creates the output directory if it doesn't exist, then converts the GR2 file to GLB if requested. Errors are mapped to ConversionError, and conversion failures are recorded as warnings. ```rust // Create output directory if it doesn't exist std::fs::create_dir_all(output_dir) .map_err(|e| Error::ConversionError(format!("Failed to create output directory: {e}")))?; // Step 1: Convert GR2 to GLB (if requested) if options.convert_to_glb { let glb_name = gr2_path.file_stem().unwrap_or_default(); let glb_path = output_dir.join(format!("{}.glb", glb_name.to_string_lossy())); match convert_gr2_to_glb(gr2_path, &glb_path) { Ok(()) => { result.glb_path = Some(glb_path); } Err(e) => { result .warnings .push(format!("Failed to convert to GLB: {e}")); } } } ``` -------------------------------- ### BG3 Installation Path Validation Source: https://docs.rs/maclarian/latest/src/maclarian/cli/commands/pak.rs.html Checks if a given path resides within a known Baldur's Gate 3 installation directory and warns the user if it does. ```rust fn is_bg3_install_path(path: &Path) -> bool { let path_str = path.to_string_lossy(); for bg3_path in BG3_PATHS { let expanded = shellexpand::tilde(bg3_path); if path_str.starts_with(expanded.as_ref()) { return true; } } false } /// Warn if destination is within BG3 install path fn warn_if_bg3_path(destination: &Path) { if is_bg3_install_path(destination) { eprintln!("WARNING: Destination is within BG3 installation directory!"); eprintln!(" This may corrupt your game installation."); eprintln!(" Path: {}", destination.display()); eprintln!(); } } ``` -------------------------------- ### Using the Prelude for Common Imports Source: https://docs.rs/maclarian/latest/index.html Shows how to import commonly used types via maclarian::prelude::*, including PakOperations, LsfDocument, LsxDocument, LsjDocument, VirtualTextureExtractor, GtsFile, GtpFile, Error, and Result. ```rust use maclarian::prelude::*; // Now you have access to: // - PakOperations, LsfDocument, LsxDocument, LsjDocument // - VirtualTextureExtractor, GtsFile, GtpFile // - Error, Result, and more ``` -------------------------------- ### create Source: https://docs.rs/maclarian/latest/src/maclarian/pak/pak_tools/operations.rs.html Creates a PAK file from a source directory. This is a convenience wrapper that calls create_with_progress with a no-op progress callback. ```APIDOC ## create ### Description Creates a PAK file from a source directory. This is a convenience wrapper that calls create_with_progress with a no-op progress callback. ### Method create ### Signature pub fn create>(source_dir: P, output_pak: P) -> Result<()> ### Parameters - **source_dir** (P) - Required - The source directory to read files from. - **output_pak** (P) - Required - The output PAK file path to write to. ### Return Value - **Result<()>** - Ok(()) on success, or an Error variant. ### Errors - Returns Error::Io if the source directory cannot be read or output file cannot be written. - Returns Error::WalkDirError if directory traversal fails. - Returns Error::CompressionError if file compression fails. ``` -------------------------------- ### Implement image, texture, and material methods for GltfBuilder Source: https://docs.rs/maclarian/latest/src/maclarian/converter/gr2_gltf/to_gltf/gltf/builder/material_methods.rs.html Provides methods: `add_embedded_image` (aligns buffer to 4 bytes, stores PNG bytes in a new buffer view, registers a glTF image), `add_sampler` (adds a default `GltfSampler`), `add_texture` (creates a texture referencing an image and optional sampler), `add_material` (builds `GltfPbrMetallicRoughness` with texture info and constructs a `GltfMaterial`), and `add_image_as_texture` (convenience wrapper that reuses sampler 0 or creates one if empty). All methods return the index of the created entity in their respective internal lists. ```Rust 1//! Image, texture, and material methods for `GltfBuilder` 2 3use super::super::materials::{ 4 GltfImage, GltfMaterial, GltfNormalTextureInfo, GltfOcclusionTextureInfo, 5 GltfPbrMetallicRoughness, GltfSampler, GltfTexture, GltfTextureInfo, 6}; 7use super::super::types::GltfBufferView; 8use super::GltfBuilder; 9 10impl GltfBuilder { 11 /// Add an embedded image (PNG bytes) to the GLB. 12 /// Returns the image index. 13 pub fn add_embedded_image(&mut self, png_data: &[u8], name: Option) -> usize { 14 // Align to 4 for consistency (not necessary but it's whatev) 15 self.align(4); 16 let byte_offset = self.buffer.len(); 17 self.buffer.extend_from_slice(png_data); 18 19 let bv_idx = self.buffer_views.len(); 20 self.buffer_views.push(GltfBufferView { 21 buffer: 0, 22 byte_offset, 23 byte_length: png_data.len(), 24 target: None, // No target for images 25 }); 26 27 let img_idx = self.images.len(); 28 self.images.push(GltfImage { 29 buffer_view: bv_idx, 30 mime_type: "image/png".to_string(), 31 name, 32 }); 33 34 img_idx 35 } 36 37 /// Add a texture sampler with default settings (linear filtering, repeat wrap). 38 /// Returns the sampler index. 39 pub fn add_sampler(&mut self) -> usize { 40 let sampler_idx = self.samplers.len(); 41 self.samplers.push(GltfSampler::default()); 42 sampler_idx 43 } 44 45 /// Add a texture referencing an image and optionally a sampler. 46 /// Returns the texture index. 47 pub fn add_texture( 48 &mut self, 49 image_index: usize, 50 sampler_index: Option, 51 name: Option, 52 ) -> usize { 53 let tex_idx = self.textures.len(); 54 self.textures.push(GltfTexture { 55 source: image_index, 56 sampler: sampler_index, 57 name, 58 }); 59 tex_idx 60 } 61 62 /// Add a PBR material with optional textures. 63 /// 64 /// # Arguments 65 /// * `name` - Optional material name 66 /// * `base_color_texture` - Albedo/diffuse texture index 67 /// * `normal_texture` - Normal map texture index 68 /// * `metallic_roughness_texture` - Metallic-roughness texture index 69 /// * `occlusion_texture` - Ambient occlusion texture index 70 /// 71 /// Returns the material index. 72 pub fn add_material( 73 &mut self, 74 name: Option, 75 base_color_texture: Option, 76 normal_texture: Option, 77 metallic_roughness_texture: Option, 78 occlusion_texture: Option, 79 ) -> usize { 80 let pbr = GltfPbrMetallicRoughness { 81 base_color_factor: Some([1.0, 1.0, 1.0, 1.0]), 82 base_color_texture: base_color_texture.map(|idx| GltfTextureInfo { 83 index: idx, 84 tex_coord: None, 85 }), 86 metallic_factor: Some(1.0), 87 roughness_factor: Some(1.0), 88 metallic_roughness_texture: metallic_roughness_texture.map(|idx| GltfTextureInfo { 89 index: idx, 90 tex_coord: None, 91 }), 92 }; 93 94 let mat_idx = self.materials.len(); 95 self.materials.push(GltfMaterial { 96 name, 97 pbr_metallic_roughness: Some(pbr), 98 normal_texture: normal_texture.map(|idx| GltfNormalTextureInfo { 99 index: idx, 100 scale: Some(1.0), 101 tex_coord: None, 102 }), 103 occlusion_texture: occlusion_texture.map(|idx| GltfOcclusionTextureInfo { 104 index: idx, 105 strength: Some(1.0), 106 tex_coord: None, 107 }), 108 emissive_texture: None, 109 emissive_factor: None, 110 alpha_mode: None, 111 alpha_cutoff: None, 112 double_sided: None, 113 }); 114 115 mat_idx 116 } 117 118 /// Convenience method to add an image, create a texture for it, and return the texture index. 119 /// Also creates a default sampler if none exists. 120 pub fn add_image_as_texture(&mut self, png_data: &[u8], name: Option) -> usize { 121 // Ensure there's at least one sampler 122 let sampler_idx = if self.samplers.is_empty() { 123 Some(self.add_sampler()) 124 } else { 125 Some(0) 126 }; 127 128 let image_idx = self.add_embedded_image(png_data, name.clone()); 129 self.add_texture(image_idx, sampler_idx, name) 130 } 131} ``` -------------------------------- ### Create PAK file from directory Source: https://docs.rs/maclarian/latest/src/maclarian/cli/commands/pak.rs.html The create function handles glob expansion, validates the mod structure for a meta.lsx file, and initiates PAK creation with the specified compression method. It supports progress bars when quiet mode is disabled. ```rust pub fn create( sources: &[PathBuf], destination: &Path, compression: &str, quiet: bool, ) -> anyhow::Result<()> { // Expand glob patterns let sources = expand_globs(sources)?; // Warn if destination is BG3 install path warn_if_bg3_path(destination); let method = match compression.to_lowercase().as_str() { "lz4" => CompressionMethod::Lz4, "zlib" => CompressionMethod::Zlib, "none" => CompressionMethod::None, other => { anyhow::bail!("Unknown compression method: '{other}'. Valid options: lz4, zlib, none"); } }; // Handle multiple sources (batch creation) if sources.len() > 1 { return create_batch(&sources, destination, method, quiet); } let source = &sources[0]; // Validate mod structure (checks for meta.lsx) let validation = validate_mod_structure(source); if !validation.valid { anyhow::bail!( "No meta.lsx found in '{}'. Use 'maclarian mods meta' to generate one first.", source.display() ); } // For single source, destination is the PAK filename println!( "Creating PAK from {} to {} (compression: {:?})", source.display(), destination.display(), method ); let dest = destination.to_path_buf(); if !quiet { let pb = simple_bar(100, "Creating PAK"); PakOperations::create_with_compression_and_progress(source, &dest, method, &|p| { pb.set_position((p.percentage() * 100.0) as u64); if let Some(ref file) = p.current_file { pb.set_message(file.clone()); } })?; pb.finish_and_clear(); } else { PakOperations::create_with_compression(source, &dest, method)?; } println!("PAK created successfully"); Ok(()) } ``` -------------------------------- ### as_deref example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Demonstrates `as_deref` to convert `Result` to `Result<&::Target, &E>` by dereferencing the `Ok` variant. The example asserts equality for both `Ok` and `Err` cases. ```rust let x: Result = Ok("hello".to_string()); let y: Result<&str, &u32> = Ok("hello"); assert_eq!(x.as_deref(), y); let x: Result = Err(42); let y: Result<&str, &u32> = Err(&42); assert_eq!(x.as_deref(), y); ``` -------------------------------- ### print_step example usage Source: https://docs.rs/maclarian/latest/src/maclarian/cli/progress.rs.html Shows how to print step indicators with emoji and message. The function prints a formatted line like `[1/3] 🔍 Reading PAK header...`. ```rust print_step(1, 3, LOOKING_GLASS, "Reading PAK header..."); print_step(2, 3, PACKAGE, "Extracting files..."); print_step(3, 3, DISK, "Writing files..."); ``` -------------------------------- ### inspect_err example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Shows `inspect_err` to call a closure with a reference to the error when the `Result` is `Err`, returning the original result. The example reads a file and prints an error message to stderr on failure. ```rust use std::{fs, io}; fn read() -> io::Result { fs::read_to_string("address.txt") .inspect_err(|e| eprintln!("failed to read file: {e}")) } ``` -------------------------------- ### iter example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Demonstrates `iter` to create an iterator over the possibly contained value, yielding one value if `Ok` and none if `Err`. The example asserts the iterator's next value for both cases. ```rust let x: Result = Ok(7); assert_eq!(x.iter().next(), Some(&7)); let x: Result = Err("nothing!"); assert_eq!(x.iter().next(), None); ``` -------------------------------- ### create Source: https://docs.rs/maclarian/latest/maclarian/pak/pak_tools/struct.PakOperations.html Creates a PAK file from a directory. Returns an error if the source directory cannot be read, the output file cannot be written, directory traversal fails, or file compression fails. ```APIDOC ## create ### Description Creates a PAK file from a directory. ### Method pub fn create>(source_dir: P, output_pak: P) -> Result<()> ### Parameters - **source_dir** (P) - Required - Directory containing files to pack. - **output_pak** (P) - Required - Path to the output PAK file. ### Errors - Returns `Error::Io` if the source directory cannot be read or output file cannot be written. - Returns `Error::WalkDirError` if directory traversal fails. - Returns `Error::CompressionError` if file compression fails. ``` -------------------------------- ### as_deref_mut example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Shows `as_deref_mut` to convert `Result` to `Result<&mut ::Target, &mut E>` and mutate the `Ok` value in place. The example uses `make_ascii_uppercase` and asserts equality for both `Ok` and `Err` cases. ```rust let mut s = "HELLO".to_string(); let mut x: Result = Ok("hello".to_string()); let y: Result<&mut str, &mut u32> = Ok(&mut s); assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); let mut i = 42; let mut x: Result = Err(42); let y: Result<&mut str, &mut u32> = Err(&mut i); assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); ``` -------------------------------- ### create_with_progress Source: https://docs.rs/maclarian/latest/maclarian/pak/pak_tools/struct.PakOperations.html Creates a PAK file from a directory with a progress callback. Returns an error if the source directory cannot be read, the output file cannot be written, directory traversal fails, or file compression fails. ```APIDOC ## create_with_progress ### Description Creates a PAK file from a directory with progress callback. ### Method pub fn create_with_progress>(source_dir: P, output_pak: P, progress: ProgressCallback<'_>) -> Result<()> ### Parameters - **source_dir** (P) - Required - Directory containing files to pack. - **output_pak** (P) - Required - Path to the output PAK file. - **progress** (ProgressCallback<'_>) - Required - Callback for progress updates. ### Errors - Returns `Error::Io` if the source directory cannot be read or output file cannot be written. - Returns `Error::WalkDirError` if directory traversal fails. - Returns `Error::CompressionError` if file compression fails. ``` -------------------------------- ### virtual_texture::gtp_info Source: https://docs.rs/maclarian/latest/maclarian/all.html Gets GTP information. ```APIDOC ## virtual_texture::gtp_info ### Description Gets GTP information. ### Function virtual_texture::gtp_info ``` -------------------------------- ### create_with_compression Source: https://docs.rs/maclarian/latest/src/maclarian/pak/pak_tools/operations.rs.html Creates a PAK file from a directory with a specified compression method. This is a convenience wrapper that calls create_with_compression_and_progress with a no-op progress callback. ```APIDOC ## create_with_compression ### Description Creates a PAK file from a directory with a specified compression method. This is a convenience wrapper that calls create_with_compression_and_progress with a no-op progress callback. ### Method create_with_compression ### Signature pub fn create_with_compression>(source_dir: P, output_pak: P, compression: CompressionMethod) -> Result<()> ### Parameters - **source_dir** (P) - Required - The source directory to read files from. - **output_pak** (P) - Required - The output PAK file path to write to. - **compression** (CompressionMethod) - Required - The compression method to use. ### Return Value - **Result<()>** - Ok(()) on success, or an Error variant. ### Errors - Returns Error::Io if the source directory cannot be read or output file cannot be written. - Returns Error::WalkDirError if directory traversal fails. - Returns Error::CompressionError if file compression fails. ``` -------------------------------- ### create_with_compression Source: https://docs.rs/maclarian/latest/maclarian/pak/pak_tools/struct.PakOperations.html Creates a PAK file from a directory with a specified compression method. Returns an error if the source directory cannot be read, the output file cannot be written, directory traversal fails, or file compression fails. ```APIDOC ## create_with_compression ### Description Creates a PAK file from a directory with specified compression. ### Method pub fn create_with_compression>(source_dir: P, output_pak: P, compression: CompressionMethod) -> Result<()> ### Parameters - **source_dir** (P) - Required - Directory containing files to pack. - **output_pak** (P) - Required - Path to the output PAK file. - **compression** (CompressionMethod) - Required - Compression method to use. ### Errors - Returns `Error::Io` if the source directory cannot be read or output file cannot be written. - Returns `Error::WalkDirError` if directory traversal fails. - Returns `Error::CompressionError` if file compression fails. ``` -------------------------------- ### MergedResolver::stats Source: https://docs.rs/maclarian/latest/maclarian/merged/struct.MergedResolver.html Gets database statistics. ```APIDOC ## MergedResolver::stats ### Description Gets database statistics. ### Method Query ### Signature pub fn stats(&self) -> DatabaseStats ### Returns DatabaseStats - Statistics about the database. ``` -------------------------------- ### LsfDocument::node_name Source: https://docs.rs/maclarian/latest/maclarian/formats/lsf/struct.LsfDocument.html Get the name of a node. ```APIDOC ## LsfDocument::node_name ### Description Retrieves the name of a node specified by its index. ### Method ```rust pub fn node_name(&self, node_idx: usize) -> Option<&str> ``` ### Parameters - **node_idx** (usize) - Required - The index of the node. ### Response - Returns `Option<&str>` - The node's name, or `None` if the index is invalid. ``` -------------------------------- ### Discover Virtual Textures Entry Point Source: https://docs.rs/maclarian/latest/src/maclarian/virtual_texture/mod_config/discovery.rs.html Public function to initiate the discovery of virtual textures across specified search paths. ```rust /// Discover virtual textures across multiple search paths /// /// Scans each path for mod directories or PAK files containing virtual texture configs. /// If a path is a .pak file, it will be scanned for VTexConfig.xml/VirtualTextures.json. /// If a path is itself a mod root, it will be scanned directly. /// If a path contains multiple mod subdirectories, each will be scanned. /// /// # Arguments /// * `search_paths` - Paths to scan (can be mod roots, directories containing mods, or .pak files) /// /// # Errors /// Returns an error if directory traversal fails or PAK files cannot be read. pub fn discover_virtual_textures( search_paths: &[PathBuf], ``` -------------------------------- ### iter_mut example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Shows `iter_mut` to create a mutable iterator over the possibly contained value, allowing modification of the `Ok` value. The example mutates the value to 40 and asserts the result, and also checks the `Err` case yields `None`. ```rust let mut x: Result = Ok(7); match x.iter_mut().next() { Some(v) => *v = 40, None => {}, } assert_eq!(x, Ok(40)); let mut x: Result = Err("nothing!"); assert_eq!(x.iter_mut().next(), None); ``` -------------------------------- ### as_mut example Source: https://docs.rs/maclarian/latest/maclarian/error/type.Result.html Demonstrates converting a mutable reference to a Result to a Result of mutable references, allowing mutation of the contained value. ```rust fn mutate(r: &mut Result) { match r.as_mut() { Ok(v) => *v = 42, Err(e) => *e = 0, } } let mut x: Result = Ok(2); mutate(&mut x); assert_eq!(x.unwrap(), 42); let mut x: Result = Err(13); mutate(&mut x); assert_eq!(x.unwrap_err(), 0); ```