From b78e4dfd11e2772eff4f5803cff1bfc19f9ae37f Mon Sep 17 00:00:00 2001 From: John Beresford Date: Mon, 21 Oct 2024 16:06:48 -0700 Subject: [PATCH] feat: `install_dir` macro for custom args Now you can use the `install_dir` macro in your profile's custom args to specify the installation directory for the game. This will allow you launch multi-file games with emulators that require a directory of files ( e.g. RPCS3 ). --- .../manage-profiles/edit-profile-dialog.tsx | 10 ++++++---- .../modals/manage-profiles/profile-list.tsx | 5 ++++- .../retrom-plugin-launcher/src/commands.rs | 20 ++++++++++++++----- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/client/web/src/components/modals/manage-profiles/edit-profile-dialog.tsx b/packages/client/web/src/components/modals/manage-profiles/edit-profile-dialog.tsx index b1b3001..49a887c 100644 --- a/packages/client/web/src/components/modals/manage-profiles/edit-profile-dialog.tsx +++ b/packages/client/web/src/components/modals/manage-profiles/edit-profile-dialog.tsx @@ -51,9 +51,11 @@ const formSchema = z.object({ (args) => args.length === 0 || args.includes("{file}") || - args.includes('"{file}"'), + args.includes('"{file}"') || + args.includes("{install_dir}") || + args.includes('"{install_dir}"'), { - message: "Custom arguments must include {file}", + message: "Custom arguments must include {file} or {install_dir}", }, ), }) satisfies InferSchema>; @@ -78,8 +80,8 @@ export function EditProfileDialog(props: Props) { useUpdateEmulatorProfiles(); const pending = creationStatus === "pending" || updateStatus === "pending"; - const canSubmit = - form.formState.isDirty && form.formState.isValid && !pending; + const { isDirty } = form.formState; + const canSubmit = isDirty && !pending; const handleSubmit = useCallback( (values: FormSchema) => { diff --git a/packages/client/web/src/components/modals/manage-profiles/profile-list.tsx b/packages/client/web/src/components/modals/manage-profiles/profile-list.tsx index f009a25..a67361f 100644 --- a/packages/client/web/src/components/modals/manage-profiles/profile-list.tsx +++ b/packages/client/web/src/components/modals/manage-profiles/profile-list.tsx @@ -63,7 +63,10 @@ export function ProfileList(props: Props) { {profiles.map((profile) => ( - + {profile.name} diff --git a/plugins/retrom-plugin-launcher/src/commands.rs b/plugins/retrom-plugin-launcher/src/commands.rs index 5fd50ac..f3958fb 100644 --- a/plugins/retrom-plugin-launcher/src/commands.rs +++ b/plugins/retrom-plugin-launcher/src/commands.rs @@ -12,7 +12,9 @@ use tracing::{info, instrument}; use crate::{desktop::GameProcess, LauncherExt, Result}; #[command] -#[instrument(skip_all)] +#[instrument(skip_all, fields( + game_id = payload.game.as_ref().map(|game| game.id), + emulator_profile_id = payload.emulator_profile.as_ref().map(|profile| profile.id)))] pub(crate) async fn play_game( app: AppHandle, payload: PlayGamePayload, @@ -26,8 +28,10 @@ pub(crate) async fn play_game( }; let game_id = game.id; - let profile = payload.emulator_profile.unwrap(); - let emulator = payload.emulator.unwrap(); + let profile = payload + .emulator_profile + .expect("No emulator profile provided"); + let emulator = payload.emulator.expect("No emulator provided"); let maybe_default_file = payload.file; let default_file_path = maybe_default_file @@ -90,6 +94,11 @@ pub(crate) async fn play_game( None => return Err(crate::Error::FileNotFound(game_id)), }; + let install_dir = match install_dir.canonicalize()?.to_str() { + Some(path) => path.to_string(), + None => return Err(crate::Error::FileNotFound(game_id)), + }; + let mut cmd = launcher.get_open_cmd(&emulator.executable_path); let args = if !profile.custom_args.is_empty() { @@ -105,12 +114,13 @@ pub(crate) async fn play_game( true => arg[1..arg.len() - 1].to_string(), }) .map(|arg| arg.replace("{file}", &file_path)) + .map(|arg| arg.replace("{install_dir}", &install_dir)) .collect() } else { vec![file_path] }; - info!("Args: {:?}", args); + info!("Args Constructed: {:?}", args); cmd.args(args); @@ -152,7 +162,7 @@ pub(crate) async fn play_game( } #[command] -#[instrument(skip_all)] +#[instrument(skip_all, fields(game_id = payload.game.as_ref().map(|game| game.id)))] pub(crate) async fn stop_game( app: AppHandle, payload: StopGamePayload,