diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-09 01:39:05 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-09 01:39:54 +0800 |
| commit | 2a6320e39485fb494b827d14d9e76895fa4f58b2 (patch) | |
| tree | b3ea4fda9c3349f4c590e297dde2d19688991549 /tools/tscn-to-bsn/src/cmd/cmd_build_cache.rs | |
| parent | 85bca704b6c807b14df4ad6d71f70ae961290495 (diff) | |
Diffstat (limited to 'tools/tscn-to-bsn/src/cmd/cmd_build_cache.rs')
| -rw-r--r-- | tools/tscn-to-bsn/src/cmd/cmd_build_cache.rs | 185 |
1 files changed, 0 insertions, 185 deletions
diff --git a/tools/tscn-to-bsn/src/cmd/cmd_build_cache.rs b/tools/tscn-to-bsn/src/cmd/cmd_build_cache.rs deleted file mode 100644 index 660caf1..0000000 --- a/tools/tscn-to-bsn/src/cmd/cmd_build_cache.rs +++ /dev/null @@ -1,185 +0,0 @@ -use std::collections::BTreeMap; -use std::io; -use std::path::{Path, PathBuf}; - -use mingling::macros::routeify; -use mingling::{ - Grouped, - macros::{buffer, command, pack_err, r_println, renderer}, -}; - -use crate::{ - Next, - gd_res_structure::{TscnValue, parse}, - res::gd_proj_dir::ResGodotProjectDirectory, -}; - -pack_err!(ErrorGodotProjectNotFound); - -/// Build result -#[derive(Grouped)] -pub struct ResultCacheBuilt { - path: PathBuf, - len: usize, -} - -#[command(node = "build-cache", routeify)] -pub fn build_cache(proj: &ResGodotProjectDirectory) -> Next { - let Some(ref dir) = proj.dir else { - return ErrorGodotProjectNotFound::default().into(); - }; - - // 1. Scan uid → res:// paths - let map = scan_project(dir)?; - - // 2. Write .godot/tscn2bsn.cache.json - let cache_path = dir.join(".godot").join("tscn2bsn.cache.json"); - if let Some(parent) = cache_path.parent() { - std::fs::create_dir_all(parent)?; - } - let json = serde_json::to_string_pretty(&map)?; - std::fs::write(&cache_path, json)?; - - ResultCacheBuilt { - path: cache_path, - len: map.len(), - } - .into() -} - -/// Recursively collect all files in the project, skipping `.godot` / `.git` -fn collect_files(dir: &Path, out: &mut Vec<PathBuf>) -> io::Result<()> { - for entry in std::fs::read_dir(dir)? { - let entry = entry?; - let path = entry.path(); - if path.is_dir() { - let name = entry.file_name().to_string_lossy().into_owned(); - if name == ".godot" || name == ".git" { - continue; - } - collect_files(&path, out)?; - } else if path.is_file() { - out.push(path); - } - } - Ok(()) -} - -/// Project relative path → `res://` form (Godot's standard in-project path) -fn to_res_path(project_dir: &Path, file: &Path) -> String { - let rel = file.strip_prefix(project_dir).unwrap_or(file); - let rel = rel.to_string_lossy().replace('\\', "/"); - format!("res://{rel}") -} - -/// Scan all uid sources, aggregate the mapping -fn scan_project(project_dir: &Path) -> io::Result<BTreeMap<String, String>> { - let mut files = Vec::new(); - collect_files(project_dir, &mut files)?; - - let mut map = BTreeMap::new(); - for file in files { - let ext = file - .extension() - .and_then(|e| e.to_str()) - .unwrap_or("") - .to_lowercase(); - match ext.as_str() { - // scenes/foo.glb.import → resource path res://scenes/foo.glb - "import" => { - if let Some(uid) = parse_import_uid(&file) { - let res_path = to_res_path(project_dir, &file); - insert_unique( - &mut map, - uid, - res_path.trim_end_matches(".import").to_string(), - ); - } - } - "tscn" | "tres" => { - if let Some(uid) = parse_scene_uid(&file) { - insert_unique(&mut map, uid, to_res_path(project_dir, &file)); - } - } - // foo.gd.uid → resource path res://foo.gd - "uid" => { - if let Some(uid) = parse_sidecar_uid(&file) { - let res_path = to_res_path(project_dir, &file); - insert_unique(&mut map, uid, res_path.trim_end_matches(".uid").to_string()); - } - } - _ => {} - } - } - Ok(map) -} - -fn insert_unique(map: &mut BTreeMap<String, String>, uid: String, res_path: String) { - match map.entry(uid.clone()) { - std::collections::btree_map::Entry::Vacant(v) => { - v.insert(res_path); - } - std::collections::btree_map::Entry::Occupied(o) => { - eprintln!("Warning: duplicate uid {uid}: {} vs {res_path}", o.get()); - } - } -} - -/// `.import` file: `uid="uid://..."` in the `[remap]` section (writer: editor_file_system.cpp L2693) -fn parse_import_uid(file: &Path) -> Option<String> { - let content = std::fs::read_to_string(file).ok()?; - let mut in_remap = false; - for line in content.lines() { - let line = line.trim(); - if line.starts_with('[') { - in_remap = line == "[remap]"; - continue; - } - if in_remap && let Some(v) = line.strip_prefix("uid=") { - let uid = v.trim().trim_matches('"'); - if uid.starts_with("uid://") { - return Some(uid.to_string()); - } - } - } - None -} - -/// `.tscn` / `.tres`: reuse the tscn parser, extract the `uid` field from the header tag -fn parse_scene_uid(file: &Path) -> Option<String> { - let content = std::fs::read_to_string(file).ok()?; - let doc = parse(&content).ok()?; - for (key, value) in &doc.header.fields { - if key == "uid" - && let TscnValue::Str(s) = value - { - return Some(s.clone()); - } - } - None -} - -/// `.uid` sidecar file: the first line is `uid://...` (writer: editor_file_system.cpp L939) -fn parse_sidecar_uid(file: &Path) -> Option<String> { - let content = std::fs::read_to_string(file).ok()?; - let first = content.lines().next()?.trim(); - if first.starts_with("uid://") { - Some(first.to_string()) - } else { - None - } -} - -#[renderer(buffer)] -pub fn render_cache_built(r: ResultCacheBuilt) { - r_println!("OK: wrote {} ({} uids)", r.path.display(), r.len); -} - -#[renderer(buffer)] -pub fn render_error_godot_project_not_found(_: ErrorGodotProjectNotFound) { - r_println!("Error: Godot project not found. "); - r_println!(""); - r_println!( - "Please specify the project directory with `/P` or run this command in the project directory!" - ) -} |
