// This file contains various mod management functions use anyhow::{anyhow, Result}; use app::NorthstarMod; use std::path::PathBuf; use app::GameInstall; use app::get_enabled_mods; use json5; /// Set the status of a passed mod to enabled/disabled pub fn set_mod_enabled_status( game_install: GameInstall, mod_name: String, is_enabled: bool, ) -> Result<(), String> { let enabledmods_json_path = format!("{}/R2Northstar/enabledmods.json", game_install.game_path); // Parse JSON let mut res: serde_json::Value = get_enabled_mods(game_install)?; // Check if key exists if res.get(mod_name.clone()).is_none() { return Err("Value not found in enabledmod.json".to_string()); } // Update value res[mod_name] = serde_json::Value::Bool(is_enabled); // Save the JSON structure into the output file std::fs::write( enabledmods_json_path, serde_json::to_string_pretty(&res).unwrap(), ) .unwrap(); Ok(()) } /// Parses `mod.json` for mod name // TODO: Maybe pass PathBuf or serde json object fn parse_mod_json_for_mod_name(mod_json_path: String) -> Result { // Read file into string and parse it let data = std::fs::read_to_string(mod_json_path)?; let parsed_json: serde_json::Value = json5::from_str(&data)?; // Extract mod name let mod_name = match parsed_json.get("Name").and_then(|value| value.as_str()) { Some(name) => name, None => return Err(anyhow!("No name found")), }; Ok(mod_name.to_string()) } /// Parse `mods` folder for installed mods. fn get_installed_mods(game_install: GameInstall) -> Result, String> { let ns_mods_folder = format!("{}/R2Northstar/mods/", game_install.game_path); let paths = std::fs::read_dir(ns_mods_folder).unwrap(); let mut directories: Vec = Vec::new(); let mut mod_names: Vec = Vec::new(); // Get list of folders in `mods` directory for path in paths { let my_path = path.unwrap().path(); let md = std::fs::metadata(my_path.clone()).unwrap(); if md.is_dir() { directories.push(my_path); } } // Iterate over folders and check if they are Northstar mods for directory in directories { // Check if mod.json exists let mod_json_path = format!("{}/mod.json", directory.to_str().unwrap()); if !std::path::Path::new(&mod_json_path).exists() { continue; } // Parse mod.json and get mod name let mod_name = match parse_mod_json_for_mod_name(mod_json_path.clone()) { Ok(mod_name) => mod_name, Err(err) => { println!("Failed parsing {} with {}", mod_json_path, err.to_string()); continue; } }; mod_names.push(mod_name); } // Return found mod names Ok(mod_names) } /// Gets list of installed mods and their properties /// - name /// - is enabled? pub fn get_installed_mods_and_properties( game_install: GameInstall, ) -> Result, String> { // Get actually installed mods let found_installed_mods = get_installed_mods(game_install.clone())?; // Get enabled mods as JSON let enabled_mods: serde_json::Value = match get_enabled_mods(game_install) { Ok(enabled_mods) => enabled_mods, Err(_) => serde_json::from_str("{}").unwrap(), // `enabledmods.json` not found, create empty object }; let mut installed_mods = Vec::new(); let mapping = enabled_mods.as_object().unwrap(); // Use list of installed mods and set enabled based on `enabledmods.json` for name in found_installed_mods { let current_mod_enabled = match mapping.get(&name) { Some(enabled) => enabled.as_bool().unwrap(), None => true, // Northstar considers mods not in mapping as enabled. }; let current_mod: NorthstarMod = NorthstarMod { name: name, enabled: current_mod_enabled, }; installed_mods.push(current_mod); } Ok(installed_mods) }