Add wine support back for Linux

This commit is contained in:
2026-01-08 11:28:25 -07:00
parent 2777e6dac0
commit f3fdf76817
8 changed files with 143 additions and 22 deletions

View File

@@ -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%", &quoted_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();

View File

@@ -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 {

View File

@@ -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,18 +128,37 @@ export default function Installs () {
{getVersionInfo(entry)?.versionName}
</p>
<div className='flex gap-2 absolute left-0 bottom-0'>
<div
className='entry-info-item absolute left-0 bottom-0'
className='entry-info-item'
title='The date the game was installed in MM/dd/yyyy format'
onClick={e => e.stopPropagation()}
>
<p>
Installed{' '}
{format(
new Date(downloadedVersionsConfig.timestamps[entry]),
new Date(
downloadedVersionsConfig.timestamps[entry]
),
'MM/dd/yyyy'
)}
</p>
</div>
<div
className='entry-info-item'
title='This version is using wine. It cannot be guarenteed to work fully and might not work at all.'
hidden={
!(
platform() === 'linux' &&
getVersionInfo(entry)?.wine
)
}
onClick={e => e.stopPropagation()}
>
<FontAwesomeIcon icon={faWarning} color='#ffc800' />
<p>Uses wine</p>
</div>
</div>
<div className='flex gap-2 absolute right-0 bottom-0'>
<button

View File

@@ -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 }
}

View File

@@ -89,6 +89,7 @@ export default function Installs () {
<div
className='entry-info-item'
title='The amount of versions installed of this game in installed/installable format.'
onClick={e => e.stopPropagation()}
>
<p>
{(() => {
@@ -103,6 +104,7 @@ export default function Installs () {
className='entry-info-item'
hidden={!i.official}
title='This game is official.'
onClick={e => e.stopPropagation()}
>
<FontAwesomeIcon icon={faCheck} color='#19c84b' />
<p>Official</p>
@@ -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()}
>
<FontAwesomeIcon
icon={i.verified ? faShieldHalved : faWarning}

View File

@@ -5,6 +5,7 @@ import { Setting } from '../componets/Setting'
import { writeNormalConfig } from '../util/BazookaManager'
import { useGlobal } from '../GlobalProvider'
import { copyToClipboard } from '../util/Clipboard'
import { platform } from '@tauri-apps/plugin-os'
export default function Settings () {
const [allowNotifications, setAllowNotifications] = useState(false)
@@ -12,6 +13,8 @@ export default function Settings () {
useState(false)
const [useLegacyInteractButtons, setUseLegacyInteractButtons] =
useState(false)
const [useWineOnUnixWhenNeeded, setUseWineOnUnixWhenNeeded] = useState(false)
const [wineOnUnixCommand, setWineOnUnixCommand] = useState('wine %path%')
const [theme, setTheme] = useState(0)
const [loaded, setLoaded] = useState(false)
@@ -27,6 +30,10 @@ export default function Settings () {
setUseLegacyInteractButtons(
normalConfig.settings.useLegacyInteractButtons
)
setUseWineOnUnixWhenNeeded(
normalConfig.settings.useWineOnUnixWhenNeeded
)
setWineOnUnixCommand(normalConfig.settings.wineOnUnixCommand)
setTheme(normalConfig.settings.theme)
setLoaded(true)
break
@@ -114,6 +121,38 @@ export default function Settings () {
}}
title='Enable the legacy method of using the installs/launch/manage buttons. In the future this setting may be removed so try and get used to the new method.'
/>
<Setting
label='Use wine when needed to launch games'
value={useWineOnUnixWhenNeeded}
onChange={async () => {
while (normalConfig != null) {
setUseWineOnUnixWhenNeeded(!useWineOnUnixWhenNeeded)
normalConfig.settings.useWineOnUnixWhenNeeded =
!useWineOnUnixWhenNeeded
await writeNormalConfig(normalConfig)
break
}
}}
className={platform() == 'linux' ? '' : 'hidden'}
/>
<p hidden={!(platform() == 'linux' && useWineOnUnixWhenNeeded)}>
Wine Command:
</p>
<input
type='text'
value={wineOnUnixCommand}
onChange={async e => {
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'
}`}
></input>
<div title='The theme you want the launcher to use.'>
<label className='text-lg'>Theme:</label>
<select

View File

@@ -9,4 +9,5 @@ export interface GameVersion {
size: number
place: number
changelog: string
wine: number | undefined
}

View File

@@ -3,6 +3,8 @@ export class SettingsType {
public allowNotifications: boolean = true,
public alwaysShowGamesInSidebar: boolean = true,
public useLegacyInteractButtons: boolean = false,
public useWineOnUnixWhenNeeded: boolean = false,
public wineOnUnixCommand: string = 'wine %path%',
public theme: number = 0
) {}
}