Merge pull request #709 from Zagrios/chore/rework-advanced-launch

Chore/rework advanced launch
This commit is contained in:
MathieuG-P
2024-12-22 16:49:39 +01:00
committed by GitHub
26 changed files with 317 additions and 127 deletions
+7 -3
View File
@@ -24,7 +24,9 @@
"unknown": "Ein unbekannter Fehler ist aufgetreten ¯\\_(ツ)_/¯",
"warning": "Achtung",
"continue": "Weiter",
"shared": "Geteilt"
"shared": "Geteilt",
"pin": "Anheften",
"unpin": "Lösen"
},
"title-bar": {
"outdated": "veraltet"
@@ -48,11 +50,13 @@
"debug-description": "Aktiviert das Ausgabeprotokollfenster für IPA. Dies zeigt die Debug-Konsole, welche die Mods verwenden.",
"outdated-tippy": "Diese Version ist veraltet, und einige Mods oder Funktionen funktionieren möglicherweise nicht wie erwartet. Es wird empfohlen, die empfohlene Version ({recommendedVersion}) von Beat Saber zu verwenden, um die neuesten Funktionen und Fehlerbehebungen zu genießen.",
"advanced-launch": {
"button": "Erweiterter Start",
"button": "Startoptionen",
"placeholder": "Weitere Argumente, bspw: --revert; --nowait"
},
"skipsteam": "Steam überspringen",
"skipsteam-description": "Verhindert, dass Steam automatisch mit Beat Saber geöffnet wird. Aktivieren Sie dies, wenn Sie eine andere VR-Laufzeit wie WiVRn oder Monado verwenden, mit der SteamVR interferieren könnte."
"skipsteam-description": "Verhindert, dass Steam automatisch mit Beat Saber geöffnet wird. Aktivieren Sie dies, wenn Sie eine andere VR-Laufzeit wie WiVRn oder Monado verwenden, mit der SteamVR interferieren könnte.",
"map-editor": "Karteneditor",
"map-editor-description": "Starte den offiziellen Beat Saber-Karteneditor anstelle des Spiels."
},
"maps": {
"search-bar": {
+7 -3
View File
@@ -24,7 +24,9 @@
"unknown": "An unknown error occurred ¯\\_(ツ)_/¯",
"warning": "Warning",
"continue": "Continue",
"shared": "Shared"
"shared": "Shared",
"pin": "Pin",
"unpin": "Unpin"
},
"title-bar": {
"outdated": "outdated"
@@ -48,11 +50,13 @@
"debug-description": "Enables the output log window for IPA. This will show the debug console that mods use.",
"outdated-tippy": "This version is outdated, and some mods or features may no longer work as expected. Prefer using the recommended version ({recommendedVersion}) of Beat Saber to enjoy the latest features and bugfixes.",
"advanced-launch": {
"button": "Advanced launch",
"button": "Launch options",
"placeholder": "Additional arguments ex: --revert; --nowait"
},
"skipsteam": "Skip Steam",
"skipsteam-description": "Stops Steam from opening automatically with Beat Saber, enable if you are using a different VR runtime like WiVRn or Monado that SteamVR may interfere with."
"skipsteam-description": "Stops Steam from opening automatically with Beat Saber, enable if you are using a different VR runtime like WiVRn or Monado that SteamVR may interfere with.",
"map-editor": "Map Editor",
"map-editor-description": "Start the official Beat Saber map editor instead of the game."
},
"maps": {
"search-bar": {
+7 -3
View File
@@ -24,7 +24,9 @@
"unknown": "Se ha producido un error desconocido ¯\\_(ツ)_/¯",
"warning": "Advertencia",
"continue": "Continuar",
"shared": "Compartido"
"shared": "Compartido",
"pin": "Fijar",
"unpin": "Desfijar"
},
"title-bar": {
"outdated": "obsoleto"
@@ -48,7 +50,7 @@
"debug-description": "Habilita la ventana de registro de salida para IPA. Esto mostrará la consola de depuración que usan los mods.",
"outdated-tippy": "Esta versión está desactualizada, y algunos mods o funciones pueden no funcionar como se espera. Es mejor usar la versión recomendada ({recommendedVersion}) de Beat Saber para disfrutar de las últimas características y correcciones.",
"advanced-launch": {
"button": "Opciones avanzadas",
"button": "Opciones de lanzamiento",
"placeholder": "Argumentos adicionales ej: --revert; --no-wait"
}
},
@@ -62,7 +64,9 @@
"delete-duplicate-maps": "Borrar duplicados"
},
"skipsteam": "Saltar Steam",
"skipsteam-description": "Evita que Steam se abra automáticamente con Beat Saber, habilita esto si estás usando un runtime de VR diferente como WiVRn o Monado que SteamVR podría interferir."
"skipsteam-description": "Evita que Steam se abra automáticamente con Beat Saber, habilita esto si estás usando un runtime de VR diferente como WiVRn o Monado que SteamVR podría interferir.",
"map-editor": "Editor de mapas",
"map-editor-description": "Inicia el editor oficial de mapas de Beat Saber en lugar del juego."
},
"tabs": {
"maps": {
+7 -3
View File
@@ -24,7 +24,9 @@
"unknown": "Une erreur inconnue s'est produite ¯\\_(ツ)_/¯",
"warning": "Attention",
"continue": "Continuer",
"shared": "Partagé"
"shared": "Partagé",
"pin": "Épingler",
"unpin": "Désépingler"
},
"title-bar": {
"outdated": "obsolète"
@@ -48,11 +50,13 @@
"debug-description": "Active la fenêtre de log pour IPA. Cela affichera la console de débogage utilisée par les mods.",
"outdated-tippy": "Cette version est obsolète et certains mods ou fonctionnalités peuvent ne plus fonctionner comme prévu. Préférez utiliser la version recommandée ({recommendedVersion}) de Beat Saber pour profiter des dernières fonctionnalités et correctifs.",
"advanced-launch": {
"button": "Lancement avancé",
"button": "Options de lancement",
"placeholder": "Arguments supplémentaires ex: --revert; --nowait"
},
"skipsteam": "Ignorer Steam",
"skipsteam-description": "Empêche Steam de s'ouvrir automatiquement avec Beat Saber, activez-le si vous utilisez un autre runtime VR comme WiVRn ou Monado avec lequel SteamVR pourrait interférer."
"skipsteam-description": "Empêche Steam de s'ouvrir automatiquement avec Beat Saber, activez-le si vous utilisez un autre runtime VR comme WiVRn ou Monado avec lequel SteamVR pourrait interférer.",
"map-editor": "Éditeur de map",
"map-editor-description": "Lance l'éditeur officiel de map de Beat Saber au lieu du jeu."
},
"maps": {
"search-bar": {
+4 -2
View File
@@ -24,7 +24,9 @@
"unknown": "不明なエラーが発生しました (´・ω・`)",
"warning": "警告",
"continue": "続ける",
"shared": "共有"
"shared": "共有",
"pin": "固定",
"unpin": "固定解除"
},
"title-bar": {
"outdated": "時代遅れ"
@@ -48,7 +50,7 @@
"debug-description": "IPAの出力ログウィンドウを有効にします。これはMODのデバッグコンソールを表示します。",
"outdated-tippy": "このバージョンは古いため、一部のMODや機能が期待通りに動作しない可能性があります。最新の機能やバグ修正を楽しむには、推奨バージョン ({recommendedVersion}) のBeat Saberを使用することをお勧めします。",
"advanced-launch": {
"button": "高度な起動",
"button": "起動オプション",
"placeholder": "追加引数 例:--revert; --nowait"
},
"skipsteam": "Steamをスキップ",
+7 -3
View File
@@ -24,7 +24,9 @@
"unknown": "알 수 없는 오류가 발생했습니다 (´・ω・`)",
"warning": "경고",
"continue": "계속",
"shared": "공유"
"shared": "공유",
"pin": "고정",
"unpin": "고정 해제"
},
"title-bar": {
"outdated": "구식"
@@ -48,11 +50,13 @@
"debug-description": "IPA 출력 로그 창을 활성화하여 MOD의 디버그 콘솔을 표시합니다.",
"outdated-tippy": "이 버전은 오래되어 일부 모드나 기능이 예상대로 작동하지 않을 수 있습니다. 최신 기능과 버그 수정을 사용하려면 권장 버전({recommendedVersion})의 Beat Saber를 사용하는 것이 좋습니다.",
"advanced-launch": {
"button": "고급 실행",
"button": "실행 옵션",
"placeholder": "추가 인수 예: --revert; --nowait"
},
"skipsteam": "Steam 실행 건너뛰기",
"skipsteam-description": "Beat Saber와 함께 Steam이 자동으로 열리는 것을 방지합니다. SteamVR이 간섭할 수 있는 WiVRn 또는 Monado와 같은 다른 VR 런타임을 사용하는 경우 활성화하세요."
"skipsteam-description": "Beat Saber와 함께 Steam이 자동으로 열리는 것을 방지합니다. SteamVR이 간섭할 수 있는 WiVRn 또는 Monado와 같은 다른 VR 런타임을 사용하는 경우 활성화하세요.",
"map-editor": "맵 편집기",
"map-editor-description": "게임 대신 공식 Beat Saber 맵 편집기를 실행해."
},
"maps": {
"search-bar": {
+7 -3
View File
@@ -24,7 +24,9 @@
"unknown": "Неизвестная ошибка ¯\\_(ツ)_/¯",
"warning": "Внимание",
"continue": "Продолжить",
"shared": "Общий"
"shared": "Общий",
"pin": "Закрепить",
"unpin": "Открепить"
},
"title-bar": {
"outdated": "устаревший"
@@ -48,11 +50,13 @@
"debug-description": "Включает окно логов для IPA. В окне будут отображаться логи модов.",
"outdated-tippy": "Эта версия устарела, и некоторые моды или функции могут работать не так, как ожидалось. Рекомендуется использовать рекомендуемую версию ({recommendedVersion}) Beat Saber, чтобы воспользоваться последними функциями и исправлениями ошибок.",
"advanced-launch": {
"button": "Расширенный запуск",
"button": "Параметры запуска",
"placeholder": "Параметры запуска, например: --revert; --nowait"
},
"skipsteam": "Пропустить Steam",
"skipsteam-description": "Предотвращает автоматическое открытие Steam с Beat Saber, включите, если вы используете другую VR-среду, такую как WiVRn или Monado, с которой SteamVR может мешать."
"skipsteam-description": "Предотвращает автоматическое открытие Steam с Beat Saber, включите, если вы используете другую VR-среду, такую как WiVRn или Monado, с которой SteamVR может мешать.",
"map-editor": "Редактор карт",
"map-editor-description": "Запусти официальный редактор карт Beat Saber вместо игры."
},
"maps": {
"search-bar": {
+7 -3
View File
@@ -24,7 +24,9 @@
"unknown": "發生了一個錯誤 ¯\\_(ツ)_/¯",
"warning": "警告",
"continue": "繼續",
"shared": "共享"
"shared": "共享",
"pin": "固定",
"unpin": "取消固定"
},
"title-bar": {
"outdated": "過時"
@@ -48,11 +50,13 @@
"debug-description": "為 IPA 啟用輸出日誌窗口。 會顯示所用 Mod 的 debug 輸出",
"outdated-tippy": "此版本已過時,某些模組或功能可能無法按預期運作。建議使用推薦版本的 Beat Saber ({recommendedVersion}),以享受最新功能和修復。",
"advanced-launch": {
"button": "高級啟動",
"button": "啟動選項",
"placeholder": "額外啟動參數,例如: --revert; --nowait"
},
"skipsteam": "跳過 Steam",
"skipsteam-description": "防止 Steam 與 Beat Saber 自動打開,如果您使用的是其他 VR 執行時,如 WiVRn 或 Monado,SteamVR 可能會干擾,請啟用此選項。"
"skipsteam-description": "防止 Steam 與 Beat Saber 自動打開,如果您使用的是其他 VR 執行時,如 WiVRn 或 Monado,SteamVR 可能會干擾,請啟用此選項。",
"map-editor": "地圖編輯器",
"map-editor-description": "啟動官方的 Beat Saber 地圖編輯器,而不是遊戲。"
},
"maps": {
"search-bar": {
+7 -3
View File
@@ -24,7 +24,9 @@
"Unknown": "发生了一个错误 ¯\\_(ツ)_/¯",
"warning": "警告",
"continue": "继续",
"shared": "共享"
"shared": "共享",
"pin": "固定",
"unpin": "取消固定"
},
"title-bar": {
"outdated": "过时"
@@ -48,11 +50,13 @@
"debug-description": "为 IPA 启用输出日志窗口。 会显示所用 Mod 的 debug 输出",
"outdated-tippy": "此版本已过时,某些模组或功能可能无法按预期运行。建议使用推荐版本的 Beat Saber ({recommendedVersion}),以享受最新功能和修复。",
"advanced-launch": {
"button": "高级启动",
"button": "启动选项",
"placeholder": "额外启动参数,例如: --revert; --nowait"
},
"skipsteam": "跳过 Steam",
"skipsteam-description": "防止 Steam 与 Beat Saber 自动打开,如果您使用的是其他 VR 运行时,如 WiVRn 或 Monado,SteamVR 可能会干扰,请启用此选项。"
"skipsteam-description": "防止 Steam 与 Beat Saber 自动打开,如果您使用的是其他 VR 运行时,如 WiVRn 或 Monado,SteamVR 可能会干扰,请启用此选项。",
"map-editor": "地图编辑器",
"map-editor-description": "启动官方的 Beat Saber 地图编辑器,而不是游戏。"
},
"maps": {
"search-bar": {
@@ -7,6 +7,7 @@ import { sToMs } from "../../../shared/helpers/time.helpers";
import { LinuxService } from "../linux.service";
import { bsmSpawn } from "main/helpers/os.helpers";
import { IS_FLATPAK } from "main/constants";
import { LaunchMods } from "shared/models/bs-launch/launch-option.interface";
export abstract class AbstractLauncherService {
@@ -24,16 +25,20 @@ export abstract class AbstractLauncherService {
if(!launchOptions.version.steam && !launchOptions.version.oculus){
launchArgs.push("--no-yeet")
}
if (launchOptions.oculus) {
if(launchOptions.launchMods?.includes(LaunchMods.OCULUS)) {
launchArgs.push("-vrmode");
launchArgs.push("oculus");
}
if (launchOptions.desktop) {
if(launchOptions.launchMods?.includes(LaunchMods.FPFC)) {
launchArgs.push("fpfc");
}
if (launchOptions.debug) {
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);
}
@@ -20,6 +20,7 @@ import { SteamLauncherService } from "./steam-launcher.service";
import { OculusLauncherService } from "./oculus-launcher.service";
import { BSVersion } from "shared/bs-version.interface";
import { BsStore } from "../../../shared/models/bs-store.enum";
import { LaunchMod, LaunchMods } from "shared/models/bs-launch/launch-option.interface";
export class BSLauncherService {
private static instance: BSLauncherService;
@@ -94,6 +95,14 @@ export class BSLauncherService {
}
private shortcutParamsToLaunchOption(params: ShortcutParams): LaunchOption{
const launchMods: LaunchMod[] = [];
if(params.oculusMode === "true"){ launchMods.push(LaunchMods.OCULUS); }
if(params.desktopMode === "true"){ launchMods.push(LaunchMods.FPFC); }
if(params.debug === "true"){ launchMods.push(LaunchMods.DEBUG); }
if(params.skipSteam === "true"){ launchMods.push(LaunchMods.SKIP_STEAM); }
const res: LaunchOption = {
version: {
BSVersion: params.version,
@@ -102,11 +111,8 @@ export class BSLauncherService {
oculus: params.versionOculus === "true",
ino: +params.versionIno
},
oculus: params.oculusMode === "true",
desktop: params.desktopMode === "true",
debug: params.debug === "true",
additionalArgs: params.additionalArgs,
skipSteam: params.skipSteam === "true",
launchMods,
};
return res;
@@ -120,11 +126,11 @@ export class BSLauncherService {
if(launchOptions.version.oculus){ res.versionOculus = `${launchOptions.version.oculus}`; }
if(launchOptions.version.ino){ res.versionIno = `${launchOptions.version.ino}`; }
if(launchOptions.oculus){ res.oculusMode = "true"; }
if(launchOptions.desktop){ res.desktopMode = "true"; }
if(launchOptions.debug){ res.debug = "true"; }
if(launchOptions.launchMods?.includes(LaunchMods.OCULUS)){ res.oculusMode = "true"; }
if(launchOptions.launchMods?.includes(LaunchMods.FPFC)){ res.desktopMode = "true"; }
if(launchOptions.launchMods?.includes(LaunchMods.DEBUG)){ res.debug = "true"; }
if(launchOptions.additionalArgs){ res.additionalArgs = launchOptions.additionalArgs; }
if(launchOptions.skipSteam){ res.skipSteam = "true"; }
if(launchOptions.launchMods?.includes(LaunchMods.SKIP_STEAM)){ res.skipSteam = "true"; }
return res;
}
@@ -10,6 +10,7 @@ import { AbstractLauncherService } from "./abstract-launcher.service";
import { CustomError } from "../../../shared/models/exceptions/custom-error.class";
import { UtilsService } from "../utils.service";
import { exec } from "child_process";
import { LaunchMods } from "shared/models/bs-launch/launch-option.interface";
export class SteamLauncherService extends AbstractLauncherService implements StoreLauncherInterface{
@@ -73,7 +74,7 @@ export class SteamLauncherService extends AbstractLauncherService implements Sto
throw CustomError.fromError(new Error(`Path not exist : ${bsExePath}`), BSLaunchError.BS_NOT_FOUND);
}
const skipSteam: boolean = launchOptions.skipSteam ?? false;
const skipSteam: boolean = launchOptions.launchMods?.includes(LaunchMods.SKIP_STEAM) ?? false;
// Open Steam if not running
if(!skipSteam && !(await this.steam.isSteamRunning())){
@@ -87,12 +88,12 @@ export class SteamLauncherService extends AbstractLauncherService implements Sto
obs.next({type: BSLaunchWarning.UNABLE_TO_LAUNCH_STEAM});
});
}
else if (launchOptions.skipSteam) {
else {
obs.next({ type: BSLaunchEvent.SKIPPING_STEAM_LAUNCH});
}
// Backup SteamVR when desktop mode is enabled
if(launchOptions.desktop){
if(launchOptions.launchMods?.includes(LaunchMods.FPFC)){
await this.backupSteamVR().catch(() => {
return this.restoreSteamVR();
});
@@ -2,7 +2,7 @@ import { BSVersion } from "shared/bs-version.interface";
import { Link, useLocation } from "react-router-dom";
import { useState } from "react";
import { distinctUntilChanged, lastValueFrom, map, of, Subscription, switchMap, take } from "rxjs";
import { BSLauncherService, LaunchMods } from "renderer/services/bs-launcher.service";
import { BSLauncherService } from "renderer/services/bs-launcher.service";
import { ConfigurationService } from "renderer/services/configuration.service";
import { BSUninstallerService } from "renderer/services/bs-uninstaller.service";
import { BSVersionManagerService } from "renderer/services/bs-version-manager.service";
@@ -60,10 +60,7 @@ export function BsVersionItem(props: { version: BSVersion }) {
if(equal(downloadingVersion, props.version)){ return; }
const launch$ = launcherService.launch({
version: state,
oculus: !!configService.get<boolean>(LaunchMods.OCULUS_MOD),
desktop: !!configService.get<boolean>(LaunchMods.DESKTOP_MOD),
debug: !!configService.get<boolean>(LaunchMods.DEBUG_MOD),
skipSteam: !!configService.get<boolean>(LaunchMods.SKIPSTEAM_MOD),
launchMods: configService.get("launch-mods") ?? [],
});
return lastValueFrom(launch$).catch(() => {});
};
@@ -16,7 +16,7 @@ import { TaskIcon } from "./icons/task-icon.component";
import { CopyIcon } from "./icons/copy-icon.component";
import { SteamIcon } from "./icons/steam-icon.component";
import { CSSProperties, memo } from "react";
import EditIcon from "./icons/edit-icon.component";
import { EditIcon } from "./icons/edit-icon.component";
import { ExportIcon } from "./icons/export-icon.component";
import PatreonIcon from "./icons/patreon-icon.component";
import { SearchIcon } from "./icons/search-icon.component";
@@ -1,9 +1,9 @@
import { CSSProperties } from "react";
import { createSvgIcon } from "../svg-icon.type";
export function DesktopIcon(props: { className?: string; style?: CSSProperties }) {
export const DesktopIcon = createSvgIcon((props, ref) => {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" height="40" width="40">
<svg ref={ref} {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" height="40" width="40">
<path fill="currentColor" d="M13.417 38V33.75H16.875V29.875H6.708Q4.917 29.875 3.687 28.646Q2.458 27.417 2.458 25.667V7.25Q2.458 5.5 3.687 4.271Q4.917 3.042 6.708 3.042H33.375Q35.125 3.042 36.375 4.271Q37.625 5.5 37.625 7.25V25.667Q37.625 27.417 36.375 28.646Q35.125 29.875 33.375 29.875H23.167V33.75H26.667V38ZM6.708 25.667H33.375Q33.375 25.667 33.375 25.667Q33.375 25.667 33.375 25.667V7.25Q33.375 7.25 33.375 7.25Q33.375 7.25 33.375 7.25H6.708Q6.708 7.25 6.708 7.25Q6.708 7.25 6.708 7.25V25.667Q6.708 25.667 6.708 25.667Q6.708 25.667 6.708 25.667ZM6.708 25.667Q6.708 25.667 6.708 25.667Q6.708 25.667 6.708 25.667V7.25Q6.708 7.25 6.708 7.25Q6.708 7.25 6.708 7.25Q6.708 7.25 6.708 7.25Q6.708 7.25 6.708 7.25V25.667Q6.708 25.667 6.708 25.667Q6.708 25.667 6.708 25.667Z" />
</svg>
);
}
})
@@ -1,9 +1,9 @@
import { CSSProperties } from "react";
import { createSvgIcon } from "../svg-icon.type";
export default function EditIcon(props: { className?: string; style?: CSSProperties }) {
export const EditIcon = createSvgIcon((props, ref) => {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" height="40" width="40">
<svg ref={ref} {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" height="40" width="40">
<path fill="currentColor" d="M7.833 32.25h1.875L26.75 15.208l-1.875-1.875L7.833 30.375Zm24.959-19.042-5.959-5.916 1.917-1.917q.833-.833 2.042-.833 1.208 0 2.083.875l1.833 1.833q.875.833.854 2.021-.02 1.187-.854 2.021ZM6.542 35.125q-.667 0-1.125-.458-.459-.459-.459-1.125v-3.709q0-.333.104-.604.105-.271.355-.521L24.875 9.25l5.958 5.958-19.458 19.459q-.25.25-.542.354-.291.104-.583.104Zm19.25-20.833-.917-.959 1.875 1.875Z" />
</svg>
);
}
})
@@ -1,12 +1,12 @@
import { HTMLProps } from "react";
import { createSvgIcon } from "../svg-icon.type";
export function OculusIcon(props: HTMLProps<SVGSVGElement>) {
export const OculusIcon = createSvgIcon((props, ref) => {
return (
<svg {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<svg ref={ref} {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path
fill="currentColor"
d="M24.182 18.599c-0.427 0.297-0.901 0.474-1.411 0.552-0.51 0.083-1.016 0.068-1.521 0.068h-10.5c-0.51 0-1.016 0.021-1.526-0.068-0.51-0.083-0.979-0.255-1.411-0.552-0.854-0.604-1.365-1.563-1.365-2.604 0-1.057 0.516-2.016 1.37-2.599 0.417-0.297 0.896-0.479 1.396-0.557 0.5-0.083 1-0.083 1.526-0.083h10.5c0.5 0 1.016-0.016 1.516 0.063s0.984 0.26 1.401 0.542c0.865 0.578 1.365 1.557 1.365 2.599 0 1.036-0.526 2-1.38 2.599zM28.411 8.526c-1.125-0.906-2.417-1.531-3.818-1.865-0.802-0.193-1.604-0.281-2.432-0.307-0.599-0.021-1.198-0.010-1.818-0.010h-8.661c-0.609 0-1.224-0.010-1.833 0.010-0.823 0.026-1.63 0.109-2.432 0.307-1.401 0.339-2.698 0.964-3.818 1.865-2.281 1.823-3.599 4.568-3.599 7.474 0 2.911 1.318 5.656 3.583 7.474 1.13 0.906 2.422 1.531 3.823 1.87 0.802 0.193 1.609 0.281 2.432 0.302 0.599 0.021 1.198 0.016 1.818 0.016h8.661c0.599 0 1.219 0.005 1.818-0.016 0.823-0.021 1.62-0.109 2.417-0.302 1.401-0.344 2.682-0.969 3.823-1.87 2.307-1.823 3.625-4.568 3.625-7.474s-1.318-5.656-3.589-7.474z"
/>
</svg>
);
}
})
@@ -0,0 +1,9 @@
import { createSvgIcon } from "../svg-icon.type";
export const PinIcon = createSvgIcon((props, ref) => {
return (
<svg ref={ref} {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor">
<path d="M648.13-763.11v274.74l66.57 66.57q6.71 6.71 10.07 15.05 3.36 8.34 3.36 17.53v26.59q0 19.15-13.17 32.33-13.18 13.17-32.33 13.17H525.5v232.09q0 19.15-13.17 32.32Q499.15-39.54 480-39.54t-32.33-13.18Q434.5-65.89 434.5-85.04v-232.09H277.37q-19.15 0-32.33-13.17-13.17-13.18-13.17-32.33v-26.59q0-9.19 3.36-17.53 3.36-8.34 10.07-15.05l66.57-66.57v-274.74q-17-1.67-28.5-14.25-11.5-12.57-11.5-30.29 0-19.15 13.17-32.33 13.18-13.17 32.33-13.17h325.26q19.15 0 32.33 13.17 13.17 13.18 13.17 32.33 0 17.72-11.5 30.29-11.5 12.58-28.5 14.25Z"/>
</svg>
)
});
@@ -1,9 +1,9 @@
import { CSSProperties } from "react";
import { createSvgIcon } from "../svg-icon.type";
export function TerminalIcon(props: { className?: string; style?: CSSProperties }) {
export const TerminalIcon = createSvgIcon((props, ref) => {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" height="40" width="40">
<svg ref={ref} {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" height="40" width="40">
<path fill="currentColor" d="M6.333 33.375Q5.125 33.375 4.229 32.479Q3.333 31.583 3.333 30.333V9.667Q3.333 8.417 4.229 7.521Q5.125 6.625 6.333 6.625H33.667Q34.875 6.625 35.771 7.521Q36.667 8.417 36.667 9.667V30.333Q36.667 31.583 35.771 32.479Q34.875 33.375 33.667 33.375ZM6.333 30.333H33.667Q33.667 30.333 33.667 30.333Q33.667 30.333 33.667 30.333V13.042H6.333V30.333Q6.333 30.333 6.333 30.333Q6.333 30.333 6.333 30.333ZM20.375 28V25.375H29.667V28ZM12.5 27.875 10.667 26.042 14.958 21.708 10.625 17.375 12.5 15.5 18.667 21.708Z" />
</svg>
);
}
})
@@ -0,0 +1,9 @@
import { createSvgIcon } from "../svg-icon.type"
export const UnpinIcon = createSvgIcon((props, ref) => {
return (
<svg ref={ref} {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor">
<path d="M570.57-514.15 294.3-790.65q-5.47-5.72-8.21-12.2-2.74-6.48-2.74-12.95 0-14.2 10.07-25.78 10.08-11.57 26.51-11.57h322.7q19.15 0 32.33 13.77 13.17 13.77 13.17 37.23 0 16.24-13.78 23.93-13.78 7.7-26.22 16.07v215.41q0 30.59-27.97 42.4-27.96 11.82-49.59-9.81ZM434.5-78.09v-239.04H290.98q-27.39 0-44.07-19.05-16.67-19.06-16.67-43.21 0-11.72 4.62-23.32 4.62-11.59 14.86-22.07l62.15-63.59v-46.72L74.91-774.28Q63.2-786 62.93-803.1q-.26-17.1 12.22-29.57 11.72-11.72 29.2-11.72 17.48 0 29.19 11.72l690.72 690.71q12.48 12.48 12.1 29.58-.38 17.1-12.86 29.58-12.48 11.71-29.32 12.09-16.83.38-29.31-12.09L530.3-317.13l-4.8.48v238.56q0 19.16-13.17 32.33Q499.15-32.59 480-32.59t-32.33-13.17Q434.5-58.93 434.5-78.09Z"/>
</svg>
)
})
@@ -1,33 +1,34 @@
import Tippy from "@tippyjs/react";
import { GlowEffect } from "renderer/components/shared/glow-effect.component";
import { BsmIcon, BsmIconType } from "renderer/components/svgs/bsm-icon.component";
import { BsmIcon } from "renderer/components/svgs/bsm-icon.component";
import { SvgIcon } from "renderer/components/svgs/svg-icon.type";
import { useTranslation } from "renderer/hooks/use-translation.hook";
type Props = {
onClick: (active: boolean) => void;
active: boolean;
text: string;
icon: BsmIconType;
icon?: SvgIcon;
infoText?: string;
};
export function LaunchModToogle({ onClick, active, text, icon, infoText }: Props) {
export function LaunchModToogle({ onClick, active, text, icon: Icon, infoText }: Props) {
const t = useTranslation();
return (
<div className={`relative rounded-full cursor-pointer group active:scale-95 transition-transform ${!active && "shadow-md shadow-black"}`} onClick={() => onClick(!active)}>
<button className={`shrink-0 relative rounded-full cursor-pointer group active:scale-95 transition-transform ${!active && "shadow-md shadow-black"}`} onClick={() => onClick(!active)}>
<GlowEffect visible={active} className="absolute !rounded-full blur-[2px]" />
<div className="w-full h-full px-6 flex gap-1.5 justify-center items-center bg-light-main-color-2 dark:bg-main-color-2 p-3 rounded-full text-gray-800 dark:text-white group-hover:bg-light-main-color-1 dark:group-hover:bg-main-color-1">
<BsmIcon icon={icon} className="h-7 shrink-0 text-gray-800 dark:text-white" />
{Icon && <Icon className="h-7 shrink-0 text-gray-800 dark:text-white" />}
<span className="w-fit min-w-fit text-lg font-bold uppercase tracking-wide italic ">{t(text)}</span>
{infoText && (
<Tippy content={t(infoText)} placement="bottom" delay={[400, 0]}>
<Tippy content={t(infoText)} placement="top" theme="default" delay={[400, 0]}>
<div className="h-[25px] w-[25px] shrink-0 p-1.5 rounded-full cursor-help bg-light-main-color-1 dark:bg-main-color-3 hover:brightness-110">
<BsmIcon className="w-full h-full" icon="info" />
</div>
</Tippy>
)}
</div>
</div>
</button>
);
}
@@ -0,0 +1,71 @@
import Tippy from "@tippyjs/react";
import { BsmCheckbox } from "renderer/components/shared/bsm-checkbox.component";
import { PinIcon } from "renderer/components/svgs/icons/pin-icon.component";
import { UnpinIcon } from "renderer/components/svgs/icons/unpin-icon.component";
import { SvgIcon } from "renderer/components/svgs/svg-icon.type";
import { cn } from "renderer/helpers/css-class.helpers";
import { useTranslationV2 } from "renderer/hooks/use-translation.hook";
import { LaunchMod } from "shared/models/bs-launch/launch-option.interface";
type Props = {
readonly className?: string;
readonly open: boolean;
readonly launchArgs?: string;
readonly launchMods?: LaunchModItemProps[];
readonly onLaunchArgsChange?: (args: string) => void;
};
export function LaunchOptionsPanel({ className, open, launchArgs, launchMods, onLaunchArgsChange }: Props) {
const {text: t} = useTranslationV2();
return (
<div className={cn("grid grid-rows-[0fr] transition-[grid-template-rows] bg-theme-2 rounded-md shadow-md shadow-black overflow-hidden", open && "!grid-rows-[1fr]", className)}>
<div className="flex flex-col overflow-y-scroll scrollbar-default">
<div className="p-3.5">
<input className="h-10 w-full rounded-md bg-theme-1 text-center mb-2" type="text" placeholder={t("pages.version-viewer.launch-mods.advanced-launch.placeholder")} value={launchArgs} onChange={e => onLaunchArgsChange(e.target.value)}/>
<div className={cn("flex gap-2 flex-wrap")}>
{launchMods?.map((mod) => (
<LaunchModItem key={mod.id} {...mod}/>
))}
</div>
</div>
</div>
</div>
)
}
export type LaunchModItemProps = {
readonly id: LaunchMod;
readonly icon?: SvgIcon;
readonly label: string;
readonly description: string;
readonly active: boolean;
readonly visible?: boolean;
readonly pinned?: boolean;
readonly onChange?: (val: boolean) => void;
readonly onPinChange?: (val: boolean) => void;
}
export function LaunchModItem({ id, icon: Icon, label, description, active, visible, pinned, onChange, onPinChange }: LaunchModItemProps) {
const { text: t } = useTranslationV2();
return (
<Tippy theme="default" placement="top" content={description}>
<button id={id} className={cn("grow rounded-md bg-theme-1 relative flex justify-center items-center h-10 py-1 px-3", visible === false && "hidden")} onClick={e => { e.preventDefault(); e.stopPropagation(); onChange?.(!active) }}>
<BsmCheckbox className="h-4 aspect-square z-[1] relative mr-1.5" checked={active} onChange={onChange}/>
{Icon && <Icon className="h-full w-fit py-0.5 mr-1.5"/>}
<span className="font-bold">{label}</span>
{onPinChange && (
<Tippy theme="default" placement="right" content={pinned ? t("misc.unpin") : t("misc.pin")} hideOnClick>
<button className="h-full py-2 px-1.5" onClick={e => { e.preventDefault(); e.stopPropagation(); onPinChange?.(!pinned) }}>
{pinned ? <UnpinIcon className="size-full"/> : <PinIcon className="size-full"/>}
</button>
</Tippy>
)}
</button>
</Tippy>
);
}
@@ -1,8 +1,8 @@
import { ChangeEvent, useEffect, useMemo, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { BsmButton } from "renderer/components/shared/bsm-button.component";
import { useObservable } from "renderer/hooks/use-observable.hook";
import { useTranslationV2 } from "renderer/hooks/use-translation.hook";
import { BSLauncherService, LaunchMods } from "renderer/services/bs-launcher.service";
import { BSLauncherService } from "renderer/services/bs-launcher.service";
import { ConfigurationService } from "renderer/services/configuration.service";
import { BSVersion } from "shared/bs-version.interface";
import { LaunchModToogle } from "./launch-mod-toogle.component";
@@ -19,6 +19,13 @@ import { BSVersionManagerService } from "renderer/services/bs-version-manager.se
import { safeLt } from "shared/helpers/semver.helpers";
import { WarningIcon } from "renderer/components/svgs/icons/warning-icon.component";
import Tippy from "@tippyjs/react";
import { LaunchModItemProps, LaunchOptionsPanel } from "./launch-options-panel.component";
import { LaunchMod, LaunchMods } from "shared/models/bs-launch/launch-option.interface";
import { OculusIcon } from "renderer/components/svgs/icons/oculus-icon.component";
import { DesktopIcon } from "renderer/components/svgs/icons/desktop-icon.component";
import { TerminalIcon } from "renderer/components/svgs/icons/terminal-icon.component";
import { DefaultConfigKey } from "renderer/config/default-configuration.config";
import { EditIcon } from "renderer/components/svgs/icons/edit-icon.component";
type Props = { version: BSVersion };
@@ -30,13 +37,12 @@ export function LaunchSlide({ version }: Props) {
const bsDownloader = useService(BsDownloaderService);
const versions = useService(BSVersionManagerService);
const [oculusMode, setOculusMode] = useState(!!configService.get<boolean>(LaunchMods.OCULUS_MOD));
const [desktopMode, setDesktopMode] = useState(!!configService.get<boolean>(LaunchMods.DESKTOP_MOD));
const [debugMode, setDebugMode] = useState(!!configService.get<boolean>(LaunchMods.DEBUG_MOD));
const [advancedLaunch, setAdvancedLaunch] = useState(false);
const [additionalArgsString, setAdditionalArgsString] = useState<string>(configService.get<string>("additionnal-args") || "");
const [skipSteamMode, setSkipSteamMode] = useState(!!configService.get<boolean>(LaunchMods.SKIPSTEAM_MOD));
const versionDownloading = useObservable(() => bsDownloader.downloadingVersion$);
const [activeLaunchMods, setActiveLaunchMods] = useState<LaunchMod[]>(configService.get("launch-mods") ?? []);
const [pinnedLaunchMods, setPinnedLaunchMods] = useState<LaunchMod[]>(configService.get("pinned-launch-mods" as DefaultConfigKey) ?? []);
const [launchModItems, setLaunchModItems] = useState<LaunchModItemProps[]>([]);
const versionRunning = useObservable(() => bsLauncherService.versionRunning$);
@@ -45,36 +51,81 @@ export function LaunchSlide({ version }: Props) {
}, [additionalArgsString]);
useEffect(() => {
if(desktopMode){ return; }
bsLauncherService.restoreSteamVR();
}, [desktopMode]);
configService.set("pinned-launch-mods", pinnedLaunchMods);
}, [pinnedLaunchMods])
const setMode = (mode: LaunchMods, value: boolean) => {
useEffect(() => {
configService.set("launch-mods", activeLaunchMods);
if (mode === LaunchMods.DEBUG_MOD) {
setDebugMode(value);
} else if (mode === LaunchMods.OCULUS_MOD) {
setOculusMode(value);
} else if (mode === LaunchMods.DESKTOP_MOD) {
setDesktopMode(value);
} else if (mode === LaunchMods.SKIPSTEAM_MOD) {
setSkipSteamMode(value);
if(!activeLaunchMods.includes("fpfc")){
bsLauncherService.restoreSteamVR();
}
configService.set(mode, value);
};
}, [activeLaunchMods]);
const handleAdditionalArgsChange = (e: ChangeEvent<HTMLInputElement>) => setAdditionalArgsString(() => e.target.value);
useEffect(() => {
setLaunchModItems(() => [
{
id: LaunchMods.OCULUS,
icon: OculusIcon,
label: t("pages.version-viewer.launch-mods.oculus"),
description: t("pages.version-viewer.launch-mods.oculus-description"),
active: activeLaunchMods.includes(LaunchMods.OCULUS),
visible: !(version.metadata?.store === BsStore.OCULUS),
pinned: pinnedLaunchMods.includes(LaunchMods.OCULUS),
onChange: checked => checked ? setActiveLaunchMods(prev => [...prev, LaunchMods.OCULUS]) : setActiveLaunchMods(prev => prev.filter(mod => mod !== LaunchMods.OCULUS)),
onPinChange: pinned => pinned ? setPinnedLaunchMods(prev => [...prev, LaunchMods.OCULUS]) : setPinnedLaunchMods(prev => prev.filter(mod => mod !== LaunchMods.OCULUS)),
},
{
id: LaunchMods.FPFC,
icon: DesktopIcon,
label: t("pages.version-viewer.launch-mods.desktop"),
description: t("pages.version-viewer.launch-mods.desktop-description"),
active: activeLaunchMods.includes(LaunchMods.FPFC),
pinned: pinnedLaunchMods.includes(LaunchMods.FPFC),
onChange: checked => checked ? setActiveLaunchMods(prev => [...prev, LaunchMods.FPFC]) : setActiveLaunchMods(prev => prev.filter(mod => mod !== LaunchMods.FPFC)),
onPinChange: pinned => pinned ? setPinnedLaunchMods(prev => [...prev, LaunchMods.FPFC]) : setPinnedLaunchMods(prev => prev.filter(mod => mod !== LaunchMods.FPFC)),
},
{
id: LaunchMods.DEBUG,
icon: TerminalIcon,
label: t("pages.version-viewer.launch-mods.debug"),
description: t("pages.version-viewer.launch-mods.debug-description"),
active: activeLaunchMods.includes(LaunchMods.DEBUG),
pinned: pinnedLaunchMods.includes(LaunchMods.DEBUG),
onChange: checked => checked ? setActiveLaunchMods(prev => [...prev, LaunchMods.DEBUG]) : setActiveLaunchMods(prev => prev.filter(mod => mod !== LaunchMods.DEBUG)),
onPinChange: pinned => pinned ? setPinnedLaunchMods(prev => [...prev, LaunchMods.DEBUG]) : setPinnedLaunchMods(prev => prev.filter(mod => mod !== LaunchMods.DEBUG)),
},
{
id: LaunchMods.SKIP_STEAM,
label: t("pages.version-viewer.launch-mods.skipsteam"),
description: t("pages.version-viewer.launch-mods.skipsteam-description"),
active: activeLaunchMods.includes(LaunchMods.SKIP_STEAM),
pinned: pinnedLaunchMods.includes(LaunchMods.SKIP_STEAM),
onChange: checked => checked ? setActiveLaunchMods(prev => [...prev, LaunchMods.SKIP_STEAM]) : setActiveLaunchMods(prev => prev.filter(mod => mod !== LaunchMods.SKIP_STEAM)),
onPinChange: pinned => pinned ? setPinnedLaunchMods(prev => [...prev, LaunchMods.SKIP_STEAM]) : setPinnedLaunchMods(prev => prev.filter(mod => mod !== LaunchMods.SKIP_STEAM)),
},
{
id: LaunchMods.EDITOR,
icon: EditIcon,
label: t("pages.version-viewer.launch-mods.map-editor"),
description: t("pages.version-viewer.launch-mods.map-editor-description"),
active: activeLaunchMods.includes(LaunchMods.EDITOR),
pinned: pinnedLaunchMods.includes(LaunchMods.EDITOR),
visible: !safeLt(version.BSVersion, "1.23.0"),
onChange: checked => checked ? setActiveLaunchMods(prev => [...prev, LaunchMods.EDITOR]) : setActiveLaunchMods(prev => prev.filter(mod => mod !== LaunchMods.EDITOR)),
onPinChange: pinned => pinned ? setPinnedLaunchMods(prev => [...prev, LaunchMods.EDITOR]) : setPinnedLaunchMods(prev => prev.filter(mod => mod !== LaunchMods.EDITOR)),
}
]);
}, [activeLaunchMods, pinnedLaunchMods, version]);
const launch = () => {
const additionalArgs = additionalArgsString?.split(";").map(arg => arg.trim()).filter(arg => arg.length > 0);
const launch$ = bsLauncherService.launch({
version,
oculus: version.oculus ? false : oculusMode,
desktop: desktopMode,
debug: debugMode,
launchMods: activeLaunchMods,
additionalArgs: advancedLaunch ? additionalArgs : [],
skipSteam: skipSteamMode,
});
return lastValueFrom(launch$).catch(() => {});
@@ -85,9 +136,11 @@ export function LaunchSlide({ version }: Props) {
}, [version]);
return (
<div className="w-full shrink-0 items-center relative flex flex-col justify-start">
<div className="flex flex-col gap-3 justify-center items-center mb-5">
<BsmImage className="relative object-cover h-28" image={BSLogo} />
<div className="w-full shrink-0 items-center relative flex flex-col justify-start overflow-hidden">
<div className="flex flex-col gap-3 justify-center items-center mb-4">
<div className="h-24 flex justify-center items-center">
<BsmImage className="relative object-cover h-28" image={BSLogo} />
</div>
<h1 className="relative text-4xl font-bold italic -top-3">
{version.name ? `${version.BSVersion} - ${version.name}` : version.BSVersion}
{isOutdated && (
@@ -99,14 +152,23 @@ export function LaunchSlide({ version }: Props) {
)}
</h1>
</div>
<div className="grid grid-flow-col gap-6">
{!(version.oculus || version.metadata?.store === BsStore.OCULUS) && <LaunchModToogle infoText="pages.version-viewer.launch-mods.oculus-description" icon="oculus" onClick={() => setMode(LaunchMods.OCULUS_MOD, !oculusMode)} active={oculusMode} text="pages.version-viewer.launch-mods.oculus" />}
<LaunchModToogle infoText="pages.version-viewer.launch-mods.desktop-description" icon="desktop" onClick={() => setMode(LaunchMods.DESKTOP_MOD, !desktopMode)} active={desktopMode} text="pages.version-viewer.launch-mods.desktop" />
<LaunchModToogle infoText="pages.version-viewer.launch-mods.debug-description" icon="terminal" onClick={() => setMode(LaunchMods.DEBUG_MOD, !debugMode)} active={debugMode} text="pages.version-viewer.launch-mods.debug" />
<div className="w-full flex justify-center items-center gap-4 flex-wrap scrollbar-default">
{pinnedLaunchMods.map(id => launchModItems.find(mod => mod.id === id)).map(launchMod => {
if(launchMod?.visible === false || !launchMod?.pinned) { return undefined; }
return (
<LaunchModToogle
icon={launchMod.icon}
infoText={launchMod.description}
text={launchMod.label}
active={launchMod.active}
onClick={() => launchMod.onChange(!launchMod.active)}
/>
);
})}
</div>
<div className="pt-4 w-2/3 flex flex-col items-center gap-3">
<div className="mt-4 flex flex-col items-center justify-center gap-3">
<div className="relative">
<GlowEffect className="!rounded-full" visible={!!(advancedLaunch && additionalArgsString)}/>
<GlowEffect className="!rounded-full" visible={!!(activeLaunchMods?.length || additionalArgsString)}/>
<BsmButton
className={cn("rounded-full w-fit text-lg py-1 px-7 bg-theme-2 text-gray-800 dark:text-white", (advancedLaunch && additionalArgsString) ? "" : "shadow-md shadow-black")}
text="pages.version-viewer.launch-mods.advanced-launch.button"
@@ -117,18 +179,13 @@ export function LaunchSlide({ version }: Props) {
}}
/>
</div>
<div className="bg-light-main-color-2 dark:bg-main-color-2 h-9 rounded-full overflow-hidden flex items-center justify-center transition-all duration-100 ease-in-out w-full origin-top shadow-black shadow-sm" style={{ scale: advancedLaunch ? "100% 100%" : "0 0" }}>
<input className="w-[calc(100%-12px)] h-[calc(100%-12px)] bg-light-main-color-1 dark:bg-main-color-1 text-black dark:text-white rounded-full outline-none text-center" type="text" placeholder={t("pages.version-viewer.launch-mods.advanced-launch.placeholder")} value={additionalArgsString} onChange={handleAdditionalArgsChange} />
</div>
<div className="grid grid-cols-3 gap-3 transition-all duration-300 ease-in-out origin-top" style={{ scale: advancedLaunch ? "75% 75%" : "0% 0%" }}>
{advancedLaunch && !(version.oculus || version.metadata?.store === BsStore.OCULUS) && <LaunchModToogle infoText="pages.version-viewer.launch-mods.skipsteam-description" icon="null" onClick={() => setMode(LaunchMods.SKIPSTEAM_MOD, !skipSteamMode)} active={skipSteamMode} text="pages.version-viewer.launch-mods.skipsteam" />}
</div>
</div>
<div className='grow flex justify-center items-center'>
<LaunchOptionsPanel open={advancedLaunch} launchMods={launchModItems} launchArgs={additionalArgsString} className="w-full max-w-3xl mt-3" onLaunchArgsChange={setAdditionalArgsString}/>
<div className='grow flex justify-center items-center p-2'>
<BsmButton
onClick={launch}
active={JSON.stringify(version) === JSON.stringify(versionRunning)}
className='relative -translate-y-1/2 text-5xl text-gray-800 dark:text-gray-200 font-bold tracking-wide pt-1 pb-3 px-7 rounded-lg shadow-md italic shadow-black active:scale-90 transition-transform'
className='relative text-5xl text-gray-800 dark:text-gray-200 font-bold tracking-wide pt-1 pb-3 px-7 rounded-lg shadow-md italic shadow-black active:scale-90 transition-transform'
text="misc.launch"
disabled={equal(version, versionDownloading)}
/>
@@ -1,3 +1,4 @@
import { LaunchMod, LaunchMods } from "shared/models/bs-launch/launch-option.interface";
import { BsvSearchOrder } from "shared/models/maps/beat-saver.model";
// NOTE: To refactor. Rename to LocalStorageConfigKeyValues since these are stored in the
@@ -12,6 +13,7 @@ export interface DefaultConfigKeyValues {
"default-shared-folders": string[];
"playlist-sort-order": BsvSearchOrder;
"map-sort-order": BsvSearchOrder;
"pinned-launch-mods": LaunchMod[];
};
export type DefaultConfigKey = keyof DefaultConfigKeyValues;
@@ -31,6 +33,7 @@ export const defaultConfiguration: {
],
"playlist-sort-order": BsvSearchOrder.Relevance,
"map-sort-order": BsvSearchOrder.Relevance,
"pinned-launch-mods": [LaunchMods.OCULUS, LaunchMods.DEBUG]
};
export type ThemeConfig = "dark" | "light" | "os";
+1 -11
View File
@@ -47,11 +47,8 @@ export class BSLauncherService {
public getLaunchOptions(version: BSVersion): LaunchOption{
return {
version,
oculus: this.config.get(LaunchMods.OCULUS_MOD),
desktop: this.config.get(LaunchMods.DESKTOP_MOD),
debug: this.config.get(LaunchMods.DEBUG_MOD),
launchMods: this.config.get("launch-mods") ?? [],
additionalArgs: (this.config.get<string>("additionnal-args") || "").split(";").map(arg => arg.trim()).filter(arg => arg.length > 0),
skipSteam: this.config.get(LaunchMods.SKIPSTEAM_MOD),
}
}
@@ -124,10 +121,3 @@ export class BSLauncherService {
return lastValueFrom(this.ipcService.sendV2("bs-launch.restore-steamvr"));
}
}
export enum LaunchMods {
OCULUS_MOD = "LAUNCH_OCULUS_MOD",
DESKTOP_MOD = "LAUNCH_DESKTOP_MOD",
DEBUG_MOD = "LAUNCH_DEBUG_MOD",
SKIPSTEAM_MOD = "LAUNCH_SKIPSTEAM_MOD",
}
@@ -1,11 +1,18 @@
import { BSVersion } from "shared/bs-version.interface";
export const LaunchMods = {
OCULUS: "oculus",
FPFC: "fpfc",
DEBUG: "debug",
SKIP_STEAM: "skip_steam",
EDITOR: "editor",
} as const;
export type LaunchMod = typeof LaunchMods[keyof typeof LaunchMods];
export interface LaunchOption {
version: BSVersion,
oculus?: boolean,
desktop?: boolean,
debug?: boolean,
launchMods?: LaunchMod[],
additionalArgs?: string[],
admin?: boolean,
skipSteam?: boolean
admin?: boolean
}