-
-
Notifications
You must be signed in to change notification settings - Fork 480
[Exp]: UMU support #3724
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Exp]: UMU support #3724
Changes from all commits
9e87a99
ca4b5af
d59aad4
f76cb56
14c4f79
d7f6272
d08399b
f972c7c
aad0792
217b7d8
788d7db
62cf6b9
43c2149
fd30517
eeefd1a
5e80536
99b556d
2c3cd0d
bb92e40
595f880
70e4fcb
52df541
2cfda8d
3d33254
494b40b
aad2ae0
accd1e5
bd0ab0d
bfbcbbb
23c4df4
460f695
bd374a2
ccb36e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ import { | |
|
||
import i18next from 'i18next' | ||
import { existsSync, mkdirSync } from 'graceful-fs' | ||
import { join, normalize } from 'path' | ||
import { join, dirname } from 'path' | ||
|
||
import { | ||
defaultWinePrefix, | ||
|
@@ -29,7 +29,8 @@ import { | |
isWindows, | ||
isSteamDeckGameMode, | ||
runtimePath, | ||
userHome | ||
userHome, | ||
defaultUmuPath | ||
} from './constants' | ||
import { | ||
constructAndUpdateRPC, | ||
|
@@ -71,14 +72,15 @@ import { readFileSync } from 'fs' | |
import { LegendaryCommand } from './storeManagers/legendary/commands' | ||
import { commandToArgsArray } from './storeManagers/legendary/library' | ||
import { searchForExecutableOnPath } from './utils/os/path' | ||
import { sendFrontendMessage } from './main_window' | ||
import { | ||
createAbortController, | ||
deleteAbortController | ||
} from './utils/aborthandler/aborthandler' | ||
import { download, isInstalled } from './wine/runtimes/runtimes' | ||
import { storeMap } from 'common/utils' | ||
import { runWineCommandOnGame } from './storeManagers/legendary/games' | ||
import { sendFrontendMessage } from './main_window' | ||
import { getUmuPath, isUmuSupported } from './utils/compatibility_layers' | ||
|
||
async function prepareLaunch( | ||
gameSettings: GameSettings, | ||
|
@@ -228,17 +230,27 @@ async function prepareLaunch( | |
} | ||
} | ||
|
||
if ( | ||
(await isUmuSupported(gameSettings.wineVersion.type, false)) && | ||
!(await isInstalled('umu')) && | ||
isOnline() && | ||
(await getUmuPath()) === defaultUmuPath | ||
) { | ||
await download('umu') | ||
} | ||
|
||
// If the Steam Runtime is enabled, find a valid one | ||
let steamRuntime: string[] = [] | ||
const shouldUseRuntime = | ||
gameSettings.useSteamRuntime && | ||
(isNative || gameSettings.wineVersion.type === 'proton') | ||
(isNative || !isUmuSupported(gameSettings.wineVersion.type)) | ||
|
||
if (shouldUseRuntime) { | ||
// Determine which runtime to use based on toolmanifest.vdf which is shipped with proton | ||
let nonNativeRuntime: SteamRuntime['type'] = 'soldier' | ||
if (!isNative) { | ||
try { | ||
const parentPath = normalize(join(gameSettings.wineVersion.bin, '..')) | ||
const parentPath = dirname(gameSettings.wineVersion.bin) | ||
const requiredAppId = VDF.parse( | ||
readFileSync(join(parentPath, 'toolmanifest.vdf'), 'utf-8') | ||
).manifest?.require_tool_appid | ||
|
@@ -250,8 +262,8 @@ async function prepareLaunch( | |
) | ||
} | ||
} | ||
// for native games lets use scout for now | ||
const runtimeType = isNative ? 'sniper' : nonNativeRuntime | ||
|
||
const runtimeType = isNative ? 'scout' : nonNativeRuntime | ||
const { path, args } = await getSteamRuntime(runtimeType) | ||
if (!path) { | ||
return { | ||
|
@@ -268,6 +280,8 @@ async function prepareLaunch( | |
} | ||
} | ||
|
||
logInfo(`Using Steam ${runtimeType} Runtime`, LogPrefix.Backend) | ||
|
||
steamRuntime = [path, ...args] | ||
} | ||
|
||
|
@@ -302,14 +316,6 @@ async function prepareWineLaunch( | |
} | ||
} | ||
|
||
// Log warning about Proton | ||
if (gameSettings.wineVersion.type === 'proton') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably still log this if UMU isn't enabled |
||
logWarning( | ||
'You are using Proton, this can lead to some bugs. Please do not open issues with bugs related to games', | ||
LogPrefix.Backend | ||
) | ||
} | ||
|
||
// Verify that the CrossOver bottle exists | ||
if (isMac && gameSettings.wineVersion.type === 'crossover') { | ||
const bottleExists = existsSync( | ||
|
@@ -497,16 +503,20 @@ function setupWrapperEnvVars(wrapperEnv: WrapperEnv) { | |
|
||
ret.HEROIC_APP_NAME = wrapperEnv.appName | ||
ret.HEROIC_APP_RUNNER = wrapperEnv.appRunner | ||
ret.GAMEID = 'umu-0' | ||
|
||
switch (wrapperEnv.appRunner) { | ||
case 'gog': | ||
ret.HEROIC_APP_SOURCE = 'gog' | ||
ret.STORE = 'gog' | ||
break | ||
case 'legendary': | ||
ret.HEROIC_APP_SOURCE = 'epic' | ||
ret.STORE = 'egs' | ||
break | ||
case 'nile': | ||
ret.HEROIC_APP_SOURCE = 'amazon' | ||
ret.STORE = 'amazon' | ||
break | ||
case 'sideload': | ||
ret.HEROIC_APP_SOURCE = 'sideload' | ||
|
@@ -527,9 +537,6 @@ function setupWineEnvVars(gameSettings: GameSettings, gameId = '0') { | |
|
||
const ret: Record<string, string> = {} | ||
|
||
ret.DOTNET_BUNDLE_EXTRACT_BASE_DIR = '' | ||
ret.DOTNET_ROOT = '' | ||
|
||
// Add WINEPREFIX / STEAM_COMPAT_DATA_PATH / CX_BOTTLE | ||
const steamInstallPath = join(flatPakHome, '.steam', 'steam') | ||
switch (wineVersion.type) { | ||
|
@@ -544,7 +551,7 @@ function setupWineEnvVars(gameSettings: GameSettings, gameId = '0') { | |
) | ||
if (dllOverridesVar) { | ||
ret[dllOverridesVar.key] = | ||
dllOverridesVar.value + ',' + wmbDisableString | ||
dllOverridesVar.value + ';' + wmbDisableString | ||
} else { | ||
ret.WINEDLLOVERRIDES = wmbDisableString | ||
} | ||
|
@@ -553,7 +560,9 @@ function setupWineEnvVars(gameSettings: GameSettings, gameId = '0') { | |
} | ||
case 'proton': | ||
ret.STEAM_COMPAT_CLIENT_INSTALL_PATH = steamInstallPath | ||
ret.WINEPREFIX = winePrefix | ||
ret.STEAM_COMPAT_DATA_PATH = winePrefix | ||
ret.PROTONPATH = dirname(gameSettings.wineVersion.bin) | ||
Etaash-mathamsetty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
break | ||
case 'crossover': | ||
ret.CX_BOTTLE = wineCrossoverBottle | ||
|
@@ -757,7 +766,7 @@ export async function verifyWinePrefix( | |
return { res: { stdout: '', stderr: '' }, updated: false } | ||
} | ||
|
||
if (!existsSync(winePrefix)) { | ||
if (!existsSync(winePrefix) && !(await isUmuSupported(wineVersion.type))) { | ||
mkdirSync(winePrefix, { recursive: true }) | ||
} | ||
|
||
|
@@ -769,9 +778,12 @@ export async function verifyWinePrefix( | |
const haveToWait = !existsSync(systemRegPath) | ||
|
||
const command = runWineCommand({ | ||
commandParts: ['wineboot', '--init'], | ||
commandParts: (await isUmuSupported(wineVersion.type)) | ||
? ['createprefix'] | ||
: ['wineboot', '--init'], | ||
wait: haveToWait, | ||
gameSettings: settings, | ||
protonVerb: 'run', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By the way, if you omit the verb, umu will default to using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we use |
||
skipPrefixCheckIKnowWhatImDoing: true | ||
}) | ||
|
||
|
@@ -801,7 +813,6 @@ function launchCleanup(rpcClient?: RpcClient) { | |
async function runWineCommand({ | ||
gameSettings, | ||
commandParts, | ||
gameInstallPath, | ||
wait, | ||
protonVerb = 'run', | ||
installFolderName, | ||
|
@@ -856,27 +867,25 @@ async function runWineCommand({ | |
|
||
const env_vars = { | ||
...process.env, | ||
...setupEnvVars(settings, gameInstallPath), | ||
...setupWineEnvVars(settings, installFolderName) | ||
} | ||
|
||
const isProton = wineVersion.type === 'proton' | ||
if (isProton) { | ||
commandParts.unshift(protonVerb) | ||
GAMEID: 'umu-0', | ||
...setupEnvVars(settings), | ||
...setupWineEnvVars(settings, installFolderName), | ||
PROTON_VERB: protonVerb | ||
} | ||
|
||
const wineBin = wineVersion.bin.replaceAll("'", '') | ||
const umuSupported = await isUmuSupported(wineVersion.type) | ||
const runnerBin = umuSupported ? await getUmuPath() : wineBin | ||
|
||
logDebug(['Running Wine command:', commandParts.join(' ')], LogPrefix.Backend) | ||
|
||
return new Promise<{ stderr: string; stdout: string }>((res) => { | ||
const wrappers = options?.wrappers || [] | ||
let bin = '' | ||
let bin = runnerBin | ||
|
||
if (wrappers.length) { | ||
bin = wrappers.shift()! | ||
commandParts.unshift(...wrappers, wineBin) | ||
} else { | ||
bin = wineBin | ||
commandParts.unshift(...wrappers, runnerBin) | ||
} | ||
|
||
const child = spawn(bin, commandParts, { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should update the JSDoc above the method with this new option so it's more clear what it's used for
at least from the usage of this in this PR I'm not sure I understand why it's needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made
invalidateCheck
to allow us to add additional checks on data. Useful for making sure we invalidate cache only when online for example. In case of umuId store, we use that to make a cache invalid only if the id wasn't found previously.