changed proton to wine

This commit is contained in:
ALEZ-DEV 2025-12-16 21:41:13 +01:00
parent 3c34d05ff0
commit bbfb912f5b
10 changed files with 183 additions and 168 deletions

21
Cargo.lock generated
View File

@ -375,6 +375,7 @@ dependencies = [
"tar", "tar",
"tokio", "tokio",
"wincompatlib", "wincompatlib",
"xz2",
] ]
[[package]] [[package]]
@ -2069,6 +2070,17 @@ version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "lzma-sys"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
@ -4269,6 +4281,15 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "xz2"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
dependencies = [
"lzma-sys",
]
[[package]] [[package]]
name = "yoke" name = "yoke"
version = "0.7.5" version = "0.7.5"

View File

@ -3,7 +3,7 @@ use std::{path::PathBuf, str::FromStr, sync::Arc};
use babylonia_terminal_sdk::{ use babylonia_terminal_sdk::{
components::{ components::{
dxvk_component::{DXVK_DEV, DXVK_REPO}, dxvk_component::{DXVK_DEV, DXVK_REPO},
proton_component::{ProtonComponent, PROTON_DEV, PROTON_REPO}, wine_component::{WineComponent, WINE_DEV, WINE_REPO},
}, },
game_config::GameConfig, game_config::GameConfig,
game_manager::{EnvironmentVariable, GameManager}, game_manager::{EnvironmentVariable, GameManager},
@ -21,8 +21,8 @@ pub async fn run(
env_vars: Vec<EnvironmentVariable>, env_vars: Vec<EnvironmentVariable>,
show_logs: bool, show_logs: bool,
) { ) {
let mut proton_component: Option<ProtonComponent> = None; let mut wine_component: Option<WineComponent> = None;
let mut proton: Option<Proton> = None; let mut wine: Option<Wine> = None;
loop { loop {
let state_result = GameState::get_current_state().await; let state_result = GameState::get_current_state().await;
@ -32,40 +32,42 @@ pub async fn run(
} }
let state = state_result.unwrap(); let state = state_result.unwrap();
if state != GameState::ProtonNotInstalled && proton == None { if state != GameState::WineNotInstalled && wine == None {
let proton_component = ProtonComponent::new(GameConfig::get_config_directory().await); let wine_component = WineComponent::new(GameConfig::get_config_directory().await);
match proton_component.init_proton() { match wine_component.init_wine() {
Ok(p) => proton = Some(p), Ok(p) => wine = Some(p),
Err(err) => panic!("{}", err), Err(err) => panic!("{}", err),
}; };
} }
match state { match state {
GameState::ProtonNotInstalled => { GameState::WineNotInstalled => {
let release; let release;
if utils::use_latest("Do you want to install latest version of Proton GE or a specific version of it?") { if utils::use_latest(
release = 0; "Do you want to install latest version of wine GE or a specific version of it?",
} else { ) {
release = utils::choose_release_version( release = 0;
PROTON_DEV, } else {
PROTON_REPO, release = utils::choose_release_version(
"Please, select a version of Proton GE to install.", WINE_DEV,
) WINE_REPO,
.await "Please, select a version of wine GE to install.",
.expect("Failed to fetch proton version!"); )
} .await
.expect("Failed to fetch wine version!");
}
info!("Proton not installed, installing it..."); info!("Wine not installed, installing it...");
proton_component = Some( wine_component = Some(
GameManager::install_wine( GameManager::install_wine(
GameConfig::get_config_directory().await, GameConfig::get_config_directory().await,
release, release,
Some(DownloadReporter::create(false)), Some(DownloadReporter::create(false)),
) )
.await .await
.expect("Failed to install Wine"), .expect("Failed to install wine"),
); );
info!("Proton installed"); info!("wine installed");
} }
GameState::DXVKNotInstalled => { GameState::DXVKNotInstalled => {
let release; let release;
@ -84,9 +86,9 @@ pub async fn run(
} }
info!("DXVK not installed, installing it..."); info!("DXVK not installed, installing it...");
debug!("{:?}", proton_component); debug!("{:?}", wine_component);
GameManager::install_dxvk( GameManager::install_dxvk(
&proton.clone().unwrap(), &wine.clone().unwrap(),
GameConfig::get_config_directory().await, GameConfig::get_config_directory().await,
release, release,
Some(DownloadReporter::create(false)), Some(DownloadReporter::create(false)),
@ -97,14 +99,14 @@ pub async fn run(
} }
GameState::FontNotInstalled => { GameState::FontNotInstalled => {
info!("Fonts not installed, installing it..."); info!("Fonts not installed, installing it...");
GameManager::install_font(&proton.clone().unwrap(), None::<Arc<DownloadReporter>>) GameManager::install_font(&wine.clone().unwrap(), None::<Arc<DownloadReporter>>)
.await .await
.expect("Failed to install fonts"); .expect("Failed to install fonts");
info!("Fonts installed"); info!("Fonts installed");
} }
GameState::DependecieNotInstalled => { GameState::DependecieNotInstalled => {
info!("Dependecies not installed, installing it..."); info!("Dependecies not installed, installing it...");
GameManager::install_dependencies(&proton.clone().unwrap()) GameManager::install_dependencies(&wine.clone().unwrap())
.await .await
.expect("Failed to install dependecies"); .expect("Failed to install dependecies");
info!("Dependecies installed"); info!("Dependecies installed");
@ -167,9 +169,9 @@ pub async fn run(
} }
info!("Starting game..."); info!("Starting game...");
debug!("{:?}", proton); debug!("{:?}", wine);
GameManager::start_game( GameManager::start_game(
&proton.unwrap(), &wine.unwrap(),
GameConfig::get_game_dir() GameConfig::get_game_dir()
.await .await
.expect("Failed to start game, the game directory was not found"), .expect("Failed to start game, the game directory was not found"),

View File

@ -1,8 +1,8 @@
use std::{ops::Deref, sync::Arc}; use std::{ops::Deref, sync::Arc};
use babylonia_terminal_sdk::{ use babylonia_terminal_sdk::{
components::proton_component::ProtonComponent, game_config::GameConfig, components::wine_component::WineComponent, game_config::GameConfig, game_manager::GameManager,
game_manager::GameManager, utils::github_requester::GithubRelease, utils::github_requester::GithubRelease,
}; };
use downloader::download; use downloader::download;
use log::{debug, error}; use log::{debug, error};
@ -10,7 +10,7 @@ use relm4::{
tokio::{self, sync::OnceCell}, tokio::{self, sync::OnceCell},
Worker, Worker,
}; };
use wincompatlib::prelude::Proton; use wincompatlib::prelude::Wine;
use crate::ui::{ use crate::ui::{
self, self,
@ -23,36 +23,33 @@ use crate::ui::{
}, },
}; };
static PROTON: OnceCell<Proton> = OnceCell::const_new(); static WINE: OnceCell<Wine> = OnceCell::const_new();
pub async fn get_proton() -> anyhow::Result<Proton> { pub async fn get_wine() -> anyhow::Result<Wine> {
if !PROTON.initialized() { if !WINE.initialized() {
let proton_component = ProtonComponent::new(GameConfig::get_config().await.config_dir); let wine_component = WineComponent::new(GameConfig::get_config().await.config_dir);
let proton = proton_component.init_proton(); let wine = wine_component.init_wine();
if let Err(ref e) = proton { if let Err(ref e) = wine {
error!("Failed to initialize proton : {}", e); error!("Failed to initialize wine : {}", e);
anyhow::bail!("Failed to initialize proton : {}", e); anyhow::bail!("Failed to initialize wine : {}", e);
} }
Ok(PROTON Ok(WINE.get_or_init(|| async { wine.unwrap() }).await.clone())
.get_or_init(|| async { proton.unwrap() })
.await
.clone())
} else { } else {
Ok(PROTON.get().unwrap().clone()) Ok(WINE.get().unwrap().clone())
} }
} }
pub async fn run_game() -> anyhow::Result<()> { pub async fn run_game() -> anyhow::Result<()> {
let proton = get_proton().await?; let wine = get_wine().await?;
let game_dir = GameConfig::get_config().await.game_dir; let game_dir = GameConfig::get_config().await.game_dir;
if game_dir.is_none() { if game_dir.is_none() {
error!("Failed to start game, the game directory was not found"); error!("Failed to start game, the game directory was not found");
anyhow::bail!("Failed to start game, the game directory was not found"); anyhow::bail!("Failed to start game, the game directory was not found");
} }
GameManager::start_game(&proton, game_dir.unwrap(), None, vec![], false).await?; GameManager::start_game(&wine, game_dir.unwrap(), None, vec![], false).await?;
Ok(()) Ok(())
} }
@ -217,7 +214,7 @@ pub enum HandleComponentInstallationMsg {
usize, usize,
Arc<download_components::DownloadComponentProgressBarReporter>, Arc<download_components::DownloadComponentProgressBarReporter>,
), ),
), // proton release and dxvk release ), // wine release and dxvk release
} }
#[derive(Debug)] #[derive(Debug)]
@ -237,7 +234,7 @@ impl Worker for HandleComponentInstallation {
fn update(&mut self, message: Self::Input, sender: relm4::ComponentSender<Self>) { fn update(&mut self, message: Self::Input, sender: relm4::ComponentSender<Self>) {
match message { match message {
HandleComponentInstallationMsg::StartInstallation(( HandleComponentInstallationMsg::StartInstallation((
proton_release, wine_release,
dxvk_release, dxvk_release,
progress_bar, progress_bar,
)) => { )) => {
@ -248,20 +245,20 @@ impl Worker for HandleComponentInstallation {
.block_on(async { .block_on(async {
let _ = sender.output( let _ = sender.output(
download_components::DownloadComponentsMsg::UpdateProgressBarMsg( download_components::DownloadComponentsMsg::UpdateProgressBarMsg(
String::from("Starting download for proton"), String::from("Starting download for wine"),
Some(String::from("Unpacking and initializing proton")), Some(String::from("Unpacking and initializing wine")),
), ),
); );
let _ = sender.output( let _ = sender.output(
download_components::DownloadComponentsMsg::UpdateCurrentlyInstalling( download_components::DownloadComponentsMsg::UpdateCurrentlyInstalling(
download_components::CurrentlyInstalling::Proton, download_components::CurrentlyInstalling::Wine,
), ),
); );
let _ = sender.output( let _ = sender.output(
download_components::DownloadComponentsMsg::UpdateDownloadedComponentName( download_components::DownloadComponentsMsg::UpdateDownloadedComponentName(
String::from("proton"), String::from("wine"),
), ),
); );
@ -271,8 +268,8 @@ impl Worker for HandleComponentInstallation {
GameConfig::get_config_directory().await GameConfig::get_config_directory().await
}; };
if let Err(error) = GameManager::install_wine(game_dir.clone(), proton_release, Some(progress_bar.clone())).await { if let Err(error) = GameManager::install_wine(game_dir.clone(), wine_release, Some(progress_bar.clone())).await {
sender.output(download_components::DownloadComponentsMsg::ShowError(format!("Failed to install proton : {}", error))).unwrap(); sender.output(download_components::DownloadComponentsMsg::ShowError(format!("Failed to install wine : {}", error))).unwrap();
return; return;
} }
@ -283,15 +280,15 @@ impl Worker for HandleComponentInstallation {
let _ = sender.output(download_components::DownloadComponentsMsg::UpdateDownloadedComponentName(String::from("DXVK"))); let _ = sender.output(download_components::DownloadComponentsMsg::UpdateDownloadedComponentName(String::from("DXVK")));
let proton = match get_proton().await { let wine = match get_wine().await {
Ok(p) => p, Ok(p) => p,
Err(e) => { Err(e) => {
sender.output(download_components::DownloadComponentsMsg::ShowError(format!("Failed to initialize proton : {:?}", e))).unwrap(); sender.output(download_components::DownloadComponentsMsg::ShowError(format!("Failed to initialize wine : {:?}", e))).unwrap();
return; return;
} }
}; };
if let Err(error) = GameManager::install_dxvk(&proton, game_dir, dxvk_release, Some(progress_bar.clone())).await { if let Err(error) = GameManager::install_dxvk(&wine, game_dir, dxvk_release, Some(progress_bar.clone())).await {
sender.output(download_components::DownloadComponentsMsg::ShowError(format!("Failed to install DXVK : {}", error))).unwrap(); sender.output(download_components::DownloadComponentsMsg::ShowError(format!("Failed to install DXVK : {}", error))).unwrap();
return; return;
} }
@ -303,7 +300,7 @@ impl Worker for HandleComponentInstallation {
let _ = sender.output(download_components::DownloadComponentsMsg::UpdateDownloadedComponentName(String::from("fonts"))); let _ = sender.output(download_components::DownloadComponentsMsg::UpdateDownloadedComponentName(String::from("fonts")));
if let Err(error) = GameManager::install_font(&proton, Some(progress_bar.clone())).await { if let Err(error) = GameManager::install_font(&wine, Some(progress_bar.clone())).await {
sender.output(download_components::DownloadComponentsMsg::ShowError(format!("Failed to install fonts : {}", error))).unwrap(); sender.output(download_components::DownloadComponentsMsg::ShowError(format!("Failed to install fonts : {}", error))).unwrap();
return; return;
} }
@ -315,7 +312,7 @@ impl Worker for HandleComponentInstallation {
let _ = sender.output(download_components::DownloadComponentsMsg::UpdateDownloadedComponentName(String::from("denpendecies"))); let _ = sender.output(download_components::DownloadComponentsMsg::UpdateDownloadedComponentName(String::from("denpendecies")));
if let Err(error) = GameManager::install_dependencies(&proton).await { if let Err(error) = GameManager::install_dependencies(&wine).await {
sender.output(download_components::DownloadComponentsMsg::ShowError(format!("Failed to install dependencies : {}", error))).unwrap(); sender.output(download_components::DownloadComponentsMsg::ShowError(format!("Failed to install dependencies : {}", error))).unwrap();
return; return;
} }

View File

@ -4,7 +4,7 @@ use arboard::Clipboard;
use babylonia_terminal_sdk::{ use babylonia_terminal_sdk::{
components::{ components::{
dxvk_component::{self, DXVKComponent}, dxvk_component::{self, DXVKComponent},
proton_component::{self, ProtonComponent}, wine_component::{self, WineComponent},
}, },
game_config::GameConfig, game_config::GameConfig,
game_state::GameState, game_state::GameState,
@ -43,7 +43,7 @@ pub enum DownloadComponentsMsg {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum CurrentlyInstalling { pub enum CurrentlyInstalling {
None, None,
Proton, Wine,
DXVK, DXVK,
Fonts, Fonts,
Denpendecies, Denpendecies,
@ -52,14 +52,14 @@ pub enum CurrentlyInstalling {
#[derive(Debug)] #[derive(Debug)]
pub struct DownloadComponentsPage { pub struct DownloadComponentsPage {
// widgets // widgets
proton_combo: adw::ComboRow, wine_combo: adw::ComboRow,
dxvk_combo: adw::ComboRow, dxvk_combo: adw::ComboRow,
//error_dialog: Controller<CopyDialog>, //error_dialog: Controller<CopyDialog>,
// values // values
proton_versions: Vec<GithubRelease>, wine_versions: Vec<GithubRelease>,
dxvk_versions: Vec<GithubRelease>, dxvk_versions: Vec<GithubRelease>,
selected_proton_version: Option<GithubRelease>, selected_wine_version: Option<GithubRelease>,
selected_dxvk_version: Option<GithubRelease>, selected_dxvk_version: Option<GithubRelease>,
game_config: GameConfig, game_config: GameConfig,
@ -108,11 +108,11 @@ impl SimpleAsyncComponent for DownloadComponentsPage {
set_vexpand: true, set_vexpand: true,
#[local_ref] #[local_ref]
proton_combo -> adw::ComboRow { wine_combo -> adw::ComboRow {
set_title: "proton version", set_title: "Wine version",
set_model: Some(&gtk::StringList::new(model set_model: Some(&gtk::StringList::new(model
.proton_versions .wine_versions
.iter() .iter()
.map(|r| r.tag_name.as_str()) .map(|r| r.tag_name.as_str())
.collect::<Vec<&str>>() .collect::<Vec<&str>>()
@ -142,7 +142,7 @@ impl SimpleAsyncComponent for DownloadComponentsPage {
set_hexpand: false, set_hexpand: false,
set_width_request: 200, set_width_request: 200,
connect_clicked => DownloadComponentsMsg::UpdateCurrentlyInstalling(CurrentlyInstalling::Proton), connect_clicked => DownloadComponentsMsg::UpdateCurrentlyInstalling(CurrentlyInstalling::Wine),
}, },
}, },
}, },
@ -168,21 +168,21 @@ impl SimpleAsyncComponent for DownloadComponentsPage {
set_vexpand: true, set_vexpand: true,
adw::ActionRow { adw::ActionRow {
set_title: "Proton", set_title: "Wine",
#[watch] #[watch]
set_subtitle: match &model.selected_proton_version { set_subtitle: match &model.selected_wine_version {
Some(release) => &release.tag_name, Some(release) => &release.tag_name,
None => "WTF??!! there's no proton version found ????", None => "WTF??!! there's no wine version found ????",
}, },
#[watch] #[watch]
set_icon_name: if model.currently_installing != CurrentlyInstalling::Proton && model.game_config.is_wine_installed { Some("emblem-ok-symbolic") } else { None }, set_icon_name: if model.currently_installing != CurrentlyInstalling::Wine && model.game_config.is_wine_installed { Some("emblem-ok-symbolic") } else { None },
add_prefix = &gtk::Spinner { add_prefix = &gtk::Spinner {
set_spinning: true, set_spinning: true,
#[watch] #[watch]
set_visible: model.currently_installing == CurrentlyInstalling::Proton, set_visible: model.currently_installing == CurrentlyInstalling::Wine,
} }
}, },
@ -191,7 +191,7 @@ impl SimpleAsyncComponent for DownloadComponentsPage {
#[watch] #[watch]
set_subtitle: match &model.selected_dxvk_version { set_subtitle: match &model.selected_dxvk_version {
Some(release) => &release.tag_name, Some(release) => &release.tag_name,
None => "WTF??!! there's no proton version found ????", None => "WTF??!! there's no wine version found ????",
}, },
#[watch] #[watch]
@ -285,12 +285,10 @@ impl SimpleAsyncComponent for DownloadComponentsPage {
root: Self::Root, root: Self::Root,
sender: AsyncComponentSender<Self>, sender: AsyncComponentSender<Self>,
) -> AsyncComponentParts<Self> { ) -> AsyncComponentParts<Self> {
let proton_releases = ProtonComponent::get_github_releases( let wine_releases =
proton_component::PROTON_DEV, WineComponent::get_github_releases(wine_component::WINE_DEV, wine_component::WINE_REPO)
proton_component::PROTON_REPO, .await
) .unwrap(); //TODO: remove unwrap()
.await
.unwrap(); //TODO: remove unwrap()
let dxvk_releases = let dxvk_releases =
DXVKComponent::get_github_releases(dxvk_component::DXVK_DEV, dxvk_component::DXVK_REPO) DXVKComponent::get_github_releases(dxvk_component::DXVK_DEV, dxvk_component::DXVK_REPO)
@ -298,12 +296,12 @@ impl SimpleAsyncComponent for DownloadComponentsPage {
.unwrap(); //TODO: remove unwrap() .unwrap(); //TODO: remove unwrap()
let model = DownloadComponentsPage { let model = DownloadComponentsPage {
proton_combo: adw::ComboRow::new(), wine_combo: adw::ComboRow::new(),
dxvk_combo: adw::ComboRow::new(), dxvk_combo: adw::ComboRow::new(),
proton_versions: proton_releases, wine_versions: wine_releases,
dxvk_versions: dxvk_releases, dxvk_versions: dxvk_releases,
selected_proton_version: None, selected_wine_version: None,
selected_dxvk_version: None, selected_dxvk_version: None,
game_config: GameConfig::get_config().await, game_config: GameConfig::get_config().await,
@ -320,7 +318,7 @@ impl SimpleAsyncComponent for DownloadComponentsPage {
msg_when_done: None, msg_when_done: None,
}; };
let proton_combo = &model.proton_combo; let wine_combo = &model.wine_combo;
let dxvk_combo = &model.dxvk_combo; let dxvk_combo = &model.dxvk_combo;
let widgets = view_output!(); let widgets = view_output!();
@ -395,21 +393,21 @@ impl SimpleAsyncComponent for DownloadComponentsPage {
DownloadComponentsMsg::Quit => relm4::main_application().quit(), DownloadComponentsMsg::Quit => relm4::main_application().quit(),
} }
if self.selected_proton_version.is_none() if self.selected_wine_version.is_none()
&& self.selected_dxvk_version.is_none() && self.selected_dxvk_version.is_none()
&& self.currently_installing != CurrentlyInstalling::None && self.currently_installing != CurrentlyInstalling::None
{ {
let proton_index = self.proton_combo.selected() as usize; let wine_index = self.wine_combo.selected() as usize;
let dxvk_index = self.dxvk_combo.selected() as usize; let dxvk_index = self.dxvk_combo.selected() as usize;
let proton_release = self.proton_versions[proton_index].clone(); let wine_release = self.wine_versions[wine_index].clone();
let dxvk_release = self.dxvk_versions[dxvk_index].clone(); let dxvk_release = self.dxvk_versions[dxvk_index].clone();
self.selected_proton_version = Some(proton_release); self.selected_wine_version = Some(wine_release);
self.selected_dxvk_version = Some(dxvk_release); self.selected_dxvk_version = Some(dxvk_release);
let _ = self.installation_handler.sender().send( let _ = self.installation_handler.sender().send(
manager::HandleComponentInstallationMsg::StartInstallation(( manager::HandleComponentInstallationMsg::StartInstallation((
proton_index, wine_index,
dxvk_index, dxvk_index,
self.progress_bar_reporter.clone(), self.progress_bar_reporter.clone(),
)), )),

View File

@ -30,7 +30,7 @@ tokio = { version = "1.37.0", features = ["fs"] }
wincompatlib = { version = "0.7.5", features = [ wincompatlib = { version = "0.7.5", features = [
"dxvk", "dxvk",
"wine-bundles", "wine-bundles",
"wine-proton",
"wine-fonts", "wine-fonts",
"winetricks", "winetricks",
] } ] }
xz2 = "0.1.7"

View File

@ -55,12 +55,12 @@ impl<'a> ComponentDownloader for DXVKComponent<'a> {
Self::uncompress(file_output.clone(), self.path.clone()).await?; Self::uncompress(file_output.clone(), self.path.clone()).await?;
let wine_with_proton_prefix = self // wine take the data/wine/pfx prefix, but we want the data/wine prefix let wine_prefix = self // wine take the data/wine/pfx prefix, but we want the data/wine prefix
.wine .wine
.clone() .clone()
.with_prefix(self.wine.prefix.parent().unwrap()); .with_prefix(self.wine.prefix.parent().unwrap());
wine_with_proton_prefix wine_prefix
.install_dxvk(self.path.clone(), InstallParams::default()) .install_dxvk(self.path.clone(), InstallParams::default())
.expect("Failed to installed DXVK"); .expect("Failed to installed DXVK");

View File

@ -1,4 +1,4 @@
pub mod component_downloader; pub mod component_downloader;
pub mod dxvk_component; pub mod dxvk_component;
pub mod game_component; pub mod game_component;
pub mod proton_component; pub mod wine_component;

View File

@ -6,37 +6,37 @@ use std::{
}; };
use downloader::{progress::Reporter, Downloader}; use downloader::{progress::Reporter, Downloader};
use flate2::read::GzDecoder;
use log::debug; use log::debug;
use tar::Archive; use tar::Archive;
use wincompatlib::wine::ext::WineBootExt; use wincompatlib::wine::ext::WineBootExt;
use xz2::read::XzDecoder;
use super::component_downloader::ComponentDownloader; use super::component_downloader::ComponentDownloader;
use crate::utils::github_requester::GithubRequester; use crate::utils::github_requester::GithubRequester;
pub static PROTON_DEV: &str = "GloriousEggroll"; pub static WINE_DEV: &str = "Kron4ek";
pub static PROTON_REPO: &str = "proton-ge-custom"; pub static WINE_REPO: &str = "Wine-Builds";
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct ProtonComponent { pub struct WineComponent {
path: PathBuf, path: PathBuf,
github_release_index: usize, github_release_index: usize,
} }
impl GithubRequester for ProtonComponent { impl GithubRequester for WineComponent {
fn set_github_release_index(&mut self, new_release_index: usize) { fn set_github_release_index(&mut self, new_release_index: usize) {
self.github_release_index = new_release_index; self.github_release_index = new_release_index;
} }
} }
impl ComponentDownloader for ProtonComponent { impl ComponentDownloader for WineComponent {
async fn install<P: Reporter + 'static>(&self, progress: Option<Arc<P>>) -> anyhow::Result<()> { async fn install<P: Reporter + 'static>(&self, progress: Option<Arc<P>>) -> anyhow::Result<()> {
let file_output = self let file_output = self
.download( .download(
&self &self
.path .path
.parent() .parent()
.expect("Failed to get the parent directory of Wine") .expect("Failed to get the parent directory of wine")
.to_path_buf(), .to_path_buf(),
progress, progress,
) )
@ -52,7 +52,7 @@ impl ComponentDownloader for ProtonComponent {
progress: Option<Arc<P>>, progress: Option<Arc<P>>,
) -> anyhow::Result<PathBuf> { ) -> anyhow::Result<PathBuf> {
let release = let release =
Self::get_github_release_version(PROTON_DEV, PROTON_REPO, self.github_release_index) Self::get_github_release_version(WINE_DEV, WINE_REPO, self.github_release_index)
.await?; .await?;
let asset = release let asset = release
@ -79,14 +79,15 @@ impl ComponentDownloader for ProtonComponent {
async fn uncompress(file: PathBuf, new_directory_name: PathBuf) -> anyhow::Result<()> { async fn uncompress(file: PathBuf, new_directory_name: PathBuf) -> anyhow::Result<()> {
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
let tar_xz = File::open(file.clone()).unwrap(); let tar_xz = File::open(file.clone()).unwrap();
let tar = GzDecoder::new(tar_xz); let tar = XzDecoder::new(tar_xz);
let mut archive = Archive::new(tar); let mut archive = Archive::new(tar);
archive.unpack(new_directory_name.parent().unwrap())?; archive.unpack(new_directory_name.parent().unwrap())?;
remove_file(file.clone())?; remove_file(file.clone())?;
rename( rename(
file.to_str().unwrap().strip_suffix(".tar.gz").unwrap(), file.to_str().unwrap().strip_suffix(".tar.xz").unwrap(),
new_directory_name, new_directory_name,
)?; )?;
debug!("???5");
Ok::<(), anyhow::Error>(()) Ok::<(), anyhow::Error>(())
}) })
@ -96,49 +97,47 @@ impl ComponentDownloader for ProtonComponent {
} }
} }
impl ProtonComponent { impl WineComponent {
pub fn new(path: PathBuf) -> Self { pub fn new(path: PathBuf) -> Self {
ProtonComponent { WineComponent {
path: path.join("proton"), path: path.join("wine"),
github_release_index: 0, github_release_index: 0,
} }
} }
pub fn init_proton(&self) -> Result<wincompatlib::prelude::Proton, String> { pub fn init_wine(&self) -> Result<wincompatlib::prelude::Wine, String> {
let prefix = self.path.parent().unwrap().join("data"); let prefix = self.path.parent().unwrap().join("data");
let wine_bin_location = self.path.join("bin/wine");
debug!("Initializing prefix with -> {:?}", prefix);
debug!("Wine binary path : {:?}", wine_bin_location);
let mut proton = let mut wine = wincompatlib::prelude::Wine::from_binary(wine_bin_location);
wincompatlib::prelude::Proton::new(self.path.clone(), Some(prefix.clone()));
let steam_location = Self::get_steam_location()?;
debug!("Steam location used -> {:?}", steam_location); wine.init_prefix(Some(prefix)).unwrap();
proton.steam_client_path = Some(steam_location); Ok(wine)
proton.init_prefix(Some(prefix)).unwrap();
Ok(proton)
} }
fn get_steam_location() -> Result<PathBuf, String> { //fn get_steam_location() -> Result<PathBuf, String> {
let specified_steam_location = std::env::var("BT_STEAM_CLIENT_PATH"); // let specified_steam_location = std::env::var("BT_STEAM_CLIENT_PATH");
if let Ok(location) = specified_steam_location { // if let Ok(location) = specified_steam_location {
return Ok(PathBuf::from(location)); // return Ok(PathBuf::from(location));
} // }
let location_to_check = [ // let location_to_check = [
dirs::home_dir().unwrap().join(".steam/steam"), // dirs::home_dir().unwrap().join(".steam/steam"),
dirs::home_dir() // dirs::home_dir()
.unwrap() // .unwrap()
.join(".var/app/com.valvesoftware.Steam/steam"), // for the flatpak version of steam // .join(".var/app/com.valvesoftware.Steam/steam"), // for the flatpak version of steam
]; // ];
for location in location_to_check { // for location in location_to_check {
if location.exists() { // if location.exists() {
return Ok(location); // return Ok(location);
} // }
} // }
debug!("Can't find steam installation"); // debug!("Can't find steam installation");
Err(String::from_str("We can't find your steam installation, please install steam in '~/.steam/steam' or specify your steam installation").unwrap()) // Err(String::from_str("We can't find your steam installation, please install steam in '~/.steam/steam' or specify your steam installation").unwrap())
} //}
} }

View File

@ -16,7 +16,7 @@ use wincompatlib::prelude::*;
use crate::{ use crate::{
components::{ components::{
component_downloader::ComponentDownloader, dxvk_component::DXVKComponent, component_downloader::ComponentDownloader, dxvk_component::DXVKComponent,
game_component::GameComponent, proton_component::ProtonComponent, game_component::GameComponent, wine_component::WineComponent,
}, },
game_config::GameConfig, game_config::GameConfig,
game_patcher, game_patcher,
@ -46,11 +46,11 @@ impl GameManager {
config_dir: PathBuf, config_dir: PathBuf,
release_index: usize, release_index: usize,
progress: Option<Arc<P>>, progress: Option<Arc<P>>,
) -> anyhow::Result<ProtonComponent> ) -> anyhow::Result<WineComponent>
where where
P: Reporter + 'static, P: Reporter + 'static,
{ {
let mut wine_component = ProtonComponent::new(config_dir); let mut wine_component = WineComponent::new(config_dir);
wine_component.set_github_release_index(release_index); wine_component.set_github_release_index(release_index);
wine_component.install(progress).await?; wine_component.install(progress).await?;
@ -63,7 +63,7 @@ impl GameManager {
} }
pub async fn install_dxvk<P>( pub async fn install_dxvk<P>(
proton: &Proton, wine: &Wine,
config_dir: PathBuf, config_dir: PathBuf,
release_index: usize, release_index: usize,
progress: Option<Arc<P>>, progress: Option<Arc<P>>,
@ -71,7 +71,7 @@ impl GameManager {
where where
P: Reporter + 'static, P: Reporter + 'static,
{ {
let mut dxvk_component = DXVKComponent::from_wine(proton.wine(), config_dir); let mut dxvk_component = DXVKComponent::from_wine(wine, config_dir);
dxvk_component.set_github_release_index(release_index); dxvk_component.set_github_release_index(release_index);
dxvk_component.install(progress).await?; dxvk_component.install(progress).await?;
@ -83,14 +83,13 @@ impl GameManager {
Ok(()) Ok(())
} }
pub async fn install_font<P>(proton: &Proton, progress: Option<Arc<P>>) -> anyhow::Result<()> pub async fn install_font<P>(wine: &Wine, progress: Option<Arc<P>>) -> anyhow::Result<()>
where where
P: Reporter + 'static, P: Reporter + 'static,
{ {
let wine_with_proton_prefix = proton // wine take the data/wine/pfx prefix, but we want the data/wine prefix let wine_prefix = wine // wine take the data/wine/pfx prefix, but we want the data/wine prefix
.wine()
.clone() .clone()
.with_prefix(proton.wine().prefix.parent().unwrap()); .with_prefix(wine.prefix.parent().unwrap());
let max = 1; let max = 1;
@ -100,7 +99,7 @@ impl GameManager {
notify_fonts_progress(0, max, &progress); notify_fonts_progress(0, max, &progress);
wine_with_proton_prefix.install_font(Font::Arial)?; wine_prefix.install_font(Font::Arial)?;
notify_fonts_progress(1, max, &progress); notify_fonts_progress(1, max, &progress);
let mut config = GameConfig::get_config().await; let mut config = GameConfig::get_config().await;
@ -110,13 +109,12 @@ impl GameManager {
Ok(()) Ok(())
} }
pub async fn install_dependencies(proton: &Proton) -> anyhow::Result<()> { pub async fn install_dependencies(wine: &Wine) -> anyhow::Result<()> {
let wine_with_proton_prefix = proton // wine take the data/wine/pfx prefix, but we want the data/wine prefix let wine_prefix = wine // wine take the data/wine/pfx prefix, but we want the data/wine prefix
.wine()
.clone() .clone()
.with_prefix(proton.wine().prefix.parent().unwrap()); .with_prefix(wine.prefix.parent().unwrap());
let winetricks = Winetricks::from_wine("/bin/winetricks", wine_with_proton_prefix); let winetricks = Winetricks::from_wine("/bin/winetricks", wine_prefix);
//winetricks.install("corefonts")?; //winetricks.install("corefonts")?;
let mut child = winetricks.install("vcrun2022")?; let mut child = winetricks.install("vcrun2022")?;
@ -165,26 +163,26 @@ impl GameManager {
} }
pub async fn start_game( pub async fn start_game(
proton: &Proton, wine: &Wine,
game_dir: PathBuf, game_dir: PathBuf,
options: Option<String>, options: Option<String>,
env_variables: Vec<EnvironmentVariable>, env_variables: Vec<EnvironmentVariable>,
show_logs: bool, show_logs: bool,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let proton_version = proton.wine().version()?; let wine_version = wine.version()?;
let binary_path = game_dir let binary_path = game_dir
.join(get_game_name()) .join(get_game_name())
.join(get_game_name_with_executable()); .join(get_game_name_with_executable());
debug!("Wine version : {:?}", proton_version); debug!("wine version : {:?}", wine_version);
let mut child = if let Some(custom_command) = options { let mut child = if let Some(custom_command) = options {
Self::run(proton, binary_path, Some(custom_command), env_variables).await? Self::run(wine, binary_path, Some(custom_command), env_variables).await?
} else { } else {
if let Some(custom_command) = GameConfig::get_launch_options().await.unwrap() { if let Some(custom_command) = GameConfig::get_launch_options().await.unwrap() {
Self::run(proton, binary_path, Some(custom_command), env_variables).await? Self::run(wine, binary_path, Some(custom_command), env_variables).await?
} else { } else {
Self::run(proton, binary_path, None, env_variables).await? Self::run(wine, binary_path, None, env_variables).await?
} }
}?; }?;
@ -205,7 +203,7 @@ impl GameManager {
.lines() .lines()
.inspect(|s| { .inspect(|s| {
if let Ok(str) = s { if let Ok(str) = s {
info!("[Proton] > {}", str); info!("[wine] > {}", str);
stdout_save.push_str(str); stdout_save.push_str(str);
} }
}) })
@ -219,7 +217,7 @@ impl GameManager {
.lines() .lines()
.inspect(|s| { .inspect(|s| {
if let Ok(str) = s { if let Ok(str) = s {
info!("[Proton] > {}", str); info!("[wine] > {}", str);
stderr_save.push_str(str); stderr_save.push_str(str);
} }
}) })
@ -292,20 +290,20 @@ impl GameManager {
} }
async fn run( async fn run(
proton: &Proton, wine: &Wine,
binary_path: PathBuf, binary_path: PathBuf,
custom_command: Option<String>, custom_command: Option<String>,
env_variables: Vec<EnvironmentVariable>, env_variables: Vec<EnvironmentVariable>,
) -> anyhow::Result<Result<Child, std::io::Error>> { ) -> anyhow::Result<Result<Child, std::io::Error>> {
let mut command: Vec<&str> = vec![]; let mut command: Vec<&str> = vec![];
let proton_path = GameConfig::get_config_directory() let wine_path = GameConfig::get_config_directory()
.await .await
.join("proton") .join("wine")
.join("proton"); .join("wine");
command.push(proton.python.to_str().unwrap()); //command.push(wine.python.to_str().unwrap());
command.push(proton_path.to_str().unwrap()); command.push(wine_path.to_str().unwrap());
command.push("run"); command.push("run");
command.push(binary_path.to_str().unwrap()); command.push(binary_path.to_str().unwrap());
@ -337,8 +335,8 @@ impl GameManager {
Ok(Command::new(command[0]) Ok(Command::new(command[0])
.args(&command[1..command.len()]) .args(&command[1..command.len()])
.envs(proton.get_envs()) .envs(wine.get_envs())
.env("PROTON_LOG", "1") .env("Wine_LOG", "1")
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())

View File

@ -2,7 +2,7 @@ use crate::{game_config::GameConfig, utils::kuro_prod_api::GameInfo};
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum GameState { pub enum GameState {
ProtonNotInstalled, WineNotInstalled,
DXVKNotInstalled, DXVKNotInstalled,
FontNotInstalled, FontNotInstalled,
DependecieNotInstalled, DependecieNotInstalled,
@ -17,7 +17,7 @@ impl GameState {
let config = GameConfig::get_config().await; let config = GameConfig::get_config().await;
if !config.is_wine_installed { if !config.is_wine_installed {
return Ok(GameState::ProtonNotInstalled); return Ok(GameState::WineNotInstalled);
} }
if !config.is_dxvk_installed { if !config.is_dxvk_installed {