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'
+ )}
+
+
+
e.stopPropagation()}
+ >
+
+
Uses wine
+
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'}
+ />
+
+ Wine Command:
+
+ {
+ 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'
+ }`}
+ >