Several changes
- added `components::mfc140` to install mfc140 in games where it's needed - renamed `WincompatlibWine` to `UnifiedWine`; implemented new traits - removed `Serialize` & `Deserialize` derives from `LauncherState`-s - added `Mfc140NotInstalled` and `CorefontsNotInstalled` states for PGR
This commit is contained in:
parent
5526e5df93
commit
9e18ba7e24
14 changed files with 383 additions and 211 deletions
|
@ -21,10 +21,10 @@ tracing = "0.1"
|
||||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||||
serde_json = { version = "1.0", optional = true }
|
serde_json = { version = "1.0", optional = true }
|
||||||
|
|
||||||
cached = { version = "0.43", features = ["proc_macro"] }
|
cached = { version = "0.44", features = ["proc_macro"] }
|
||||||
enum-ordinalize = { version = "3.1", optional = true }
|
enum-ordinalize = { version = "3.1", optional = true }
|
||||||
|
|
||||||
wincompatlib = { version = "0.4", features = ["all"], optional = true }
|
wincompatlib = { version = "0.7.2", features = ["all"], optional = true }
|
||||||
lazy_static = { version = "1.4", optional = true }
|
lazy_static = { version = "1.4", optional = true }
|
||||||
md-5 = { version = "0.10", features = ["asm"], optional = true }
|
md-5 = { version = "0.10", features = ["asm"], optional = true }
|
||||||
discord-rich-presence = { version = "0.2.3", optional = true }
|
discord-rich-presence = { version = "0.2.3", optional = true }
|
||||||
|
|
|
@ -171,7 +171,7 @@ impl Version {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[tracing::instrument(level = "debug", ret)]
|
#[tracing::instrument(level = "debug", ret)]
|
||||||
/// Install current dxvk
|
/// Install current dxvk
|
||||||
pub fn install<T: Into<PathBuf> + std::fmt::Debug>(&self, dxvks_folder: T, wine: &Wine, params: InstallParams) -> std::io::Result<()> {
|
pub fn install<T: Into<PathBuf> + std::fmt::Debug>(&self, dxvks_folder: T, wine: &Wine, params: InstallParams) -> anyhow::Result<()> {
|
||||||
tracing::debug!("Installing DXVK");
|
tracing::debug!("Installing DXVK");
|
||||||
|
|
||||||
Dxvk::install(
|
Dxvk::install(
|
||||||
|
@ -184,7 +184,7 @@ impl Version {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[tracing::instrument(level = "debug", ret)]
|
#[tracing::instrument(level = "debug", ret)]
|
||||||
/// Uninstall current dxvk
|
/// Uninstall current dxvk
|
||||||
pub fn uninstall(&self, wine: &Wine, params: InstallParams) -> std::io::Result<()> {
|
pub fn uninstall(&self, wine: &Wine, params: InstallParams) -> anyhow::Result<()> {
|
||||||
tracing::debug!("Uninstalling DXVK");
|
tracing::debug!("Uninstalling DXVK");
|
||||||
|
|
||||||
Dxvk::uninstall(
|
Dxvk::uninstall(
|
||||||
|
|
69
src/components/mfc140.rs
Normal file
69
src/components/mfc140.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use anime_game_core::installer::downloader::Downloader;
|
||||||
|
|
||||||
|
// Source: https://github.com/Winetricks/winetricks/blob/e9454179686b3659ad3f47a5d49e6e4e82862cd5/src/winetricks#L13206
|
||||||
|
|
||||||
|
const URL: &str = "https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe";
|
||||||
|
|
||||||
|
const LIBRARIES: &[&str] = &[
|
||||||
|
"mfc140.dll",
|
||||||
|
"mfc140u.dll",
|
||||||
|
"mfcm140.dll",
|
||||||
|
"mfcm140u.dll"
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn is_installed(wine_prefix: impl AsRef<Path>) -> bool {
|
||||||
|
wine_prefix.as_ref().join("drive_c/windows/system32/mfc140.dll").exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn install(wine_prefix: impl AsRef<Path>) -> anyhow::Result<()> {
|
||||||
|
let vcredist = std::env::temp_dir().join("vcredist/vc_redist.x86.exe");
|
||||||
|
let vcredist_extracted = std::env::temp_dir().join("vcredist/extracted");
|
||||||
|
|
||||||
|
Downloader::new(URL)?
|
||||||
|
.with_continue_downloading(false)
|
||||||
|
.download(&vcredist, |_, _| {})?;
|
||||||
|
|
||||||
|
// w_try_cabextract --directory="${W_TMP}/win64" "${W_CACHE}"/vcrun2015/vc_redist.x64.exe -F 'a11'
|
||||||
|
let output = Command::new("cabextract")
|
||||||
|
.arg("-d")
|
||||||
|
.arg(&vcredist_extracted)
|
||||||
|
.arg(vcredist)
|
||||||
|
.arg("-F")
|
||||||
|
.arg("a11")
|
||||||
|
.spawn()?
|
||||||
|
.wait_with_output()?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
anyhow::bail!("Failed to extract vcrun2015 (1): {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// w_try_cabextract --directory="${W_TMP}/win64" "${W_TMP}/win64/a11"
|
||||||
|
let output = Command::new("cabextract")
|
||||||
|
.arg("-d")
|
||||||
|
.arg(&vcredist_extracted)
|
||||||
|
.arg(vcredist_extracted.join("a11"))
|
||||||
|
.arg("-F")
|
||||||
|
.arg("a11")
|
||||||
|
.spawn()?
|
||||||
|
.wait_with_output()?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
anyhow::bail!("Failed to extract vcrun2015 (2): {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// w_try_cp_dll "${W_TMP}/win64"/mfc140.dll "${W_SYSTEM64_DLLS}"/mfc140.dll
|
||||||
|
for lib in LIBRARIES {
|
||||||
|
let dest = wine_prefix.as_ref().join("drive_c/windows/system32").join(lib);
|
||||||
|
|
||||||
|
if dest.exists() {
|
||||||
|
std::fs::remove_file(&dest)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::copy(vcredist_extracted.join(lib), dest)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod loader;
|
pub mod loader;
|
||||||
pub mod wine;
|
pub mod wine;
|
||||||
pub mod dxvk;
|
pub mod dxvk;
|
||||||
|
pub mod mfc140;
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::process::{Child, Output};
|
|
||||||
use std::io::Result;
|
|
||||||
use std::ffi::OsStr;
|
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
use wincompatlib::prelude::*;
|
use wincompatlib::prelude::*;
|
||||||
|
|
||||||
use super::loader::ComponentsLoader;
|
use super::loader::ComponentsLoader;
|
||||||
|
|
||||||
|
mod unified_wine;
|
||||||
|
|
||||||
|
pub use unified_wine::UnifiedWine;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Group {
|
pub struct Group {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -224,7 +226,7 @@ impl Version {
|
||||||
/// Convert current wine struct to one from `wincompatlib`
|
/// Convert current wine struct to one from `wincompatlib`
|
||||||
///
|
///
|
||||||
/// `wine_folder` should point to the folder with wine binaries, so e.g. `/path/to/runners/wine-proton-ge-7.11`
|
/// `wine_folder` should point to the folder with wine binaries, so e.g. `/path/to/runners/wine-proton-ge-7.11`
|
||||||
pub fn to_wine<T: Into<PathBuf>>(&self, components: T, wine_folder: Option<T>) -> WincompatlibWine {
|
pub fn to_wine<T: Into<PathBuf>>(&self, components: T, wine_folder: Option<T>) -> UnifiedWine {
|
||||||
let wine_folder = wine_folder.map(|folder| folder.into()).unwrap_or_default();
|
let wine_folder = wine_folder.map(|folder| folder.into()).unwrap_or_default();
|
||||||
|
|
||||||
let (wine, arch) = match self.files.wine64.as_ref() {
|
let (wine, arch) = match self.files.wine64.as_ref() {
|
||||||
|
@ -253,18 +255,23 @@ impl Version {
|
||||||
// Small workaround. Most of stuff will work with just this
|
// Small workaround. Most of stuff will work with just this
|
||||||
proton.steam_client_path = Some(PathBuf::from(""));
|
proton.steam_client_path = Some(PathBuf::from(""));
|
||||||
|
|
||||||
return WincompatlibWine::Proton(proton);
|
return UnifiedWine::Proton(proton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WincompatlibWine::Default(Wine::new(
|
let mut wine = Wine::from_binary(wine_folder.join(wine))
|
||||||
wine_folder.join(wine),
|
.with_loader(WineLoader::Current)
|
||||||
None,
|
.with_arch(arch);
|
||||||
Some(arch),
|
|
||||||
wineboot,
|
if let Some(wineboot) = wineboot {
|
||||||
wineserver,
|
wine = wine.with_boot(wineboot);
|
||||||
WineLoader::Current
|
}
|
||||||
))
|
|
||||||
|
if let Some(wineserver) = wineserver {
|
||||||
|
wine = wine.with_server(wineserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
UnifiedWine::Default(wine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,161 +283,6 @@ pub struct Files {
|
||||||
pub wineboot: Option<String>
|
pub wineboot: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub enum WincompatlibWine {
|
|
||||||
Default(Wine),
|
|
||||||
Proton(Proton)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Wine> for WincompatlibWine {
|
|
||||||
#[inline]
|
|
||||||
fn from(wine: Wine) -> Self {
|
|
||||||
Self::Default(wine)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Proton> for WincompatlibWine {
|
|
||||||
#[inline]
|
|
||||||
fn from(proton: Proton) -> Self {
|
|
||||||
Self::Proton(proton)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WineWithExt for WincompatlibWine {
|
|
||||||
#[inline]
|
|
||||||
fn with_prefix<T: Into<PathBuf>>(self, prefix: T) -> Self {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => Self::Default(wine.with_prefix(prefix)),
|
|
||||||
Self::Proton(proton) => Self::Proton(proton.with_prefix(prefix))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_arch(self, arch: WineArch) -> Self {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => Self::Default(wine.with_arch(arch)),
|
|
||||||
Self::Proton(proton) => Self::Proton(proton.with_arch(arch))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_boot(self, boot: WineBoot) -> Self {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => Self::Default(wine.with_boot(boot)),
|
|
||||||
Self::Proton(proton) => Self::Proton(proton.with_boot(boot))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_server<T: Into<PathBuf>>(self, server: T) -> Self {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => Self::Default(wine.with_server(server)),
|
|
||||||
Self::Proton(proton) => Self::Proton(proton.with_server(server))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_loader(self, loader: WineLoader) -> Self {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => Self::Default(wine.with_loader(loader)),
|
|
||||||
Self::Proton(proton) => Self::Proton(proton.with_loader(loader))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WineBootExt for WincompatlibWine {
|
|
||||||
#[inline]
|
|
||||||
fn wineboot_command(&self) -> std::process::Command {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => wine.wineboot_command(),
|
|
||||||
Self::Proton(proton) => proton.wineboot_command()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn update_prefix<T: Into<PathBuf>>(&self, path: Option<T>) -> Result<Output> {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => wine.update_prefix(path),
|
|
||||||
Self::Proton(proton) => proton.update_prefix(path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn stop_processes(&self, force: bool) -> Result<Output> {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => wine.stop_processes(force),
|
|
||||||
Self::Proton(proton) => proton.stop_processes(force)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn restart(&self) -> Result<Output> {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => wine.restart(),
|
|
||||||
Self::Proton(proton) => proton.restart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn shutdown(&self) -> Result<Output> {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => wine.shutdown(),
|
|
||||||
Self::Proton(proton) => proton.shutdown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn end_session(&self) -> Result<Output> {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => wine.end_session(),
|
|
||||||
Self::Proton(proton) => proton.end_session()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WineRunExt for WincompatlibWine {
|
|
||||||
#[inline]
|
|
||||||
fn run<T: AsRef<OsStr>>(&self, binary: T) -> Result<Child> {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => wine.run(binary),
|
|
||||||
Self::Proton(proton) => proton.run(binary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn run_args<T, S>(&self, args: T) -> Result<Child>
|
|
||||||
where
|
|
||||||
T: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => wine.run_args(args),
|
|
||||||
Self::Proton(proton) => proton.run_args(args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn run_args_with_env<T, K, S>(&self, args: T, envs: K) -> Result<Child>
|
|
||||||
where
|
|
||||||
T: IntoIterator<Item = S>,
|
|
||||||
K: IntoIterator<Item = (S, S)>,
|
|
||||||
S: AsRef<OsStr>
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => wine.run_args_with_env(args, envs),
|
|
||||||
Self::Proton(proton) => proton.run_args_with_env(args, envs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn winepath(&self, path: &str) -> Result<PathBuf> {
|
|
||||||
match self {
|
|
||||||
Self::Default(wine) => wine.winepath(path),
|
|
||||||
Self::Proton(proton) => proton.winepath(path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_groups<T: Into<PathBuf>>(components: T) -> anyhow::Result<Vec<Group>> {
|
pub fn get_groups<T: Into<PathBuf>>(components: T) -> anyhow::Result<Vec<Group>> {
|
||||||
ComponentsLoader::new(components).get_wine_versions()
|
ComponentsLoader::new(components).get_wine_versions()
|
240
src/components/wine/unified_wine.rs
Normal file
240
src/components/wine/unified_wine.rs
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::{Output, Child};
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
|
use wincompatlib::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum UnifiedWine {
|
||||||
|
Default(Wine),
|
||||||
|
Proton(Proton)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Wine> for UnifiedWine {
|
||||||
|
#[inline]
|
||||||
|
fn from(wine: Wine) -> Self {
|
||||||
|
Self::Default(wine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Proton> for UnifiedWine {
|
||||||
|
#[inline]
|
||||||
|
fn from(proton: Proton) -> Self {
|
||||||
|
Self::Proton(proton)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UnifiedWine> for Wine {
|
||||||
|
fn from(wine: UnifiedWine) -> Self {
|
||||||
|
match wine {
|
||||||
|
UnifiedWine::Default(wine) => wine,
|
||||||
|
|
||||||
|
// Kind of unsafe but who cares?
|
||||||
|
// I don't like proton anyway lol
|
||||||
|
UnifiedWine::Proton(proton) => proton.wine().to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WineWithExt for UnifiedWine {
|
||||||
|
#[inline]
|
||||||
|
fn with_prefix<T: Into<PathBuf>>(self, prefix: T) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => Self::Default(wine.with_prefix(prefix)),
|
||||||
|
Self::Proton(proton) => Self::Proton(proton.with_prefix(prefix))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_arch(self, arch: WineArch) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => Self::Default(wine.with_arch(arch)),
|
||||||
|
Self::Proton(proton) => Self::Proton(proton.with_arch(arch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_boot(self, boot: WineBoot) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => Self::Default(wine.with_boot(boot)),
|
||||||
|
Self::Proton(proton) => Self::Proton(proton.with_boot(boot))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_server<T: Into<PathBuf>>(self, server: T) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => Self::Default(wine.with_server(server)),
|
||||||
|
Self::Proton(proton) => Self::Proton(proton.with_server(server))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_loader(self, loader: WineLoader) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => Self::Default(wine.with_loader(loader)),
|
||||||
|
Self::Proton(proton) => Self::Proton(proton.with_loader(loader))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_wine_libs(self, wine_libs: WineSharedLibs) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => Self::Default(wine.with_wine_libs(wine_libs)),
|
||||||
|
Self::Proton(proton) => Self::Proton(proton.with_wine_libs(wine_libs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_gstreamer_libs(self, gstreamer_libs: GstreamerSharedLibs) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => Self::Default(wine.with_gstreamer_libs(gstreamer_libs)),
|
||||||
|
Self::Proton(proton) => Self::Proton(proton.with_gstreamer_libs(gstreamer_libs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WineBootExt for UnifiedWine {
|
||||||
|
#[inline]
|
||||||
|
fn wineboot_command(&self) -> std::process::Command {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.wineboot_command(),
|
||||||
|
Self::Proton(proton) => proton.wineboot_command()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn init_prefix(&self, path: Option<impl Into<PathBuf>>) -> anyhow::Result<Output> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.init_prefix(path),
|
||||||
|
Self::Proton(proton) => proton.init_prefix(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn update_prefix(&self, path: Option<impl Into<PathBuf>>) -> anyhow::Result<Output> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.update_prefix(path),
|
||||||
|
Self::Proton(proton) => proton.update_prefix(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn stop_processes(&self, force: bool) -> anyhow::Result<Output> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.stop_processes(force),
|
||||||
|
Self::Proton(proton) => proton.stop_processes(force)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn restart(&self) -> anyhow::Result<Output> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.restart(),
|
||||||
|
Self::Proton(proton) => proton.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn shutdown(&self) -> anyhow::Result<Output> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.shutdown(),
|
||||||
|
Self::Proton(proton) => proton.shutdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn end_session(&self) -> anyhow::Result<Output> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.end_session(),
|
||||||
|
Self::Proton(proton) => proton.end_session()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WineRunExt for UnifiedWine {
|
||||||
|
#[inline]
|
||||||
|
fn run<T: AsRef<OsStr>>(&self, binary: T) -> anyhow::Result<Child> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.run(binary),
|
||||||
|
Self::Proton(proton) => proton.run(binary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn run_args<T, S>(&self, args: T) -> anyhow::Result<Child>
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = S>,
|
||||||
|
S: AsRef<OsStr>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.run_args(args),
|
||||||
|
Self::Proton(proton) => proton.run_args(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn run_args_with_env<T, K, S>(&self, args: T, envs: K) -> anyhow::Result<Child>
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = S>,
|
||||||
|
K: IntoIterator<Item = (S, S)>,
|
||||||
|
S: AsRef<OsStr>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.run_args_with_env(args, envs),
|
||||||
|
Self::Proton(proton) => proton.run_args_with_env(args, envs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn winepath(&self, path: &str) -> anyhow::Result<PathBuf> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.winepath(path),
|
||||||
|
Self::Proton(proton) => proton.winepath(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WineOverridesExt for UnifiedWine {
|
||||||
|
#[inline]
|
||||||
|
fn add_override(&self, dll_name: impl AsRef<str>, modes: impl IntoIterator<Item = OverrideMode>) -> anyhow::Result<()> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.add_override(dll_name, modes),
|
||||||
|
Self::Proton(proton) => proton.add_override(dll_name, modes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn delete_override(&self, dll_name: impl AsRef<str>) -> anyhow::Result<()> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.delete_override(dll_name),
|
||||||
|
Self::Proton(proton) => proton.delete_override(dll_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WineFontsExt for UnifiedWine {
|
||||||
|
#[inline]
|
||||||
|
fn register_font(&self, ttf: impl AsRef<str>, font_name: impl AsRef<str>) -> anyhow::Result<()> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.register_font(ttf, font_name),
|
||||||
|
Self::Proton(proton) => proton.register_font(ttf, font_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn font_is_installed(&self, ttf: impl AsRef<str>) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.font_is_installed(ttf),
|
||||||
|
Self::Proton(proton) => proton.font_is_installed(ttf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn install_corefont(&self, corefont: Corefont) -> anyhow::Result<()> {
|
||||||
|
match self {
|
||||||
|
Self::Default(wine) => wine.install_corefont(corefont),
|
||||||
|
Self::Proton(proton) => proton.install_corefont(corefont)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ use crate::config::schema_blanks::sandbox::Sandbox;
|
||||||
#[cfg(feature = "components")]
|
#[cfg(feature = "components")]
|
||||||
use crate::components::{
|
use crate::components::{
|
||||||
wine::{
|
wine::{
|
||||||
WincompatlibWine,
|
UnifiedWine,
|
||||||
Version as WineVersion
|
Version as WineVersion
|
||||||
},
|
},
|
||||||
dxvk::Version as DxvkVersion
|
dxvk::Version as DxvkVersion
|
||||||
|
@ -118,13 +118,11 @@ impl Schema {
|
||||||
.with_prefix(&self.game.wine.prefix);
|
.with_prefix(&self.game.wine.prefix);
|
||||||
|
|
||||||
let prefix = match wine {
|
let prefix = match wine {
|
||||||
WincompatlibWine::Default(wine) => wine.prefix,
|
UnifiedWine::Default(wine) => wine.prefix,
|
||||||
WincompatlibWine::Proton(proton) => proton.wine().prefix.clone()
|
UnifiedWine::Proton(proton) => proton.wine().prefix.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(prefix) = prefix {
|
return prefix;
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.game.wine.prefix.clone()
|
self.game.wine.prefix.clone()
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
use anime_game_core::prelude::*;
|
use anime_game_core::prelude::*;
|
||||||
use anime_game_core::genshin::prelude::*;
|
use anime_game_core::genshin::prelude::*;
|
||||||
|
|
||||||
use crate::config::ConfigExt;
|
use crate::config::ConfigExt;
|
||||||
use crate::genshin::config::Config;
|
use crate::genshin::config::Config;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LauncherState {
|
pub enum LauncherState {
|
||||||
Launch,
|
Launch,
|
||||||
|
|
||||||
|
@ -51,7 +49,7 @@ pub enum LauncherState {
|
||||||
GameNotInstalled(VersionDiff)
|
GameNotInstalled(VersionDiff)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum StateUpdating {
|
pub enum StateUpdating {
|
||||||
Game,
|
Game,
|
||||||
Voice(VoiceLocale),
|
Voice(VoiceLocale),
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::config::schema_blanks::sandbox::Sandbox;
|
||||||
#[cfg(feature = "components")]
|
#[cfg(feature = "components")]
|
||||||
use crate::components::{
|
use crate::components::{
|
||||||
wine::{
|
wine::{
|
||||||
WincompatlibWine,
|
UnifiedWine,
|
||||||
Version as WineVersion
|
Version as WineVersion
|
||||||
},
|
},
|
||||||
dxvk::Version as DxvkVersion
|
dxvk::Version as DxvkVersion
|
||||||
|
@ -118,13 +118,11 @@ impl Schema {
|
||||||
.with_prefix(&self.game.wine.prefix);
|
.with_prefix(&self.game.wine.prefix);
|
||||||
|
|
||||||
let prefix = match wine {
|
let prefix = match wine {
|
||||||
WincompatlibWine::Default(wine) => wine.prefix,
|
UnifiedWine::Default(wine) => wine.prefix,
|
||||||
WincompatlibWine::Proton(proton) => proton.wine().prefix.clone()
|
UnifiedWine::Proton(proton) => proton.wine().prefix.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(prefix) = prefix {
|
return prefix;
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.game.wine.prefix.clone()
|
self.game.wine.prefix.clone()
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
use anime_game_core::prelude::*;
|
use anime_game_core::prelude::*;
|
||||||
use anime_game_core::honkai::prelude::*;
|
use anime_game_core::honkai::prelude::*;
|
||||||
|
|
||||||
use crate::config::ConfigExt;
|
use crate::config::ConfigExt;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LauncherState {
|
pub enum LauncherState {
|
||||||
Launch,
|
Launch,
|
||||||
|
|
||||||
|
@ -26,7 +24,7 @@ pub enum LauncherState {
|
||||||
GameNotInstalled(VersionDiff)
|
GameNotInstalled(VersionDiff)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum StateUpdating {
|
pub enum StateUpdating {
|
||||||
Game,
|
Game,
|
||||||
Patch
|
Patch
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::config::schema_blanks::sandbox::Sandbox;
|
||||||
#[cfg(feature = "components")]
|
#[cfg(feature = "components")]
|
||||||
use crate::components::{
|
use crate::components::{
|
||||||
wine::{
|
wine::{
|
||||||
WincompatlibWine,
|
UnifiedWine,
|
||||||
Version as WineVersion
|
Version as WineVersion
|
||||||
},
|
},
|
||||||
dxvk::Version as DxvkVersion
|
dxvk::Version as DxvkVersion
|
||||||
|
@ -109,13 +109,11 @@ impl Schema {
|
||||||
.with_prefix(&self.game.wine.prefix);
|
.with_prefix(&self.game.wine.prefix);
|
||||||
|
|
||||||
let prefix = match wine {
|
let prefix = match wine {
|
||||||
WincompatlibWine::Default(wine) => wine.prefix,
|
UnifiedWine::Default(wine) => wine.prefix,
|
||||||
WincompatlibWine::Proton(proton) => proton.wine().prefix.clone()
|
UnifiedWine::Proton(proton) => proton.wine().prefix.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(prefix) = prefix {
|
return prefix;
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.game.wine.prefix.clone()
|
self.game.wine.prefix.clone()
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use wincompatlib::wine::ext::Corefont;
|
||||||
|
|
||||||
use anime_game_core::prelude::*;
|
use anime_game_core::prelude::*;
|
||||||
use anime_game_core::pgr::prelude::*;
|
use anime_game_core::pgr::prelude::*;
|
||||||
|
|
||||||
use crate::config::ConfigExt;
|
use crate::config::ConfigExt;
|
||||||
|
use crate::components::mfc140;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LauncherState {
|
pub enum LauncherState {
|
||||||
Launch,
|
Launch,
|
||||||
|
|
||||||
|
@ -16,6 +17,9 @@ pub enum LauncherState {
|
||||||
|
|
||||||
PrefixNotExists,
|
PrefixNotExists,
|
||||||
|
|
||||||
|
Mfc140NotInstalled,
|
||||||
|
CorefontsNotInstalled(Vec<Corefont>),
|
||||||
|
|
||||||
// Always contains `VersionDiff::Diff`
|
// Always contains `VersionDiff::Diff`
|
||||||
GameUpdateAvailable(VersionDiff),
|
GameUpdateAvailable(VersionDiff),
|
||||||
|
|
||||||
|
@ -23,8 +27,9 @@ pub enum LauncherState {
|
||||||
GameNotInstalled(VersionDiff)
|
GameNotInstalled(VersionDiff)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum StateUpdating {
|
pub enum StateUpdating {
|
||||||
|
Components,
|
||||||
Game
|
Game
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +50,25 @@ impl LauncherState {
|
||||||
return Ok(Self::PrefixNotExists);
|
return Ok(Self::PrefixNotExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check wine components installation status
|
||||||
|
(params.status_updater)(StateUpdating::Components);
|
||||||
|
|
||||||
|
if !mfc140::is_installed(¶ms.wine_prefix) {
|
||||||
|
return Ok(Self::Mfc140NotInstalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut corefonts = Vec::new();
|
||||||
|
|
||||||
|
for font in Corefont::iterator() {
|
||||||
|
if !font.is_installed(¶ms.wine_prefix) {
|
||||||
|
corefonts.push(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !corefonts.is_empty() {
|
||||||
|
return Ok(Self::CorefontsNotInstalled(corefonts));
|
||||||
|
}
|
||||||
|
|
||||||
// Check game installation status
|
// Check game installation status
|
||||||
(params.status_updater)(StateUpdating::Game);
|
(params.status_updater)(StateUpdating::Game);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::config::schema_blanks::sandbox::Sandbox;
|
||||||
#[cfg(feature = "components")]
|
#[cfg(feature = "components")]
|
||||||
use crate::components::{
|
use crate::components::{
|
||||||
wine::{
|
wine::{
|
||||||
WincompatlibWine,
|
UnifiedWine,
|
||||||
Version as WineVersion
|
Version as WineVersion
|
||||||
},
|
},
|
||||||
dxvk::Version as DxvkVersion
|
dxvk::Version as DxvkVersion
|
||||||
|
@ -118,13 +118,11 @@ impl Schema {
|
||||||
.with_prefix(&self.game.wine.prefix);
|
.with_prefix(&self.game.wine.prefix);
|
||||||
|
|
||||||
let prefix = match wine {
|
let prefix = match wine {
|
||||||
WincompatlibWine::Default(wine) => wine.prefix,
|
UnifiedWine::Default(wine) => wine.prefix,
|
||||||
WincompatlibWine::Proton(proton) => proton.wine().prefix.clone()
|
UnifiedWine::Proton(proton) => proton.wine().prefix.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(prefix) = prefix {
|
return prefix;
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.game.wine.prefix.clone()
|
self.game.wine.prefix.clone()
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
use anime_game_core::prelude::*;
|
use anime_game_core::prelude::*;
|
||||||
use anime_game_core::star_rail::prelude::*;
|
use anime_game_core::star_rail::prelude::*;
|
||||||
|
|
||||||
use crate::config::ConfigExt;
|
use crate::config::ConfigExt;
|
||||||
use crate::star_rail::config::Config;
|
use crate::star_rail::config::Config;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LauncherState {
|
pub enum LauncherState {
|
||||||
Launch,
|
Launch,
|
||||||
|
|
||||||
|
@ -32,7 +30,7 @@ pub enum LauncherState {
|
||||||
GameNotInstalled(VersionDiff)
|
GameNotInstalled(VersionDiff)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum StateUpdating {
|
pub enum StateUpdating {
|
||||||
Game,
|
Game,
|
||||||
Patch
|
Patch
|
||||||
|
|
Loading…
Reference in a new issue