Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add custom launch options to game #1355

Merged
merged 5 commits into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@
"loading_save_preview": "Searching for save games…",
"wine_prefix": "Wine Prefix",
"wine_prefix_description": "The Wine prefix used to run this game",
"launch_options": "Launch Options",
"launch_options_description": "Advanced users may choose to enter modifications to their launch options",
"launch_options_placeholder": "No parameter specified",
"no_download_option_info": "No information available",
"backup_deletion_failed": "Failed to delete backup",
"max_number_of_artifacts_reached": "Maximum number of backups reached for this game",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/pt-BR/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@
"loading_save_preview": "Buscando por arquivos de salvamento…",
"wine_prefix": "Prefixo Wine",
"wine_prefix_description": "O prefixo Wine que foi utilizado para instalar o jogo",
"launch_options": "Opções de Inicialização",
"launch_options_description": "Usuários avançados podem adicionar opções de inicialização no jogo",
"launch_options_placeholder": "Nenhum parâmetro informado",
"no_download_option_info": "Sem informações disponíveis",
"backup_deletion_failed": "Falha ao apagar backup",
"max_number_of_artifacts_reached": "Número máximo de backups atingido para este jogo",
Expand Down
3 changes: 3 additions & 0 deletions src/main/entity/game.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export class Game {
@Column("text", { nullable: true })
executablePath: string | null;

@Column("text", { nullable: true })
launchOptions: string | null;

@Column("text", { nullable: true })
winePrefixPath: string | null;

Expand Down
9 changes: 9 additions & 0 deletions src/main/events/helpers/parse-launch-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const parseLaunchOptions = (params: string | null): string[] => {
if (params == null || params == "") {
return [];
}

const paramsSplit = params.split(" ");

return paramsSplit;
};
1 change: 1 addition & 0 deletions src/main/events/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import "./library/open-game-executable-path";
import "./library/open-game-installer";
import "./library/open-game-installer-path";
import "./library/update-executable-path";
import "./library/update-launch-options";
import "./library/verify-executable-path";
import "./library/remove-game";
import "./library/remove-game-from-library";
Expand Down
16 changes: 13 additions & 3 deletions src/main/events/library/open-game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,28 @@ import { gameRepository } from "@main/repository";

import { registerEvent } from "../register-event";
import { shell } from "electron";
import { spawn } from "child_process";
import { parseExecutablePath } from "../helpers/parse-executable-path";
import { parseLaunchOptions } from "../helpers/parse-launch-options";

const openGame = async (
_event: Electron.IpcMainInvokeEvent,
gameId: number,
executablePath: string
executablePath: string,
launchOptions: string | null
) => {
const parsedPath = parseExecutablePath(executablePath);
const parsedParams = parseLaunchOptions(launchOptions);

await gameRepository.update({ id: gameId }, { executablePath: parsedPath });
await gameRepository.update({ id: gameId }, { executablePath: parsedPath, launchOptions });

shell.openPath(parsedPath);
if (process.platform === "linux" || process.platform === "darwin") {
shell.openPath(parsedPath);
}

if (process.platform === "win32") {
spawn(parsedPath, parsedParams, { shell: false });
zamitto marked this conversation as resolved.
Show resolved Hide resolved
zamitto marked this conversation as resolved.
Show resolved Hide resolved
}
};

registerEvent("openGame", openGame);
19 changes: 19 additions & 0 deletions src/main/events/library/update-launch-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { gameRepository } from "@main/repository";
import { registerEvent } from "../register-event";

const updateLaunchOptions = async (
_event: Electron.IpcMainInvokeEvent,
id: number,
launchOptions: string | null
) => {
return gameRepository.update(
{
id,
},
{
launchOptions: launchOptions?.trim() != "" ? launchOptions : null,
}
);
};

registerEvent("updateLaunchOptions", updateLaunchOptions);
2 changes: 2 additions & 0 deletions src/main/knex-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { AddDisableNsfwAlertColumn } from "./migrations/20241106053733_add_disab
import { AddShouldSeedColumn } from "./migrations/20241108200154_add_should_seed_colum";
import { AddSeedAfterDownloadColumn } from "./migrations/20241108201806_add_seed_after_download";
import { AddHiddenAchievementDescriptionColumn } from "./migrations/20241216140633_add_hidden_achievement_description_column ";
import { AddLaunchOptionsColumnToGame } from "./migrations/20241226044022_add_launch_options_column_to_game";

export type HydraMigration = Knex.Migration & { name: string };

Expand All @@ -37,6 +38,7 @@ class MigrationSource implements Knex.MigrationSource<HydraMigration> {
AddShouldSeedColumn,
AddSeedAfterDownloadColumn,
AddHiddenAchievementDescriptionColumn,
AddLaunchOptionsColumnToGame,
]);
}
getMigrationName(migration: HydraMigration): string {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { HydraMigration } from "@main/knex-client";
import type { Knex } from "knex";

export const AddLaunchOptionsColumnToGame: HydraMigration = {
name: "AddLaunchOptionsColumnToGame",
up: (knex: Knex) => {
return knex.schema.alterTable("game", (table) => {
return table.string("launchOptions").nullable();
});
},

down: async (knex: Knex) => {
return knex.schema.alterTable("game", (table) => {
return table.dropColumn("launchOptions");
});
},
};
9 changes: 7 additions & 2 deletions src/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ contextBridge.exposeInMainWorld("electron", {
ipcRenderer.invoke("createGameShortcut", id),
updateExecutablePath: (id: number, executablePath: string | null) =>
ipcRenderer.invoke("updateExecutablePath", id, executablePath),
updateLaunchOptions: (id: number, launchOptions: string | null) =>
ipcRenderer.invoke("updateLaunchOptions", id, launchOptions),
selectGameWinePrefix: (id: number, winePrefixPath: string | null) =>
ipcRenderer.invoke("selectGameWinePrefix", id, winePrefixPath),
verifyExecutablePathInUse: (executablePath: string) =>
Expand All @@ -115,8 +117,11 @@ contextBridge.exposeInMainWorld("electron", {
ipcRenderer.invoke("openGameInstallerPath", gameId),
openGameExecutablePath: (gameId: number) =>
ipcRenderer.invoke("openGameExecutablePath", gameId),
openGame: (gameId: number, executablePath: string) =>
ipcRenderer.invoke("openGame", gameId, executablePath),
openGame: (
gameId: number,
executablePath: string,
launchOptions: string | null
) => ipcRenderer.invoke("openGame", gameId, executablePath, launchOptions),
closeGame: (gameId: number) => ipcRenderer.invoke("closeGame", gameId),
removeGameFromLibrary: (gameId: number) =>
ipcRenderer.invoke("removeGameFromLibrary", gameId),
Expand Down
6 changes: 5 additions & 1 deletion src/renderer/src/components/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,11 @@ export function Sidebar() {

if (event.detail === 2) {
if (game.executablePath) {
window.electron.openGame(game.id, game.executablePath);
window.electron.openGame(
game.id,
game.executablePath,
game.launchOptions
);
} else {
showWarningToast(t("game_has_no_executable"));
}
Expand Down
10 changes: 9 additions & 1 deletion src/renderer/src/declaration.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ declare global {
id: number,
executablePath: string | null
) => Promise<void>;
updateLaunchOptions: (
id: number,
launchOptions: string | null
) => Promise<void>;
selectGameWinePrefix: (
id: number,
winePrefixPath: string | null
Expand All @@ -102,7 +106,11 @@ declare global {
openGameInstaller: (gameId: number) => Promise<boolean>;
openGameInstallerPath: (gameId: number) => Promise<boolean>;
openGameExecutablePath: (gameId: number) => Promise<void>;
openGame: (gameId: number, executablePath: string) => Promise<void>;
openGame: (
gameId: number,
executablePath: string,
launchOptions: string | null
) => Promise<void>;
closeGame: (gameId: number) => Promise<boolean>;
removeGameFromLibrary: (gameId: number) => Promise<void>;
removeGame: (gameId: number) => Promise<void>;
Expand Down
12 changes: 10 additions & 2 deletions src/renderer/src/pages/game-details/hero/hero-panel-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,21 @@ export function HeroPanelActions() {
const openGame = async () => {
if (game) {
if (game.executablePath) {
window.electron.openGame(game.id, game.executablePath);
window.electron.openGame(
game.id,
game.executablePath,
game.launchOptions
);
return;
}

const gameExecutablePath = await selectGameExecutable();
if (gameExecutablePath)
window.electron.openGame(game.id, gameExecutablePath);
window.electron.openGame(
game.id,
gameExecutablePath,
game.launchOptions
);
}
};

Expand Down
45 changes: 45 additions & 0 deletions src/renderer/src/pages/game-details/modals/game-options-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export function GameOptionsModal({

const [showDeleteModal, setShowDeleteModal] = useState(false);
const [showRemoveGameModal, setShowRemoveGameModal] = useState(false);
const [launchOptions, setLaunchOptions] = useState(game.launchOptions ?? "");

const {
removeGameInstaller,
Expand Down Expand Up @@ -116,9 +117,26 @@ export function GameOptionsModal({
updateGame();
};

const handleChangeLaunchOptions = async (event) => {
const value = event.target.value;

setLaunchOptions(value);

window.electron.updateLaunchOptions(game.id, value).then(updateGame);
};

const handleClearLaunchOptions = async () => {
setLaunchOptions("");

window.electron.updateLaunchOptions(game.id, null).then(updateGame);
};

zamitto marked this conversation as resolved.
Show resolved Hide resolved
const shouldShowWinePrefixConfiguration =
window.electron.platform === "linux";

const shouldShowLaunchOptionsConfiguration =
window.electron.platform === "win32";

return (
<>
<DeleteGameModal
Expand Down Expand Up @@ -226,6 +244,33 @@ export function GameOptionsModal({
</div>
)}

{shouldShowLaunchOptionsConfiguration && (
<div className={styles.gameOptionHeader}>
<h2>{t("launch_options")}</h2>
<h4 className={styles.gameOptionHeaderDescription}>
{t("launch_options_description")}
</h4>
<TextField
value={launchOptions}
theme="dark"
placeholder={t("launch_options_placeholder")}
onChange={handleChangeLaunchOptions}
rightContent={
<>
{game.launchOptions && (
<Button
onClick={handleClearLaunchOptions}
theme="outline"
>
{t("clear")}
</Button>
)}
</>
zamitto marked this conversation as resolved.
Show resolved Hide resolved
}
/>
</div>
)}

<div className={styles.gameOptionHeader}>
<h2>{t("downloads_secion_title")}</h2>
<h4 className={styles.gameOptionHeaderDescription}>
Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export interface Game {
downloader: Downloader;
winePrefixPath: string | null;
executablePath: string | null;
launchOptions: string | null;
lastTimePlayed: Date | null;
uri: string | null;
fileSize: number;
Expand Down
Loading