diff --git a/src/basic_types.rs b/src/basic_types.rs index 75a83e7..0151555 100644 --- a/src/basic_types.rs +++ b/src/basic_types.rs @@ -170,6 +170,9 @@ pub struct ModdedInstance { #[serde(default)] pub load_order: Vec, + + #[serde(default)] + game_file_overrides: Vec, } impl ModdedInstance { @@ -178,6 +181,7 @@ impl ModdedInstance { name: name.to_owned(), mods: Vec::new(), load_order: Vec::new(), + game_file_overrides: Vec::new(), } } @@ -252,6 +256,10 @@ impl ModdedInstance { pub fn load_order(&self) -> &[String] { &self.load_order } + + pub fn game_file_overrides(&self) -> &[Link] { + &self.game_file_overrides + } } #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] diff --git a/src/linker.rs b/src/linker.rs index 2253636..5f5ea02 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -1,9 +1,6 @@ use log::debug; -use crate::{ - basic_types::{Game, Link, ModdedInstance, RootConfig}, - utils::walk_files_recursive, -}; +use crate::basic_types::{Game, Link, ModdedInstance, RootConfig}; use std::io::Write; use std::{fs, io, os::unix, path::Path}; @@ -27,12 +24,11 @@ pub fn link_instance_to_target( Ok(()) } -pub fn link_game_to_target(game: &Game, target: impl AsRef) -> Result<(), io::Error> { - for link in game.export_links()? { - link_file(&link.src, &target.as_ref().join(&link.dst))?; - } +pub fn apply_link(link: &Link, target: impl AsRef) -> Result<(), io::Error> { + let link_target = &link.src; + let link_name = target.as_ref().join(&link.dst); - Ok(()) + link_file(&link_target, &link_name) } fn link_file(target: &Path, link_name: &Path) -> Result<(), io::Error> { diff --git a/src/main.rs b/src/main.rs index f2073da..8d947ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,14 +2,15 @@ use clap::Parser; use globset::{Glob, GlobSet, GlobSetBuilder}; use log::debug; use std::{ + collections::HashMap, error::Error, path::{Path, PathBuf}, }; use crate::{ - basic_types::{ModConfig, ModFile, ModdedInstance, RootConfig}, + basic_types::{Game, Link, ModConfig, ModFile, ModdedInstance, RootConfig}, cli::Args, - linker::{create_plugins_txt, link_game_to_target, link_instance_to_target}, + linker::{apply_link, create_plugins_txt}, load_order::LoadOrder, mod_config_installer::FomodInstaller, utils::{resolve_case_insensitive, walk_files_recursive}, @@ -150,13 +151,60 @@ pub fn activate_instance( ) -> Result<(), Box> { let instance_config = root_config.load_instance_by_id(instance_id)?; - link_game_to_target(root_config.games.first().unwrap(), target)?; - link_instance_to_target(root_config, &instance_config, target)?; + let links = gen_links_for_activation( + root_config, + &instance_config, + root_config.games.first().unwrap(), + )?; + + links.iter().try_for_each(|link| apply_link(link, target)); create_plugins_txt(&instance_config, target)?; Ok(()) } +pub fn gen_links_for_activation( + root_config: &RootConfig, + instance: &ModdedInstance, + game: &Game, +) -> Result, Box> { + let game_links = game.export_links()?; + let mod_links = gen_links_for_instance(root_config, instance)?; + let overrides = instance.game_file_overrides().to_owned(); + + let mut map: HashMap = HashMap::new(); + + for link in game_links.into_iter().chain(mod_links).chain(overrides) { + map.insert(link.dst, link.src); + } + + let final_links: Vec = map + .into_iter() + .map(|(dst, src)| Link::new(src, dst)) + .collect(); + + Ok(final_links) +} + +fn gen_links_for_instance( + root_config: &RootConfig, + instance: &ModdedInstance, +) -> Result, Box> { + let mut links: Vec = Vec::new(); + + for installed_mod in &instance.mods { + let mod_config = root_config.get_mod_by_id(&installed_mod.mod_id()).unwrap(); + let mod_source_root = root_config.get_mod_location(&mod_config); + + for link in installed_mod.files() { + let link_target = mod_source_root.join(&link.src); + links.push(Link::new(link_target, &link.dst)); + } + } + + Ok(links) +} + pub fn add_mod_to_instance( root_config: &RootConfig, instance_id: &str,