refactored actions to own files
This commit is contained in:
11
src/actions.rs
Normal file
11
src/actions.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
mod activate;
|
||||||
|
mod download;
|
||||||
|
mod include;
|
||||||
|
mod install;
|
||||||
|
mod load_order;
|
||||||
|
|
||||||
|
pub use activate::{ActivationError, activate_instance};
|
||||||
|
pub use download::handle_nxm;
|
||||||
|
pub use include::insert_mod_to_instance;
|
||||||
|
pub use install::resolve_files_for_install;
|
||||||
|
pub use load_order::{LoadOrderError, create_loadorder};
|
||||||
@@ -7,6 +7,7 @@ use std::io::Write;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{fs, io, os::unix, path::Path};
|
use std::{fs, io, os::unix, path::Path};
|
||||||
|
|
||||||
|
/// Create the symlinks for a instance in a given directory
|
||||||
pub fn activate_instance(
|
pub fn activate_instance(
|
||||||
root_config: &RootConfig,
|
root_config: &RootConfig,
|
||||||
instance: &ModdedInstance,
|
instance: &ModdedInstance,
|
||||||
42
src/actions/download.rs
Normal file
42
src/actions/download.rs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
|
use log::error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
nexus::{NXMUrl, download_nxm},
|
||||||
|
types::RootConfig,
|
||||||
|
unpacker::unpack,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Handles a nexus mod url. Downloads, unpacks and adds the mod to the config
|
||||||
|
pub fn handle_nxm(root_config: &mut RootConfig, raw_url: &str) -> anyhow::Result<()> {
|
||||||
|
let Some(dl_location) = root_config.download_location() else {
|
||||||
|
return Err(anyhow!("No download location set"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(api_key) = root_config.nexus_api_key() else {
|
||||||
|
return Err(anyhow!("No API key provided"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(nxm_url) = NXMUrl::parse_url(raw_url) else {
|
||||||
|
return Err(anyhow!("Failed to parse URL"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let (dl_file, mod_info) = download_nxm(api_key, &nxm_url, dl_location)?;
|
||||||
|
|
||||||
|
let mod_id = format!("{}-{}", mod_info.generate_id(), nxm_url.file);
|
||||||
|
if root_config.game_by_id(&mod_id).is_some() {
|
||||||
|
error!(
|
||||||
|
"Generated mod id already exists. Pleas install downloaded mod manually. Downloaded at {}",
|
||||||
|
&dl_file.to_string_lossy()
|
||||||
|
);
|
||||||
|
return Err(anyhow!("Mod with generated id already exists"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_mod = unpack(root_config, &mod_id, dl_file)?;
|
||||||
|
|
||||||
|
root_config.add_mod(&new_mod);
|
||||||
|
|
||||||
|
root_config.save_to_file()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
70
src/actions/include.rs
Normal file
70
src/actions/include.rs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
use log::warn;
|
||||||
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
file_conflict_solver::ConflictSolver,
|
||||||
|
types::{InstalledMod, ModConfig, ModFile, ModdedInstance},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn insert_mod_to_instance(
|
||||||
|
instance: &mut ModdedInstance,
|
||||||
|
from_mod: &ModConfig,
|
||||||
|
files_to_add: &[ModFile],
|
||||||
|
priority: isize,
|
||||||
|
) -> Option<FileConflict> {
|
||||||
|
let mut solver = ConflictSolver::new();
|
||||||
|
|
||||||
|
let mut installed_files: Vec<(ModFile, &InstalledMod)> = Vec::new();
|
||||||
|
for installed_mod in instance.mods() {
|
||||||
|
for link in installed_mod.files() {
|
||||||
|
let recreated_mod_file = ModFile::new(link.src(), link.dst(), 0);
|
||||||
|
installed_files.push((recreated_mod_file, installed_mod));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (file, from_mod) in &installed_files {
|
||||||
|
if let Some(conflict) = solver.add_file(file, from_mod) {
|
||||||
|
warn!("File conflict on already added file: {:?}", conflict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_mod = InstalledMod::new(from_mod.id(), priority);
|
||||||
|
for file in files_to_add {
|
||||||
|
if let Some(conflict) = solver.add_file(file, &new_mod) {
|
||||||
|
return Some(FileConflict {
|
||||||
|
lhs_mod_id: conflict.lhs_mod.mod_id().to_owned(),
|
||||||
|
rhs_mod_id: conflict.rhs_mod.mod_id().to_owned(),
|
||||||
|
path: conflict.rhs_file.dst().to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_link_tree = solver.export_files();
|
||||||
|
|
||||||
|
let mut map: HashMap<String, InstalledMod> = HashMap::new();
|
||||||
|
|
||||||
|
for (file, from_mod) in new_link_tree {
|
||||||
|
match map.get_mut(from_mod.mod_id()) {
|
||||||
|
Some(existing) => {
|
||||||
|
existing.add_file(file);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let mut new_mod = InstalledMod::new(from_mod.mod_id(), from_mod.priority());
|
||||||
|
new_mod.add_file(file);
|
||||||
|
map.insert(new_mod.mod_id().to_owned(), new_mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, installed_mod) in map {
|
||||||
|
instance.update_or_create_mod(&installed_mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FileConflict {
|
||||||
|
pub lhs_mod_id: String,
|
||||||
|
pub rhs_mod_id: String,
|
||||||
|
pub path: PathBuf,
|
||||||
|
}
|
||||||
@@ -1,79 +1,19 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
io,
|
io,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||||
use log::{debug, trace, warn};
|
use log::{debug, trace};
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
file_conflict_solver::ConflictSolver,
|
|
||||||
fomod, install_prompt,
|
fomod, install_prompt,
|
||||||
mod_config_installer::run_fomod_installer,
|
mod_config_installer::run_fomod_installer,
|
||||||
types::{InstalledMod, ModConfig, ModFile, ModdedInstance, RootConfig},
|
types::{ModConfig, ModFile, ModdedInstance, RootConfig},
|
||||||
utils::{resolve_case_insensitive, walk_all_files},
|
utils::{resolve_case_insensitive, walk_all_files},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn insert_mod_to_instance(
|
pub fn resolve_files_for_install(
|
||||||
instance: &mut ModdedInstance,
|
|
||||||
from_mod: &ModConfig,
|
|
||||||
files: &[ModFile],
|
|
||||||
priority: isize,
|
|
||||||
) -> Result<(), InststanceError> {
|
|
||||||
let mut solver = ConflictSolver::new();
|
|
||||||
|
|
||||||
let mut installed_files: Vec<(ModFile, &InstalledMod)> = Vec::new();
|
|
||||||
for installed_mod in instance.mods() {
|
|
||||||
for link in installed_mod.files() {
|
|
||||||
let recreated_mod_file = ModFile::new(link.src(), link.dst(), 0);
|
|
||||||
installed_files.push((recreated_mod_file, installed_mod));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (file, from_mod) in &installed_files {
|
|
||||||
if let Some(conflict) = solver.add_file(file, from_mod) {
|
|
||||||
warn!("File conflict on already added file: {:?}", conflict);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_mod = InstalledMod::new(from_mod.id(), priority);
|
|
||||||
for file in files {
|
|
||||||
if let Some(conflict) = solver.add_file(file, &new_mod) {
|
|
||||||
return Err(InststanceError::FileConflict {
|
|
||||||
lhs_mod_id: conflict.lhs_mod.mod_id().to_owned(),
|
|
||||||
rhs_mod_id: conflict.rhs_mod.mod_id().to_owned(),
|
|
||||||
path: conflict.rhs_file.dst().to_owned(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_link_tree = solver.export_files();
|
|
||||||
|
|
||||||
let mut map: HashMap<String, InstalledMod> = HashMap::new();
|
|
||||||
|
|
||||||
for (file, from_mod) in new_link_tree {
|
|
||||||
match map.get_mut(from_mod.mod_id()) {
|
|
||||||
Some(existing) => {
|
|
||||||
existing.add_file(file);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let mut new_mod = InstalledMod::new(from_mod.mod_id(), from_mod.priority());
|
|
||||||
new_mod.add_file(file);
|
|
||||||
map.insert(new_mod.mod_id().to_owned(), new_mod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (_, installed_mod) in map {
|
|
||||||
instance.update_or_create_mod(&installed_mod);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn files_to_install_mod(
|
|
||||||
root_config: &RootConfig,
|
root_config: &RootConfig,
|
||||||
instance: &ModdedInstance,
|
instance: &ModdedInstance,
|
||||||
mod_to_install: &ModConfig,
|
mod_to_install: &ModConfig,
|
||||||
@@ -126,14 +66,11 @@ fn install_fomod(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
trace!("Current loded plugins: {:?}", active_plugins);
|
trace!("Current loded plugins: {:?}", active_plugins);
|
||||||
let files = run_fomod_installer(module_config, &active_plugins, install_prompt::prompt)
|
let files = run_fomod_installer(module_config, &active_plugins, install_prompt::prompt)?;
|
||||||
.map_err(|_| InststanceError::FomodRunInstaller)?;
|
|
||||||
|
|
||||||
let mod_files: Vec<_> = files
|
let mod_files: Vec<_> = files
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| {
|
.map(|f| ModFile::from_installer(f.clone(), &mod_root))
|
||||||
ModFile::from_installer(f.clone(), &mod_root).map_err(InststanceError::FomodFinalize)
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
@@ -226,19 +163,3 @@ fn should_be_included(path: impl AsRef<Path>) -> bool {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum InststanceError {
|
|
||||||
#[error("Two mods write the same file")]
|
|
||||||
FileConflict {
|
|
||||||
lhs_mod_id: String,
|
|
||||||
rhs_mod_id: String,
|
|
||||||
path: PathBuf,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[error("Failed to run fomod installer")]
|
|
||||||
FomodRunInstaller,
|
|
||||||
|
|
||||||
#[error("Failed to handle results of fomod installer")]
|
|
||||||
FomodFinalize(io::Error),
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,10 @@ use std::{
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::{types::{self, ModdedInstance, RootConfig}, utils::is_plugin_file};
|
use crate::{
|
||||||
|
types::{self, ModdedInstance, RootConfig},
|
||||||
|
utils::is_plugin_file,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn create_loadorder(
|
pub fn create_loadorder(
|
||||||
root_config: &RootConfig,
|
root_config: &RootConfig,
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
pub mod activator;
|
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod file_conflict_solver;
|
pub mod file_conflict_solver;
|
||||||
pub mod fomod;
|
pub mod fomod;
|
||||||
pub mod install_prompt;
|
pub mod install_prompt;
|
||||||
pub mod instance;
|
|
||||||
pub mod load_order;
|
|
||||||
pub mod mod_config_installer;
|
pub mod mod_config_installer;
|
||||||
pub mod nexus;
|
pub mod nexus;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod unpacker;
|
pub mod unpacker;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod actions;
|
||||||
|
|||||||
83
src/main.rs
83
src/main.rs
@@ -4,11 +4,12 @@ use log::{debug, error, info};
|
|||||||
use std::{error::Error, path::Path};
|
use std::{error::Error, path::Path};
|
||||||
|
|
||||||
use fomod_manager::{
|
use fomod_manager::{
|
||||||
activator::activate_instance,
|
actions::{
|
||||||
|
activate_instance, create_loadorder, handle_nxm, insert_mod_to_instance,
|
||||||
|
resolve_files_for_install,
|
||||||
|
},
|
||||||
cli::{self, Args},
|
cli::{self, Args},
|
||||||
instance::{self, files_to_install_mod, insert_mod_to_instance},
|
nexus::NexusAPI,
|
||||||
load_order,
|
|
||||||
nexus::{NXMUrl, NexusAPI, download_nxm},
|
|
||||||
types::RootConfig,
|
types::RootConfig,
|
||||||
unpacker::unpack,
|
unpacker::unpack,
|
||||||
};
|
};
|
||||||
@@ -29,40 +30,23 @@ fn command_add(root_config: &RootConfig, instance_id: &str, mod_id: &str) -> any
|
|||||||
.mod_by_id(mod_id)
|
.mod_by_id(mod_id)
|
||||||
.ok_or(anyhow!("Can't find mod in config"))?;
|
.ok_or(anyhow!("Can't find mod in config"))?;
|
||||||
|
|
||||||
let files = files_to_install_mod(root_config, &instance, &mod_to_install)?;
|
let files = resolve_files_for_install(root_config, &instance, &mod_to_install)?;
|
||||||
|
|
||||||
match insert_mod_to_instance(&mut instance, &mod_to_install, &files, 0) {
|
match insert_mod_to_instance(&mut instance, &mod_to_install, &files, 0) {
|
||||||
Ok(_) => {
|
None => {
|
||||||
instance.save_to_file()?;
|
instance.save_to_file()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Some(conflict) => {
|
||||||
match &err {
|
error!(
|
||||||
instance::InststanceError::FileConflict {
|
"File conflict between {} and {} at {}",
|
||||||
lhs_mod_id,
|
conflict.lhs_mod_id,
|
||||||
rhs_mod_id,
|
conflict.rhs_mod_id,
|
||||||
path,
|
conflict.path.to_string_lossy()
|
||||||
} => {
|
);
|
||||||
error!(
|
info!("To resolve file conflicts give one mod a higher priority in the config");
|
||||||
"File conflict between {} and {} at {}",
|
|
||||||
lhs_mod_id,
|
|
||||||
rhs_mod_id,
|
|
||||||
path.to_string_lossy()
|
|
||||||
);
|
|
||||||
info!("To resolve file conflicts give one mod a higher priority in the config");
|
|
||||||
}
|
|
||||||
instance::InststanceError::FomodRunInstaller => {
|
|
||||||
error!("Failed to run FOMod installer");
|
|
||||||
}
|
|
||||||
instance::InststanceError::FomodFinalize(error) => {
|
|
||||||
error!(
|
|
||||||
"FOMod installer finished but failed to finalize result: {}",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Err(err.into())
|
Err(anyhow!("File conflict"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,46 +55,15 @@ fn command_order(root_config: &RootConfig, instance_id: &str) -> anyhow::Result<
|
|||||||
let mut instance = root_config.load_instance_by_id(instance_id)?;
|
let mut instance = root_config.load_instance_by_id(instance_id)?;
|
||||||
let game = root_config.game_by_id(instance.game_id()).unwrap();
|
let game = root_config.game_by_id(instance.game_id()).unwrap();
|
||||||
|
|
||||||
let new_load_order = load_order::create_loadorder(root_config, &game, &instance)?;
|
let new_load_order = create_loadorder(root_config, &game, &instance)?;
|
||||||
|
|
||||||
instance.set_load_order(new_load_order);
|
instance.set_load_order(new_load_order);
|
||||||
|
|
||||||
instance.save_to_file()?;
|
instance.save_to_file()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command_download(root_config: &mut RootConfig, raw_url: &str) -> anyhow::Result<()> {
|
fn command_download(root_config: &mut RootConfig, raw_url: &str) -> anyhow::Result<()> {
|
||||||
let Some(dl_location) = root_config.download_location() else {
|
handle_nxm(root_config, raw_url)
|
||||||
return Err(anyhow!("No download location set"));
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(api_key) = root_config.nexus_api_key() else {
|
|
||||||
return Err(anyhow!("No API key provided"));
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(nxm_url) = NXMUrl::parse_url(raw_url) else {
|
|
||||||
return Err(anyhow!("Failed to parse URL"));
|
|
||||||
};
|
|
||||||
|
|
||||||
let (dl_file, mod_info) = download_nxm(api_key, &nxm_url, dl_location)?;
|
|
||||||
|
|
||||||
let mod_id = format!("{}-{}", mod_info.generate_id(), nxm_url.file);
|
|
||||||
if root_config.game_by_id(&mod_id).is_some() {
|
|
||||||
error!(
|
|
||||||
"Generated mod id already exists. Pleas install downloaded mod manually. Downloaded at {}",
|
|
||||||
&dl_file.to_string_lossy()
|
|
||||||
);
|
|
||||||
return Err(anyhow!("Mod with generated id already exists"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_mod = unpack(root_config, &mod_id, dl_file)?;
|
|
||||||
|
|
||||||
root_config.add_mod(&new_mod);
|
|
||||||
|
|
||||||
root_config.save_to_file()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command_unpack(
|
fn command_unpack(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{collections::HashSet, error::Error, path::PathBuf};
|
use std::{collections::HashSet, error::Error, path::PathBuf};
|
||||||
|
|
||||||
use fomod_manager::{
|
use fomod_manager::{
|
||||||
instance::{files_to_install_mod, insert_mod_to_instance},
|
actions::{insert_mod_to_instance, resolve_files_for_install},
|
||||||
types::{Link, RootConfig},
|
types::{Link, RootConfig},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20,9 +20,9 @@ fn add_plain() -> Result<(), Box<dyn Error>> {
|
|||||||
let mod_to_install = root_config
|
let mod_to_install = root_config
|
||||||
.mod_by_id("add_test_plain")
|
.mod_by_id("add_test_plain")
|
||||||
.expect("Mod not found");
|
.expect("Mod not found");
|
||||||
let files_to_add = files_to_install_mod(&root_config, &instance, &mod_to_install)?;
|
let files_to_add = resolve_files_for_install(&root_config, &instance, &mod_to_install)?;
|
||||||
|
|
||||||
insert_mod_to_instance(&mut instance, &mod_to_install, &files_to_add, 0)?;
|
insert_mod_to_instance(&mut instance, &mod_to_install, &files_to_add, 0);
|
||||||
|
|
||||||
let installed_mods = instance.mods();
|
let installed_mods = instance.mods();
|
||||||
|
|
||||||
@@ -53,9 +53,9 @@ fn add_nested() -> Result<(), Box<dyn Error>> {
|
|||||||
let mod_to_install = root_config
|
let mod_to_install = root_config
|
||||||
.mod_by_id("add_test_nested")
|
.mod_by_id("add_test_nested")
|
||||||
.expect("Mod not found");
|
.expect("Mod not found");
|
||||||
let files_to_add = files_to_install_mod(&root_config, &instance, &mod_to_install)?;
|
let files_to_add = resolve_files_for_install(&root_config, &instance, &mod_to_install)?;
|
||||||
|
|
||||||
insert_mod_to_instance(&mut instance, &mod_to_install, &files_to_add, 0)?;
|
insert_mod_to_instance(&mut instance, &mod_to_install, &files_to_add, 0);
|
||||||
|
|
||||||
let installed_mods = instance.mods();
|
let installed_mods = instance.mods();
|
||||||
|
|
||||||
@@ -86,9 +86,9 @@ fn add_root() -> Result<(), Box<dyn Error>> {
|
|||||||
let mod_to_install = root_config
|
let mod_to_install = root_config
|
||||||
.mod_by_id("add_test_root")
|
.mod_by_id("add_test_root")
|
||||||
.expect("Mod not found");
|
.expect("Mod not found");
|
||||||
let files_to_add = files_to_install_mod(&root_config, &instance, &mod_to_install)?;
|
let files_to_add = resolve_files_for_install(&root_config, &instance, &mod_to_install)?;
|
||||||
|
|
||||||
insert_mod_to_instance(&mut instance, &mod_to_install, &files_to_add, 0)?;
|
insert_mod_to_instance(&mut instance, &mod_to_install, &files_to_add, 0);
|
||||||
|
|
||||||
let installed_mods = instance.mods();
|
let installed_mods = instance.mods();
|
||||||
|
|
||||||
@@ -117,9 +117,9 @@ fn add_filter() -> Result<(), Box<dyn Error>> {
|
|||||||
let mod_to_install = root_config
|
let mod_to_install = root_config
|
||||||
.mod_by_id("add_test_filter")
|
.mod_by_id("add_test_filter")
|
||||||
.expect("Mod not found");
|
.expect("Mod not found");
|
||||||
let files_to_add = files_to_install_mod(&root_config, &instance, &mod_to_install)?;
|
let files_to_add = resolve_files_for_install(&root_config, &instance, &mod_to_install)?;
|
||||||
|
|
||||||
insert_mod_to_instance(&mut instance, &mod_to_install, &files_to_add, 0)?;
|
insert_mod_to_instance(&mut instance, &mod_to_install, &files_to_add, 0);
|
||||||
|
|
||||||
let installed_mods = instance.mods();
|
let installed_mods = instance.mods();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user