use std::path::PathBuf; use anyhow::{anyhow, Result}; use ini::Ini; use crate::{model::{profile::{Aime, Segatools}, segatools_base::segatools_base}, profiles::ProfilePaths, util::{self, PathStr}}; use crate::pkg_store::PackageStore; impl Segatools { pub fn fix(&mut self, store: &PackageStore) { macro_rules! remove_if_nonpresent { ($item:expr,$key:expr,$emptyval:expr,$store:expr) => { if let Ok(pkg) = $store.get($key) { if pkg.loc.is_none() { $item = $emptyval; } } else { $item = $emptyval; } } } if let Some(key) = &self.hook { remove_if_nonpresent!(self.hook, key, None, store); } if let Some(key) = &self.io { remove_if_nonpresent!(self.io, key, None, store); } match &self.aime { Aime::AMNet(key) => remove_if_nonpresent!(self.aime, key, Aime::BuiltIn, store), Aime::Other(key) => remove_if_nonpresent!(self.aime, key, Aime::BuiltIn, store), _ => {}, } } pub async fn line_up(&self, p: &impl ProfilePaths) -> Result { log::debug!("begin line-up: segatools"); let pfx_dir = p.data_dir(); let exe_dir = self.target.parent().ok_or_else(|| anyhow!("Invalid target path"))?; log::debug!("segatools: {:?} {:?}", pfx_dir, exe_dir); let ini_path = p.config_dir().join("segatools-base.ini"); if !ini_path.exists() { tokio::fs::write(&ini_path, segatools_base()).await .map_err(|e| anyhow!("Error creating {:?}: {}", ini_path, e))?; } if !pfx_dir.exists() { tokio::fs::create_dir(&pfx_dir).await .map_err(|e| anyhow!("Error creating {:?}: {}", pfx_dir, e))?; } let ini_in = tokio::fs::read_to_string(&ini_path).await?; let ini_in = Ini::load_from_str(&ini_in)?; let opt_dir_out = &pfx_dir.join("option"); let opt_dir_in = if self.option.as_os_str().len() > 0 && self.option.is_relative() { exe_dir.join(&self.option) } else { self.option.clone() }; let mut ini_out = ini_in.clone(); ini_out.with_section(Some("vfs")) .set( "option", opt_dir_out.stringify()? ) .set("amfs", self.amfs.stringify()?) .set("appdata", self.appdata.stringify()?); ini_out.with_section(Some("unity")) .set("enable", "1") .set( "targetAssembly", pfx_dir.join("BepInEx").join("core").join("BepInEx.Preloader.dll").stringify()? ); if self.aime != Aime::Disabled { ini_out.with_section(Some("aime")) .set("enable", "1") .set("aimePath", p.config_dir().join("aime.txt").stringify()?); if let Aime::AMNet(key) = &self.aime { let mut aimeio = ini_out.with_section(Some("aimeio")); aimeio .set("path", util::pkg_dir().join(key.to_string()).join("segatools").join("aimeio.dll").stringify()?) .set("gameId", "SDDT") .set("serverAddress", &self.amnet.addr) .set("useAimeDBForPhysicalCards", if self.amnet.physical { "1" } else { "0" }) .set("enableKeyboardMode", "0"); if let Ok(keyboard_code) = std::fs::read_to_string(p.config_dir().join("aime.txt")) { log::debug!("{} {}", keyboard_code, keyboard_code.len()); if keyboard_code.len() == 20 { aimeio.set("enableKeyboardMode", "1"); } } if self.amnet.name.len() > 0 { aimeio.set("serverName", &self.amnet.name); } } } else { ini_out.with_section(Some("aime")) .set("enable", "0"); } if let Some(io) = &self.io { ini_out.with_section(Some("mu3io")) .set("path", util::pkg_dir().join(io.to_string()).join("segatools").join("mu3io.dll").stringify()?); } else { ini_out.with_section(Some("mu3io")) .set("path", ""); } log::debug!("option dir: {:?} -> {:?}", opt_dir_in, opt_dir_out); if !opt_dir_out.exists() { tokio::fs::create_dir(opt_dir_out).await?; } if opt_dir_in.as_os_str().len() > 0 { for opt in opt_dir_in.read_dir()? { let opt = opt?; util::symlink(&opt.path(), opt_dir_out.join(opt.file_name())).await?; } } if !exe_dir.join("DEVICE").join("ca.crt").exists() { util::copy_directory( util::pkg_dir().join(self.hook_dir()?).join("DEVICE"), exe_dir.join("DEVICE"), false )?; } log::debug!("end line-up: segatools"); Ok(ini_out) } pub fn hook_dir(&self) -> Result { Ok(util::pkg_dir() .join(self.hook.as_ref().ok_or_else(|| anyhow!("No hook"))?.to_string()) .join("segatools")) } }