feat: added wine drives feature
This commit is contained in:
parent
cd76037015
commit
7c85637bc3
6 changed files with 225 additions and 0 deletions
|
@ -1,9 +1,12 @@
|
||||||
pub mod wine_lang;
|
pub mod wine_lang;
|
||||||
pub mod wine_sync;
|
pub mod wine_sync;
|
||||||
|
pub mod wine_drives;
|
||||||
pub mod virtual_desktop;
|
pub mod virtual_desktop;
|
||||||
pub mod shared_libraries;
|
pub mod shared_libraries;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
|
pub use super::wine_drives::*;
|
||||||
|
|
||||||
pub use super::wine_lang::WineLang;
|
pub use super::wine_lang::WineLang;
|
||||||
pub use super::wine_sync::WineSync;
|
pub use super::wine_sync::WineSync;
|
||||||
pub use super::virtual_desktop::VirtualDesktop;
|
pub use super::virtual_desktop::VirtualDesktop;
|
||||||
|
@ -21,6 +24,7 @@ macro_rules! config_impl_wine_schema {
|
||||||
pub sync: WineSync,
|
pub sync: WineSync,
|
||||||
pub language: WineLang,
|
pub language: WineLang,
|
||||||
pub borderless: bool,
|
pub borderless: bool,
|
||||||
|
pub drives: WineDrives,
|
||||||
pub virtual_desktop: VirtualDesktop,
|
pub virtual_desktop: VirtualDesktop,
|
||||||
pub shared_libraries: SharedLibraries
|
pub shared_libraries: SharedLibraries
|
||||||
}
|
}
|
||||||
|
@ -37,6 +41,7 @@ macro_rules! config_impl_wine_schema {
|
||||||
sync: WineSync::default(),
|
sync: WineSync::default(),
|
||||||
language: WineLang::default(),
|
language: WineLang::default(),
|
||||||
borderless: false,
|
borderless: false,
|
||||||
|
drives: WineDrives::default(),
|
||||||
virtual_desktop: VirtualDesktop::default(),
|
virtual_desktop: VirtualDesktop::default(),
|
||||||
shared_libraries: SharedLibraries::default()
|
shared_libraries: SharedLibraries::default()
|
||||||
}
|
}
|
||||||
|
@ -84,6 +89,10 @@ macro_rules! config_impl_wine_schema {
|
||||||
.and_then(|value| value.as_bool())
|
.and_then(|value| value.as_bool())
|
||||||
.unwrap_or(default.borderless),
|
.unwrap_or(default.borderless),
|
||||||
|
|
||||||
|
drives: value.get("drives")
|
||||||
|
.map(WineDrives::from)
|
||||||
|
.unwrap_or(default.drives),
|
||||||
|
|
||||||
virtual_desktop: value.get("virtual_desktop")
|
virtual_desktop: value.get("virtual_desktop")
|
||||||
.map(VirtualDesktop::from)
|
.map(VirtualDesktop::from)
|
||||||
.unwrap_or(default.virtual_desktop),
|
.unwrap_or(default.virtual_desktop),
|
||||||
|
|
156
src/config/schema_blanks/wine/wine_drives.rs
Normal file
156
src/config/schema_blanks/wine/wine_drives.rs
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
pub enum AllowedDrives {
|
||||||
|
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
||||||
|
N, O, P, Q, R, S, T, U, V, W, X, Y, Z
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AllowedDrives {
|
||||||
|
#[inline]
|
||||||
|
pub fn list() -> &'static [Self] {
|
||||||
|
&[
|
||||||
|
Self::A, Self::B, Self::C, Self::D, Self::E, Self::F, Self::G, Self::H, Self::I, Self::J, Self::K, Self::L, Self::M,
|
||||||
|
Self::N, Self::O, Self::P, Self::Q, Self::R, Self::S, Self::T, Self::U, Self::V, Self::W, Self::X, Self::Y, Self::Z
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get unix drive name
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// assert_eq!(AllowedDrives::F, "f:");
|
||||||
|
/// ```
|
||||||
|
pub fn to_drive(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::A => "a:",
|
||||||
|
Self::B => "b:",
|
||||||
|
Self::C => "c:",
|
||||||
|
Self::D => "d:",
|
||||||
|
Self::E => "e:",
|
||||||
|
Self::F => "f:",
|
||||||
|
Self::G => "g:",
|
||||||
|
Self::H => "h:",
|
||||||
|
Self::I => "i:",
|
||||||
|
Self::J => "j:",
|
||||||
|
Self::K => "k:",
|
||||||
|
Self::L => "l:",
|
||||||
|
Self::M => "m:",
|
||||||
|
Self::N => "n:",
|
||||||
|
Self::O => "o:",
|
||||||
|
Self::P => "p:",
|
||||||
|
Self::Q => "q:",
|
||||||
|
Self::R => "r:",
|
||||||
|
Self::S => "s:",
|
||||||
|
Self::T => "t:",
|
||||||
|
Self::U => "u:",
|
||||||
|
Self::V => "v:",
|
||||||
|
Self::W => "w:",
|
||||||
|
Self::X => "x:",
|
||||||
|
Self::Y => "y:",
|
||||||
|
Self::Z => "z:"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct WineDrives {
|
||||||
|
/// Symlink prefix's `drive_c` folder to the `c:` folder in the `dosdevices`
|
||||||
|
pub drive_c: bool,
|
||||||
|
|
||||||
|
/// If `Some`, then symlink game folder to the given folder in the `dosdevices`
|
||||||
|
pub game_folder: Option<AllowedDrives>,
|
||||||
|
|
||||||
|
/// Symlink paths to the given letters in the `dosdevices`
|
||||||
|
pub map_folders: HashMap<AllowedDrives, PathBuf>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WineDrives {
|
||||||
|
/// Automatically map all the configured folders
|
||||||
|
pub fn map_folders(&self, game_folder: impl Into<PathBuf>, prefix_folder: impl Into<PathBuf>) -> anyhow::Result<()> {
|
||||||
|
let mut drives = self.map_folders.clone();
|
||||||
|
|
||||||
|
let game_folder = game_folder.into();
|
||||||
|
let prefix_folder = prefix_folder.into();
|
||||||
|
|
||||||
|
if self.drive_c {
|
||||||
|
drives.insert(AllowedDrives::C, prefix_folder.join("drive_c"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(drive) = self.game_folder {
|
||||||
|
drives.insert(drive, game_folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (drive, path) in drives {
|
||||||
|
Self::map_folder(&prefix_folder, drive, path)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Map specific folder
|
||||||
|
pub fn map_folder(prefix_folder: impl AsRef<Path>, drive: AllowedDrives, symlink_folder: impl AsRef<Path>) -> anyhow::Result<()> {
|
||||||
|
let drive_folder = prefix_folder.as_ref()
|
||||||
|
.join("dosdevices")
|
||||||
|
.join(drive.to_drive());
|
||||||
|
|
||||||
|
if drive_folder.exists() {
|
||||||
|
std::fs::remove_file(&drive_folder)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::os::unix::fs::symlink(symlink_folder.as_ref(), drive_folder)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for WineDrives {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
drive_c: true,
|
||||||
|
game_folder: Some(AllowedDrives::G),
|
||||||
|
map_folders: HashMap::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&JsonValue> for WineDrives {
|
||||||
|
fn from(value: &JsonValue) -> Self {
|
||||||
|
let default = Self::default();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
drive_c: value.get("drive_c")
|
||||||
|
.and_then(JsonValue::as_bool)
|
||||||
|
.unwrap_or(default.drive_c),
|
||||||
|
|
||||||
|
game_folder: value.get("game_folder")
|
||||||
|
.and_then(|value| serde_json::from_value(value.clone()).ok())
|
||||||
|
.unwrap_or(default.game_folder),
|
||||||
|
|
||||||
|
map_folders: match value.get("map_folders") {
|
||||||
|
Some(value) => match value.as_object() {
|
||||||
|
Some(values) => {
|
||||||
|
let mut drives = HashMap::new();
|
||||||
|
|
||||||
|
for (drive, path) in values {
|
||||||
|
let drive = serde_json::from_str::<AllowedDrives>(drive);
|
||||||
|
let path = path.as_str();
|
||||||
|
|
||||||
|
if let (Ok(drive), Some(path)) = (drive, path) {
|
||||||
|
drives.insert(drive, PathBuf::from(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drives
|
||||||
|
},
|
||||||
|
None => default.map_folders
|
||||||
|
},
|
||||||
|
None => default.map_folders
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,11 @@ use crate::components::wine::Bundle as WineBundle;
|
||||||
use crate::config::ConfigExt;
|
use crate::config::ConfigExt;
|
||||||
use crate::genshin::config::Config;
|
use crate::genshin::config::Config;
|
||||||
|
|
||||||
|
use crate::config::schema_blanks::prelude::{
|
||||||
|
WineDrives,
|
||||||
|
AllowedDrives
|
||||||
|
};
|
||||||
|
|
||||||
use crate::genshin::consts;
|
use crate::genshin::consts;
|
||||||
|
|
||||||
#[cfg(feature = "fps-unlocker")]
|
#[cfg(feature = "fps-unlocker")]
|
||||||
|
@ -131,6 +136,16 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare wine prefix drives
|
||||||
|
|
||||||
|
config.game.wine.drives.map_folders(&folders.game, &folders.prefix)?;
|
||||||
|
|
||||||
|
// Workaround for sandboxing feature
|
||||||
|
if config.sandbox.enabled {
|
||||||
|
WineDrives::map_folder(&folders.prefix, AllowedDrives::C, "../drive_c")?;
|
||||||
|
WineDrives::map_folder(&folders.prefix, AllowedDrives::Z, "/")?;
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare bash -c '<command>'
|
// Prepare bash -c '<command>'
|
||||||
// %command% = %bash_command% %windows_command% %launch_args%
|
// %command% = %bash_command% %windows_command% %launch_args%
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,11 @@ use crate::components::wine::Bundle as WineBundle;
|
||||||
use crate::config::ConfigExt;
|
use crate::config::ConfigExt;
|
||||||
use crate::honkai::config::Config;
|
use crate::honkai::config::Config;
|
||||||
|
|
||||||
|
use crate::config::schema_blanks::prelude::{
|
||||||
|
WineDrives,
|
||||||
|
AllowedDrives
|
||||||
|
};
|
||||||
|
|
||||||
use crate::honkai::consts;
|
use crate::honkai::consts;
|
||||||
|
|
||||||
#[cfg(feature = "discord-rpc")]
|
#[cfg(feature = "discord-rpc")]
|
||||||
|
@ -74,6 +79,16 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
return Err(anyhow::anyhow!("Telemetry server is not disabled: {server}"));
|
return Err(anyhow::anyhow!("Telemetry server is not disabled: {server}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare wine prefix drives
|
||||||
|
|
||||||
|
config.game.wine.drives.map_folders(&folders.game, &folders.prefix)?;
|
||||||
|
|
||||||
|
// Workaround for sandboxing feature
|
||||||
|
if config.sandbox.enabled {
|
||||||
|
WineDrives::map_folder(&folders.prefix, AllowedDrives::C, "../drive_c")?;
|
||||||
|
WineDrives::map_folder(&folders.prefix, AllowedDrives::Z, "/")?;
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare bash -c '<command>'
|
// Prepare bash -c '<command>'
|
||||||
// %command% = %bash_command% %windows_command% %launch_args%
|
// %command% = %bash_command% %windows_command% %launch_args%
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,11 @@ use crate::components::wine::Bundle as WineBundle;
|
||||||
use crate::config::ConfigExt;
|
use crate::config::ConfigExt;
|
||||||
use crate::pgr::config::Config;
|
use crate::pgr::config::Config;
|
||||||
|
|
||||||
|
use crate::config::schema_blanks::prelude::{
|
||||||
|
WineDrives,
|
||||||
|
AllowedDrives
|
||||||
|
};
|
||||||
|
|
||||||
use crate::pgr::consts;
|
use crate::pgr::consts;
|
||||||
|
|
||||||
#[cfg(feature = "discord-rpc")]
|
#[cfg(feature = "discord-rpc")]
|
||||||
|
@ -70,6 +75,16 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
return Err(anyhow::anyhow!("Telemetry server is not disabled: {server}"));
|
return Err(anyhow::anyhow!("Telemetry server is not disabled: {server}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare wine prefix drives
|
||||||
|
|
||||||
|
config.game.wine.drives.map_folders(&folders.game, &folders.prefix)?;
|
||||||
|
|
||||||
|
// Workaround for sandboxing feature
|
||||||
|
if config.sandbox.enabled {
|
||||||
|
WineDrives::map_folder(&folders.prefix, AllowedDrives::C, "../drive_c")?;
|
||||||
|
WineDrives::map_folder(&folders.prefix, AllowedDrives::Z, "/")?;
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare bash -c '<command>'
|
// Prepare bash -c '<command>'
|
||||||
// %command% = %bash_command% %windows_command% %launch_args%
|
// %command% = %bash_command% %windows_command% %launch_args%
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,11 @@ use crate::components::wine::Bundle as WineBundle;
|
||||||
use crate::config::ConfigExt;
|
use crate::config::ConfigExt;
|
||||||
use crate::star_rail::config::Config;
|
use crate::star_rail::config::Config;
|
||||||
|
|
||||||
|
use crate::config::schema_blanks::prelude::{
|
||||||
|
WineDrives,
|
||||||
|
AllowedDrives
|
||||||
|
};
|
||||||
|
|
||||||
use crate::star_rail::consts;
|
use crate::star_rail::consts;
|
||||||
|
|
||||||
#[cfg(feature = "discord-rpc")]
|
#[cfg(feature = "discord-rpc")]
|
||||||
|
@ -74,6 +79,16 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
return Err(anyhow::anyhow!("Telemetry server is not disabled: {server}"));
|
return Err(anyhow::anyhow!("Telemetry server is not disabled: {server}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare wine prefix drives
|
||||||
|
|
||||||
|
config.game.wine.drives.map_folders(&folders.game, &folders.prefix)?;
|
||||||
|
|
||||||
|
// Workaround for sandboxing feature
|
||||||
|
if config.sandbox.enabled {
|
||||||
|
WineDrives::map_folder(&folders.prefix, AllowedDrives::C, "../drive_c")?;
|
||||||
|
WineDrives::map_folder(&folders.prefix, AllowedDrives::Z, "/")?;
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare bash -c '<command>'
|
// Prepare bash -c '<command>'
|
||||||
// %command% = %bash_command% %windows_command% %launch_args%
|
// %command% = %bash_command% %windows_command% %launch_args%
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue