aboutsummaryrefslogtreecommitdiff
path: root/src-tauri/src/mod_management/legacy.rs
blob: f24f44b63cc10f954706a3cb9599c13839e833cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
use crate::constants::BLACKLISTED_MODS;
use crate::mod_management::{
    delete_mod_folder, get_installed_mods_and_properties, ParsedThunderstoreModString,
};
use crate::GameInstall;
use crate::NorthstarMod;
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::{io::Read, path::PathBuf};

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ModJson {
    #[serde(rename = "Name")]
    name: String,
    #[serde(rename = "ThunderstoreModString")]
    thunderstore_mod_string: Option<String>,
    #[serde(rename = "Version")]
    version: Option<String>,
}

/// Parses `manifest.json` for Thunderstore mod string
fn parse_for_thunderstore_mod_string(nsmod_path: &str) -> Result<String, anyhow::Error> {
    let manifest_json_path = format!("{}/manifest.json", nsmod_path);
    let ts_author_txt_path = format!("{}/thunderstore_author.txt", nsmod_path);

    // Check if `manifest.json` exists and parse
    let data = std::fs::read_to_string(manifest_json_path)?;
    let thunderstore_manifest: super::ThunderstoreManifest = json5::from_str(&data)?;

    // Check if `thunderstore_author.txt` exists and parse
    let mut file = std::fs::File::open(ts_author_txt_path)?;
    let mut thunderstore_author = String::new();
    file.read_to_string(&mut thunderstore_author)?;

    // Build mod string
    let thunderstore_mod_string = format!(
        "{}-{}-{}",
        thunderstore_author, thunderstore_manifest.name, thunderstore_manifest.version_number
    );

    Ok(thunderstore_mod_string)
}

/// Parse `mods` folder for installed mods.
pub fn parse_installed_mods(
    game_install: &GameInstall,
) -> Result<Vec<NorthstarMod>, anyhow::Error> {
    let ns_mods_folder = format!("{}/R2Northstar/mods/", game_install.game_path);

    let paths = match std::fs::read_dir(ns_mods_folder) {
        Ok(paths) => paths,
        Err(_err) => return Err(anyhow!("No mods folder found")),
    };

    let mut directories: Vec<PathBuf> = Vec::new();
    let mut mods: Vec<NorthstarMod> = Vec::new();

    // Get list of folders in `mods` directory
    for path in paths {
        log::info!("{path:?}");
        let my_path = path.unwrap().path();
        log::info!("{my_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 {
        let directory_str = directory.to_str().unwrap().to_string();
        // Check if mod.json exists
        let mod_json_path = format!("{}/mod.json", directory_str);
        if !std::path::Path::new(&mod_json_path).exists() {
            continue;
        }

        // Parse mod.json and get mod name

        // Read file into string and parse it
        let data = std::fs::read_to_string(mod_json_path.clone())?;
        let parsed_mod_json: ModJson = match json5::from_str(&data) {
            Ok(parsed_json) => parsed_json,
            Err(err) => {
                log::warn!("Failed parsing {} with {}", mod_json_path, err.to_string());
                continue;
            }
        };
        // Get Thunderstore mod string if it exists
        let thunderstore_mod_string = match parsed_mod_json.thunderstore_mod_string {
            // Attempt legacy method for getting Thunderstore string first
            Some(ts_mod_string) => Some(ts_mod_string),
            // Legacy method failed
            None => match parse_for_thunderstore_mod_string(&directory_str) {
                Ok(thunderstore_mod_string) => Some(thunderstore_mod_string),
                Err(_err) => None,
            },
        };
        // Get directory path
        let mod_directory = directory.to_str().unwrap().to_string();

        let ns_mod = NorthstarMod {
            name: parsed_mod_json.name,
            version: parsed_mod_json.version,
            thunderstore_mod_string,
            enabled: false, // Placeholder
            directory: mod_directory,
        };

        mods.push(ns_mod);
    }

    // Return found mod names
    Ok(mods)
}

/// Deletes all NorthstarMods related to a Thunderstore mod
pub fn delete_thunderstore_mod(
    game_install: GameInstall,
    thunderstore_mod_string: String,
) -> Result<(), String> {
    // Prevent deleting core mod
    for core_ts_mod in BLACKLISTED_MODS {
        if thunderstore_mod_string == core_ts_mod {
            return Err(format!("Cannot remove core mod {thunderstore_mod_string}"));
        }
    }

    let parsed_ts_mod_string: ParsedThunderstoreModString =
        thunderstore_mod_string.parse().unwrap();

    // Get installed mods
    let installed_ns_mods = get_installed_mods_and_properties(game_install)?;

    // List of mod folders to remove
    let mut mod_folders_to_remove: Vec<String> = Vec::new();

    // Get folder name based on Thundestore mod string
    for installed_ns_mod in installed_ns_mods {
        if installed_ns_mod.thunderstore_mod_string.is_none() {
            // Not a Thunderstore mod
            continue;
        }

        let installed_ns_mod_ts_string: ParsedThunderstoreModString = installed_ns_mod
            .thunderstore_mod_string
            .unwrap()
            .parse()
            .unwrap();

        // Installed mod matches specified Thunderstore mod string
        if parsed_ts_mod_string.author_name == installed_ns_mod_ts_string.author_name
            && parsed_ts_mod_string.mod_name == installed_ns_mod_ts_string.mod_name
        {
            // Add folder to list of folder to remove
            mod_folders_to_remove.push(installed_ns_mod.directory);
        }
    }

    if mod_folders_to_remove.is_empty() {
        return Err(format!(
            "No mods removed as no Northstar mods matching {thunderstore_mod_string} were found to be installed."
        ));
    }

    // Delete given folders
    for mod_folder in mod_folders_to_remove {
        delete_mod_folder(&mod_folder)?;
    }

    Ok(())
}