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
|
use crate::util::copy_dir_all;
use crate::GameInstall;
// These folders are part of Titanfall 2 and
// should NEVER be used as a Profile
const SKIP_PATHS: [&str; 8] = [
"___flightcore-temp",
"__overlay",
"bin",
"Core",
"r2",
"vpk",
"platform",
"Support",
];
// A profile may have one of these to be detected
const MAY_CONTAIN: [&str; 10] = [
"mods/",
"plugins/",
"packages/",
"logs/",
"runtime/",
"save_data/",
"Northstar.dll",
"enabledmods.json",
"placeholder.playerdata.pdata",
"LEGAL.txt",
];
/// Returns a list of Profile names
/// All the returned Profiles can be found relative to the game path
#[tauri::command]
pub fn fetch_profiles(game_install: GameInstall) -> Result<Vec<String>, String> {
let mut profiles: Vec<String> = Vec::new();
for content in MAY_CONTAIN {
let pattern = format!("{}/*/{}", game_install.game_path, content);
for e in glob::glob(&pattern).expect("Failed to read glob pattern") {
let path = e.unwrap();
let mut ancestors = path.ancestors();
ancestors.next();
let profile_path = std::path::Path::new(ancestors.next().unwrap());
let profile_name = profile_path
.file_name()
.unwrap()
.to_os_string()
.into_string()
.unwrap();
if !profiles.contains(&profile_name) {
profiles.push(profile_name);
}
}
}
Ok(profiles)
}
/// Validates if a given profile is actually a valid profile
#[tauri::command]
pub fn validate_profile(game_install: GameInstall, profile: String) -> bool {
// Game files are never a valid profile
// Prevent users with messed up installs from making it even worse
if SKIP_PATHS.contains(&profile.as_str()) {
return false;
}
log::info!("Validating Profile {}", profile);
let profile_path = format!("{}/{}", game_install.game_path, profile);
let profile_dir = std::path::Path::new(profile_path.as_str());
profile_dir.is_dir()
}
#[tauri::command]
pub fn delete_profile(game_install: GameInstall, profile: String) -> Result<(), String> {
// Check if the Profile actually exists
if !validate_profile(game_install.clone(), profile.clone()) {
return Err(format!("{} is not a valid Profile", profile));
}
log::info!("Deleting Profile {}", profile);
let profile_path = format!("{}/{}", game_install.game_path, profile);
match std::fs::remove_dir_all(profile_path) {
Ok(()) => Ok(()),
Err(err) => Err(format!("Failed to delete Profile: {}", err)),
}
}
/// Clones a profile by simply duplicating the folder under a new name
#[tauri::command]
pub fn clone_profile(
game_install: GameInstall,
old_profile: String,
new_profile: String,
) -> Result<(), String> {
// Check if the old Profile already exists
if !validate_profile(game_install.clone(), old_profile.clone()) {
return Err(format!("{} is not a valid Profile", old_profile));
}
// Check that new Profile does not already exist
if validate_profile(game_install.clone(), new_profile.clone()) {
return Err(format!("{} already exists", new_profile));
}
log::info!("Cloning Profile {} to {}", old_profile, new_profile);
let old_profile_path = format!("{}/{}", game_install.game_path, old_profile);
let new_profile_path = format!("{}/{}", game_install.game_path, new_profile);
copy_dir_all(old_profile_path, new_profile_path).unwrap();
Ok(())
}
|