From 3bec5628ad4b5f0fbb932a800c3abc17147b2543 Mon Sep 17 00:00:00 2001 From: Tormak <63308171+Tormak9970@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:15:53 -0400 Subject: [PATCH] feat: added custom steam path support --- src-tauri/src/main.rs | 50 ++++++++++++++++-------------- src-tauri/src/steam.rs | 28 ++++++++--------- src/lib/controllers/RustInterop.ts | 35 ++++++++++++--------- 3 files changed, 62 insertions(+), 51 deletions(-) diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 6af97aff..985a007f 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -86,9 +86,9 @@ fn adjust_path(app_handle: &AppHandle, appid: &str, path: &str, grid_type: &str) } /// Filters the grid paths based on which have change. -fn filter_paths(app_handle: &AppHandle, steam_active_user_id: String, current_paths: &GridImageCache, original_paths: &GridImageCache, shortcut_icons: &Map) -> Vec { - let grids_dir = PathBuf::from(steam::get_grids_directory(app_handle.to_owned(), steam_active_user_id)); - let lib_cache_dir = PathBuf::from(steam::get_library_cache_directory(app_handle.to_owned())); +fn filter_paths(app_handle: &AppHandle, steam_path: String, steam_active_user_id: String, current_paths: &GridImageCache, original_paths: &GridImageCache, shortcut_icons: &Map) -> Vec { + let grids_dir = PathBuf::from(steam::get_grids_directory(app_handle.to_owned(), steam_path.to_owned(), steam_active_user_id)); + let lib_cache_dir = PathBuf::from(steam::get_library_cache_directory(app_handle.to_owned(), steam_path.to_owned())); let mut res:Vec = Vec::new(); for (appid, grids_map) in current_paths.into_iter() { @@ -156,7 +156,7 @@ fn check_for_shortcut_changes(shortcut_icons: &Map, original_shor #[tauri::command] /// Exports the users grids to a Grids zip file. -async fn export_grids_to_zip(app_handle: AppHandle, steam_active_user_id: String, platform_id_map: Map, id_name_map: Map) -> bool { +async fn export_grids_to_zip(app_handle: AppHandle, steam_path: String, steam_active_user_id: String, platform_id_map: Map, id_name_map: Map) -> bool { let file_dialog = FileDialogBuilder::new() .set_title("Save Grids Zip") .set_file_name("Steam_Grids_Export.zip") @@ -169,7 +169,7 @@ async fn export_grids_to_zip(app_handle: AppHandle, steam_active_user_id: String let zip_path = file_path.unwrap(); logger::log_to_core_file(app_handle.to_owned(), format!("Got save path: {}", zip_path.to_str().expect("Should have been able to convert path to string.")).as_str(), 0); - let grids_dir_path = steam::get_grids_directory(app_handle.to_owned(), steam_active_user_id); + let grids_dir_path = steam::get_grids_directory(app_handle.to_owned(), steam_path, steam_active_user_id); let succeeded = zip_controller::generate_grids_zip(&app_handle, PathBuf::from(grids_dir_path), zip_path, &platform_id_map, &id_name_map); if succeeded { @@ -187,7 +187,7 @@ async fn export_grids_to_zip(app_handle: AppHandle, steam_active_user_id: String #[tauri::command] /// Sets the users grids from a Grids zip file. -async fn import_grids_from_zip(app_handle: AppHandle, steam_active_user_id: String, name_id_map: Map) -> (bool, Map) { +async fn import_grids_from_zip(app_handle: AppHandle, steam_path: String, steam_active_user_id: String, name_id_map: Map) -> (bool, Map) { let file_dialog = FileDialogBuilder::new() .set_title("Pick a Grids Zip") .add_filter("zip", &["zip"]) @@ -199,7 +199,7 @@ async fn import_grids_from_zip(app_handle: AppHandle, steam_active_user_id: Stri let zip_path = file_path.unwrap(); logger::log_to_core_file(app_handle.to_owned(), format!("Got file path: {}", zip_path.to_str().expect("Should have been able to convert path to string.")).as_str(), 0); - let grids_dir_path = steam::get_grids_directory(app_handle.to_owned(), steam_active_user_id); + let grids_dir_path = steam::get_grids_directory(app_handle.to_owned(), steam_path, steam_active_user_id); let (success, icon_map) = zip_controller::set_grids_from_zip(&app_handle, PathBuf::from(grids_dir_path), zip_path, &name_id_map); if success { @@ -217,16 +217,16 @@ async fn import_grids_from_zip(app_handle: AppHandle, steam_active_user_id: Stri #[tauri::command] /// Reads the user's appinfo.vdf file. -async fn read_appinfo_vdf(app_handle: AppHandle) -> String { - let appinfo_path: PathBuf = PathBuf::from(steam::get_appinfo_path(app_handle.to_owned())); +async fn read_appinfo_vdf(app_handle: AppHandle, steam_path: String) -> String { + let appinfo_path: PathBuf = PathBuf::from(steam::get_appinfo_path(app_handle.to_owned(), steam_path)); let appinfo_vdf: Map = open_appinfo_vdf(&appinfo_path); return serde_json::to_string(&appinfo_vdf).expect("Should have been able to serialize AppInfo vdf to string."); } #[tauri::command] /// Reads the user's shortcuts.vdf file. -async fn read_shortcuts_vdf(app_handle: AppHandle, steam_active_user_id: String) -> String { - let shortcuts_path = PathBuf::from(steam::get_shortcuts_path(app_handle.to_owned(), steam_active_user_id)); +async fn read_shortcuts_vdf(app_handle: AppHandle, steam_path: String, steam_active_user_id: String) -> String { + let shortcuts_path = PathBuf::from(steam::get_shortcuts_path(app_handle.to_owned(), steam_path, steam_active_user_id)); if shortcuts_path.as_path().exists() { logger::log_to_core_file(app_handle.to_owned(), "shortcuts.vdf exists, reading...", 0); @@ -240,8 +240,8 @@ async fn read_shortcuts_vdf(app_handle: AppHandle, steam_active_user_id: String) #[tauri::command] /// Reads the user's localconfig.vdf file. -async fn read_localconfig_vdf(app_handle: AppHandle, steam_active_user_id: String) -> String { - let localconfig_path = PathBuf::from(steam::get_localconfig_path(app_handle.to_owned(), steam_active_user_id)); +async fn read_localconfig_vdf(app_handle: AppHandle, steam_path: String, steam_active_user_id: String) -> String { + let localconfig_path = PathBuf::from(steam::get_localconfig_path(app_handle.to_owned(), steam_path, steam_active_user_id)); if localconfig_path.as_path().exists() { logger::log_to_core_file(app_handle.to_owned(), "localconfig.vdf exists, reading...", 0); @@ -268,12 +268,12 @@ async fn read_localconfig_vdf(app_handle: AppHandle, steam_active_user_id: Strin #[tauri::command] /// Applies the changes the user has made. -async fn save_changes(app_handle: AppHandle, steam_active_user_id: String, current_art: String, original_art: String, shortcuts_str: String, shortcut_icons: Map, original_shortcut_icons: Map, changed_logo_positions: Map) -> String { +async fn save_changes(app_handle: AppHandle, steam_path: String, steam_active_user_id: String, current_art: String, original_art: String, shortcuts_str: String, shortcut_icons: Map, original_shortcut_icons: Map, changed_logo_positions: Map) -> String { let current_art_dict: GridImageCache = serde_json::from_str(current_art.as_str()).unwrap(); let original_art_dict: GridImageCache = serde_json::from_str(original_art.as_str()).unwrap(); logger::log_to_core_file(app_handle.to_owned(), "Converting current path entries to grid paths...", 0); - let paths_to_set: Vec = filter_paths(&app_handle, steam_active_user_id.clone(), ¤t_art_dict, &original_art_dict, &shortcut_icons); + let paths_to_set: Vec = filter_paths(&app_handle, steam_path.to_owned(), steam_active_user_id.clone(), ¤t_art_dict, &original_art_dict, &shortcut_icons); let paths_id_map: HashMap = paths_to_set.clone().iter().map(| entry | (format!("{}_{}", entry.appId.to_owned(), entry.gridType.to_owned()).to_string(), entry.to_owned())).collect(); logger::log_to_core_file(app_handle.to_owned(), "Current path entries converted to grid paths.", 0); @@ -313,7 +313,7 @@ async fn save_changes(app_handle: AppHandle, steam_active_user_id: String, curre } } - let grids_directory: PathBuf = PathBuf::from(steam::get_grids_directory(app_handle.to_owned(), steam_active_user_id.clone())); + let grids_directory: PathBuf = PathBuf::from(steam::get_grids_directory(app_handle.to_owned(), steam_path.to_owned(), steam_active_user_id.clone())); for (appid, steam_logo_str_val) in changed_logo_positions.into_iter() { let steam_logo_str: &str = steam_logo_str_val.as_str().expect("Should have been able to convert steamLogo pos into str."); let logo_config_path: PathBuf = grids_directory.join(format!("{}.json", appid)); @@ -365,7 +365,7 @@ async fn save_changes(app_handle: AppHandle, steam_active_user_id: String, curre modified_shortcuts_data.insert(String::from("shortcuts"), shortcuts_obj_map.to_owned()); shortcuts_data = Value::Object(modified_shortcuts_data); - let shortcuts_vdf_path: PathBuf = PathBuf::from(steam::get_shortcuts_path(app_handle.to_owned(), steam_active_user_id)); + let shortcuts_vdf_path: PathBuf = PathBuf::from(steam::get_shortcuts_path(app_handle.to_owned(), steam_path.to_owned(), steam_active_user_id)); write_shortcuts_vdf(&shortcuts_vdf_path, shortcuts_data); logger::log_to_core_file(app_handle.to_owned(), "Changes to shortcuts saved.", 0); } else { @@ -385,9 +385,9 @@ async fn save_changes(app_handle: AppHandle, steam_active_user_id: String, curre #[tauri::command] /// Writes the user's shortcuts.vdf file. -async fn write_shortcuts(app_handle: AppHandle, steam_active_user_id: String, shortcuts_str: String) -> bool { +async fn write_shortcuts(app_handle: AppHandle, steam_path: String, steam_active_user_id: String, shortcuts_str: String) -> bool { logger::log_to_core_file(app_handle.to_owned(), "Writing shortcuts.vdf...", 0); - let shortcuts_vdf_path: PathBuf = PathBuf::from(steam::get_shortcuts_path(app_handle.to_owned(), steam_active_user_id)); + let shortcuts_vdf_path: PathBuf = PathBuf::from(steam::get_shortcuts_path(app_handle.to_owned(), steam_path, steam_active_user_id)); let shortcuts_data: Value = serde_json::from_str(shortcuts_str.as_str()).expect("Should have been able to parse json string."); let success: bool = write_shortcuts_vdf(&shortcuts_vdf_path, shortcuts_data); @@ -435,12 +435,12 @@ async fn download_grid(app_handle: AppHandle, grid_url: String, dest_path: Strin #[tauri::command] /// Downloads a file from a url. -async fn clean_grids(app_handle: AppHandle, steam_active_user_id: String, preset: String, all_appids: String, selected_game_ids: String) -> String { +async fn clean_grids(app_handle: AppHandle, steam_path: String, steam_active_user_id: String, preset: String, all_appids: String, selected_game_ids: String) -> String { logger::log_to_core_file(app_handle.to_owned(), format!("Starting {} grid cleaning.", preset).as_str(), 0); let appids_arr: Vec = serde_json::from_str(all_appids.as_str()).expect("Should have been able to deserialize appids array."); - let grids_dir_path: String = steam::get_grids_directory(app_handle.to_owned(), steam_active_user_id); + let grids_dir_path: String = steam::get_grids_directory(app_handle.to_owned(), steam_path, steam_active_user_id); let grids_dir_contents = fs::read_dir(grids_dir_path).unwrap(); let mut found_apps: HashMap = HashMap::new(); @@ -551,11 +551,15 @@ async fn add_steam_to_scope(app_handle: AppHandle) -> String { if steam_path_res.is_ok() { let steam_path: PathBuf = steam_path_res.ok().expect("Should have been able to get steam path from result."); - let steam_path_str: String = String::from(steam_path.as_os_str().to_str().expect("Should have been able to convert Steam path PathBuf to str.")); + let steam_path_str: String = steam_path.as_path().display().to_string(); let was_added: bool = add_path_to_scope(app_handle, steam_path_str.to_owned()).await; if was_added { - return steam_path_str; + if &steam_path_str == "c:/program files (x86)/steam" { + return String::from("C:/Program Files (x86)/Steam"); + } else { + return steam_path_str; + } } else { return String::from(""); } diff --git a/src-tauri/src/steam.rs b/src-tauri/src/steam.rs index 3b594321..8410d1a6 100644 --- a/src-tauri/src/steam.rs +++ b/src-tauri/src/steam.rs @@ -56,10 +56,10 @@ pub fn get_steam_root_dir() -> Result { #[tauri::command] /// Gets the steam grids directory. -pub fn get_grids_directory(app_handle: AppHandle, steam_active_user_id: String) -> String { +pub fn get_grids_directory(app_handle: AppHandle, steam_path: String, steam_active_user_id: String) -> String { logger::log_to_core_file(app_handle.to_owned(), "Getting steam grids folder...", 0); - let steam_root: PathBuf = get_steam_root_dir().ok().expect("Steam install path should have been fine if this point is reached."); + let steam_root: PathBuf = PathBuf::from(steam_path); let grids_dir: String = steam_root.join("userdata").join(steam_active_user_id.to_string()).join("config/grid").to_str().expect("Should have been able to convert to a string.").to_owned().replace("\\", "/"); let dir_create_res = fs::create_dir_all(grids_dir.clone()); @@ -73,37 +73,37 @@ pub fn get_grids_directory(app_handle: AppHandle, steam_active_user_id: String) #[tauri::command] /// Gets the steam library cache directory. -pub fn get_library_cache_directory(app_handle: AppHandle) -> String { +pub fn get_library_cache_directory(app_handle: AppHandle, steam_path: String) -> String { logger::log_to_core_file(app_handle.to_owned(), "Getting steam library cache folder...", 0); - let steam_root: PathBuf = get_steam_root_dir().ok().expect("Steam install path should have been fine if this point is reached."); + let steam_root: PathBuf = PathBuf::from(steam_path); return steam_root.join("appcache/librarycache").to_str().expect("Should have been able to convert to a string.").to_owned().replace("\\", "/"); } #[tauri::command] /// Gets the steam appinfo.vdf path. -pub fn get_appinfo_path(app_handle: AppHandle) -> String { +pub fn get_appinfo_path(app_handle: AppHandle, steam_path: String) -> String { logger::log_to_core_file(app_handle.to_owned(), "Getting steam appinfo.vdf...", 0); - let steam_root: PathBuf = get_steam_root_dir().ok().expect("Steam install path should have been fine if this point is reached."); + let steam_root: PathBuf = PathBuf::from(steam_path); return steam_root.join("appcache/appinfo.vdf").to_str().expect("Should have been able to convert to a string.").to_owned().replace("\\", "/"); } #[tauri::command] /// Gets the steam shortcuts.vdf path. -pub fn get_shortcuts_path(app_handle: AppHandle, steam_active_user_id: String) -> String { +pub fn get_shortcuts_path(app_handle: AppHandle, steam_path: String, steam_active_user_id: String) -> String { logger::log_to_core_file(app_handle.to_owned(), "Getting steam shortcuts.vdf...", 0); - let steam_root: PathBuf = get_steam_root_dir().ok().expect("Steam install path should have been fine if this point is reached."); + let steam_root: PathBuf = PathBuf::from(steam_path); return steam_root.join("userdata").join(steam_active_user_id.to_string()).join("config/shortcuts.vdf").to_str().expect("Should have been able to convert to a string.").to_owned().replace("\\", "/"); } #[tauri::command] /// Gets the steam localconfig.vdf path. -pub fn get_localconfig_path(app_handle: AppHandle, steam_active_user_id: String) -> String { +pub fn get_localconfig_path(app_handle: AppHandle, steam_path: String, steam_active_user_id: String) -> String { logger::log_to_core_file(app_handle.to_owned(), "Getting steam localconfig.vdf...", 0); - let steam_root: PathBuf = get_steam_root_dir().ok().expect("Steam install path should have been fine if this point is reached."); + let steam_root: PathBuf = PathBuf::from(steam_path); return steam_root.join("userdata").join(steam_active_user_id.to_string()).join("config/localconfig.vdf").to_str().expect("Should have been able to convert to a string.").to_owned().replace("\\", "/"); } @@ -142,10 +142,10 @@ fn read_steam_user(user_id: &str, user_block: &str) -> Map { } /// Reads the steam users. -fn read_steam_users() -> Map { +fn read_steam_users(steam_path: String) -> Map { let mut steam_users: Map = Map::new(); - let steam_root: PathBuf = get_steam_root_dir().ok().expect("Steam install path should have been fine if this point is reached."); + let steam_root: PathBuf = PathBuf::from(steam_path); let loginusers_vdf: PathBuf = steam_root.join("config/loginusers.vdf"); let contents: String = fs::read_to_string(loginusers_vdf).unwrap(); @@ -170,10 +170,10 @@ fn read_steam_users() -> Map { #[tauri::command] /// Gets all steam users that have logged in on this computer. -pub fn get_steam_users(app_handle: AppHandle) -> String { +pub fn get_steam_users(app_handle: AppHandle, steam_path: String) -> String { logger::log_to_core_file(app_handle.to_owned(), "Checking config/loginusers.vdf for current user info.", 0); - let steam_users = read_steam_users(); + let steam_users = read_steam_users(steam_path); logger::log_to_core_file(app_handle.to_owned(), format!("Loaded {} steam users.", steam_users.len()).as_str(), 0); diff --git a/src/lib/controllers/RustInterop.ts b/src/lib/controllers/RustInterop.ts index d40d8a4b..49ec0f27 100644 --- a/src/lib/controllers/RustInterop.ts +++ b/src/lib/controllers/RustInterop.ts @@ -16,6 +16,8 @@ * along with this program. If not, see */ import { invoke } from "@tauri-apps/api"; +import { get } from "svelte/store"; +import { steamInstallPath } from "../../Stores"; /** * The available logging levels. @@ -31,6 +33,11 @@ export enum LogLevel { * ! Should do no logging here. */ export class RustInterop { + + private static get steamPath() { + return get(steamInstallPath); + } + /** * Checks if steam is installed, and if so, it adds it to the file access scope. */ @@ -76,7 +83,7 @@ export class RustInterop { * @returns A promise resolving to the active steam user's grids directory. */ static async getGridsDirectory(activeUserId: string): Promise { - return await invoke("get_grids_directory", { steamActiveUserId: activeUserId }); + return await invoke("get_grids_directory", { steamPath: RustInterop.steamPath, steamActiveUserId: activeUserId }); } /** @@ -84,7 +91,7 @@ export class RustInterop { * @returns A promise resolving to the active steam user's appinfo.vdf path. */ static async getAppinfoPath(): Promise { - return await invoke("get_appinfo_path", {}); + return await invoke("get_appinfo_path", { steamPath: RustInterop.steamPath }); } /** @@ -93,7 +100,7 @@ export class RustInterop { * @returns A promise resolving to the active steam user's shortcuts.vdf path. */ static async getShortcutsPath(activeUserId: string): Promise { - return await invoke("get_shortcuts_path", { steamActiveUserId: activeUserId }); + return await invoke("get_shortcuts_path", { steamPath: RustInterop.steamPath, steamActiveUserId: activeUserId }); } /** @@ -102,7 +109,7 @@ export class RustInterop { * @returns A promise resolving to the active steam user's localconfig.vdf path. */ static async getLocalconfigPath(activeUserId: string): Promise { - return await invoke("get_localconfig_path", { steamActiveUserId: activeUserId }); + return await invoke("get_localconfig_path", { steamPath: RustInterop.steamPath, steamActiveUserId: activeUserId }); } /** @@ -110,7 +117,7 @@ export class RustInterop { * @returns A promise resolving to the active steam user's library cache directory. */ static async getLibraryCacheDirectory(): Promise { - return await invoke("get_library_cache_directory", {}); + return await invoke("get_library_cache_directory", { steamPath: RustInterop.steamPath }); } /** @@ -118,7 +125,7 @@ export class RustInterop { * @returns A promise resolving to the list of steam users on this computer. */ static async getSteamUsers(): Promise<{ [id: string]: SteamUser }> { - return JSON.parse(await invoke("get_steam_users", {})); + return JSON.parse(await invoke("get_steam_users", { steamPath: RustInterop.steamPath })); } /** @@ -129,7 +136,7 @@ export class RustInterop { * @returns A promise resolving to true if the operation suceeded, false if it was cancelled. */ static async exportGridsToZip(activeUserId: string, platformIdMap: { [id: string]: string }, idNameMap: { [id: string]: string }): Promise { - return await invoke("export_grids_to_zip", { steamActiveUserId: activeUserId, platformIdMap: platformIdMap, idNameMap: idNameMap }); + return await invoke("export_grids_to_zip", { steamPath: RustInterop.steamPath, steamActiveUserId: activeUserId, platformIdMap: platformIdMap, idNameMap: idNameMap }); } /** @@ -139,7 +146,7 @@ export class RustInterop { * @returns A promise resolving to a tuple of (success, map of shortcut icons that need to be written). */ static async importGridsFromZip(activeUserId: string, nameIdMap: { [id: string]: string }): Promise<[boolean, { [appid: string]: string}]> { - const res = await invoke<[boolean, { [appid: string]: string}]>("import_grids_from_zip", { steamActiveUserId: activeUserId, nameIdMap: nameIdMap }); + const res = await invoke<[boolean, { [appid: string]: string}]>("import_grids_from_zip", { steamPath: RustInterop.steamPath, steamActiveUserId: activeUserId, nameIdMap: nameIdMap }); return res; } @@ -148,7 +155,7 @@ export class RustInterop { * @returns A promise resolving to the contents of the appinfo.vdf file. */ static async readAppinfoVdf(): Promise { - return JSON.parse(await invoke("read_appinfo_vdf", {})); + return JSON.parse(await invoke("read_appinfo_vdf", { steamPath: RustInterop.steamPath })); } /** @@ -157,7 +164,7 @@ export class RustInterop { * @returns A promise resolving to the contents of the shortcuts.vdf file. */ static async readShortcutsVdf(activeUserId: string): Promise { - return JSON.parse(await invoke("read_shortcuts_vdf", { steamActiveUserId: activeUserId })); + return JSON.parse(await invoke("read_shortcuts_vdf", { steamPath: RustInterop.steamPath, steamActiveUserId: activeUserId })); } /** @@ -166,7 +173,7 @@ export class RustInterop { * @returns A promise resolving to the contents of the localconfig.vdf file. */ static async readLocalconfigVdf(activeUserId: string): Promise { - return JSON.parse(await invoke("read_localconfig_vdf", { steamActiveUserId: activeUserId })); + return JSON.parse(await invoke("read_localconfig_vdf", { steamPath: RustInterop.steamPath, steamActiveUserId: activeUserId })); } /** @@ -192,7 +199,7 @@ export class RustInterop { const shortcutsObj = { "shortcuts": {...shortcuts} } - const res = await invoke("save_changes", { currentArt: JSON.stringify(currentArt), originalArt: JSON.stringify(originalArt), shortcutsStr: JSON.stringify(shortcutsObj), steamActiveUserId: activeUserId, shortcutIcons: shortcutIcons, originalShortcutIcons: originalShortcutIcons, changedLogoPositions: changedLogoPositions }); + const res = await invoke("save_changes", { steamPath: RustInterop.steamPath, currentArt: JSON.stringify(currentArt), originalArt: JSON.stringify(originalArt), shortcutsStr: JSON.stringify(shortcutsObj), steamActiveUserId: activeUserId, shortcutIcons: shortcutIcons, originalShortcutIcons: originalShortcutIcons, changedLogoPositions: changedLogoPositions }); return JSON.parse(res); } @@ -206,7 +213,7 @@ export class RustInterop { const shortcutsObj = { "shortcuts": {...shortcuts} } - const res = await invoke("write_shortcuts", { shortcutsStr: JSON.stringify(shortcutsObj), steamActiveUserId: activeUserId }); + const res = await invoke("write_shortcuts", { steamPath: RustInterop.steamPath, shortcutsStr: JSON.stringify(shortcutsObj), steamActiveUserId: activeUserId }); return JSON.parse(res); } @@ -236,6 +243,6 @@ export class RustInterop { * @returns A promise resolving to an array of CleanConflicts. */ static async cleanGrids(steamActiveUserId: string, preset: string, allAppids: string[], selectedGameIds: string[]): Promise { - return JSON.parse(await invoke("clean_grids", { steamActiveUserId: steamActiveUserId, preset: preset, allAppids: JSON.stringify(allAppids), selectedGameIds: JSON.stringify(selectedGameIds) })); + return JSON.parse(await invoke("clean_grids", { steamPath: RustInterop.steamPath, steamActiveUserId: steamActiveUserId, preset: preset, allAppids: JSON.stringify(allAppids), selectedGameIds: JSON.stringify(selectedGameIds) })); } } \ No newline at end of file