[bugfix-733] manually set WINEPREFIX when executing IPA.exe

This commit is contained in:
silentrald
2025-01-09 23:42:56 +08:00
parent 664e28ad05
commit 65d26dc819
6 changed files with 78 additions and 46 deletions
+1
View File
@@ -61,6 +61,7 @@ module.exports = {
"react/button-has-type": "off",
"max-classes-per-file": "off",
"jest/no-standalone-expect": "off",
"no-bitwise": "off",
},
parserOptions: {
ecmaVersion: 2020,
+5 -4
View File
@@ -1,4 +1,5 @@
import {
BsmShellLog,
bsmSpawn,
// bsmExec,
isProcessRunning,
@@ -76,7 +77,7 @@ describe("Test os.helpers bsmSpawn", () => {
it("Simple spawn command with logging", () => {
bsmSpawn("mkdir", {
args: ["new_folder"],
log: true,
log: BsmShellLog.Command,
});
expect(spawnSpy).toHaveBeenCalledTimes(1);
expect(spawnSpy).toHaveBeenCalledWith("mkdir new_folder", expect.anything());
@@ -86,7 +87,7 @@ describe("Test os.helpers bsmSpawn", () => {
it("Complex spawn command call (Mods install)", () => {
bsmSpawn(`"./BSIPA.exe" "./Beat Saber.exe" -n`, {
log: true,
log: BsmShellLog.Command,
linux: { prefix: `"./wine64"` },
});
@@ -109,7 +110,7 @@ describe("Test os.helpers bsmSpawn", () => {
detached: true,
env: BS_ENV,
},
log: true,
log: BsmShellLog.Command,
linux: { prefix: `"./proton" run` },
});
@@ -152,7 +153,7 @@ describe("Test os.helpers bsmSpawn", () => {
detached: true,
env: newEnv,
},
log: true,
log: BsmShellLog.Command,
linux: { prefix: `"./proton" run` },
flatpak: {
host: true,
+28 -21
View File
@@ -18,21 +18,22 @@ type FlatpakOptions = {
env?: string[];
};
export type BsmSpawnOptions = {
export enum BsmShellLog {
Command = 0x0000_0001,
EnvVariables = 0x0000_0002,
};
interface BsmShellOptions<OptionsType> {
args?: string[];
options?: cp.SpawnOptions;
log?: boolean;
options?: OptionsType;
// Look into BsmShellLog values
log?: number;
linux?: LinuxOptions;
flatpak?: FlatpakOptions;
};
export type BsmExecOptions = {
args?: string[];
options?: cp.ExecOptions;
log?: boolean;
linux?: LinuxOptions;
flatpak?: FlatpakOptions;
};
export type BsmSpawnOptions = BsmShellOptions<cp.SpawnOptions>;
export type BsmExecOptions = BsmShellOptions<cp.ExecOptions>;
function updateCommand(command: string, options: BsmSpawnOptions) {
if (options?.args) {
@@ -63,14 +64,25 @@ function updateCommand(command: string, options: BsmSpawnOptions) {
return command;
}
function logValues(shell: "spawn" | "exec", command: string, options?: BsmShellOptions<cp.SpawnOptions | cp.ExecOptions>) {
const platform = process.platform === "win32" ? "Windows" : "Linux";
const optionsLog = options?.log || 0;
if ((optionsLog & BsmShellLog.EnvVariables) > 0) {
log.info(platform, shell, "env", options?.options?.env);
}
if ((optionsLog & BsmShellLog.Command) > 0) {
log.info(platform, shell, "command\n>", command);
}
}
export function bsmSpawn(command: string, options?: BsmSpawnOptions) {
options = options || {};
options.options = options.options || {};
command = updateCommand(command, options);
if (options?.log) {
log.info(process.platform === "win32" ? "Windows" : "Linux", "spawn command\n>", command);
}
logValues("spawn", command, options);
return cp.spawn(command, options.options);
}
@@ -83,12 +95,7 @@ export function bsmExec(command: string, options?: BsmExecOptions): Promise<{
options.options = options.options || {};
command = updateCommand(command, options);
if (options?.log) {
log.info(
process.platform === "win32" ? "Windows" : "Linux",
"exec command\n>", command
);
}
logValues("exec", command, options);
return new Promise((resolve, reject) => {
cp.exec(command, options?.options || {}, (error: Error, stdout: string, stderr: string) => {
@@ -111,7 +118,7 @@ async function isProcessRunningLinux(name: string): Promise<boolean> {
try {
const processName = transformProcessNameForPS(name);
const { stdout: count } = await bsmExec(`ps awwxo args | grep -c "${processName}"`, {
log: true,
log: BsmShellLog.Command,
flatpak: { host: IS_FLATPAK },
});
@@ -157,7 +164,7 @@ async function getProcessIdLinux(name: string): Promise<number | null> {
try {
const processName = transformProcessNameForPS(name);
const { stdout } = await bsmExec(`ps awwxo pid,args | grep "${processName}"`, {
log: true,
log: BsmShellLog.Command,
flatpak: { host: IS_FLATPAK },
});
@@ -5,7 +5,7 @@ import path from "path";
import log from "electron-log";
import { sToMs } from "../../../shared/helpers/time.helpers";
import { LinuxService } from "../linux.service";
import { bsmSpawn } from "main/helpers/os.helpers";
import { BsmShellLog, bsmSpawn } from "main/helpers/os.helpers";
import { IS_FLATPAK } from "main/constants";
import { LaunchMods } from "shared/models/bs-launch/launch-option.interface";
@@ -56,7 +56,7 @@ export abstract class AbstractLauncherService {
spawnOptions.shell = true; // For windows to spawn properly
return bsmSpawn(`"${bsExePath}"`, {
args, options: spawnOptions, log: true,
args, options: spawnOptions, log: BsmShellLog.Command,
linux: { prefix: this.linux.getProtonPrefix() },
flatpak: {
host: IS_FLATPAK,
+24 -11
View File
@@ -3,9 +3,10 @@ import log from "electron-log";
import path from "path";
import { BS_APP_ID, IS_FLATPAK, PROTON_BINARY_PREFIX, WINE_BINARY_PREFIX } from "main/constants";
import { StaticConfigurationService } from "./static-configuration.service";
import { SteamService } from "./steam.service";
import { CustomError } from "shared/models/exceptions/custom-error.class";
import { BSLaunchError, LaunchOption } from "shared/models/bs-launch";
import { bsmExec } from "main/helpers/os.helpers";
import { BsmShellLog, bsmExec } from "main/helpers/os.helpers";
import { LaunchMods } from "shared/models/bs-launch/launch-option.interface";
export class LinuxService {
@@ -19,16 +20,31 @@ export class LinuxService {
}
private readonly staticConfig: StaticConfigurationService;
private readonly steamService: SteamService;
private protonPrefix = "";
private nixOS: boolean | undefined;
private constructor() {
this.staticConfig = StaticConfigurationService.getInstance();
this.steamService = SteamService.getInstance();
}
// === Launching === //
private getCompatDataPath(steamPath: string) {
// Create the compat data path if it doesn't exist.
// If the user never ran Beat Saber through steam before
// using bsmanager, it won't exist, and proton will fail
// to launch the game.
const compatDataPath = path.join(steamPath, "steamapps", "compatdata", BS_APP_ID);
if (!fs.existsSync(compatDataPath)) {
log.info(`Proton compat data path not found at '${compatDataPath}', creating directory`);
fs.mkdirSync(compatDataPath);
}
return compatDataPath;
}
public async setupLaunch(
launchOptions: LaunchOption,
steamPath: string,
@@ -40,15 +56,7 @@ export class LinuxService {
launchOptions.admin = false;
}
// Create the compat data path if it doesn't exist.
// If the user never ran Beat Saber through steam before
// using bsmanager, it won't exist, and proton will fail
// to launch the game.
const compatDataPath = `${steamPath}/steamapps/compatdata/${BS_APP_ID}`;
if (!fs.existsSync(compatDataPath)) {
log.info(`Proton compat data path not found at '${compatDataPath}', creating directory`);
fs.mkdirSync(compatDataPath);
}
const compatDataPath = this.getCompatDataPath(steamPath);
if (!this.staticConfig.has("proton-folder")) {
throw CustomError.fromError(
@@ -120,6 +128,11 @@ export class LinuxService {
return winePath;
}
public async getWinePrefixPath(): Promise<string> {
const compatDataPath = this.getCompatDataPath(await this.steamService.getSteamPath());
return path.join(compatDataPath, "pfx");
}
public getProtonPrefix(): string {
// Set in setupLaunch
return this.protonPrefix;
@@ -134,7 +147,7 @@ export class LinuxService {
try {
await bsmExec("nixos-version", {
log: true,
log: BsmShellLog.Command,
flatpak: { host: IS_FLATPAK },
});
this.nixOS = true;
@@ -17,7 +17,7 @@ import { LinuxService } from "../linux.service";
import { tryit } from "shared/helpers/error.helpers";
import crypto from "crypto";
import { BsmZipExtractor } from "main/models/bsm-zip-extractor.class";
import { bsmSpawn } from "main/helpers/os.helpers";
import { BsmShellLog, bsmSpawn } from "main/helpers/os.helpers";
import { BbmFullMod, BbmModVersion, ExternalMod } from "../../../shared/models/mods/mod.interface";
export class BsModsManagerService {
@@ -139,25 +139,35 @@ export class BsModsManagerService {
return false;
}
const env: Record<string, string> = {};
const cmd = `"${ipaPath}" "${bsExePath}" ${args.join(" ")}`;
let winePath: string = "";
if (process.platform === "linux") {
const { error, result } = tryit(() => this.linuxService.getWinePath());
if (error) {
log.error(error);
const { error: winePathError, result: winePathResult } =
tryit(() => this.linuxService.getWinePath());
if (winePathError) {
log.error(winePathError);
return false;
}
winePath = `"${result}"`;
winePath = `"${winePathResult}"`;
const { error: winePrefixError, result: winePrefixResult } =
await tryit(async () => this.linuxService.getWinePrefixPath());
if (winePrefixError) {
log.warn("Could not get WINEPREFIX value", winePrefixError);
} else {
env.WINEPREFIX = winePrefixResult;
}
}
return new Promise<boolean>(resolve => {
log.info("START IPA PROCESS", cmd);
const processIPA = bsmSpawn(cmd, {
log: true,
log: BsmShellLog.Command | BsmShellLog.EnvVariables,
options: {
cwd: versionPath,
detached: true,
shell: true
shell: true,
env
},
linux: { prefix: winePath },
});