Compare commits

..

2 Commits

Author SHA1 Message Date
96dda41c46 pass active plugins to fomod installer 2026-03-11 00:30:50 +01:00
295c9bd8c3 fixed fomod visable condition 2026-03-11 00:29:38 +01:00
7 changed files with 68 additions and 17 deletions

View File

@@ -4,6 +4,7 @@
use std::{fs, io, path::Path}; use std::{fs, io, path::Path};
use log::debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
@@ -55,6 +56,11 @@ pub struct Config {
impl Config { impl Config {
pub fn load_from_file(path: impl AsRef<Path>) -> Result<Self, FOModError> { pub fn load_from_file(path: impl AsRef<Path>) -> Result<Self, FOModError> {
debug!(
"Loading FOmod config from {}",
path.as_ref().to_string_lossy()
);
let data = fs::read_to_string(path)?; let data = fs::read_to_string(path)?;
let config = quick_xml::de::from_str(&data)?; let config = quick_xml::de::from_str(&data)?;
@@ -142,7 +148,7 @@ pub struct InstallStep {
#[serde(rename = "@name")] #[serde(rename = "@name")]
pub name: String, pub name: String,
pub visible: Option<CompositeDependency>, pub visible: Option<ModuleDependency>,
#[serde(rename = "optionalFileGroups")] #[serde(rename = "optionalFileGroups")]
pub optional_file_groups: GroupList, pub optional_file_groups: GroupList,
@@ -151,6 +157,7 @@ pub struct InstallStep {
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModuleDependency { pub struct ModuleDependency {
#[serde(rename = "@operator")] #[serde(rename = "@operator")]
#[serde(default)]
pub operator: DependencyOperator, pub operator: DependencyOperator,
#[serde(rename = "$value")] #[serde(rename = "$value")]
pub list: Vec<CompositeDependency>, pub list: Vec<CompositeDependency>,
@@ -207,8 +214,11 @@ pub enum DependencyState {
Missing, Missing,
} }
#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(
Copy, Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash,
)]
pub enum DependencyOperator { pub enum DependencyOperator {
#[default]
And, And,
Or, Or,
} }

View File

@@ -5,7 +5,7 @@ use std::{
}; };
use globset::{Glob, GlobSet, GlobSetBuilder}; use globset::{Glob, GlobSet, GlobSetBuilder};
use log::warn; use log::{debug, trace, warn};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
@@ -114,14 +114,21 @@ fn determain_mod_kind(
} }
fn install_fomod( fn install_fomod(
_instance: &ModdedInstance, instance: &ModdedInstance,
module_config_path: impl AsRef<Path>, module_config_path: impl AsRef<Path>,
mod_root: impl AsRef<Path>, mod_root: impl AsRef<Path>,
) -> anyhow::Result<Vec<ModFile>> { ) -> anyhow::Result<Vec<ModFile>> {
debug!("Running FOmod installer");
let module_config = fomod::Config::load_from_file(module_config_path)?; let module_config = fomod::Config::load_from_file(module_config_path)?;
// TODO: add active plugins from instance config let active_plugins: Vec<_> = instance
let files = run_fomod_installer(module_config, &[], install_prompt::prompt) .active_plugins()
.map(|e| e.to_string_lossy())
.map(|e| e.to_string())
.collect();
trace!("Current loded plugins: {:?}", active_plugins);
let files = run_fomod_installer(module_config, &active_plugins, install_prompt::prompt)
.map_err(|_| InststanceError::FomodRunInstaller)?; .map_err(|_| InststanceError::FomodRunInstaller)?;
let mod_files: Vec<_> = files let mod_files: Vec<_> = files

View File

@@ -10,7 +10,7 @@ use std::{
use thiserror::Error; use thiserror::Error;
use walkdir::WalkDir; use walkdir::WalkDir;
use crate::types::{self, ModdedInstance, RootConfig}; use crate::{types::{self, ModdedInstance, RootConfig}, utils::is_plugin_file};
pub fn create_loadorder( pub fn create_loadorder(
root_config: &RootConfig, root_config: &RootConfig,
@@ -76,13 +76,6 @@ pub fn create_loadorder(
Ok(sorted) Ok(sorted)
} }
fn is_plugin_file(filename: impl AsRef<Path>) -> bool {
filename
.as_ref()
.extension()
.is_some_and(|ext| ext == "esp" || ext == "esm" || ext == "esl")
}
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum LoadOrderError { pub enum LoadOrderError {
#[error("Failed to read game directory")] #[error("Failed to read game directory")]

View File

@@ -4,7 +4,7 @@ use log::{debug, warn};
use crate::fomod::{ use crate::fomod::{
CompositeDependency, Config, DependencyOperator, DependencyState, FileList, FileTypeEnum, CompositeDependency, Config, DependencyOperator, DependencyState, FileList, FileTypeEnum,
Group, GroupType, Plugin, PluginTypeDescriptorEnum, PluginTypeEnum, Group, GroupType, ModuleDependency, Plugin, PluginTypeDescriptorEnum, PluginTypeEnum,
}; };
#[derive(Debug)] #[derive(Debug)]
@@ -101,6 +101,22 @@ fn evaluate_dependency(
} }
} }
fn evaluate_module_depbendecy(
dep: &ModuleDependency,
state: &InstallerState,
installed_plugins: &[String],
) -> bool {
let mut evaluated = dep
.list
.iter()
.map(|e| evaluate_dependency(e, state, installed_plugins));
match dep.operator {
DependencyOperator::And => evaluated.all(|r| r),
DependencyOperator::Or => evaluated.any(|r| r),
}
}
pub struct GroupPrompt { pub struct GroupPrompt {
pub name: String, pub name: String,
pub select_type: GroupType, pub select_type: GroupType,
@@ -191,7 +207,7 @@ pub fn run_fomod_installer(
if step if step
.visible .visible
.as_ref() .as_ref()
.is_some_and(|v| !evaluate_dependency(v, &state, installed_plugins)) .is_some_and(|v| !evaluate_module_depbendecy(v, &state, installed_plugins))
{ {
// Dependency to show the step not meet. Skipping. // Dependency to show the step not meet. Skipping.
continue; continue;

View File

@@ -1,6 +1,11 @@
use std::ffi::OsStr;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{link::Link, mod_file::ModFile}; use crate::{
types::{link::Link, mod_file::ModFile},
utils::is_plugin_file,
};
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct InstalledMod { pub struct InstalledMod {
@@ -36,4 +41,12 @@ impl InstalledMod {
pub fn files(&self) -> &[Link] { pub fn files(&self) -> &[Link] {
&self.files &self.files
} }
pub fn active_plugins(&self) -> impl Iterator<Item = &OsStr> {
self.files
.iter()
.filter(|e| is_plugin_file(e.dst()))
.map(|e| e.dst())
.flat_map(|e| e.file_name())
}
} }

View File

@@ -1,4 +1,5 @@
use std::{ use std::{
ffi::OsStr,
fs::{self, read_to_string}, fs::{self, read_to_string},
io::Write, io::Write,
path::{Path, PathBuf}, path::{Path, PathBuf},
@@ -88,4 +89,8 @@ impl ModdedInstance {
pub fn mods(&self) -> &[InstalledMod] { pub fn mods(&self) -> &[InstalledMod] {
&self.mods &self.mods
} }
pub fn active_plugins(&self) -> impl Iterator<Item = &OsStr> {
self.mods.iter().flat_map(|e| e.active_plugins())
}
} }

View File

@@ -56,3 +56,10 @@ pub fn walk_all_files(
Ok(a) Ok(a)
} }
pub fn is_plugin_file(filename: impl AsRef<Path>) -> bool {
filename
.as_ref()
.extension()
.is_some_and(|ext| ext == "esp" || ext == "esm" || ext == "esl")
}