From f2042be088c1139345c57538c54d41b1653397c5 Mon Sep 17 00:00:00 2001 From: Niklas Kapelle Date: Tue, 3 Mar 2026 16:02:06 +0100 Subject: [PATCH] mods without a fomod config can now be installed --- src/main.rs | 90 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 66b4348..6b7124d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,18 @@ use clap::Parser; use log::debug; -use std::{error::Error, path::Path}; +use std::{ + error::Error, + fs, + path::{Path, PathBuf}, +}; use crate::{ basic_types::{ModConfig, ModFile, ModdedInstance, RootConfig}, cli::Args, - fomod::Config, linker::{create_plugins_txt, link_game_to_target, link_instance_to_target}, load_order::LoadOrder, mod_config_installer::FomodInstaller, - utils::resolve_case_insensitive, + utils::{resolve_case_insensitive, walk_files_recursive}, }; mod basic_types; @@ -22,31 +25,92 @@ mod load_order; mod mod_config_installer; mod utils; -pub fn load_mod_config(mod_root: impl AsRef) -> Result> { - let path = resolve_case_insensitive(&mod_root, "fomod/ModuleConfig.xml")?; - let mod_config = Config::load_from_file(path)?; - Ok(mod_config) -} - pub fn gen_filelist_for_mod( root_config: &RootConfig, instance: &ModdedInstance, mod_config: &ModConfig, ) -> Result, Box> { let mod_location = root_config.get_mod_location(mod_config); - let module_config = load_mod_config(&mod_location)?; + let module_config_path = resolve_case_insensitive(&mod_location, "fomod/ModuleConfig.xml")?; + + let files: Vec = match module_config_path { + Some(path) => { + debug!("Found a ModuleConfig.xml"); + gen_filelist_from_fomod(instance, path, &mod_location)? + } + None => { + debug!("Did not find a ModuleConfig.xml"); + gen_filelist_from_mod_dir(&mod_location)? + } + }; + + Ok(files) +} + +pub fn gen_filelist_from_mod_dir( + mod_location: impl AsRef, +) -> Result, Box> { + // Check for Data dir in root + let files = match resolve_case_insensitive(&mod_location, "data")? { + Some(data_path) => gen_filelist_from_dir(data_path), + None => gen_filelist_from_dir(&mod_location), + }?; + + let mod_files: Vec<_> = files + .iter() + .filter(|e| should_be_included(e)) + .map(|e| ModFile::new(e, PathBuf::from("Data").join(e), 0)) + .collect(); + + Ok(mod_files) +} + +fn should_be_included(path: impl AsRef) -> bool { + matches!( + path.as_ref().extension().and_then(|e| e.to_str()), + Some( + "esp" + | "esm" + | "esl" + | "bsa" + | "ba2" + | "bsl" + | "ini" + | "pex" + | "psc" + | "strings" + | "ilstrings" + | "dlstrings" + | "dll" + ) + ) +} + +pub fn gen_filelist_from_dir(path: impl AsRef) -> Result, Box> { + let files: Vec<_> = walk_files_recursive(&path)? + .map(|file| file.path().strip_prefix(&path).unwrap().to_owned()) + .collect(); + + Ok(files) +} + +pub fn gen_filelist_from_fomod( + instance: &ModdedInstance, + xml_path: impl AsRef, + mod_location: impl AsRef, +) -> Result, Box> { + let module_config = fomod::Config::load_from_file(xml_path)?; // TODO: add active plugins from instance config let installer = FomodInstaller::new(module_config, vec![], install_prompt::prompt); - let files = installer.run(); - let converted_files: Vec<_> = files + let mod_files: Vec<_> = files .iter() .flat_map(|f| ModFile::from_installer(f.clone(), &mod_location).unwrap()) .collect(); - Ok(converted_files) + Ok(mod_files) } pub fn activate_instance(