Compare commits

...

3 Commits

3 changed files with 83 additions and 22 deletions

View File

@@ -44,7 +44,7 @@ impl RootConfig {
#[inline] #[inline]
pub fn get_mod_location(&self, mod_config: &ModConfig) -> PathBuf { pub fn get_mod_location(&self, mod_config: &ModConfig) -> PathBuf {
self.mod_location.join(mod_config.source.clone()) self.mod_location.join(mod_config.path.clone())
} }
pub fn get_mod_by_id(&self, id: &str) -> Option<ModConfig> { pub fn get_mod_by_id(&self, id: &str) -> Option<ModConfig> {
@@ -83,14 +83,14 @@ pub struct ModConfig {
pub id: String, pub id: String,
/// Relative to the mod_location from root config /// Relative to the mod_location from root config
pub source: PathBuf, pub path: PathBuf,
} }
impl ModConfig { impl ModConfig {
pub fn new(id: &str, source: impl AsRef<Path>) -> Self { pub fn new(id: &str, source: impl AsRef<Path>) -> Self {
Self { Self {
id: id.to_owned(), id: id.to_owned(),
source: source.as_ref().to_owned(), path: source.as_ref().to_owned(),
} }
} }
} }

View File

@@ -1,15 +1,18 @@
use clap::Parser; use clap::Parser;
use log::debug; use log::debug;
use std::{error::Error, path::Path}; use std::{
error::Error,
fs,
path::{Path, PathBuf},
};
use crate::{ use crate::{
basic_types::{ModConfig, ModFile, ModdedInstance, RootConfig}, basic_types::{ModConfig, ModFile, ModdedInstance, RootConfig},
cli::Args, cli::Args,
fomod::Config,
linker::{create_plugins_txt, link_game_to_target, link_instance_to_target}, linker::{create_plugins_txt, link_game_to_target, link_instance_to_target},
load_order::LoadOrder, load_order::LoadOrder,
mod_config_installer::FomodInstaller, mod_config_installer::FomodInstaller,
utils::resolve_case_insensitive, utils::{resolve_case_insensitive, walk_files_recursive},
}; };
mod basic_types; mod basic_types;
@@ -22,31 +25,92 @@ mod load_order;
mod mod_config_installer; mod mod_config_installer;
mod utils; mod utils;
pub fn load_mod_config(mod_root: impl AsRef<Path>) -> Result<fomod::Config, Box<dyn Error>> {
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( pub fn gen_filelist_for_mod(
root_config: &RootConfig, root_config: &RootConfig,
instance: &ModdedInstance, instance: &ModdedInstance,
mod_config: &ModConfig, mod_config: &ModConfig,
) -> Result<Vec<ModFile>, Box<dyn Error>> { ) -> Result<Vec<ModFile>, Box<dyn Error>> {
let mod_location = root_config.get_mod_location(mod_config); 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<ModFile> = 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<Path>,
) -> Result<Vec<ModFile>, Box<dyn Error>> {
// 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<Path>) -> 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<Path>) -> Result<Vec<PathBuf>, Box<dyn Error>> {
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<Path>,
mod_location: impl AsRef<Path>,
) -> Result<Vec<ModFile>, Box<dyn Error>> {
let module_config = fomod::Config::load_from_file(xml_path)?;
// TODO: add active plugins from instance config // TODO: add active plugins from instance config
let installer = FomodInstaller::new(module_config, vec![], install_prompt::prompt); let installer = FomodInstaller::new(module_config, vec![], install_prompt::prompt);
let files = installer.run(); let files = installer.run();
let converted_files: Vec<_> = files let mod_files: Vec<_> = files
.iter() .iter()
.flat_map(|f| ModFile::from_installer(f.clone(), &mod_location).unwrap()) .flat_map(|f| ModFile::from_installer(f.clone(), &mod_location).unwrap())
.collect(); .collect();
Ok(converted_files) Ok(mod_files)
} }
pub fn activate_instance( pub fn activate_instance(

View File

@@ -34,7 +34,7 @@ pub fn path_to_lowercase(path: impl AsRef<Path>) -> PathBuf {
pub fn resolve_case_insensitive( pub fn resolve_case_insensitive(
base: impl AsRef<Path>, base: impl AsRef<Path>,
rel: impl AsRef<Path>, rel: impl AsRef<Path>,
) -> io::Result<PathBuf> { ) -> io::Result<Option<PathBuf>> {
let mut current = base.as_ref().to_path_buf(); let mut current = base.as_ref().to_path_buf();
for part in rel.as_ref().iter() { for part in rel.as_ref().iter() {
@@ -56,13 +56,10 @@ pub fn resolve_case_insensitive(
match found { match found {
Some(path) => current = path, Some(path) => current = path,
None => { None => {
return Err(io::Error::new( return Ok(None);
io::ErrorKind::NotFound,
format!("Path component not found: {}", target),
));
} }
} }
} }
Ok(current) Ok(Some(current))
} }