mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[bugfix-733] manually set WINEPREFIX when executing IPA.exe
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 },
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user