From f3fdf7681738cd85b91ce3bb7cced5139f6b2bc1 Mon Sep 17 00:00:00 2001 From: Lncvrt Date: Thu, 8 Jan 2026 11:28:25 -0700 Subject: [PATCH] Add wine support back for Linux --- src-tauri/src/lib.rs | 32 +++++++++++++++++-- src/app/Globals.css | 2 +- src/app/game/page.tsx | 59 ++++++++++++++++++++++++++++------- src/app/layout.tsx | 27 ++++++++++++---- src/app/page.tsx | 3 ++ src/app/settings/page.tsx | 39 +++++++++++++++++++++++ src/app/types/GameVersion.ts | 1 + src/app/types/SettingsType.ts | 2 ++ 8 files changed, 143 insertions(+), 22 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 7e53c58..2aef1bf 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -255,7 +255,14 @@ async fn download( #[allow(unused_variables)] #[tauri::command] -fn launch_game(app: AppHandle, name: String, executable: String, display_name: String) { +fn launch_game( + app: AppHandle, + name: String, + executable: String, + display_name: String, + use_wine: bool, + wine_command: String, +) { let game_folder = app .path() .app_local_data_dir() @@ -266,10 +273,12 @@ fn launch_game(app: AppHandle, name: String, executable: String, display_name: S return; } + let exe_path = game_folder.join(&executable); + //if already running on macos, it'll auto take the user to that proccess #[cfg(any(target_os = "windows", target_os = "linux"))] { - if is_running_by_path(&game_folder.join(&executable)) { + if !use_wine && is_running_by_path(&exe_path) { app.dialog() .message(format!( "{} is already running, if this doesn't seem true, try to kill the proccess.", @@ -282,6 +291,23 @@ fn launch_game(app: AppHandle, name: String, executable: String, display_name: S } } + #[cfg(target_os = "linux")] + { + if use_wine { + let quoted_path = format!("\"{}\"", exe_path.to_string_lossy()); + let cmd = wine_command.replace("%path%", "ed_path); + + Command::new("bash") + .arg("-c") + .arg(cmd) + .current_dir(&game_folder) + .spawn() + .unwrap(); + + return; + } + } + if platform() == "macos" { Command::new("open") .arg(&executable) @@ -289,7 +315,7 @@ fn launch_game(app: AppHandle, name: String, executable: String, display_name: S .spawn() .unwrap(); } else { - Command::new(&game_folder.join(&executable)) + Command::new(&exe_path) .current_dir(&game_folder) .spawn() .unwrap(); diff --git a/src/app/Globals.css b/src/app/Globals.css index 6cc6297..6f787ed 100644 --- a/src/app/Globals.css +++ b/src/app/Globals.css @@ -155,7 +155,7 @@ body { } .input-field { - @apply border-2 border-(--col4) rounded-md bg-(--col2) p-2 px-4 focus:border-blue-600 transition-colors; + @apply border-2 border-(--col4) rounded-md bg-(--col2) py-1 px-2 focus:bg-(--col3) focus:border-(--col6) transition-colors w-full; } .entry-info-item { diff --git a/src/app/game/page.tsx b/src/app/game/page.tsx index ae7d94b..afa54cd 100644 --- a/src/app/game/page.tsx +++ b/src/app/game/page.tsx @@ -7,6 +7,8 @@ import { invoke } from '@tauri-apps/api/core' import { useGlobal } from '../GlobalProvider' import { useSearchParams } from 'next/navigation' import { platform } from '@tauri-apps/plugin-os' +import { faWarning } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' export default function Installs () { const { @@ -71,6 +73,12 @@ export default function Installs () { .filter(v => { const info = getVersionInfo(v) if (!info) return false + if ( + platform() === 'linux' && + info.wine && + !normalConfig?.settings.useWineOnUnixWhenNeeded + ) + return false return info.game === Number(params.get('id') || 0) }) .map((entry, i) => ( @@ -95,11 +103,19 @@ export default function Installs () { invoke('launch_game', { name: verInfo.id, executable: verInfo.executable, - displayName: `${gameInfo.name} v${verInfo.versionName}` + displayName: `${gameInfo.name} v${verInfo.versionName}`, + useWine: !!( + platform() === 'linux' && + verInfo.wine && + normalConfig?.settings.useWineOnUnixWhenNeeded + ), + wineCommand: normalConfig?.settings.wineOnUnixCommand }) }} onContextMenu={e => { e.preventDefault() + if (normalConfig?.settings.useLegacyInteractButtons) return + setManagingVersion(entry) setPopupMode(2) setShowPopup(true) @@ -112,17 +128,36 @@ export default function Installs () { {getVersionInfo(entry)?.versionName}

-
-

- Installed{' '} - {format( - new Date(downloadedVersionsConfig.timestamps[entry]), - 'MM/dd/yyyy' - )} -

+
+
e.stopPropagation()} + > +

+ Installed{' '} + {format( + new Date( + downloadedVersionsConfig.timestamps[entry] + ), + 'MM/dd/yyyy' + )} +

+
+
diff --git a/src/app/layout.tsx b/src/app/layout.tsx index d9d9e6a..52a9644 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -89,6 +89,13 @@ export default function RootLayout ({ return serverVersionList.versions .filter(v => !downloadedVersionsConfig?.list.includes(v.id)) .filter(v => { + if ( + platform() === 'linux' && + v.wine && + !normalConfig.settings.useWineOnUnixWhenNeeded + ) + return false + if (game && v.game != game) return false if (downloadProgress.length != 0) { return !downloadProgress.some(d => d.version === v.id) @@ -133,13 +140,21 @@ export default function RootLayout ({ } | null { if (!downloadedVersionsConfig || !serverVersionList) return null - const installed = downloadedVersionsConfig.list.filter( - v => getGameInfo(getVersionInfo(v)?.game)?.id === gameId - ).length + const allowWine = + platform() !== 'linux' || normalConfig?.settings.useWineOnUnixWhenNeeded - const total = serverVersionList.versions.filter( - v => getGameInfo(v?.game)?.id === gameId - ).length + const installed = downloadedVersionsConfig.list.filter(v => { + const info = getVersionInfo(v) + if (!info) return false + if (info.wine && !allowWine) return false + return getGameInfo(info.game)?.id === gameId + }).length + + const total = serverVersionList.versions.filter(v => { + if (!v) return false + if (v.wine && !allowWine) return false + return getGameInfo(v.game)?.id === gameId + }).length return { installed, total } } diff --git a/src/app/page.tsx b/src/app/page.tsx index 2f1175e..2c35058 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -89,6 +89,7 @@ export default function Installs () {
e.stopPropagation()} >

{(() => { @@ -103,6 +104,7 @@ export default function Installs () { className='entry-info-item' hidden={!i.official} title='This game is official.' + onClick={e => e.stopPropagation()} >

Official

@@ -115,6 +117,7 @@ export default function Installs () { ? 'This game is verified to be safe' : 'This game is not verified to be save. Proceed with caution.' } + onClick={e => e.stopPropagation()} > + { + while (normalConfig != null) { + setUseWineOnUnixWhenNeeded(!useWineOnUnixWhenNeeded) + normalConfig.settings.useWineOnUnixWhenNeeded = + !useWineOnUnixWhenNeeded + await writeNormalConfig(normalConfig) + break + } + }} + className={platform() == 'linux' ? '' : 'hidden'} + /> + + { + while (normalConfig != null) { + setWineOnUnixCommand(e.target.value) + normalConfig.settings.wineOnUnixCommand = e.target.value + await writeNormalConfig(normalConfig) + break + } + }} + className={`input-field my-1 ${ + platform() == 'linux' && useWineOnUnixWhenNeeded ? '' : 'hidden' + }`} + >