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

[bugfix] fixed flatpack issues #745

Merged
merged 7 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 0 additions & 4 deletions build/after-install.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
# Add write permissions to anybody so that this can be sync with the
# github's bs-versions.json when starting bsmanager
/usr/bin/chmod +002 /opt/BSManager/resources/assets/jsons/bs-versions.json

# https://github.com/electron/electron/issues/42510
/usr/bin/chmod 4755 /opt/BSManager/chrome-sandbox
1 change: 0 additions & 1 deletion docs/wiki/Home.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ Guidance on fixing errors during setup or version updates

- __🐧Linux__:
- [Missing Icons in Game]([Linux]-Missing-Icons-in-Game)
- [Permission Denied on "bs-versions.json"]([Linux]-Permission-Denied-on-bs-version.json)
- [[Deb] The SUID Sandbox Helper Binary Was Found]([Linux]-[deb]-The-SUID-Sandbox-Helper-Binary-Was-Found)
- [[Flatpak] Steam Beat Saber Version Not Showing / Proton Not Detected]([Linux]-[Flatpak]-Steam-Beat-Saber-Version-Not-Showing-Proton-Not-Detected)
- [[Flatpak] Changing Installation Folder]([Linux]-[Flatpak]-Changing-Installation-Folder)
Expand Down

This file was deleted.

1 change: 0 additions & 1 deletion docs/wiki/_Sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
<summary>🐧 Linux</summary>
<ul>
<li><a href="%5BLinux%5D-Missing-Icons-in-Game">Missing Icons in Game</a></li>
<li><a href="%5BLinux%5D-Permission-Denied-on-bs-version.json">Permission Denied on "bs-versions.json"</a></li>
<li><a href="%5BLinux%5D-%5Bdeb%5D-The-SUID-Sandbox-Helper-Binary-Was-Found">[Deb] The SUID Sandbox Helper Binary Was Found</a></li>
<li><a href="%5BLinux%5D-%5BFlatpak%5D-Steam-Beat-Saber-Version-Not-Showing-Proton-Not-Detected">[Flatpak] Steam Beat Saber Version Not Showing / Proton Not Detected</a></li>
<li><a href="%5BLinux%5D-%5BFlatpak%5D-Changing-Installation-Folder">[Flatpak] Changing Installation Folder</a></li>
Expand Down
2 changes: 2 additions & 0 deletions electron-builder.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ const config = {
"--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
Expand Down
67 changes: 35 additions & 32 deletions src/main/services/bs-launcher/abstract-launcher.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -19,34 +46,7 @@ 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?: SpawnOptionsWithoutStdio): ChildProcessWithoutNullStreams {
protected launchBSProcess(bsExePath: string, args: string[], options?: SpawnBsProcessOptions): ChildProcessWithoutNullStreams {

const spawnOptions: SpawnOptionsWithoutStdio = { detached: true, cwd: path.dirname(bsExePath), ...(options || {}) };

Expand All @@ -57,7 +57,7 @@ export abstract class AbstractLauncherService {
spawnOptions.shell = true; // For windows to spawn properly
return bsmSpawn(`"${bsExePath}"`, {
args, options: spawnOptions, log: BsmShellLog.Command,
linux: { prefix: this.linux.getProtonPrefix() },
linux: { prefix: options?.protonPrefix || "" },
flatpak: {
host: IS_FLATPAK,
env: [
Expand All @@ -70,6 +70,8 @@ export abstract class AbstractLauncherService {
"STEAM_COMPAT_CLIENT_INSTALL_PATH",
"STEAM_COMPAT_APP_ID",
"SteamEnv",
"PROTON_LOG",
"PROTON_LOG_DIR",
],
},
});
Expand All @@ -78,7 +80,7 @@ export abstract class AbstractLauncherService {
protected launchBs(bsExePath: string, args: string[], options?: SpawnBsProcessOptions): {process: ChildProcessWithoutNullStreams, exit: Promise<number>} {
const process = this.launchBSProcess(bsExePath, args, options);

let timoutId: NodeJS.Timeout;
let timeoutId: NodeJS.Timeout;

const exit = new Promise<number>((resolve, reject) => {
// Don't remove, useful for debugging!
Expand All @@ -101,21 +103,22 @@ export abstract class AbstractLauncherService {

const unrefAfter = options?.unrefAfter ?? sToMs(10);

timoutId = setTimeout(() => {
timeoutId = setTimeout(() => {
log.error("BS process unref after timeout", unrefAfter);
process.unref();
process.removeAllListeners();
resolve(-1);
}, unrefAfter);

}).finally(() => {
clearTimeout(timoutId);
clearTimeout(timeoutId);
});

return { process, exit };
}
}

export type SpawnBsProcessOptions = {
protonPrefix?: string;
unrefAfter?: number;
} & SpawnOptionsWithoutStdio;
74 changes: 33 additions & 41 deletions src/main/services/bs-launcher/bs-launcher.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { LaunchMod, LaunchMods } from "shared/models/bs-launch/launch-option.int
import { StaticConfigurationService } from "../static-configuration.service";
import { SteamService } from "../steam.service";
import { tryit } from "shared/helpers/error.helpers";
import { LinuxService } from "../linux.service";

export class BSLauncherService {
private static instance: BSLauncherService;
Expand All @@ -37,6 +38,7 @@ export class BSLauncherService {
private readonly steam: SteamService;
private readonly oculusLauncher: OculusLauncherService;
private readonly staticConfig: StaticConfigurationService;
private readonly linux: LinuxService;

public static getInstance(): BSLauncherService {
if (!BSLauncherService.instance) {
Expand All @@ -55,6 +57,7 @@ export class BSLauncherService {
this.oculusLauncher = OculusLauncherService.getInstance();
this.staticConfig = StaticConfigurationService.getInstance();
this.steam = SteamService.getInstance();
this.linux = LinuxService.getInstance();

this.bsmProtocolService.on("launch", link => {
log.info("Launch from bsm protocol", link.toString());
Expand Down Expand Up @@ -182,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);
Expand All @@ -208,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({
Expand All @@ -230,12 +244,13 @@ export class BSLauncherService {
description: [shortcutName, launchOptions.version.color].join(" "), // <= Need color in description to help windows know that the shortcut is different
})
),
linux: async () => (
createDesktopUrlShortcut(path.join(app.getPath("desktop"), `${shortcutName}.desktop`), {
name: shortcutName,
url: shortcutUrl,
icon: await this.createShortcutPng(shortcutIconColor),
})
linux: async () => this.linux.createDesktopShortcut(
path.join(app.getPath("desktop"), `${shortcutName}.desktop`),
shortcutName,
await this.createShortcutPng(shortcutIconColor),
launchOptions,
await this.steam.getSteamPath(),
await this.localVersionService.getVersionPath(launchOptions.version)
)
})

Expand Down Expand Up @@ -282,26 +297,3 @@ type ShortcutParams = {
versionOculus?: string;
}

/**
* Create .desktop file for url shortcut (only for linux)
* @param {string} shortcutPath
* @param options
* @returns
*/
function createDesktopUrlShortcut(shortcutPath: string, options?: {
url: string
name: string,
icon: string
}): Promise<boolean> {
const { url, name, icon } = options || {};

const data = [
"[Desktop Entry]",
"Type=Link",
`Name=${name}`,
`Icon=${icon}`,
`URL=${url}`
].join("\n");

return writeFile(shortcutPath, data).then(() => true);
}
4 changes: 2 additions & 2 deletions src/main/services/bs-launcher/oculus-launcher.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);
Expand Down
16 changes: 12 additions & 4 deletions src/main/services/bs-launcher/steam-launcher.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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 = {
Expand All @@ -112,17 +112,25 @@ export class SteamLauncherService extends AbstractLauncherService implements Sto
"SteamGameId": BS_APP_ID,
};

let protonPrefix = "";
// Linux setup
if (process.platform === "linux") {
await this.linux.setupLaunch(launchOptions, steamPath, bsFolderPath, env);
const linuxSetup = await this.linux.setupLaunch(
launchOptions, steamPath, bsFolderPath
);
protonPrefix = linuxSetup.protonPrefix;
Object.assign(env, linuxSetup.env);
}

obs.next({type: BSLaunchEvent.BS_LAUNCHING});

const spawnOpts = { env, cwd: bsFolderPath };

const launchPromise = !launchOptions.admin ? (
this.launchBs(bsExePath, launchArgs, spawnOpts).exit
this.launchBs(bsExePath, launchArgs, {
...spawnOpts,
protonPrefix
}).exit
) : (
new Promise<number>(resolve => {
const adminProcess = exec(`"${this.getStartBsAsAdminExePath()}" "${bsExePath}" ${launchArgs.join(" ")} --log-path "${path.join(app.getPath("logs"), "bs-admin-start.log")}"`, spawnOpts);
Expand Down
Loading
Loading