pacenotes_installer\install/
rbr.rs1pub const PACENOTE_SETTINGS: &str = "Plugins/Pacenote/PaceNote.ini";
5
6const PACENOTE_CONFIG_DIR: &str = "Plugins/Pacenote/config";
8
9const PACENOTE_SOUNDS: &str = "Plugins/Pacenote/sounds";
11
12const TEMPLATE: &str = "[SETTINGS]\r\n\
15 sounds=\r\n\
16 language=english\r\n\
17 replaySpeeds=0.005 0.01 0.03 0.06 0.125 0.25 0.5 0.75 1 1.25 1.5 1.75 2 4 6 8 10\r\n\
18 enableGUI=1\r\n\
19 showReplayHUD=1\r\n\
20 muteReplayPacenotes=0\r\n";
21
22const SECTION: &str = "SETTINGS";
23
24pub fn configure(
25 game_dir: &std::path::Path,
26 picks: &std::collections::BTreeMap<String, String>,
27) -> Result<super::Configured, super::ConfigureError> {
28 if !crate::relative_path::join(game_dir, PACENOTE_CONFIG_DIR).is_dir() {
29 return Err(super::ConfigureError::PluginMissing);
30 }
31
32 let mut outcome = super::Configured::default();
33 let path = crate::relative_path::join(game_dir, PACENOTE_SETTINGS);
34 let shipped = std::fs::read_to_string(&path).ok();
35 if shipped.is_none() {
36 outcome.notes.push(format!(
37 "{PACENOTE_SETTINGS} was missing; writing a default one"
38 ));
39 }
40 let original = shipped.as_deref().unwrap_or(TEMPLATE);
41
42 let mut text = original.to_string();
43 if let Some(language) = picks
44 .get(pacenotes_shared::CATEGORY_LANGUAGE)
45 .and_then(|key| leaf_of(key))
46 {
47 text = super::ini::set_ini_key(&text, SECTION, "language", language);
48 }
49 if let Some(sounds) = picks
50 .get(pacenotes_shared::CATEGORY_CODRIVER)
51 .and_then(|key| below_category(key))
52 {
53 let audio = crate::relative_path::join(game_dir, &format!("{PACENOTE_SOUNDS}/{sounds}"));
55 if audio.is_dir() {
56 text = super::ini::set_ini_key(&text, SECTION, "sounds", sounds);
57 } else {
58 outcome.notes.push(format!(
59 "no audio folder at {PACENOTE_SOUNDS}/{sounds}; leaving the sounds setting \
60 as the package shipped it"
61 ));
62 }
63 }
64
65 if shipped.as_deref() == Some(text.as_str()) {
66 return Ok(outcome);
67 }
68 write_settings(&path, &text)?;
69 outcome.files.push(PACENOTE_SETTINGS.to_string());
70 Ok(outcome)
71}
72
73fn write_settings(path: &std::path::Path, text: &str) -> Result<(), super::ConfigureError> {
74 let io_error = |doing: String, e: std::io::Error| super::ConfigureError::Io {
75 doing,
76 reason: e.to_string(),
77 };
78 if let Some(parent) = path.parent() {
79 std::fs::create_dir_all(parent)
80 .map_err(|e| io_error(format!("creating {}", parent.display()), e))?;
81 }
82 std::fs::write(path, text.as_bytes())
83 .map_err(|e| io_error(format!("writing {}", path.display()), e))
84}
85
86fn leaf_of(key: &str) -> Option<&str> {
88 let (_, _, name) = pacenotes_shared::split_download_path(key)?;
89 name.rsplit('/').next()
90}
91
92fn below_category(key: &str) -> Option<&str> {
95 let (_, _, name) = pacenotes_shared::split_download_path(key)?;
96 let (_, rest) = name.split_once('/')?;
97 Some(rest)
98}
99
100#[cfg(test)]
101mod tests;