Skip to main content

launcher/app/
logic.rs

1use super::LauncherApp;
2use crate::pages::trainer::TrainerData;
3use crate::pages::troubleshoot::TroubleshootData;
4use crate::tasks::TaskEvent;
5use std::io::Write;
6
7impl LauncherApp {
8    pub fn save_all_configs(&mut self) {
9        match self.config_manager.save_all() {
10            Ok(()) => {
11                self.error_message = None;
12            }
13            Err(errors) => {
14                let error_msg = errors.join("\n");
15                self.error_message = Some(format!(
16                    "{error_msg}\nClick \"Play\" again to start anyway."
17                ));
18            }
19        }
20    }
21
22    pub fn load_music_configs(&mut self) {
23        self.config_manager.load_music_configs();
24        self.music_state.is_scanned = false;
25    }
26
27    #[cfg(feature = "local")]
28    pub fn export_configs(&mut self) {
29        match self.config_manager.export() {
30            Ok(_export_path) => {
31                self.error_message = None;
32            }
33            Err(errors) => {
34                self.error_message = Some(errors.join("\n"));
35            }
36        }
37    }
38
39    pub fn update_unified_operations(&mut self) {
40        // Update dependency operations
41        if let Some(handle) = self.dependency_receiver.take() {
42            while let Ok(event) = handle.try_recv() {
43                self.handle_task_event(event);
44            }
45            if self.unified_operation.is_running {
46                self.dependency_receiver = Some(handle);
47            } else {
48                self.dependency_receiver = None;
49                self.trainer_state.last_checked = None; // Force refresh after operations complete
50            }
51        }
52
53        // Update troubleshoot operations
54        if let Some(handle) = self.troubleshoot_receiver.take() {
55            while let Ok(event) = handle.try_recv() {
56                match event {
57                    TaskEvent::PageData(data) => match data {
58                        TroubleshootData::Diagnostics(d) => {
59                            self.unified_operation.diagnostics = Some(d);
60                        }
61                        TroubleshootData::Profiles(_) => {}
62                        TroubleshootData::RefreshStatus(_) => {}
63                    },
64                    event => self.handle_task_event(event.map(|_| ())),
65                }
66            }
67            if self.unified_operation.is_running {
68                self.troubleshoot_receiver = Some(handle);
69            } else {
70                self.troubleshoot_receiver = None;
71            }
72        }
73
74        // Update trainer operations
75        if let Some(handle) = self.trainer_receiver.take() {
76            while let Ok(event) = handle.try_recv() {
77                match event {
78                    TaskEvent::PageData(data) => match data {
79                        TrainerData::DependenciesCheck(installed) => {
80                            self.trainer_state.dependencies_installed = installed;
81                            self.trainer_state.is_checking = false;
82                            self.trainer_state.last_checked = Some(std::time::Instant::now());
83                        }
84                        TrainerData::HdFontsCheck(needed) => {
85                            self.trainer_state.hd_fonts_needed = needed;
86                        }
87                    },
88                    event => self.handle_task_event(event.map(|_| ())),
89                }
90            }
91            if !self.unified_operation.is_running && !self.trainer_state.is_checking {
92                self.trainer_receiver = None;
93            } else {
94                self.trainer_receiver = Some(handle);
95            }
96        }
97    }
98
99    pub fn handle_task_event<T>(&mut self, event: TaskEvent<T>) {
100        use TaskEvent;
101        match event {
102            TaskEvent::Log(msg) => {
103                self.unified_operation.logs.push(msg);
104            }
105            TaskEvent::SetStatus(msg) => {
106                self.unified_operation.status = msg;
107            }
108            TaskEvent::InitProgress(total) => {
109                self.unified_operation.total_items = total;
110                self.unified_operation.processed_items = 0;
111            }
112            TaskEvent::IncrementProgress => {
113                self.unified_operation.processed_items += 1;
114            }
115            TaskEvent::UpdateProgress(p) => {
116                self.unified_operation.processed_items = p;
117            }
118            TaskEvent::Perf(_op, _target, _ms) => {
119                // Ignore perf in unified operation
120            }
121            TaskEvent::PageData(_) => {
122                // Ignore generic data in unified operation; handled in update_unified_operations specifically
123            }
124            TaskEvent::Finished(res) => {
125                self.unified_operation.is_running = false;
126                match res {
127                    Ok(_) => {
128                        self.unified_operation.status =
129                            "Operation completed successfully.".to_string();
130                        self.unified_operation.processed_items = self.unified_operation.total_items;
131                    }
132                    Err(e) => {
133                        self.unified_operation.status = format!("Error: {e}");
134                        self.unified_operation.logs.push(format!("Error: {e}"));
135                    }
136                }
137            }
138        }
139    }
140
141    pub fn run_injector(&mut self) {
142        let resources_dir = self.storage.game_path().join("Display_Config_Resources");
143        let injector_path = resources_dir.join("Injector.exe");
144        let log_path = resources_dir.join("Display_Config_Helper.log");
145
146        if !injector_path.exists() {
147            // Start normally when there is no injector
148            std::process::exit(0);
149        }
150
151        let mut attempts = 0;
152        let max_attempts = 2;
153
154        while attempts < max_attempts {
155            let mut command = std::process::Command::new(&injector_path);
156            command.current_dir(&resources_dir);
157            command.stdout(std::process::Stdio::piped());
158            command.stderr(std::process::Stdio::piped());
159
160            let result = command.output();
161
162            // Log output if possible
163            if let Ok(ref output) = result
164                && let Ok(mut file) = std::fs::OpenOptions::new()
165                    .create(true)
166                    .append(true)
167                    .open(&log_path)
168            {
169                if let Err(e) = writeln!(file, "\n--- Injector Log (Attempt {}) ---", attempts + 1)
170                {
171                    eprintln!("Failed to write injector log header: {e}");
172                }
173                if let Err(e) = file.write_all(&output.stdout) {
174                    eprintln!("Failed to write injector stdout to log: {e}");
175                }
176                if let Err(e) = file.write_all(&output.stderr) {
177                    eprintln!("Failed to write injector stderr to log: {e}");
178                }
179                if let Err(e) = writeln!(file, "--- End Log ---") {
180                    eprintln!("Failed to write injector log footer: {e}");
181                }
182            }
183            if let Err(ref e) = result
184                && let Ok(mut file) = std::fs::OpenOptions::new()
185                    .create(true)
186                    .append(true)
187                    .open(&log_path)
188            {
189                if let Err(write_err) = writeln!(file, "\n--- Injector Execution Error ---") {
190                    eprintln!("Failed to write injector error header: {write_err}");
191                }
192                if let Err(write_err) = writeln!(file, "Error: {e}") {
193                    eprintln!("Failed to write injector error detail: {write_err}");
194                }
195                if let Err(write_err) = writeln!(file, "--- End Log ---") {
196                    eprintln!("Failed to write injector error footer: {write_err}");
197                }
198            }
199
200            match result {
201                Ok(output) if output.status.success() => {
202                    // Injection succeeded, exit
203                    std::process::exit(0);
204                }
205                _ => {
206                    // Injection failed
207                    let failed_with_logs_disabled =
208                        !self.config_manager.trainer_config.enable_logging;
209
210                    self.error_message = Some(
211                        "Failed to inject patches.\nClick \"Play\" again to force start."
212                            .to_string(),
213                    );
214
215                    if attempts == 0 && failed_with_logs_disabled {
216                        // Turn on logs and retry
217                        self.config_manager.trainer_config.enable_logging = true;
218                        if let Err(e) = self.config_manager.save_all() {
219                            eprintln!("Failed to save config after enabling logging: {e:?}");
220                        }
221                        attempts += 1;
222                        continue;
223                    }
224                    // Don't retry further, just exit
225                    break;
226                }
227            }
228        }
229    }
230}