diff --git a/backend/src/main.rs b/backend/src/main.rs index 80435f7..a8418d3 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -29,6 +29,8 @@ struct AppState { battles_db: PathBuf, teams_db: PathBuf, leaderboard_cache: Mutex>, + vehicle_names: HashMap>, + vehicle_icons: HashMap, } struct CachedLeaderboard { @@ -317,7 +319,20 @@ async fn main() -> Result<(), Box> { battles_db: resolve_db_path("TSS_BATTLES_DB", "tss_battles.db"), teams_db: resolve_db_path("TSS_TEAMS_DB", "tss_teams.db"), leaderboard_cache: Mutex::new(None), + vehicle_names: load_vehicle_names(&resolve_db_path( + "VEHICLE_TRANSLATIONS_JSON", + "vehicle_translations.json", + )), + vehicle_icons: load_vehicle_icons(&resolve_db_path( + "VEHICLE_DATA_CACHE_JSON", + "vehicle_data_cache_all.json", + )), }); + tracing::info!( + "loaded {} vehicle name maps, {} vehicle icons", + state.vehicle_names.len(), + state.vehicle_icons.len() + ); spawn_leaderboard_refresh(state.clone()); let app = Router::new() @@ -1621,6 +1636,54 @@ fn allowed_origins() -> AllowOrigin { } } +fn load_vehicle_names(path: &FsPath) -> HashMap> { + match fs::read_to_string(path) { + Ok(s) => serde_json::from_str(&s).unwrap_or_default(), + Err(_) => HashMap::new(), + } +} + +fn load_vehicle_icons(path: &FsPath) -> HashMap { + // vehicle_data_cache_all.json is [[cdk, name, icon, tags], ...] + let raw: Vec = match fs::read_to_string(path) { + Ok(s) => serde_json::from_str(&s).unwrap_or_default(), + Err(_) => Vec::new(), + }; + let mut out = HashMap::new(); + for entry in raw { + if let (Some(cdk), Some(icon)) = ( + entry.get(0).and_then(|v| v.as_str()), + entry.get(2).and_then(|v| v.as_str()), + ) { + out.insert(cdk.to_string(), icon.to_string()); + } + } + out +} + +fn lookup_vehicle_name( + names: &HashMap>, + cdk: &str, + lang: &str, +) -> String { + if let Some(by_lang) = names.get(cdk) { + if let Some(n) = by_lang.get(lang) { + return n.clone(); + } + if let Some(n) = by_lang.get("en") { + return n.clone(); + } + } + cdk.to_string() +} + +fn lookup_vehicle_icon(icons: &HashMap, cdk: &str) -> String { + icons + .get(cdk) + .cloned() + .unwrap_or_else(|| format!("{cdk}.png")) +} + fn resolve_db_path(env_key: &str, default_file: &str) -> PathBuf { let raw = env::var(env_key).unwrap_or_else(|_| default_file.to_string()); let expanded = expand_home(&raw); @@ -1702,3 +1765,43 @@ fn load_env_file(path: &FsPath) { env::set_var(key, value); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn vehicle_name_prefers_lang_then_en_then_cdk() { + let mut names = HashMap::new(); + let mut t = HashMap::new(); + t.insert("en".to_string(), "T-34".to_string()); + t.insert("ru".to_string(), "Т-34".to_string()); + names.insert("ussr_t_34".to_string(), t); + assert_eq!(lookup_vehicle_name(&names, "ussr_t_34", "ru"), "Т-34"); + assert_eq!(lookup_vehicle_name(&names, "ussr_t_34", "de"), "T-34"); + assert_eq!(lookup_vehicle_name(&names, "unknown_cdk", "en"), "unknown_cdk"); + } + + #[test] + fn vehicle_icon_falls_back_to_cdk_png() { + let mut icons = HashMap::new(); + icons.insert("ussr_t_34".to_string(), "ussr_t_34.png".to_string()); + assert_eq!(lookup_vehicle_icon(&icons, "ussr_t_34"), "ussr_t_34.png"); + assert_eq!(lookup_vehicle_icon(&icons, "germ_pz"), "germ_pz.png"); + } + + #[test] + fn load_vehicle_icons_parses_cache_array() { + let dir = std::env::temp_dir(); + let p = dir.join("test_vehicle_cache_all.json"); + fs::write( + &p, + r#"[["ussr_t_34","T-34","ussr_t_34.png",{}],["germ_pz","Pz","germ_pz.png",{}]]"#, + ) + .unwrap(); + let icons = load_vehicle_icons(&p); + assert_eq!(icons.get("ussr_t_34").unwrap(), "ussr_t_34.png"); + assert_eq!(icons.len(), 2); + let _ = fs::remove_file(&p); + } +}