diff --git a/src/backend/launcher.ts b/src/backend/launcher.ts index 1ff89dfb03..029b9f31ac 100644 --- a/src/backend/launcher.ts +++ b/src/backend/launcher.ts @@ -101,7 +101,8 @@ const launchEventCallback: (args: LaunchParams) => StatusPromise = async ({ appName, launchArguments, runner, - skipVersionCheck + skipVersionCheck, + args }) => { const game = gameManagerMap[runner].getGameInfo(appName) const gameSettings = await gameManagerMap[runner].getSettings(appName) @@ -203,6 +204,7 @@ const launchEventCallback: (args: LaunchParams) => StatusPromise = async ({ const command = gameManagerMap[runner].launch( appName, launchArguments, + args, skipVersionCheck ) diff --git a/src/backend/protocol.ts b/src/backend/protocol.ts index 296324ea05..478d5ef226 100644 --- a/src/backend/protocol.ts +++ b/src/backend/protocol.ts @@ -35,6 +35,7 @@ function handlePing(url: URL) { async function handleLaunch(url: URL) { let appName let runnerStr + let args: string[] = [] if (url.pathname) { // Old-style pathname URLs: @@ -48,6 +49,7 @@ async function handleLaunch(url: URL) { // `heroic://launch?appName=Quail&runner=legendary&arg=foo&arg=bar` appName = url.searchParams.get('appName') runnerStr = url.searchParams.get('runner') + args = url.searchParams.getAll('arg') } if (!appName) { @@ -75,7 +77,8 @@ async function handleLaunch(url: URL) { return launchEventCallback({ appName: appName, runner: gameInfo.runner, - skipVersionCheck: settings.ignoreGameUpdates + skipVersionCheck: settings.ignoreGameUpdates, + args }) } diff --git a/src/backend/storeManagers/gog/games.ts b/src/backend/storeManagers/gog/games.ts index 1b7cb698ab..425fc9b941 100644 --- a/src/backend/storeManagers/gog/games.ts +++ b/src/backend/storeManagers/gog/games.ts @@ -485,7 +485,8 @@ export async function removeShortcuts(appName: string) { export async function launch( appName: string, - launchArguments?: LaunchOption + launchArguments?: LaunchOption, + args: string[] = [] ): Promise { const gameSettings = await getSettings(appName) const gameInfo = getGameInfo(appName) @@ -600,7 +601,8 @@ export async function launch( ...shlex.split( (launchArguments as BaseLaunchOption | undefined)?.parameters ?? '' ), - ...shlex.split(gameSettings.launcherArgs ?? '') + ...shlex.split(gameSettings.launcherArgs ?? ''), + ...args ] if (gameInfo.install.cyberpunk?.modsEnabled) { diff --git a/src/backend/storeManagers/legendary/games.ts b/src/backend/storeManagers/legendary/games.ts index e879d197ba..b21b8c3464 100644 --- a/src/backend/storeManagers/legendary/games.ts +++ b/src/backend/storeManagers/legendary/games.ts @@ -838,6 +838,7 @@ export async function syncSaves( export async function launch( appName: string, launchArguments?: LaunchOption, + args: string[] = [], skipVersionCheck = false ): Promise { const gameSettings = await getSettings(appName) @@ -929,6 +930,7 @@ export async function launch( subcommand: 'launch', appName: LegendaryAppName.parse(appNameToLaunch), extraArguments: [ + ...args, launchArguments?.type !== 'dlc' ? launchArguments?.parameters : undefined, gameSettings.launcherArgs ] diff --git a/src/backend/storeManagers/nile/games.ts b/src/backend/storeManagers/nile/games.ts index d21fd28b5e..edcf47bfdc 100644 --- a/src/backend/storeManagers/nile/games.ts +++ b/src/backend/storeManagers/nile/games.ts @@ -310,7 +310,8 @@ export async function removeShortcuts(appName: string) { export async function launch( appName: string, - launchArguments?: LaunchOption + launchArguments?: LaunchOption, + args: string[] = [] ): Promise { const gameSettings = await getSettings(appName) const gameInfo = getGameInfo(appName) @@ -407,7 +408,8 @@ export async function launch( (launchArguments as BaseLaunchOption | undefined)?.parameters ?? '' ), ...shlex.split(gameSettings.launcherArgs ?? ''), - appName + appName, + ...args ] const fullCommand = getRunnerCallWithoutCredentials( commandParts, diff --git a/src/backend/storeManagers/sideload/games.ts b/src/backend/storeManagers/sideload/games.ts index ca256f71d8..c34276a955 100644 --- a/src/backend/storeManagers/sideload/games.ts +++ b/src/backend/storeManagers/sideload/games.ts @@ -68,10 +68,10 @@ export async function isGameAvailable(appName: string): Promise { export async function launch( appName: string, - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - launchArguments?: LaunchOption + launchArguments?: LaunchOption, + args: string[] = [] ): Promise { - return launchGame(appName, getGameInfo(appName), 'sideload') + return launchGame(appName, getGameInfo(appName), 'sideload', args) } export async function stop(appName: string): Promise { diff --git a/src/backend/storeManagers/storeManagerCommon/games.ts b/src/backend/storeManagers/storeManagerCommon/games.ts index 43c84846e3..c6cfd20900 100644 --- a/src/backend/storeManagers/storeManagerCommon/games.ts +++ b/src/backend/storeManagers/storeManagerCommon/games.ts @@ -120,7 +120,8 @@ const openNewBrowserGameWindow = async ({ export async function launchGame( appName: string, gameInfo: GameInfo, - runner: Runner + runner: Runner, + args: string[] = [] ): Promise { if (!gameInfo) { return false @@ -151,7 +152,7 @@ export async function launchGame( const gameSettings = await getAppSettings(appName) const { launcherArgs } = gameSettings - const extraArgs = shlex.split(launcherArgs ?? '') + const extraArgs = [...shlex.split(launcherArgs ?? ''), ...args] const extraArgsJoined = extraArgs.join(' ') if (executable) { diff --git a/src/common/types.ts b/src/common/types.ts index 36bcb0f216..bdd2dd18fb 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -29,6 +29,7 @@ export type LaunchParams = { launchArguments?: LaunchOption runner: Runner skipVersionCheck?: boolean + args?: string[] } export type LaunchOption = BaseLaunchOption | DLCLaunchOption diff --git a/src/common/types/frontend_messages.ts b/src/common/types/frontend_messages.ts index 17b16a68ac..86fcb66779 100644 --- a/src/common/types/frontend_messages.ts +++ b/src/common/types/frontend_messages.ts @@ -34,7 +34,7 @@ type FrontendMessages = { status: ConnectivityStatus retryIn: number }) => void - launchGame: (appName: string, runner: Runner) => void + launchGame: (appName: string, runner: Runner, args: string[]) => void installGame: (appName: string, runner: Runner) => void recentGamesChanged: (newRecentGames: RecentGame[]) => void pushGameToLibrary: (info: GameInfo) => void diff --git a/src/common/types/game_manager.ts b/src/common/types/game_manager.ts index 4d10569cd6..25b1f202c1 100644 --- a/src/common/types/game_manager.ts +++ b/src/common/types/game_manager.ts @@ -43,6 +43,7 @@ export interface GameManager { launch: ( appName: string, launchArguments?: LaunchOption, + args?: string[], skipVersionCheck?: boolean ) => Promise moveInstall: ( diff --git a/src/frontend/helpers/library.ts b/src/frontend/helpers/library.ts index 8eb949a539..4f1c719d46 100644 --- a/src/frontend/helpers/library.ts +++ b/src/frontend/helpers/library.ts @@ -168,6 +168,7 @@ type LaunchOptions = { runner: Runner hasUpdate: boolean showDialogModal: (options: DialogModalOptions) => void + args?: string[] } const launch = async ({ @@ -176,7 +177,8 @@ const launch = async ({ launchArguments, runner, hasUpdate, - showDialogModal + showDialogModal, + args }: LaunchOptions): Promise<{ status: 'done' | 'error' | 'abort' }> => { if (hasUpdate) { const { ignoreGameUpdates } = await window.api.requestGameSettings(appName) @@ -186,6 +188,7 @@ const launch = async ({ appName, runner, launchArguments, + args, skipVersionCheck: true }) } @@ -216,6 +219,7 @@ const launch = async ({ appName, runner, launchArguments, + args, skipVersionCheck: true }) ) @@ -229,7 +233,7 @@ const launch = async ({ return launchFinished } - return window.api.launch({ appName, launchArguments, runner }) + return window.api.launch({ appName, launchArguments, runner, args }) } const updateGame = (args: UpdateParams) => {