|
|
@ -1,4 +1,3 @@
|
|
|
|
use ini::Ini;
|
|
|
|
|
|
|
|
use log;
|
|
|
|
use log;
|
|
|
|
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
|
|
|
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use std::path::PathBuf;
|
|
|
@ -66,7 +65,7 @@ pub async fn startline(app: AppHandle, refresh: bool) -> Result<(), String> {
|
|
|
|
let mut amd_dlls = Vec::new();
|
|
|
|
let mut amd_dlls = Vec::new();
|
|
|
|
if let Some(p) = &appd.profile {
|
|
|
|
if let Some(p) = &appd.profile {
|
|
|
|
hash = appd.sum_packages(p);
|
|
|
|
hash = appd.sum_packages(p);
|
|
|
|
(game_dlls, amd_dlls) = prepare_dlls(p.meta.game, p.mod_pkgs(), &appd.pkgs).map_err(|e| e.to_string())?
|
|
|
|
(game_dlls, amd_dlls) = prepare_dlls(p.meta.game, p.mod_pkgs(), &appd.pkgs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(p) = &appd.profile {
|
|
|
|
if let Some(p) = &appd.profile {
|
|
|
|
log::debug!("{}", hash);
|
|
|
|
log::debug!("{}", hash);
|
|
|
@ -74,13 +73,12 @@ pub async fn startline(app: AppHandle, refresh: bool) -> Result<(), String> {
|
|
|
|
let patches_enabled = appd.patches_enabled(
|
|
|
|
let patches_enabled = appd.patches_enabled(
|
|
|
|
&p.data.sgt.target,
|
|
|
|
&p.data.sgt.target,
|
|
|
|
&p.data.sgt.target.parent().unwrap().join("amdaemon.exe")
|
|
|
|
&p.data.sgt.target.parent().unwrap().join("amdaemon.exe")
|
|
|
|
).map_err(|e| e.to_string())?;
|
|
|
|
).map_err(|e| format!("Unable to apply patches: {e}"))?;
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
let info = p.prepare_display()
|
|
|
|
let info = p.prepare_display()
|
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
.map_err(|e| format!("Unable to configure displays: {e}"))?;
|
|
|
|
let lineup_res = p.line_up(hash, refresh, patches_enabled).await
|
|
|
|
let lineup_res = p.line_up(hash, refresh, patches_enabled).await;
|
|
|
|
.map_err(|e| e.to_string());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
if let Some(info) = info {
|
|
|
|
if let Some(info) = info {
|
|
|
@ -88,11 +86,12 @@ pub async fn startline(app: AppHandle, refresh: bool) -> Result<(), String> {
|
|
|
|
if lineup_res.is_ok() {
|
|
|
|
if lineup_res.is_ok() {
|
|
|
|
Display::wait_for_exit(app.clone(), info);
|
|
|
|
Display::wait_for_exit(app.clone(), info);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Display::clean_up(&info).map_err(|e| e.to_string())?;
|
|
|
|
Display::clean_up(&info)
|
|
|
|
|
|
|
|
.map_err(|e| format!("Unable to restore displays: {e}"))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
lineup_res?;
|
|
|
|
lineup_res.map_err(|e| format!("Init failed: {e}"))?;
|
|
|
|
|
|
|
|
|
|
|
|
let app_clone = app.clone();
|
|
|
|
let app_clone = app.clone();
|
|
|
|
let p_clone = p.clone();
|
|
|
|
let p_clone = p.clone();
|
|
|
@ -133,7 +132,7 @@ pub async fn install_package(
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
appd.pkgs.install_package(&key, force, true, enable)
|
|
|
|
appd.pkgs.install_package(&key, force, true, enable)
|
|
|
|
.await
|
|
|
|
.await
|
|
|
|
.map_err(|e| e.to_string())
|
|
|
|
.map_err(|e| format!("Unable to install {key}: {e}"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[tauri::command]
|
|
|
|
#[tauri::command]
|
|
|
@ -143,10 +142,10 @@ pub async fn delete_package(state: State<'_, tokio::sync::Mutex<AppData>>, key:
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
appd.pkgs.delete_package(&key, true)
|
|
|
|
appd.pkgs.delete_package(&key, true)
|
|
|
|
.await
|
|
|
|
.await
|
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
.map_err(|e| format!("Unable to delete {key}: {e}"))?;
|
|
|
|
|
|
|
|
|
|
|
|
appd.toggle_package(key, ToggleAction::Disable)
|
|
|
|
appd.toggle_package(key.clone(), ToggleAction::Disable)
|
|
|
|
.map_err(|e| e.to_string())
|
|
|
|
.map_err(|e| format!("Unable to disable {key}: {e}"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[tauri::command]
|
|
|
|
#[tauri::command]
|
|
|
@ -155,7 +154,7 @@ pub async fn get_package(state: State<'_, tokio::sync::Mutex<AppData>>, key: Pkg
|
|
|
|
|
|
|
|
|
|
|
|
let appd = state.lock().await;
|
|
|
|
let appd = state.lock().await;
|
|
|
|
appd.pkgs.get(&key)
|
|
|
|
appd.pkgs.get(&key)
|
|
|
|
.map_err(|e| e.to_string())
|
|
|
|
.map_err(|e| format!("Unable to load {key}: {e}"))
|
|
|
|
.cloned()
|
|
|
|
.cloned()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -164,8 +163,8 @@ pub async fn toggle_package(state: State<'_, tokio::sync::Mutex<AppData>>, key:
|
|
|
|
log::debug!("invoke: toggle_package({}, {})", key, enable);
|
|
|
|
log::debug!("invoke: toggle_package({}, {})", key, enable);
|
|
|
|
|
|
|
|
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
appd.toggle_package(key, if enable { ToggleAction::EnableRecursive } else { ToggleAction::Disable })
|
|
|
|
appd.toggle_package(key.clone(), if enable { ToggleAction::EnableRecursive } else { ToggleAction::Disable })
|
|
|
|
.map_err(|e| e.to_string())
|
|
|
|
.map_err(|e| format!("Unable to toggle {key}: {e}"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[tauri::command]
|
|
|
|
#[tauri::command]
|
|
|
@ -220,9 +219,12 @@ pub async fn create_package(
|
|
|
|
games: Some(games)
|
|
|
|
games: Some(games)
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
std::fs::create_dir(&dir).map_err(|e| e.to_string())?;
|
|
|
|
std::fs::create_dir(&dir)
|
|
|
|
let json = serde_json::to_string_pretty(&manifest).map_err(|e| e.to_string())?;
|
|
|
|
.map_err(|e| format!("Unable to create {} directory: {e}", dir.file_name().unwrap_or_default().to_string_lossy()))?;
|
|
|
|
std::fs::write(dir.join("manifest.json"), json).map_err(|e| e.to_string())?;
|
|
|
|
let json = serde_json::to_string_pretty(&manifest)
|
|
|
|
|
|
|
|
.map_err(|e| format!("Unable to serialize manifest.json: {e}"))?;
|
|
|
|
|
|
|
|
std::fs::write(dir.join("manifest.json"), json)
|
|
|
|
|
|
|
|
.map_err(|e| format!("Unable to write manifest.json: {e}"))?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -234,7 +236,7 @@ pub async fn reload_all_packages(state: State<'_, tokio::sync::Mutex<AppData>>)
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
appd.pkgs.reload_all()
|
|
|
|
appd.pkgs.reload_all()
|
|
|
|
.await
|
|
|
|
.await
|
|
|
|
.map_err(|e| e.to_string())
|
|
|
|
.map_err(|e| format!("Unable to reload packages: {e}"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[tauri::command]
|
|
|
|
#[tauri::command]
|
|
|
@ -288,17 +290,17 @@ pub async fn fetch_listings(state: State<'_, Mutex<AppData>>) -> Result<(), Stri
|
|
|
|
|
|
|
|
|
|
|
|
// Can be this lazy for now as there are only two short lists
|
|
|
|
// Can be this lazy for now as there are only two short lists
|
|
|
|
let listings1 = PackageStore::fetch_listings(Game::Ongeki).await
|
|
|
|
let listings1 = PackageStore::fetch_listings(Game::Ongeki).await
|
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
.map_err(|e| format!("Unable to fetch Chunithm listings: {e}"))?;
|
|
|
|
|
|
|
|
|
|
|
|
let listings2 = PackageStore::fetch_listings(Game::Chunithm).await
|
|
|
|
let listings2 = PackageStore::fetch_listings(Game::Chunithm).await
|
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
.map_err(|e| format!("Unable to fetch Ongeki listings: {e}"))?;
|
|
|
|
|
|
|
|
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
appd.pkgs.process_fetched_listings(listings1, Game::Ongeki);
|
|
|
|
appd.pkgs.process_fetched_listings(listings1, Game::Ongeki);
|
|
|
|
appd.pkgs.process_fetched_listings(listings2, Game::Chunithm);
|
|
|
|
appd.pkgs.process_fetched_listings(listings2, Game::Chunithm);
|
|
|
|
|
|
|
|
|
|
|
|
appd.pkgs.save().await
|
|
|
|
appd.pkgs.save().await
|
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
.map_err(|e| format!("Unable to save package-list: {e}"))?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -307,7 +309,9 @@ pub async fn fetch_listings(state: State<'_, Mutex<AppData>>) -> Result<(), Stri
|
|
|
|
pub async fn list_profiles() -> Result<Vec<ProfileMeta>, String> {
|
|
|
|
pub async fn list_profiles() -> Result<Vec<ProfileMeta>, String> {
|
|
|
|
log::debug!("invoke: list_profiles");
|
|
|
|
log::debug!("invoke: list_profiles");
|
|
|
|
|
|
|
|
|
|
|
|
let list = crate::profiles::list_profiles().await.map_err(|e| e.to_string())?;
|
|
|
|
let list = crate::profiles::list_profiles()
|
|
|
|
|
|
|
|
.await
|
|
|
|
|
|
|
|
.map_err(|e| format!("Unable to list profiles: {e}"))?;
|
|
|
|
Ok(list)
|
|
|
|
Ok(list)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -321,7 +325,7 @@ pub async fn init_profile(
|
|
|
|
|
|
|
|
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
let new_profile = Profile::new(ProfileMeta { game, name })
|
|
|
|
let new_profile = Profile::new(ProfileMeta { game, name })
|
|
|
|
.map_err(|e| format!("Unable to create profile: {}", e))?;
|
|
|
|
.map_err(|e| format!("Unable to create a profile: {}", e))?;
|
|
|
|
|
|
|
|
|
|
|
|
appd.profile = Some(new_profile);
|
|
|
|
appd.profile = Some(new_profile);
|
|
|
|
|
|
|
|
|
|
|
@ -333,7 +337,8 @@ pub async fn load_profile(state: State<'_, Mutex<AppData>>, game: Game, name: St
|
|
|
|
log::debug!("invoke: load_profile({} {:?})", game, name);
|
|
|
|
log::debug!("invoke: load_profile({} {:?})", game, name);
|
|
|
|
|
|
|
|
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
appd.switch_profile(game, name).map_err(|e| e.to_string())?;
|
|
|
|
appd.switch_profile(game, name)
|
|
|
|
|
|
|
|
.map_err(|e| format!("Unable to switch profile: {e}"))?;
|
|
|
|
appd.fix();
|
|
|
|
appd.fix();
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -440,7 +445,7 @@ pub async fn save_current_profile(state: State<'_, Mutex<AppData>>) -> Result<()
|
|
|
|
appd.fix();
|
|
|
|
appd.fix();
|
|
|
|
match &mut appd.profile {
|
|
|
|
match &mut appd.profile {
|
|
|
|
Some(p) => {
|
|
|
|
Some(p) => {
|
|
|
|
p.save().map_err(|e| e.to_string())
|
|
|
|
p.save().map_err(|e| format!("Unable to save profile: {e}"))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
None => {
|
|
|
|
Err("no profile to save".to_owned())
|
|
|
|
Err("no profile to save".to_owned())
|
|
|
@ -454,16 +459,7 @@ pub async fn load_segatools_ini(state: State<'_, Mutex<AppData>>, path: PathBuf)
|
|
|
|
|
|
|
|
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
if let Some(p) = &mut appd.profile {
|
|
|
|
if let Some(p) = &mut appd.profile {
|
|
|
|
let str = std::fs::read_to_string(path).map_err(|e| e.to_string())?;
|
|
|
|
p.load_segatools_ini(path).map_err(|e| format!("Unable to load segatools.ini: {e}"))?;
|
|
|
|
// Stupid path escape hack for the ini reader
|
|
|
|
|
|
|
|
let str = str.replace("\\", "\\\\").replace("\\\\\\\\", "\\\\");
|
|
|
|
|
|
|
|
let ini = Ini::load_from_str(&str).map_err(|e| e.to_string())?;
|
|
|
|
|
|
|
|
p.data.sgt.load_from_ini(&ini, p.config_dir()).map_err(|e| e.to_string())?;
|
|
|
|
|
|
|
|
p.data.network.load_from_ini(&ini).map_err(|e| e.to_string())?;
|
|
|
|
|
|
|
|
if let Some(kb) = &mut p.data.keyboard {
|
|
|
|
|
|
|
|
kb.load_from_ini(&ini).map_err(|e| e.to_string())?;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
p.save().map_err(|e| e.to_string())?;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
@ -474,7 +470,8 @@ pub async fn create_shortcut(_app: AppHandle, profile_meta: ProfileMeta) -> Resu
|
|
|
|
log::debug!("invoke: create_shortcut({:?})", profile_meta);
|
|
|
|
log::debug!("invoke: create_shortcut({:?})", profile_meta);
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
return util::create_shortcut(_app, &profile_meta).map_err(|e| e.to_string());
|
|
|
|
return util::create_shortcut(_app, &profile_meta)
|
|
|
|
|
|
|
|
.map_err(|e| format!("Unable to create a shortcut: {e}"));
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
|
|
return Err("unsupported".to_owned());
|
|
|
|
return Err("unsupported".to_owned());
|
|
|
@ -493,7 +490,7 @@ pub async fn export_profile(
|
|
|
|
match &appd.profile {
|
|
|
|
match &appd.profile {
|
|
|
|
Some(p) => {
|
|
|
|
Some(p) => {
|
|
|
|
p.export(export_keychip, files, is_diagnostic)
|
|
|
|
p.export(export_keychip, files, is_diagnostic)
|
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
.map_err(|e| format!("Unable to export profile: {e}"))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
None => {
|
|
|
|
let err = "export_profile: no profile".to_owned();
|
|
|
|
let err = "export_profile: no profile".to_owned();
|
|
|
@ -509,7 +506,7 @@ pub async fn export_profile(
|
|
|
|
pub async fn import_profile(path: PathBuf) -> Result<(), String> {
|
|
|
|
pub async fn import_profile(path: PathBuf) -> Result<(), String> {
|
|
|
|
log::debug!("invoke: import_profile({:?})", path);
|
|
|
|
log::debug!("invoke: import_profile({:?})", path);
|
|
|
|
|
|
|
|
|
|
|
|
Profile::import(path).map_err(|e| e.to_string())
|
|
|
|
Profile::import(path).map_err(|e| format!("Unable to import profile: {e}"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[tauri::command]
|
|
|
|
#[tauri::command]
|
|
|
@ -521,11 +518,13 @@ pub async fn clear_cache(state: State<'_, Mutex<AppData>>) -> Result<(), String>
|
|
|
|
let dir = p.data_dir().join("mu3-mods-cache");
|
|
|
|
let dir = p.data_dir().join("mu3-mods-cache");
|
|
|
|
let path = dir.join("data_cache.bin");
|
|
|
|
let path = dir.join("data_cache.bin");
|
|
|
|
if path.exists() {
|
|
|
|
if path.exists() {
|
|
|
|
std::fs::remove_file(path).map_err(|e| e.to_string())?;
|
|
|
|
std::fs::remove_file(path)
|
|
|
|
|
|
|
|
.map_err(|e| format!("Unable to delete data_cache: {e}"))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let path = dir.join("data_fumen_analysis_cache.bin");
|
|
|
|
let path = dir.join("data_fumen_analysis_cache.bin");
|
|
|
|
if path.exists() {
|
|
|
|
if path.exists() {
|
|
|
|
std::fs::remove_file(path).map_err(|e| e.to_string())?;
|
|
|
|
std::fs::remove_file(path)
|
|
|
|
|
|
|
|
.map_err(|e| format!("Unable to delete data_fumen_analysis_cache: {e}"))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -565,7 +564,7 @@ pub async fn set_global_config(state: State<'_, Mutex<AppData>>, field: GlobalCo
|
|
|
|
GlobalConfigField::EnableAutoupdates => appd.cfg.enable_autoupdates = value,
|
|
|
|
GlobalConfigField::EnableAutoupdates => appd.cfg.enable_autoupdates = value,
|
|
|
|
GlobalConfigField::Verbose => appd.cfg.verbose = value,
|
|
|
|
GlobalConfigField::Verbose => appd.cfg.verbose = value,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
appd.write().map_err(|e| e.to_string())
|
|
|
|
appd.write().map_err(|e| format!("Unable to write config.json: {e}"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[tauri::command]
|
|
|
|
#[tauri::command]
|
|
|
@ -613,7 +612,7 @@ pub async fn file_exists(path: String) -> Result<bool, ()> {
|
|
|
|
// Easier than trying to get the barely-documented tauri permissions system to work
|
|
|
|
// Easier than trying to get the barely-documented tauri permissions system to work
|
|
|
|
#[tauri::command]
|
|
|
|
#[tauri::command]
|
|
|
|
pub async fn open_file(path: String) -> Result<(), String> {
|
|
|
|
pub async fn open_file(path: String) -> Result<(), String> {
|
|
|
|
open::that(path).map_err(|e| e.to_string())?;
|
|
|
|
open::that(&path).map_err(|e| format!("Unable to open {path}: {e}"))?;
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -638,12 +637,14 @@ pub async fn list_com_ports() -> Result<BTreeMap<String, i32>, String> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[tauri::command]
|
|
|
|
#[tauri::command]
|
|
|
|
pub async fn list_patches(state: State<'_, Mutex<AppData>>, target: String) -> Result<Vec<Patch>, String> {
|
|
|
|
pub async fn list_patches(state: State<'_, Mutex<AppData>>, target: PathBuf) -> Result<Vec<Patch>, String> {
|
|
|
|
log::debug!("invoke: list_patches({})", target);
|
|
|
|
log::debug!("invoke: list_patches({:?})", target);
|
|
|
|
|
|
|
|
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
let mut appd = state.lock().await;
|
|
|
|
appd.fix();
|
|
|
|
appd.fix();
|
|
|
|
let list = appd.patch_vec.find_patches(target).map_err(|e| e.to_string())?;
|
|
|
|
let list = appd.patch_vec
|
|
|
|
|
|
|
|
.find_patches(&target)
|
|
|
|
|
|
|
|
.map_err(|e| format!("Unable to list patches for {}: {e}", target.file_name().unwrap_or_default().to_string_lossy()))?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(list)
|
|
|
|
Ok(list)
|
|
|
|
}
|
|
|
|
}
|