mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[bugfix-742] launch bs version directly with steam shortcut
This commit is contained in:
@@ -65,11 +65,12 @@ const config = {
|
||||
// Audio output
|
||||
"--socket=pulseaudio",
|
||||
// Read/write home directory access
|
||||
"--filesystem=~/Desktop:rw", // allow writing shortcuts to desktop
|
||||
"--filesystem=~/BSManager:create", // Default BSManager installation folder
|
||||
"--filesystem=~/.steam/steam/steamapps:ro", // for the libraryfolders.vdf
|
||||
"--filesystem=~/.steam/steam/steamapps/common:create", // Steam game folder
|
||||
"--filesystem=~/.steam/steam/steamapps/common/Beat Saber:create", // For installing mods/maps to original Beat Saber version
|
||||
"--filesystem=~/Desktop", // allow writing shortcuts to desktop
|
||||
"--filesystem=~/.steam/steam/userdata", // allow writing steam shortcuts
|
||||
// Allow BSManager to create the compat folder if it does not exist
|
||||
"--filesystem=~/.steam/steam/steamapps/compatdata/620980:create",
|
||||
// Allow communication with network
|
||||
|
||||
@@ -9,6 +9,33 @@ import { BsmShellLog, bsmSpawn } from "main/helpers/os.helpers";
|
||||
import { IS_FLATPAK } from "main/constants";
|
||||
import { LaunchMods } from "shared/models/bs-launch/launch-option.interface";
|
||||
|
||||
export function buildBsLaunchArgs(launchOptions: LaunchOption): string[] {
|
||||
const launchArgs = [];
|
||||
|
||||
if(!launchOptions.version.steam && !launchOptions.version.oculus){
|
||||
launchArgs.push("--no-yeet")
|
||||
}
|
||||
if(launchOptions.launchMods?.includes(LaunchMods.OCULUS)) {
|
||||
launchArgs.push("-vrmode");
|
||||
launchArgs.push("oculus");
|
||||
}
|
||||
if(launchOptions.launchMods?.includes(LaunchMods.FPFC)) {
|
||||
launchArgs.push("fpfc");
|
||||
}
|
||||
if(launchOptions.launchMods?.includes(LaunchMods.DEBUG)) {
|
||||
launchArgs.push("--verbose");
|
||||
}
|
||||
if(launchOptions.launchMods?.includes(LaunchMods.EDITOR)) {
|
||||
launchArgs.push("editor");
|
||||
}
|
||||
|
||||
if (launchOptions.additionalArgs) {
|
||||
launchArgs.push(...launchOptions.additionalArgs);
|
||||
}
|
||||
|
||||
return Array.from(new Set(launchArgs).values());
|
||||
}
|
||||
|
||||
export abstract class AbstractLauncherService {
|
||||
|
||||
protected readonly linux = LinuxService.getInstance();
|
||||
@@ -19,33 +46,6 @@ export abstract class AbstractLauncherService {
|
||||
this.localVersions = BSLocalVersionService.getInstance();
|
||||
}
|
||||
|
||||
protected buildBsLaunchArgs(launchOptions: LaunchOption): string[]{
|
||||
const launchArgs = [];
|
||||
|
||||
if(!launchOptions.version.steam && !launchOptions.version.oculus){
|
||||
launchArgs.push("--no-yeet")
|
||||
}
|
||||
if(launchOptions.launchMods?.includes(LaunchMods.OCULUS)) {
|
||||
launchArgs.push("-vrmode");
|
||||
launchArgs.push("oculus");
|
||||
}
|
||||
if(launchOptions.launchMods?.includes(LaunchMods.FPFC)) {
|
||||
launchArgs.push("fpfc");
|
||||
}
|
||||
if(launchOptions.launchMods?.includes(LaunchMods.DEBUG)) {
|
||||
launchArgs.push("--verbose");
|
||||
}
|
||||
if(launchOptions.launchMods?.includes(LaunchMods.EDITOR)) {
|
||||
launchArgs.push("editor");
|
||||
}
|
||||
|
||||
if (launchOptions.additionalArgs) {
|
||||
launchArgs.push(...launchOptions.additionalArgs);
|
||||
}
|
||||
|
||||
return Array.from(new Set(launchArgs).values());
|
||||
}
|
||||
|
||||
protected launchBSProcess(bsExePath: string, args: string[], options?: SpawnBsProcessOptions): ChildProcessWithoutNullStreams {
|
||||
|
||||
const spawnOptions: SpawnOptionsWithoutStdio = { detached: true, cwd: path.dirname(bsExePath), ...(options || {}) };
|
||||
|
||||
@@ -185,7 +185,7 @@ export class BSLauncherService {
|
||||
* @returns {Promise<string>} Path of the icon
|
||||
*/
|
||||
private async createShortcutIco(color: Color): Promise<string>{
|
||||
const pngBuffer = await this.createShortcutPngBuffer(color);
|
||||
const pngBuffer = this.createShortcutPngBuffer(color);
|
||||
const icoBuffer = await toIco([pngBuffer]);
|
||||
|
||||
await ensureDir(IMAGE_CACHE_PATH);
|
||||
@@ -211,17 +211,28 @@ export class BSLauncherService {
|
||||
if(steamShortcut){
|
||||
const userId = await tryit(() => this.steam.getActiveUser());
|
||||
const exePath = app.getPath("exe");
|
||||
return this.steam.createShortcut({
|
||||
AppName: shortcutName,
|
||||
Exe: exePath,
|
||||
StartDir: path.dirname(exePath),
|
||||
LaunchOptions: this.createLaunchLink(launchOptions),
|
||||
icon: await this.createShortcutPng(shortcutIconColor),
|
||||
OpenVR: "\u0001"
|
||||
}, userId.result).then(() => true).catch(e => {
|
||||
log.error(e);
|
||||
return false;
|
||||
});
|
||||
const icon = await this.createShortcutPng(shortcutIconColor)
|
||||
return this.steam.createShortcut(
|
||||
process.platform === "win32"
|
||||
? {
|
||||
AppName: shortcutName,
|
||||
Exe: exePath,
|
||||
StartDir: path.dirname(exePath),
|
||||
LaunchOptions: this.createLaunchLink(launchOptions),
|
||||
OpenVR: "\u0001", icon,
|
||||
}
|
||||
: await this.linux.getSteamShortcutData(
|
||||
shortcutName, icon, launchOptions,
|
||||
await this.steam.getSteamPath(),
|
||||
await this.localVersionService.getVersionPath(launchOptions.version)
|
||||
),
|
||||
userId.result
|
||||
)
|
||||
.then(() => true)
|
||||
.catch(e => {
|
||||
log.error(e);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return execOnOs({
|
||||
|
||||
@@ -6,7 +6,7 @@ import { BS_EXECUTABLE } from "../../constants";
|
||||
import path from "path";
|
||||
import log from "electron-log";
|
||||
import { pathExists } from "fs-extra";
|
||||
import { AbstractLauncherService } from "./abstract-launcher.service";
|
||||
import { AbstractLauncherService, buildBsLaunchArgs } from "./abstract-launcher.service";
|
||||
import { isProcessRunning } from "../../helpers/os.helpers";
|
||||
import { CustomError } from "../../../shared/models/exceptions/custom-error.class";
|
||||
import { UtilsService } from "../utils.service";
|
||||
@@ -57,7 +57,7 @@ export class OculusLauncherService extends AbstractLauncherService implements St
|
||||
obs.next({type: BSLaunchEvent.BS_LAUNCHING});
|
||||
|
||||
// Launch Beat Saber
|
||||
const process = this.launchBs(exePath, this.buildBsLaunchArgs(launchOptions));
|
||||
const process = this.launchBs(exePath, buildBsLaunchArgs(launchOptions));
|
||||
|
||||
return process.exit.catch(err => {
|
||||
throw CustomError.fromError(err, BSLaunchError.BS_EXIT_ERROR);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { SteamService } from "../steam.service";
|
||||
import path from "path";
|
||||
import { BS_APP_ID, BS_EXECUTABLE, STEAMVR_APP_ID } from "../../constants";
|
||||
import log from "electron-log";
|
||||
import { AbstractLauncherService } from "./abstract-launcher.service";
|
||||
import { AbstractLauncherService, buildBsLaunchArgs } from "./abstract-launcher.service";
|
||||
import { CustomError } from "../../../shared/models/exceptions/custom-error.class";
|
||||
import { UtilsService } from "../utils.service";
|
||||
import { exec } from "child_process";
|
||||
@@ -102,7 +102,7 @@ export class SteamLauncherService extends AbstractLauncherService implements Sto
|
||||
await this.restoreSteamVR().catch(log.error);
|
||||
}
|
||||
|
||||
const launchArgs = this.buildBsLaunchArgs(launchOptions);
|
||||
const launchArgs = buildBsLaunchArgs(launchOptions);
|
||||
const steamPath = await this.steam.getSteamPath();
|
||||
|
||||
const env = {
|
||||
|
||||
@@ -8,6 +8,8 @@ import { CustomError } from "shared/models/exceptions/custom-error.class";
|
||||
import { BSLaunchError, LaunchOption } from "shared/models/bs-launch";
|
||||
import { BsmShellLog, bsmExec } from "main/helpers/os.helpers";
|
||||
import { LaunchMods } from "shared/models/bs-launch/launch-option.interface";
|
||||
import { SteamShortcutData } from "shared/models/steam/shortcut.model";
|
||||
import { buildBsLaunchArgs } from "./bs-launcher/abstract-launcher.service";
|
||||
|
||||
export class LinuxService {
|
||||
private static instance: LinuxService;
|
||||
@@ -49,6 +51,16 @@ export class LinuxService {
|
||||
launchOptions.admin = false;
|
||||
}
|
||||
|
||||
const protonPath = await this.getProtonPath();
|
||||
return {
|
||||
protonPrefix: await this.isNixOS()
|
||||
? `steam-run "${protonPath}" run`
|
||||
: `"${protonPath}" run`,
|
||||
env: await this.buildEnvVariables(launchOptions, steamPath, bsFolderPath)
|
||||
};
|
||||
}
|
||||
|
||||
private async getProtonPath(): Promise<string> {
|
||||
if (!this.staticConfig.has("proton-folder")) {
|
||||
throw CustomError.fromError(
|
||||
new Error("Proton folder not set"),
|
||||
@@ -66,15 +78,10 @@ export class LinuxService {
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
protonPrefix: await this.isNixOS()
|
||||
? `steam-run "${protonPath}" run`
|
||||
: `"${protonPath}" run`,
|
||||
env: await this.prepareEnvVariables(launchOptions, steamPath, bsFolderPath)
|
||||
};
|
||||
return protonPath;
|
||||
}
|
||||
|
||||
private async prepareEnvVariables(
|
||||
private async buildEnvVariables(
|
||||
launchOptions: LaunchOption,
|
||||
steamPath: string,
|
||||
bsFolderPath: string
|
||||
@@ -167,6 +174,20 @@ export class LinuxService {
|
||||
|
||||
// === Shortcuts === //
|
||||
|
||||
private getCommand(
|
||||
protonPrefix: string,
|
||||
bsFolderPath: string,
|
||||
env: Record<string, string>,
|
||||
launchOptions: LaunchOption
|
||||
): string {
|
||||
const envString = Object.entries(env)
|
||||
.map(([ key, value ]) => `${key}="${value}"`)
|
||||
.join(" ");
|
||||
const bsExe = path.join(bsFolderPath, BS_EXECUTABLE);
|
||||
const args = buildBsLaunchArgs(launchOptions).join(" ");
|
||||
return `${envString} ${protonPrefix} "${bsExe}" ${args}`;
|
||||
}
|
||||
|
||||
public async createDesktopShortcut(
|
||||
shortcutPath: string,
|
||||
name: string,
|
||||
@@ -186,12 +207,10 @@ export class LinuxService {
|
||||
"SteamGameId": BS_APP_ID,
|
||||
});
|
||||
|
||||
const envString = Object.entries(env)
|
||||
.map(([ key, value ]) => `${key}="${value}"`)
|
||||
.join(" ");
|
||||
const command = `${envString} ${protonPrefix} "${
|
||||
path.join(bsFolderPath, BS_EXECUTABLE)
|
||||
}"`;
|
||||
const command = this.getCommand(
|
||||
protonPrefix, bsFolderPath,
|
||||
env, launchOptions
|
||||
);
|
||||
|
||||
const desktopEntry = [
|
||||
"[Desktop Entry]",
|
||||
@@ -210,4 +229,38 @@ export class LinuxService {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async getSteamShortcutData(
|
||||
shortcutName: string,
|
||||
icon: string,
|
||||
launchOptions: LaunchOption,
|
||||
steamPath: string,
|
||||
bsFolderPath: string
|
||||
): Promise<SteamShortcutData> {
|
||||
const env = await this.buildEnvVariables(
|
||||
launchOptions, steamPath, bsFolderPath
|
||||
);
|
||||
Object.assign(env, {
|
||||
"SteamAppId": BS_APP_ID,
|
||||
"SteamOverlayGameId": BS_APP_ID,
|
||||
"SteamGameId": BS_APP_ID,
|
||||
});
|
||||
|
||||
const protonPrefix = await this.isNixOS()
|
||||
? "steam-run %command% run"
|
||||
: "%command% run";
|
||||
|
||||
return {
|
||||
AppName: shortcutName,
|
||||
Exe: await this.getProtonPath(),
|
||||
StartDir: bsFolderPath,
|
||||
icon,
|
||||
OpenVR: "\x01",
|
||||
LaunchOptions: this.getCommand(
|
||||
protonPrefix, bsFolderPath,
|
||||
env, launchOptions
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user