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 log::debug;
use serde::{Deserialize, Serialize};
use thiserror::Error;
@@ -55,6 +56,11 @@ pub struct Config {
impl Config {
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 config = quick_xml::de::from_str(&data)?;
@@ -142,7 +148,7 @@ pub struct InstallStep {
#[serde(rename = "@name")]
pub name: String,
pub visible: Option<CompositeDependency>,
pub visible: Option<ModuleDependency>,
#[serde(rename = "optionalFileGroups")]
pub optional_file_groups: GroupList,
@@ -151,6 +157,7 @@ pub struct InstallStep {
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModuleDependency {
#[serde(rename = "@operator")]
#[serde(default)]
pub operator: DependencyOperator,
#[serde(rename = "$value")]
pub list: Vec<CompositeDependency>,
@@ -207,8 +214,11 @@ pub enum DependencyState {
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 {
#[default]
And,
Or,
}

View File

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

View File

@@ -10,7 +10,7 @@ use std::{
use thiserror::Error;
use walkdir::WalkDir;
use crate::types::{self, ModdedInstance, RootConfig};
use crate::{types::{self, ModdedInstance, RootConfig}, utils::is_plugin_file};
pub fn create_loadorder(
root_config: &RootConfig,
@@ -76,13 +76,6 @@ pub fn create_loadorder(
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)]
pub enum LoadOrderError {
#[error("Failed to read game directory")]

View File

@@ -4,7 +4,7 @@ use log::{debug, warn};
use crate::fomod::{
CompositeDependency, Config, DependencyOperator, DependencyState, FileList, FileTypeEnum,
Group, GroupType, Plugin, PluginTypeDescriptorEnum, PluginTypeEnum,
Group, GroupType, ModuleDependency, Plugin, PluginTypeDescriptorEnum, PluginTypeEnum,
};
#[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 name: String,
pub select_type: GroupType,
@@ -191,7 +207,7 @@ pub fn run_fomod_installer(
if step
.visible
.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.
continue;

View File

@@ -1,6 +1,11 @@
use std::ffi::OsStr;
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)]
pub struct InstalledMod {
@@ -36,4 +41,12 @@ impl InstalledMod {
pub fn files(&self) -> &[Link] {
&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::{
ffi::OsStr,
fs::{self, read_to_string},
io::Write,
path::{Path, PathBuf},
@@ -88,4 +89,8 @@ impl ModdedInstance {
pub fn mods(&self) -> &[InstalledMod] {
&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)
}
pub fn is_plugin_file(filename: impl AsRef<Path>) -> bool {
filename
.as_ref()
.extension()
.is_some_and(|ext| ext == "esp" || ext == "esm" || ext == "esl")
}