forked from akanyan/STARTLINER
245 lines
9.4 KiB
Rust
245 lines
9.4 KiB
Rust
use std::path::{PathBuf, Path};
|
|
use anyhow::{anyhow, Result};
|
|
use ini::Ini;
|
|
use crate::{model::{misc::{ConfigHook, ConfigHookAime, ConfigHookAimeUnit, ConfigHookAuth, Game}, profile::{Aime, IOSelection, Segatools}}, 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 IOSelection::Custom(key) = &self.io2 {
|
|
remove_if_nonpresent!(self.io2, key, IOSelection::default(), 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 fn load_from_ini(&mut self, ini: &Ini, config_dir: impl AsRef<Path>) -> Result<()> {
|
|
log::debug!("loading sgt");
|
|
if let Some(s) = ini.section(Some("vfs")) {
|
|
s.get("amfs").map(|v| self.amfs = PathBuf::from(v));
|
|
s.get("appdata").map(|v| self.appdata = PathBuf::from(v));
|
|
s.get("option").map(|v| self.option = PathBuf::from(v));
|
|
}
|
|
|
|
if let Some(s) = ini.section(Some("aime")) {
|
|
if s.get("enable").unwrap_or("0") == "1" {
|
|
if let Some(aime_path) = s.get("aimePath") {
|
|
if let Some(game_dir) = self.target.parent() {
|
|
let target = game_dir.join(aime_path);
|
|
std::fs::copy(target, config_dir.as_ref().join("aime.txt"))?;
|
|
} else {
|
|
log::error!("profile doesn't have a game directory");
|
|
}
|
|
} else {
|
|
log::warn!("aime emulation is enabled, but no aimePath specified");
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
pub async fn line_up(&self, p: &impl ProfilePaths, game: Game) -> Result<Ini> {
|
|
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() {
|
|
match game {
|
|
Game::Ongeki => tokio::fs::write(&ini_path, include_bytes!("../../static/segatools-ongeki.ini"))
|
|
.await.map_err(|e| anyhow!("Error creating {:?}: {}", ini_path, e))?,
|
|
Game::Chunithm => tokio::fs::write(&ini_path, include_bytes!("../../static/segatools-chunithm.ini"))
|
|
.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()?);
|
|
|
|
if game == Game::Ongeki {
|
|
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("serverAddress", &self.amnet.addr)
|
|
.set("useAimeDBForPhysicalCards", if self.amnet.physical { "1" } else { "0" })
|
|
.set("enableKeyboardMode", "0");
|
|
|
|
match game {
|
|
Game::Ongeki => aimeio.set("gameId", "SDDT"),
|
|
Game::Chunithm => aimeio.set("gameId", "SDHD")
|
|
};
|
|
|
|
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 game == Game::Ongeki {
|
|
if let IOSelection::Custom(io) = &self.io2 {
|
|
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", "");
|
|
}
|
|
}
|
|
match game {
|
|
Game::Ongeki => {
|
|
match &self.io2 {
|
|
IOSelection::Custom(io) => {
|
|
ini_out.with_section(Some("mu3io"))
|
|
.set("path", util::pkg_dir().join(io.to_string()).join("segatools").join("mu3io.dll").stringify()?);
|
|
}
|
|
IOSelection::SegatoolsBuiltIn => {
|
|
ini_out.with_section(Some("mu3io"))
|
|
.set("path", "");
|
|
}
|
|
IOSelection::Hardware => {
|
|
ini_out.with_section(Some("io4"))
|
|
.set("enable", "0");
|
|
}
|
|
}
|
|
},
|
|
Game::Chunithm => {
|
|
match &self.io2 {
|
|
IOSelection::Custom(io) => {
|
|
ini_out.with_section(Some("chuniio"))
|
|
.set("path32", util::pkg_dir().join(io.to_string()).join("segatools").join("chuniio32.dll").stringify()?)
|
|
.set("path64", util::pkg_dir().join(io.to_string()).join("segatools").join("chuniio64.dll").stringify()?);
|
|
}
|
|
IOSelection::SegatoolsBuiltIn => {
|
|
ini_out.with_section(Some("chuniio"))
|
|
.set("path32", "")
|
|
.set("path64", "");
|
|
}
|
|
IOSelection::Hardware => {
|
|
ini_out.with_section(Some("io4"))
|
|
.set("enable", "0");
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
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
|
|
)?;
|
|
}
|
|
|
|
let mut cfg_hook = ConfigHook::default();
|
|
|
|
if game == Game::Chunithm {
|
|
cfg_hook.allnet_auth = Some({
|
|
ConfigHookAuth {
|
|
r#type: "1.0".to_owned()
|
|
}
|
|
})
|
|
}
|
|
if let Some(port) = self.aime_port {
|
|
if self.aime == Aime::Disabled {
|
|
cfg_hook.aime = Some({
|
|
ConfigHookAime {
|
|
unit: vec![
|
|
ConfigHookAimeUnit {
|
|
port,
|
|
id: 1
|
|
}
|
|
]
|
|
}
|
|
})
|
|
}
|
|
}
|
|
std::fs::write(pfx_dir.join("config_hook.json"), serde_json::to_string(&cfg_hook)?)?;
|
|
|
|
log::debug!("end line-up: segatools");
|
|
|
|
Ok(ini_out)
|
|
}
|
|
|
|
pub fn hook_dir(&self) -> Result<PathBuf> {
|
|
Ok(util::pkg_dir()
|
|
.join(self.hook.as_ref().ok_or_else(|| anyhow!("No hook"))?.to_string())
|
|
.join("segatools"))
|
|
}
|
|
} |