1#[allow(deprecated)]
6use std::env::home_dir;
7
8use std::fs;
9use std::fs::read_dir;
10use std::path::PathBuf;
11
12#[derive(Clone, Copy)]
14#[repr(C)]
15pub enum ExistingInstallType {
16 OfficialLauncher,
18 XIVQuickLauncher,
20 XIVLauncherCore,
22 XIVOnMac,
24 Astra,
26}
27
28pub struct ExistingGameDirectory {
30 pub install_type: ExistingInstallType,
32 pub path: String,
34}
35
36pub fn find_existing_game_dirs() -> Vec<ExistingGameDirectory> {
38 let mut install_dirs = Vec::new();
39
40 match std::env::consts::OS {
41 "linux" => {
42 install_dirs.push(ExistingGameDirectory {
44 install_type: ExistingInstallType::OfficialLauncher,
45 path: from_home_dir(".wine/drive_c/Program Files (x86)/SquareEnix/FINAL FANTASY XIV - A Realm Reborn")
46 });
47
48 install_dirs.push(ExistingGameDirectory {
50 install_type: ExistingInstallType::OfficialLauncher,
51 path: from_home_dir(
52 ".steam/steam/steamapps/common/FINAL FANTASY XIV - A Realm Reborn",
53 ),
54 });
55
56 install_dirs.push(ExistingGameDirectory {
58 install_type: ExistingInstallType::XIVLauncherCore,
59 path: from_home_dir(".xlcore/ffxiv"),
60 });
61
62 if let Ok(entries) = read_dir(from_home_dir(".local/share/astra/game/")) {
64 entries
65 .flatten()
66 .flat_map(|entry| {
67 let Ok(meta) = entry.metadata() else {
68 return vec![];
69 };
70 if meta.is_dir() {
71 return vec![entry.path()];
72 }
73 vec![]
74 })
75 .for_each(|path| {
76 install_dirs.push(ExistingGameDirectory {
77 install_type: ExistingInstallType::Astra,
78 path: path.into_os_string().into_string().unwrap(),
79 })
80 });
81 }
82 }
83 "macos" => {
84 install_dirs.push(ExistingGameDirectory {
86 install_type: ExistingInstallType::OfficialLauncher,
87 path: from_home_dir("Library/Application Support/FINAL FANTASY XIV ONLINE/Bottles/published_Final_Fantasy/drive_c/Program Files (x86)/SquareEnix/FINAL FANTASY XIV - A Realm Reborn")
88 });
89
90 }
92 "windows" => {
93 install_dirs.push(ExistingGameDirectory {
95 install_type: ExistingInstallType::OfficialLauncher,
96 path: "C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn"
97 .parse()
98 .unwrap(),
99 });
100
101 }
103 &_ => {}
104 }
105
106 install_dirs
107 .into_iter()
108 .filter(|dir| is_valid_game_dir(&dir.path))
109 .collect()
110}
111
112pub struct ExistingUserDirectory {
114 pub install_type: ExistingInstallType,
116 pub path: String,
118}
119
120pub fn find_existing_user_dirs() -> Vec<ExistingUserDirectory> {
122 let mut user_dirs = Vec::new();
123 #[allow(deprecated)] let Some(_) = home_dir() else {
125 return user_dirs;
126 };
127
128 match std::env::consts::OS {
129 "linux" => {
130 user_dirs.push(ExistingUserDirectory {
132 install_type: ExistingInstallType::OfficialLauncher,
133 path: from_home_dir("Documents/My Games/FINAL FANTASY XIV - A Realm Reborn"),
134 });
135
136 user_dirs.push(ExistingUserDirectory {
138 install_type: ExistingInstallType::XIVLauncherCore,
139 path: from_home_dir(".xlcore/ffxivConfig"),
140 });
141
142 if let Ok(entries) = read_dir(from_home_dir(".local/share/astra/user/")) {
144 entries
145 .flatten()
146 .flat_map(|entry| {
147 let Ok(meta) = entry.metadata() else {
148 return vec![];
149 };
150 if meta.is_dir() {
151 return vec![entry.path()];
152 }
153 vec![]
154 })
155 .for_each(|path| {
156 user_dirs.push(ExistingUserDirectory {
157 install_type: ExistingInstallType::Astra,
158 path: path.into_os_string().into_string().unwrap(),
159 })
160 });
161 }
162 }
163 "macos" => {
164 user_dirs.push(ExistingUserDirectory {
166 install_type: ExistingInstallType::OfficialLauncher,
167 path: from_home_dir("Documents/My Games/FINAL FANTASY XIV - A Realm Reborn"),
168 })
169
170 }
172 "windows" => {
173 user_dirs.push(ExistingUserDirectory {
175 install_type: ExistingInstallType::OfficialLauncher,
176 path: from_home_dir("Documents/My Games/FINAL FANTASY XIV - A Realm Reborn"),
177 })
178
179 }
181 &_ => {}
182 }
183
184 user_dirs
185 .into_iter()
186 .filter(|dir| is_valid_user_dir(&dir.path))
187 .collect()
188}
189
190fn from_home_dir(path: &'static str) -> String {
191 #[allow(deprecated)] let mut new_path = home_dir().unwrap();
193 new_path.push(path);
194 new_path.into_os_string().into_string().unwrap()
195}
196
197fn is_valid_game_dir(path: &String) -> bool {
198 let mut d = PathBuf::from(path);
199
200 if fs::metadata(d.as_path()).is_err() {
202 return false;
203 }
204
205 d.push("game");
207
208 if fs::metadata(d.as_path()).is_err() {
209 return false;
210 }
211
212 d.pop();
214 d.push("boot");
215
216 if fs::metadata(d.as_path()).is_err() {
217 return false;
218 }
219
220 true
221}
222
223fn is_valid_user_dir(path: &String) -> bool {
224 let mut d = PathBuf::from(path);
225
226 if fs::metadata(d.as_path()).is_err() {
228 return false;
229 }
230
231 d.push("FFXIV.cfg");
233
234 if fs::metadata(d.as_path()).is_err() {
235 return false;
236 }
237
238 true
239}