emu_runner/contexts/
bizhawk.rs1use camino::Utf8PathBuf;
2use crate::{EmulatorContext, Error};
3use crate::includes::{BIZHAWK_BASH_DEFAULT, BIZHAWK_BASH_PRE290, copy_if_different};
4
5#[derive(Debug, Clone, PartialEq)]
6pub struct BizHawkContext {
7 pub config: Option<Utf8PathBuf>,
8 pub movie: Option<Utf8PathBuf>,
9 pub lua: Option<Utf8PathBuf>,
10 pub rom: Option<Utf8PathBuf>,
11 pub working_dir: Utf8PathBuf,
12}
13impl EmulatorContext for BizHawkContext {
14 fn cmd_name(&self) -> String {
15 #[cfg(target_family = "unix")]
16 { "bash".into() }
17
18 #[cfg(target_family = "windows")]
19 { "EmuHawk.exe".into() }
20 }
21
22 fn args(&self) -> Vec<String> {
23 let mut args = Vec::with_capacity(5);
24
25 #[cfg(target_family = "unix")]
26 {
27 args.push("start-bizhawk.sh".into());
28 }
29
30 if let Some(config) = self.config.as_ref() {
31 args.push(format!("--config={config}"));
32 }
33 if let Some(movie) = self.movie.as_ref() {
34 args.push(format!("--movie={movie}"));
35 }
36 if let Some(lua) = self.lua.as_ref() {
37 args.push(format!("--lua={lua}"));
38 }
39 if let Some(rom) = self.rom.as_ref() {
40 args.push(rom.to_string());
41 }
42
43 args
44 }
45
46 fn env(&self) -> Vec<(String, String)> {
47 vec![]
48 }
49
50 fn prepare(&mut self) -> Result<(), Error> {
51 if let Some(config) = self.config.as_ref() {
58 if !config.is_file() {
59 return Err(Error::MissingConfig(config.clone()));
60 }
61 if !config.is_absolute() {
62 return Err(Error::AbsolutePathFailed);
63 }
64 }
65 if let Some(movie) = self.movie.as_ref() {
66 if !movie.is_file() {
67 return Err(Error::MissingMovie(movie.clone()));
68 }
69 if !movie.is_absolute() {
70 return Err(Error::AbsolutePathFailed);
71 }
72 }
73 if let Some(lua) = self.lua.as_ref() {
74 if !lua.is_file() {
75 return Err(Error::MissingLua(lua.clone()));
76 }
77 if !lua.is_absolute() {
78 return Err(Error::AbsolutePathFailed);
79 }
80 }
81 if let Some(rom) = self.rom.as_ref() {
82 if !rom.is_file() {
83 return Err(Error::MissingRom(rom.clone()));
84 }
85 if !rom.is_absolute() {
86 return Err(Error::AbsolutePathFailed);
87 }
88 }
89
90 #[cfg(target_family = "unix")]
92 {
93 let bash = match self.detect_version() {
94 Some(ver) => match ver.as_str() {
95 "2.8" | "2.8-rc1" | "2.7" | "2.6.3" | "2.6.2" | "2.6.1" | "2.6" => BIZHAWK_BASH_PRE290,
96
97 "2.5.2" | "2.5.1" | "2.5.0" | "2.4.2" | "2.4.1" | "2.4" | "2.3.3"
98 | "2.3.2" | "2.3.1" | "2.3" | "2.2.2" | "2.2.1" | "2.2" | "2.1.1"
99 | "2.1.0" | "1.13.2" | "1.9.2" | "1.6.1" => return Err(Error::IncompatibleOSVersion),
100
101 _ => BIZHAWK_BASH_DEFAULT,
102 },
103 None => BIZHAWK_BASH_DEFAULT
104 };
105
106 let mut path = self.working_dir.clone();
107 path.push("start-bizhawk.sh");
108 copy_if_different(bash, path)?;
109 }
110
111 Ok(())
112 }
113
114 fn working_dir(&self) -> Utf8PathBuf {
115 self.working_dir.clone()
116 }
117}
118impl BizHawkContext {
119 pub fn new<P: Into<Utf8PathBuf>>(working_dir: P) -> Result<Self, Error> {
124 let mut working_dir = working_dir.into();
125 if working_dir.is_file() {
126 working_dir.pop();
127 }
128
129 working_dir = working_dir.canonicalize_utf8().unwrap_or(working_dir);
130
131 let mut detect_exe = working_dir.clone();
132 detect_exe.push("EmuHawk.exe");
133 if working_dir.is_file() || !working_dir.exists() || !detect_exe.is_file() {
134 return Err(Error::MissingExecutable(detect_exe));
135 }
136
137 Ok(Self {
138 config: None,
139 movie: None,
140 lua: None,
141 rom: None,
142 working_dir,
143 })
144 }
145
146 pub fn with_config<P: Into<Utf8PathBuf>>(self, config: P) -> Self {
147 let config = config.into();
148 Self {
149 config: Some(config.canonicalize_utf8().unwrap_or_else(|_| config)),
150 ..self
151 }
152 }
153
154 pub fn with_movie<P: Into<Utf8PathBuf>>(self, movie: P) -> Self {
155 let movie = movie.into();
156 Self {
157 movie: Some(movie.canonicalize_utf8().unwrap_or_else(|_| movie)),
158 ..self
159 }
160 }
161
162 pub fn with_lua<P: Into<Utf8PathBuf>>(self, lua: P) -> Self {
163 let lua = lua.into();
164 Self {
165 lua: Some(lua.canonicalize_utf8().unwrap_or_else(|_| lua)),
166 ..self
167 }
168 }
169
170 pub fn with_rom<P: Into<Utf8PathBuf>>(self, rom: P) -> Self {
171 let rom = rom.into();
172 Self {
173 rom: Some(rom.canonicalize_utf8().unwrap_or_else(|_| rom)),
174 ..self
175 }
176 }
177
178 pub fn detect_version(&self) -> Option<String> {
180 let mut exe = self.working_dir.clone();
181 exe.push("EmuHawk.exe");
182 let exe = std::fs::read(exe).unwrap();
183 let sha1 = sha1_smol::Sha1::from(exe).digest().to_string().to_lowercase();
184
185 Some(match sha1.as_str() {
186 "ef7c4067cec01b60b89ff8c271f3c72a0b2d009f" => "2.9.1",
187 "c9be7f8e4a05122e60545e8988920b710bd50ea7" => "2.9",
188 "31a2fadd049957377358a0b7b1267f3d8ecebfd9" => "2.9-rc3",
189 "a6ff6e02a05a0ec52695a7ec757aedcdc16e0192" => "2.9-rc2",
190 "288e310c430cbcbc0881913efd82e91f16dc14dd" => "2.9-rc1",
191 "88e476295d004a80ea514847c0d590879e7b3d88" => "2.8",
192 "9d2738265a37e28813eeff08e41def697f58cbee" => "2.8-rc1",
193 "eac6aa28589372d120e23e5b2f69b56c2542273b" => "2.7",
194 "3261214b9991918c5224d27b6cf7d84f9acd3566" => "1.9.2",
195 "202a0d945cd20a1b2e5021d3499ac7b5c2f5ca46" => "1.6.1",
196 "7dd9dce90e16138ca38ef92cdb1270a378d21dad" => "2.6.3",
197 "3668613ed1fc61f1dafde9b678e6a637da23d882" => "2.6.2",
198 "115cb73156b4a288378fd00aa0fd982fb0c311c5" => "2.6.1",
199 "307526d8171fa9aa2dfbf735aa1eca23425b829a" => "2.6",
200 "7bcc6337005dba33fbc8a454cf7f669563f39e85" => "2.5.2",
201 "410c423feef9666955b2a0d66c3b64c3e432988a" => "2.5.1",
202 "d45a7348a8e5505b294df9add852787d04b569e4" => "2.5.0",
203 "6e169792aebef5942c9fabd276c7d3e07e2c3196" => "2.4.2",
204 "71d9bd1ae6d60b6fc7d3aebe474eae50995c29d7" => "2.4.1",
205 "2668ef81bad2459a9a14a09a3a8d5ee2c6e9cbac" => "2.4",
206 "1fbf1b672ddb4e98aef77a8edd5655149b4b4c72" => "2.3.3",
207 "d9365fd6f1f979a52689979e5709b26dfef7dc09" => "2.3.2",
208 "c2f4b95b86a11c472f7e8522598be644e9e05c6d" => "2.3.1",
209 "b2072e0bdf4944d060c83f44df17e88da4007c81" => "2.3",
210 "ab83cfd3ed5b9dc392d2b0d4aa1b99723c5bf4c9" => "1.13.2",
211 "4c1599c7ed7e5216477454ac7fac0719f2ee6e66" => "2.2.2",
212 "6095cb07bd79703527c01ad4f27ed4e907d2f030" => "2.2.1",
213 "4e2ec35bff8798494d3cc0e22276f2456939257d" => "2.2",
214 "fc372a78d03ca5229f3c125a9dff91a779a66b7a" => "2.1.1",
215 "c2e31867428e03ba2ef23911d605163a7008d6a5" => "2.1.0",
216
217 _ => return None
218 }.to_string())
219 }
220}