#![allow(clippy::unwrap_used, clippy::expect_used, clippy::too_many_lines)] use std::env; use std::fmt::Write; use std::fs; use std::path::Path; fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("template_embeddings.rs"); let mut code = String::from( " #[allow(clippy::too_many_lines)] #[allow(clippy::match_same_arms)] #[allow(clippy::missing_const_for_fn)] #[allow(clippy::match_single_binding)] #[must_use] pub fn get_template_bytes(path: &str) -> Option<&'static [u8]> {\n match path {\n", ); let mut pool_code = String::from( " #[allow(clippy::too_many_lines)] #[allow(clippy::match_same_arms)] #[allow(clippy::missing_const_for_fn)] #[allow(clippy::match_single_binding)] #[must_use] pub fn get_pool_elements(pool_id: &str) -> Option<&'static [&'static str]> {\n match pool_id {\n", ); let mut template_pool_json_code = String::from( " #[allow(clippy::too_many_lines)] #[allow(clippy::match_same_arms)] #[allow(clippy::missing_const_for_fn)] #[allow(clippy::match_single_binding)] #[must_use] pub fn get_template_pool_json(path: &str) -> Option<&'static str> {\n match path {\n", ); let mut processor_list_json_code = String::from( " #[allow(clippy::too_many_lines)] #[allow(clippy::match_same_arms)] #[allow(clippy::missing_const_for_fn)] #[allow(clippy::match_single_binding)] #[must_use] pub fn get_processor_list_json(path: &str) -> Option<&'static str> {\n match path {\n", ); let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let datapack_dir = Path::new(&manifest_dir).join("../../assets/datapacks/26_2/data/minecraft"); let structures_dir = datapack_dir.join("structure"); let mut all_template_names: Vec = Vec::new(); let mut all_pool_names: Vec = Vec::new(); if structures_dir.exists() { let mut pools = std::collections::BTreeMap::new(); process_dir( &structures_dir, "", &mut code, &mut pools, &mut all_template_names, ); for (pool_id, elements) in pools { all_pool_names.push(pool_id.clone()); let _ = writeln!( pool_code, " \"minecraft:{pool_id}\" | \"{pool_id}\" => Some(&[" ); for element in elements { let _ = writeln!(pool_code, " \"{element}\","); } pool_code.push_str(" ]),\n"); } } code.push_str(" _ => None,\n"); code.push_str(" }\n}\n"); // Generate a function returning all available template names (for tab-completion) code.push_str( "#[must_use]\n#[allow(clippy::too_many_lines, clippy::large_stack_arrays)]\npub const fn _generated_all_template_names() -> &'static [&'static str] {\n &[\n", ); for name in &all_template_names { let _ = writeln!(code, " \"{name}\","); } code.push_str(" ]\n}\n"); // Generate a function returning all available pool names (for tab-completion) code.push_str( "#[must_use]\n#[allow(clippy::too_many_lines, clippy::large_stack_arrays)]\npub const fn _generated_all_pool_names() -> &'static [&'static str] {\n &[\n", ); for name in &all_pool_names { let _ = writeln!(code, " \"{name}\","); } code.push_str(" ]\n}\n"); pool_code.push_str(" _ => None,\n"); pool_code.push_str(" }\n}\n"); let worldgen_dir = datapack_dir.join("worldgen"); process_json_dir( &worldgen_dir.join("template_pool"), "", &mut template_pool_json_code, &mut all_pool_names, ); process_json_dir( &worldgen_dir.join("processor_list"), "", &mut processor_list_json_code, &mut Vec::new(), ); template_pool_json_code.push_str(" _ => None,\n"); template_pool_json_code.push_str(" }\n}\n"); processor_list_json_code.push_str(" _ => None,\n"); processor_list_json_code.push_str(" }\n}\n"); fs::write( &dest_path, format!("{code}\n{pool_code}\n{template_pool_json_code}\n{processor_list_json_code}"), ) .unwrap(); println!("cargo:rerun-if-changed=../../assets/datapacks/26_2/data/minecraft/structure"); println!( "cargo:rerun-if-changed=../../assets/datapacks/26_2/data/minecraft/worldgen/template_pool" ); println!( "cargo:rerun-if-changed=../../assets/datapacks/26_2/data/minecraft/worldgen/processor_list" ); } fn process_dir( dir: &Path, prefix: &str, code: &mut String, pools: &mut std::collections::BTreeMap>, names: &mut Vec, ) { let mut entries = fs::read_dir(dir) .unwrap() .map(Result::unwrap) .collect::>(); entries.sort_by_key(std::fs::DirEntry::file_name); for entry in entries { let path = entry.path(); let name = entry.file_name().into_string().unwrap(); if path.is_dir() { let new_prefix = if prefix.is_empty() { name } else { format!("{prefix}/{name}") }; process_dir(&path, &new_prefix, code, pools, names); } else if path .extension() .and_then(|s| s.to_str()) .is_some_and(|ext| ext.eq_ignore_ascii_case("nbt")) { let stem = path.file_stem().unwrap().to_string_lossy(); let template_name = if prefix.is_empty() { stem.to_string() } else { format!("{prefix}/{stem}") }; let abs_path = path.canonicalize().unwrap(); let _ = writeln!( code, " \"{template_name}\" => Some(include_bytes!(r#\"{abs}\"#)),", template_name = template_name, abs = abs_path.display() ); names.push(template_name.clone()); if !prefix.is_empty() { pools .entry(prefix.to_string()) .or_default() .push(template_name); } } } } fn process_json_dir(dir: &Path, prefix: &str, code: &mut String, names: &mut Vec) { if !dir.exists() { return; } let mut entries = fs::read_dir(dir) .unwrap() .map(Result::unwrap) .collect::>(); entries.sort_by_key(std::fs::DirEntry::file_name); for entry in entries { let path = entry.path(); let name = entry.file_name().into_string().unwrap(); if path.is_dir() { let new_prefix = if prefix.is_empty() { name } else { format!("{prefix}/{name}") }; process_json_dir(&path, &new_prefix, code, names); } else if let Some(stem) = name.strip_suffix(".json") { let id = if prefix.is_empty() { stem.to_string() } else { format!("{prefix}/{stem}") }; names.push(id.clone()); let abs_path = path.canonicalize().unwrap(); let _ = writeln!( code, " \"minecraft:{id}\" | \"{id}\" => Some(include_str!(r#\"{abs}\"#)),", id = id, abs = abs_path.display() ); } } }