From 9c582d1257f43b5c4ab78b09d4d15e93c9159fd6 Mon Sep 17 00:00:00 2001 From: hheik <4469778+hheik@users.noreply.github.com> Date: Wed, 4 Sep 2024 17:17:45 +0300 Subject: [PATCH] Mod dependency sorting with only exact version matching --- src/lib.rs | 6 ++--- src/main.rs | 77 ++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7838394..6d9caef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ pub struct ModInfo { pub version: (i64, i64, i64), pub website_url: String, pub enabled: bool, - pub dependencies: Vec>, + pub dependencies: Vec, } impl ModInfo { @@ -36,7 +36,7 @@ impl ModInfo { dependencies: yaml["dependencies"] .as_vec()? .iter() - .map(|y| y.as_str().map(|str| str.to_owned())) + .filter_map(|y| y.as_str().map(|str| str.to_owned())) .collect(), }) } @@ -226,6 +226,6 @@ pub fn game_dir() -> PathBuf { match var("GAME_DIR").ok() { Some(game_dir) => game_dir.into(), None => PathBuf::from(var("HOME").unwrap()) - .join(".steam/steam/steamapps/common/Lethal Company"), + .join("steam/SteamLibrary/steamapps/common/Lethal Company"), } } diff --git a/src/main.rs b/src/main.rs index d5a6797..e93416c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,7 @@ fn main() { }; let mod_list = fetch_mod_list(&profile_fetcher, &profile_uuid).unwrap(); + let mod_list = sort_by_dependencies(&mod_list); fetch_mods(&mod_fetcher, &mod_list).unwrap(); println!(""); @@ -80,26 +81,70 @@ fn fetch_mod_list( // Handle yaml let mods = &YamlLoader::load_from_str(&mods_yaml)?[0]; - Ok(sort_mods( - &mods - .as_vec() - .ok_or(std::io::Error::new( - std::io::ErrorKind::Other, - format!("YAML file is not a list: {:?}", mods_yaml_path), - ))? - .iter() - .filter(|yaml| yaml["enabled"] == Yaml::Boolean(true)) - .map(|yaml| ModInfo::from_yaml(yaml).unwrap()) - .collect(), - )) + Ok(mods + .as_vec() + .ok_or(std::io::Error::new( + std::io::ErrorKind::Other, + format!("YAML file is not a list: {:?}", mods_yaml_path), + ))? + .iter() + .filter(|yaml| yaml["enabled"] == Yaml::Boolean(true)) + .map(|yaml| ModInfo::from_yaml(yaml).unwrap()) + .collect()) } -/// Sort mods by dependency order -fn sort_mods(mods: &Vec) -> Vec { - // TODO: Actual dependecy sorting +/// Sort mods so that dependencies are installed before dependants +fn sort_by_dependencies(mods: &Vec) -> Vec { + let mut resolved_mods: Vec = Vec::with_capacity(mods.len()); let mut mods = mods.clone(); + // Sort mods initially by their dependency count, so we are more likely to hit them in order mods.sort_unstable_by_key(|mod_info| mod_info.dependencies.len()); - mods + + let mut unsatisfied_iterations: Vec> = vec![]; + + while mods.len() > 0 { + // Find a mod with satisfied dependencies + let index = mods + .iter() + .enumerate() + .find(|(_, mod_info)| { + mod_info.dependencies.iter().all(|dependency| { + resolved_mods + .iter() + .any(|resolved| *dependency == resolved.dependency_string()) + }) + }) + .map(|(index, _)| index); + if index.is_none() { + unsatisfied_iterations.push(mods.clone()); + } + // Even if no mods were satisfied, just pick one. + resolved_mods.push(mods.remove(index.unwrap_or(0))); + } + + if unsatisfied_iterations.len() > 0 { + eprintln!( + "{} unsatisfied dependencies:\n{:?}\n", + unsatisfied_iterations[0].len(), + unsatisfied_iterations[0] + ); + + eprintln!( + "Unsatisfied iterations:\n{:?}\n", + unsatisfied_iterations + .iter() + .map(|list| { + let list = list + .iter() + .map(|mod_info| mod_info.name.clone()) + .collect::>(); + format!("({} unsatisfied) {:?}", list.len(), list) + }) + .collect::>() + ); + } + + resolved_mods } /// Download and extract mods