From cb42c8cdace8061790c664793a9cb4b5331bc073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20Fearn?= <26871415+flavioislima@users.noreply.github.com> Date: Fri, 26 Jul 2024 13:38:12 +0200 Subject: [PATCH] [Feat-macOS] Download GPTK from Wine Manager (#3868) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Feat-macOS] Download GPTK from Wine Manager * feat: auto update Wine Selector on new version download * fix: tests * feat: Update function names for Game Porting Toolkit * Update src/frontend/screens/Settings/components/WineVersionSelector.tsx Co-authored-by: Mathis Dröge * chore: pr comments --------- Co-authored-by: Flavio F Lima Co-authored-by: Mathis Dröge --- src/backend/config.ts | 9 ++- src/backend/utils.ts | 2 +- src/backend/utils/compatibility_layers.ts | 69 ++++++++++++++++--- .../wine/manager/downloader/constants.ts | 4 ++ src/backend/wine/manager/downloader/main.ts | 17 ++++- .../wine/manager/downloader/utilities.ts | 14 +++- src/backend/wine/manager/utils.ts | 24 +++++-- src/common/types.ts | 4 +- .../components/WineVersionSelector.tsx | 1 + src/frontend/screens/WineManager/index.tsx | 12 ++-- 10 files changed, 128 insertions(+), 28 deletions(-) diff --git a/src/backend/config.ts b/src/backend/config.ts index 44ae15f707..ee3bcb1e36 100644 --- a/src/backend/config.ts +++ b/src/backend/config.ts @@ -24,8 +24,9 @@ import { logError, logInfo, LogPrefix } from './logger/logger' import { getCrossover, getDefaultWine, - getGamingPortingToolkitWine, + getGamePortingToolkitWine, getLinuxWineSet, + getSystemGamePortingToolkitWine, getWhisky, getWineOnMac, getWineskinWine @@ -134,14 +135,16 @@ abstract class GlobalConfig { return new Set() } + const getGPTKWine = await getGamePortingToolkitWine() + const getSystemGPTK = await getSystemGamePortingToolkitWine() const crossover = await getCrossover() const wineOnMac = await getWineOnMac() const wineskinWine = await getWineskinWine() - const gamingPortingToolkitWine = await getGamingPortingToolkitWine() const whiskyWine = await getWhisky() return new Set([ - ...gamingPortingToolkitWine, + ...getGPTKWine, + ...getSystemGPTK, ...crossover, ...wineOnMac, ...wineskinWine, diff --git a/src/backend/utils.ts b/src/backend/utils.ts index 8463e38e26..7e6005cad2 100644 --- a/src/backend/utils.ts +++ b/src/backend/utils.ts @@ -907,7 +907,7 @@ export async function downloadDefaultWine() { !version.version.endsWith('-LoL') ) } else if (isMac) { - return version.version.includes('Wine-Crossover') + return version.version.includes('Game-Porting-Toolkit') } return false })[0] diff --git a/src/backend/utils/compatibility_layers.ts b/src/backend/utils/compatibility_layers.ts index 2fd5180c1a..4336ddf917 100644 --- a/src/backend/utils/compatibility_layers.ts +++ b/src/backend/utils/compatibility_layers.ts @@ -334,12 +334,62 @@ export async function getCrossover(): Promise> { * Detects Gaming Porting Toolkit Wine installs on Mac * @returns Promise> **/ -export async function getGamingPortingToolkitWine(): Promise< +export async function getGamePortingToolkitWine(): Promise< Set > { - const gamingPortingToolkitWine = new Set() + const gamePortingToolkitWine = new Set() if (!isMac) { - return gamingPortingToolkitWine + return gamePortingToolkitWine + } + + const GPTK_ToolPath = join(toolsPath, 'game-porting-toolkit') + const wineGPTKPaths = new Set() + + if (existsSync(GPTK_ToolPath)) { + readdirSync(GPTK_ToolPath).forEach((path) => { + wineGPTKPaths.add(join(GPTK_ToolPath, path)) + }) + } + + wineGPTKPaths.forEach((winePath) => { + const infoFilePath = join(winePath, 'Contents/Info.plist') + if (existsSync(infoFilePath)) { + const wineBin = join(winePath, '/Contents/Resources/wine/bin/wine64') + try { + const name = winePath.split('/').pop() || '' + if (existsSync(wineBin)) { + gamePortingToolkitWine.add({ + ...getWineExecs(wineBin), + lib: `${winePath}/Contents/Resources/wine/lib`, + lib32: `${winePath}/Contents/Resources/wine/lib`, + bin: wineBin, + name, + type: 'toolkit', + ...getWineExecs(wineBin) + }) + } + } catch (error) { + logError( + `Error getting wine version for GPTK ${wineBin}`, + LogPrefix.GlobalConfig + ) + } + } + }) + + return gamePortingToolkitWine +} + +/** + * Detects Gaming Porting Toolkit Wine installs on Mac + * @returns Promise> + **/ +export async function getSystemGamePortingToolkitWine(): Promise< + Set +> { + const systemGPTK = new Set() + if (!isMac) { + return systemGPTK } logInfo('Searching for Gaming Porting Toolkit Wine', LogPrefix.GlobalConfig) @@ -350,18 +400,19 @@ export async function getGamingPortingToolkitWine(): Promise< if (existsSync(wineBin)) { logInfo( - `Found Gaming Porting Toolkit Wine at ${dirname(wineBin)}`, + `Found Game Porting Toolkit Wine at ${dirname(wineBin)}`, LogPrefix.GlobalConfig ) try { const { stdout: out } = await execAsync(`'${wineBin}' --version`) const version = out.split('\n')[0] - gamingPortingToolkitWine.add({ + const GPTKDIR = join(dirname(wineBin), '..') + systemGPTK.add({ ...getWineExecs(wineBin), - name: `GPTK Wine (DX11/DX12 Only) - ${version}`, + name: `GPTK System (DX11/DX12 Only) - ${version}`, type: 'toolkit', - lib: `${dirname(wineBin)}/../lib`, - lib32: `${dirname(wineBin)}/../lib`, + lib: join(GPTKDIR, 'lib'), + lib32: join(GPTKDIR, 'lib'), bin: wineBin }) } catch (error) { @@ -372,7 +423,7 @@ export async function getGamingPortingToolkitWine(): Promise< } } - return gamingPortingToolkitWine + return systemGPTK } /** diff --git a/src/backend/wine/manager/downloader/constants.ts b/src/backend/wine/manager/downloader/constants.ts index d991fa2378..6de77eb396 100644 --- a/src/backend/wine/manager/downloader/constants.ts +++ b/src/backend/wine/manager/downloader/constants.ts @@ -21,3 +21,7 @@ export const WINECROSSOVER_URL = /// Url to Wine Staging for macOS github release page export const WINESTAGINGMACOS_URL = 'https://api.github.com/repos/Gcenx/macOS_Wine_builds/releases' + +/// Url to Game Porting Toolkit from Gcenx github release page +export const GPTK_URL = + 'https://api.github.com/repos/Gcenx/game-porting-toolkit/releases' diff --git a/src/backend/wine/manager/downloader/main.ts b/src/backend/wine/manager/downloader/main.ts index d37728dbdb..37fe55e5e9 100644 --- a/src/backend/wine/manager/downloader/main.ts +++ b/src/backend/wine/manager/downloader/main.ts @@ -15,7 +15,8 @@ import { PROTON_URL, WINELUTRIS_URL, WINECROSSOVER_URL, - WINESTAGINGMACOS_URL + WINESTAGINGMACOS_URL, + GPTK_URL } from './constants' import { VersionInfo, Repositorys } from 'common/types' import { @@ -134,6 +135,20 @@ async function getAvailableVersions({ }) break } + case Repositorys.GPTK: { + await fetchReleases({ + url: GPTK_URL, + type: 'Game-Porting-Toolkit', + count: count + }) + .then((fetchedReleases: VersionInfo[]) => { + releases.push(...fetchedReleases) + }) + .catch((error: Error) => { + logError(error, LogPrefix.WineDownloader) + }) + break + } default: { logWarning( `Unknown and not supported repository key passed! Skip fetch for ${repo}`, diff --git a/src/backend/wine/manager/downloader/utilities.ts b/src/backend/wine/manager/downloader/utilities.ts index 809ba11cda..4b94498735 100644 --- a/src/backend/wine/manager/downloader/utilities.ts +++ b/src/backend/wine/manager/downloader/utilities.ts @@ -11,6 +11,16 @@ interface fetchProps { count: number } +function getVersionName(type: string, tag_name: string): string { + if (type.includes('Wine')) { + return `Wine-${tag_name}` + } else if (type.includes('Toolkit')) { + return `${tag_name}` + } else { + return `Proton-${tag_name}` + } +} + /** * Helper to fetch releases from given url. * @@ -32,9 +42,7 @@ async function fetchReleases({ .then((data) => { for (const release of data.data) { const release_data = {} as VersionInfo - release_data.version = type.includes('Wine') - ? `Wine-${release.tag_name}` - : `Proton-${release.tag_name}` + release_data.version = getVersionName(type, release.tag_name) release_data.type = type release_data.date = release.published_at.split('T')[0] release_data.disksize = 0 diff --git a/src/backend/wine/manager/utils.ts b/src/backend/wine/manager/utils.ts index 0dc88a5a4a..55e17f9fc5 100644 --- a/src/backend/wine/manager/utils.ts +++ b/src/backend/wine/manager/utils.ts @@ -40,7 +40,11 @@ async function updateWineVersionInfos( logInfo('Fetching upstream information...', LogPrefix.WineDownloader) const repositorys = isMac - ? [Repositorys.WINECROSSOVER, Repositorys.WINESTAGINGMACOS] + ? [ + Repositorys.WINECROSSOVER, + Repositorys.WINESTAGINGMACOS, + Repositorys.GPTK + ] : [Repositorys.WINEGE, Repositorys.PROTONGE] await getAvailableVersions({ @@ -86,6 +90,16 @@ async function updateWineVersionInfos( return releases } +function getInstallDir(release: WineVersionInfo): string { + if (release?.type?.includes('Wine')) { + return `${toolsPath}/wine` + } else if (release.type.includes('Toolkit')) { + return `${toolsPath}/game-porting-toolkit` + } else { + return `${toolsPath}/proton` + } +} + async function installWineVersion( release: WineVersionInfo, onProgress: (status: WineManagerStatus) => void @@ -97,6 +111,10 @@ async function installWineVersion( mkdirSync(`${toolsPath}/wine`, { recursive: true }) } + if (isMac && !existsSync(`${toolsPath}/game-porting-toolkit`)) { + mkdirSync(`${toolsPath}/game-porting-toolkit`, { recursive: true }) + } + if (!existsSync(`${toolsPath}/proton`)) { mkdirSync(`${toolsPath}/proton`, { recursive: true }) } @@ -106,9 +124,7 @@ async function installWineVersion( LogPrefix.WineDownloader ) - const installDir = release?.type?.includes('Wine') - ? `${toolsPath}/wine` - : `${toolsPath}/proton` + const installDir = getInstallDir(release) const abortController = createAbortController(release.version) diff --git a/src/common/types.ts b/src/common/types.ts index 6faef86a29..ae5d5243fd 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -684,6 +684,7 @@ export type Type = | 'Wine-Kron4ek' | 'Wine-Crossover' | 'Wine-Staging-macOS' + | 'Game-Porting-Toolkit' /** * Interface contains information about a version @@ -713,7 +714,8 @@ export enum Repositorys { PROTON, WINELUTRIS, WINECROSSOVER, - WINESTAGINGMACOS + WINESTAGINGMACOS, + GPTK } export type WineManagerStatus = diff --git a/src/frontend/screens/Settings/components/WineVersionSelector.tsx b/src/frontend/screens/Settings/components/WineVersionSelector.tsx index 104cf9ccf5..4a0b67a092 100644 --- a/src/frontend/screens/Settings/components/WineVersionSelector.tsx +++ b/src/frontend/screens/Settings/components/WineVersionSelector.tsx @@ -32,6 +32,7 @@ export default function WineVersionSelector() { setRefreshing(false) } getAltWine() + return window.api.handleWineVersionsUpdated(getAltWine) }, []) useEffect(() => { diff --git a/src/frontend/screens/WineManager/index.tsx b/src/frontend/screens/WineManager/index.tsx index 79a72a59c3..b75fb64f3b 100644 --- a/src/frontend/screens/WineManager/index.tsx +++ b/src/frontend/screens/WineManager/index.tsx @@ -50,22 +50,22 @@ export default function WineManager(): JSX.Element | null { value: 'winege', enabled: isLinux } - const winecrossover: WineManagerUISettings = { - type: 'Wine-Crossover', - value: 'winecrossover', + const gamePortingToolkit: WineManagerUISettings = { + type: 'Game-Porting-Toolkit', + value: 'gpt', enabled: !isLinux } const [repository, setRepository] = useState( - isLinux ? winege : winecrossover + isLinux ? winege : gamePortingToolkit ) const [wineManagerSettings, setWineManagerSettings] = useState< WineManagerUISettings[] >([ { type: 'Wine-GE', value: 'winege', enabled: isLinux }, { type: 'Proton-GE', value: 'protonge', enabled: isLinux }, - { type: 'Wine-Crossover', value: 'winecrossover', enabled: !isLinux }, - { type: 'Wine-Staging-macOS', value: 'winestagingmacos', enabled: !isLinux } + { type: 'Game-Porting-Toolkit', value: 'gpt', enabled: !isLinux }, + { type: 'Wine-Crossover', value: 'winecrossover', enabled: !isLinux } ]) const getWineVersions = (repo: Type) => {