From e685cf757ddb92cf3a7c48f4b0758a5c127c8c5d Mon Sep 17 00:00:00 2001 From: Gabriele Musco Date: Wed, 4 Dec 2024 20:32:36 +0100 Subject: [PATCH] feat!: enable support for different openvr compatibility modules other than opencomposite --- src/builders/build_opencomposite.rs | 12 +-- src/config.rs | 36 +++++++- src/file_builders/openvrpaths_vrpath.rs | 2 +- src/profile.rs | 114 ++++++++++++++++++++++-- src/profiles/lighthouse.rs | 10 ++- src/profiles/openhmd.rs | 7 +- src/profiles/simulated.rs | 7 +- src/profiles/survive.rs | 7 +- src/profiles/wivrn.rs | 10 ++- src/profiles/wmr.rs | 7 +- src/ui/app.rs | 8 +- src/ui/profile_editor.rs | 38 +++++--- test/files/profile.json | 6 +- 13 files changed, 219 insertions(+), 45 deletions(-) diff --git a/src/builders/build_opencomposite.rs b/src/builders/build_opencomposite.rs index 631b69f..cca52e7 100644 --- a/src/builders/build_opencomposite.rs +++ b/src/builders/build_opencomposite.rs @@ -19,13 +19,15 @@ pub fn get_build_opencomposite_jobs(profile: &Profile, clean_build: bool) -> Vec let git = Git { repo: profile - .opencomposite_repo + .ovr_comp + .repo .as_ref() .unwrap_or(&"https://gitlab.com/znixian/OpenOVR.git".into()) .clone(), - dir: profile.opencomposite_path.clone(), + dir: profile.ovr_comp.path.clone(), branch: profile - .opencomposite_branch + .ovr_comp + .branch .as_ref() .unwrap_or(&"openxr".into()) .clone(), @@ -33,14 +35,14 @@ pub fn get_build_opencomposite_jobs(profile: &Profile, clean_build: bool) -> Vec jobs.extend(git.get_pre_build_jobs(profile.pull_on_build)); - let build_dir = profile.opencomposite_path.join("build"); + let build_dir = profile.ovr_comp.path.join("build"); let mut cmake_vars: HashMap = HashMap::new(); cmake_vars.insert("CMAKE_EXPORT_COMPILE_COMMANDS".into(), "ON".into()); cmake_vars.insert("CMAKE_BUILD_TYPE".into(), "RelWithDebInfo".into()); let cmake = Cmake { env: None, vars: Some(cmake_vars), - source_dir: profile.opencomposite_path.clone(), + source_dir: profile.ovr_comp.path.clone(), build_dir: build_dir.clone(), }; if !Path::new(&build_dir).is_dir() || clean_build { diff --git a/src/config.rs b/src/config.rs index 1ee2430..a35dd93 100644 --- a/src/config.rs +++ b/src/config.rs @@ -65,10 +65,42 @@ impl Config { } fn from_path(path: &Path) -> Self { - File::open(path) + let mut this: Self = File::open(path) .ok() .and_then(|file| serde_json::from_reader(BufReader::new(file)).ok()) - .unwrap_or_default() + .unwrap_or_default(); + + let mut needs_save = false; + + // remap legacy opencomposite data to new ovr_comp + #[allow(deprecated)] + for prof in this.user_profiles.iter_mut() { + if prof + .ovr_comp + .path + .file_name() + .unwrap_or_default() + .to_string_lossy() + == "__envision__fallbackovrcomp" + { + prof.ovr_comp.path = prof.opencomposite_path.clone(); + needs_save = true; + } + if prof.opencomposite_repo.is_some() && prof.ovr_comp.repo.is_none() { + prof.ovr_comp.repo = prof.opencomposite_repo.take(); + needs_save = true; + } + if prof.opencomposite_branch.is_some() && prof.ovr_comp.branch.is_none() { + prof.ovr_comp.branch = prof.opencomposite_branch.take(); + needs_save = true; + } + } + + if needs_save { + this.save_to_path(path).expect("Failed to save config"); + } + + this } fn save_to_path(&self, path: &Path) -> Result<(), serde_json::Error> { diff --git a/src/file_builders/openvrpaths_vrpath.rs b/src/file_builders/openvrpaths_vrpath.rs index 1108717..773902c 100644 --- a/src/file_builders/openvrpaths_vrpath.rs +++ b/src/file_builders/openvrpaths_vrpath.rs @@ -98,7 +98,7 @@ pub fn build_profile_openvrpaths(profile: &Profile) -> OpenVrPaths { external_drivers: None, jsonid: "vrpathreg".into(), log: vec![datadir.join("Steam/logs")], - runtime: vec![profile.opencomposite_path.join("build")], + runtime: vec![profile.ovr_comp.path.join("build")], version: 1, } } diff --git a/src/profile.rs b/src/profile.rs index e199980..bf81c5e 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -17,6 +17,7 @@ use std::{ io::BufReader, path::{Path, PathBuf}, slice::Iter, + str::FromStr, }; use uuid::Uuid; @@ -258,6 +259,78 @@ impl Display for LighthouseDriver { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] +pub enum OvrCompatibilityModuleType { + #[default] + Opencomposite, +} + +impl Display for OvrCompatibilityModuleType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::Opencomposite => "OpenComposite", + }) + } +} + +impl OvrCompatibilityModuleType { + pub fn iter() -> Iter<'static, Self> { + [Self::Opencomposite].iter() + } +} + +impl FromStr for OvrCompatibilityModuleType { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().trim() { + "opencomposite" => Ok(Self::Opencomposite), + _ => Err(format!("no match for ovr compatibility module `{s}`")), + } + } +} + +impl From for OvrCompatibilityModuleType { + fn from(value: u32) -> Self { + match value { + 0 => Self::Opencomposite, + _ => panic!("OvrCompatibilityModuleType index out of bounds"), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct ProfileOvrCompatibilityModule { + pub mod_type: OvrCompatibilityModuleType, + pub repo: Option, + pub branch: Option, + pub path: PathBuf, +} + +impl ProfileOvrCompatibilityModule { + fn default_for_uuid(uuid: &str) -> Self { + let mod_type = OvrCompatibilityModuleType::default(); + Self { + mod_type, + repo: None, + branch: None, + path: get_data_dir().join(uuid).join(mod_type.to_string()), + } + } +} + +impl Default for ProfileOvrCompatibilityModule { + fn default() -> Self { + let mod_type = OvrCompatibilityModuleType::default(); + Self { + mod_type, + repo: None, + branch: None, + path: get_data_dir().join("__envision__fallbackovrcomp"), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Profile { pub uuid: String, @@ -268,9 +341,15 @@ pub struct Profile { pub xrservice_branch: Option, #[serde(default = "HashMap::::default")] pub xrservice_cmake_flags: HashMap, + #[deprecated] + #[serde(default)] pub opencomposite_path: PathBuf, + #[deprecated] pub opencomposite_repo: Option, + #[deprecated] pub opencomposite_branch: Option, + #[serde(default)] + pub ovr_comp: ProfileOvrCompatibilityModule, pub features: ProfileFeatures, pub environment: HashMap, /// Install prefix @@ -295,6 +374,7 @@ impl Display for Profile { } impl Default for Profile { + #[allow(deprecated)] fn default() -> Self { let uuid = Self::new_uuid(); let profile_dir = get_data_dir().join(&uuid); @@ -330,12 +410,13 @@ impl Default for Profile { mercury_enabled: false, }, environment: HashMap::new(), - prefix: get_data_dir().join("prefixes").join(&uuid), + prefix: Self::default_prefix_path(&uuid), can_be_built: true, pull_on_build: true, opencomposite_path: profile_dir.join("opencomposite"), opencomposite_repo: None, opencomposite_branch: None, + ovr_comp: ProfileOvrCompatibilityModule::default_for_uuid(&uuid), editable: true, lighthouse_driver: LighthouseDriver::default(), xrservice_launch_options: String::default(), @@ -347,6 +428,10 @@ impl Default for Profile { } impl Profile { + fn default_prefix_path(uuid: &str) -> PathBuf { + get_data_dir().join("prefixes").join(uuid) + } + pub fn xr_runtime_json_env_var(&self) -> String { format!( "XR_RUNTIME_JSON=\"{prefix}/share/openxr/1/openxr_{runtime}.json\"", @@ -424,8 +509,8 @@ impl Profile { } let uuid = Self::new_uuid(); let profile_dir = get_data_dir().join(&uuid); + #[allow(deprecated)] let mut dup = Self { - uuid, name: format!("Duplicate of {}", self.name), xrservice_type: self.xrservice_type.clone(), xrservice_repo: self.xrservice_repo.clone(), @@ -465,7 +550,16 @@ impl Profile { opencomposite_path: profile_dir.join("opencomposite"), skip_dependency_check: self.skip_dependency_check, xrservice_launch_options: self.xrservice_launch_options.clone(), - ..Default::default() + prefix: Self::default_prefix_path(&uuid), + ovr_comp: ProfileOvrCompatibilityModule { + mod_type: self.ovr_comp.mod_type, + repo: self.ovr_comp.repo.clone(), + branch: self.ovr_comp.branch.clone(), + path: profile_dir.join(self.ovr_comp.mod_type.to_string()), + }, + can_be_built: self.can_be_built, + editable: true, + uuid, }; if dup.environment.contains_key("LD_LIBRARY_PATH") { dup.environment.insert( @@ -612,7 +706,10 @@ mod tests { path::{Path, PathBuf}, }; - use crate::profile::{ProfileFeature, ProfileFeatureType, ProfileFeatures, XRServiceType}; + use crate::profile::{ + OvrCompatibilityModuleType, ProfileFeature, ProfileFeatureType, ProfileFeatures, + ProfileOvrCompatibilityModule, XRServiceType, + }; use super::Profile; @@ -622,7 +719,7 @@ mod tests { assert_eq!(profile.name, "Demo profile"); assert_eq!(profile.xrservice_path, PathBuf::from("/home/user/monado")); assert_eq!( - profile.opencomposite_path, + profile.ovr_comp.path, PathBuf::from("/home/user/opencomposite") ); assert_eq!(profile.prefix, PathBuf::from("/home/user/envisionprefix")); @@ -653,7 +750,12 @@ mod tests { name: "Demo profile".into(), xrservice_path: PathBuf::from("/home/user/monado"), xrservice_type: XRServiceType::Monado, - opencomposite_path: PathBuf::from("/home/user/opencomposite"), + ovr_comp: ProfileOvrCompatibilityModule { + path: PathBuf::from("/home/user/opencomposite"), + repo: None, + branch: None, + mod_type: OvrCompatibilityModuleType::default(), + }, features: ProfileFeatures { libsurvive: ProfileFeature { feature_type: ProfileFeatureType::Libsurvive, diff --git a/src/profiles/lighthouse.rs b/src/profiles/lighthouse.rs index 794ee3e..97f3a1f 100644 --- a/src/profiles/lighthouse.rs +++ b/src/profiles/lighthouse.rs @@ -1,7 +1,10 @@ use crate::{ constants::APP_NAME, paths::{data_monado_path, data_opencomposite_path, get_data_dir}, - profile::{prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeatures, XRServiceType}, + profile::{ + prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeatures, + ProfileOvrCompatibilityModule, XRServiceType, + }, }; use std::collections::HashMap; @@ -21,7 +24,10 @@ pub fn lighthouse_profile() -> Profile { name: format!("Lighthouse Driver - {name} Default", name = APP_NAME), xrservice_path: data_monado_path(), xrservice_type: XRServiceType::Monado, - opencomposite_path: data_opencomposite_path(), + ovr_comp: ProfileOvrCompatibilityModule { + path: data_opencomposite_path(), + ..Default::default() + }, features: ProfileFeatures::default(), environment, prefix, diff --git a/src/profiles/openhmd.rs b/src/profiles/openhmd.rs index b045c1e..8709725 100644 --- a/src/profiles/openhmd.rs +++ b/src/profiles/openhmd.rs @@ -3,7 +3,7 @@ use crate::{ paths::{data_monado_path, data_opencomposite_path, data_openhmd_path, get_data_dir}, profile::{ prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType, - ProfileFeatures, XRServiceType, + ProfileFeatures, ProfileOvrCompatibilityModule, XRServiceType, }, }; use std::collections::HashMap; @@ -24,7 +24,10 @@ pub fn openhmd_profile() -> Profile { name: format!("OpenHMD - {name} Default", name = APP_NAME), xrservice_path: data_monado_path(), xrservice_type: XRServiceType::Monado, - opencomposite_path: data_opencomposite_path(), + ovr_comp: ProfileOvrCompatibilityModule { + path: data_opencomposite_path(), + ..Default::default() + }, features: ProfileFeatures { openhmd: ProfileFeature { feature_type: ProfileFeatureType::OpenHmd, diff --git a/src/profiles/simulated.rs b/src/profiles/simulated.rs index 2283caf..a39a66b 100644 --- a/src/profiles/simulated.rs +++ b/src/profiles/simulated.rs @@ -1,7 +1,7 @@ use crate::{ constants::APP_NAME, paths::{data_monado_path, data_opencomposite_path, get_data_dir}, - profile::{Profile, ProfileFeatures, XRServiceType}, + profile::{Profile, ProfileFeatures, ProfileOvrCompatibilityModule, XRServiceType}, }; use std::collections::HashMap; @@ -25,7 +25,10 @@ pub fn simulated_profile() -> Profile { name: format!("Simulated Driver - {name} Default", name = APP_NAME), xrservice_path: data_monado_path(), xrservice_type: XRServiceType::Monado, - opencomposite_path: data_opencomposite_path(), + ovr_comp: ProfileOvrCompatibilityModule { + path: data_opencomposite_path(), + ..Default::default() + }, features: ProfileFeatures::default(), environment, prefix, diff --git a/src/profiles/survive.rs b/src/profiles/survive.rs index 481f624..d3e8ff6 100644 --- a/src/profiles/survive.rs +++ b/src/profiles/survive.rs @@ -3,7 +3,7 @@ use crate::{ paths::{data_libsurvive_path, data_monado_path, data_opencomposite_path, get_data_dir}, profile::{ prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType, - ProfileFeatures, XRServiceType, + ProfileFeatures, ProfileOvrCompatibilityModule, XRServiceType, }, }; use std::collections::HashMap; @@ -26,7 +26,10 @@ pub fn survive_profile() -> Profile { name: format!("Survive - {name} Default", name = APP_NAME), xrservice_path: data_monado_path(), xrservice_type: XRServiceType::Monado, - opencomposite_path: data_opencomposite_path(), + ovr_comp: ProfileOvrCompatibilityModule { + path: data_opencomposite_path(), + ..Default::default() + }, features: ProfileFeatures { libsurvive: ProfileFeature { feature_type: ProfileFeatureType::Libsurvive, diff --git a/src/profiles/wivrn.rs b/src/profiles/wivrn.rs index dd58da9..a6e4f83 100644 --- a/src/profiles/wivrn.rs +++ b/src/profiles/wivrn.rs @@ -1,7 +1,10 @@ use crate::{ constants::APP_NAME, paths::{data_opencomposite_path, data_wivrn_path, get_data_dir}, - profile::{prepare_ld_library_path, Profile, ProfileFeatures, XRServiceType}, + profile::{ + prepare_ld_library_path, Profile, ProfileFeatures, ProfileOvrCompatibilityModule, + XRServiceType, + }, }; use std::collections::HashMap; @@ -18,7 +21,10 @@ pub fn wivrn_profile() -> Profile { name: format!("WiVRn - {name} Default", name = APP_NAME), xrservice_path: data_wivrn_path(), xrservice_type: XRServiceType::Wivrn, - opencomposite_path: data_opencomposite_path(), + ovr_comp: ProfileOvrCompatibilityModule { + path: data_opencomposite_path(), + ..Default::default() + }, features: ProfileFeatures { ..Default::default() }, diff --git a/src/profiles/wmr.rs b/src/profiles/wmr.rs index 23e238d..c332f6a 100644 --- a/src/profiles/wmr.rs +++ b/src/profiles/wmr.rs @@ -3,7 +3,7 @@ use crate::{ paths::{data_basalt_path, data_monado_path, data_opencomposite_path, get_data_dir}, profile::{ prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType, - ProfileFeatures, XRServiceType, + ProfileFeatures, ProfileOvrCompatibilityModule, XRServiceType, }, }; use std::collections::HashMap; @@ -24,7 +24,10 @@ pub fn wmr_profile() -> Profile { name: format!("WMR - {name} Default", name = APP_NAME), xrservice_path: data_monado_path(), xrservice_type: XRServiceType::Monado, - opencomposite_path: data_opencomposite_path(), + ovr_comp: ProfileOvrCompatibilityModule { + path: data_opencomposite_path(), + ..Default::default() + }, features: ProfileFeatures { basalt: ProfileFeature { feature_type: ProfileFeatureType::Basalt, diff --git a/src/ui/app.rs b/src/ui/app.rs index 54f3d31..ca00f4b 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -36,7 +36,7 @@ use crate::{ linux_distro::LinuxDistro, openxr_prober::is_openxr_ready, paths::get_data_dir, - profile::{Profile, XRServiceType}, + profile::{OvrCompatibilityModuleType, Profile, XRServiceType}, stateless_action, steam_linux_runtime_injector::{ restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile, @@ -486,7 +486,11 @@ impl AsyncComponent for App { XRServiceType::Wivrn => get_build_wivrn_jobs(&profile, clean_build), }); } - jobs.extend(get_build_opencomposite_jobs(&profile, clean_build)); + jobs.extend(match profile.ovr_comp.mod_type { + OvrCompatibilityModuleType::Opencomposite => { + get_build_opencomposite_jobs(&profile, clean_build) + } + }); let missing_deps = profile.missing_dependencies(); if !(self.skip_depcheck || profile.skip_dependency_check || missing_deps.is_empty()) { diff --git a/src/ui/profile_editor.rs b/src/ui/profile_editor.rs index 348df30..de8affa 100644 --- a/src/ui/profile_editor.rs +++ b/src/ui/profile_editor.rs @@ -6,7 +6,7 @@ use super::{ }; use crate::{ env_var_descriptions::ENV_VAR_DESCRIPTIONS_AS_PARAGRAPH, - profile::{LighthouseDriver, Profile, XRServiceType}, + profile::{LighthouseDriver, OvrCompatibilityModuleType, Profile, XRServiceType}, }; use adw::prelude::*; use gtk::glib::{self, clone}; @@ -216,31 +216,43 @@ impl SimpleComponent for ProfileEditor { ), }, add: model.xrservice_cmake_flags_rows.widget(), - add: opencompgrp = &adw::PreferencesGroup { - set_title: "OpenComposite", - set_description: Some("OpenVR driver built on top of OpenXR"), + add: ovr_comp_grp = &adw::PreferencesGroup { + set_title: "OpenVR Compatibility", + set_description: Some("OpenVR compatibility module, translates between OpenXR and OpenVR to run legacy OpenVR apps"), + add: &combo_row( + "OpenVR Module Type", + None, + model.profile.borrow().ovr_comp.mod_type.to_string().as_str(), + OvrCompatibilityModuleType::iter() + .map(OvrCompatibilityModuleType::to_string) + .collect::>(), + clone!(#[strong] prof, move |row| { + prof.borrow_mut().ovr_comp.mod_type = + OvrCompatibilityModuleType::from(row.selected()); + }), + ), add: &path_row( - "OpenComposite Path", None, - Some(model.profile.borrow().opencomposite_path.clone().to_string_lossy().to_string()), + "OpenVR Module Path", None, + Some(model.profile.borrow().ovr_comp.path.clone().to_string_lossy().to_string()), Some(init.root_win.clone()), clone!(#[strong] prof, move |n_path| { - prof.borrow_mut().opencomposite_path = n_path.unwrap_or_default().into(); + prof.borrow_mut().ovr_comp.path = n_path.unwrap_or_default().into(); }) ), add: &entry_row( - "OpenComposite Repo", - model.profile.borrow().opencomposite_repo.clone().unwrap_or_default().as_str(), + "OpenVR Compatibility Repo", + model.profile.borrow().ovr_comp.repo.clone().unwrap_or_default().as_str(), clone!(#[strong] prof, move |row| { let n_val = row.text().to_string(); - prof.borrow_mut().opencomposite_repo = (!n_val.is_empty()).then_some(n_val); + prof.borrow_mut().ovr_comp.repo = (!n_val.is_empty()).then_some(n_val); }) ), add: &entry_row( - "OpenComposite Branch", - model.profile.borrow().opencomposite_branch.clone().unwrap_or_default().as_str(), + "OpenVR Compatibility Branch", + model.profile.borrow().ovr_comp.branch.clone().unwrap_or_default().as_str(), clone!(#[strong] prof, move |row| { let n_val = row.text().to_string(); - prof.borrow_mut().opencomposite_branch = (!n_val.is_empty()).then_some(n_val); + prof.borrow_mut().ovr_comp.branch = (!n_val.is_empty()).then_some(n_val); }) ), }, diff --git a/test/files/profile.json b/test/files/profile.json index cb69c6f..ab167a3 100644 --- a/test/files/profile.json +++ b/test/files/profile.json @@ -5,9 +5,7 @@ "xrservice_path": "/home/user/monado", "xrservice_repo": null, "xrservice_branch": null, - "opencomposite_path": "/home/user/opencomposite", - "opencomposite_repo": null, - "opencomposite_branch": null, + "ovr_comp": { "mod_type": "Opencomposite", "path": "/home/user/opencomposite", "repo": null, "branch": null }, "features": { "libsurvive": { "feature_type": "Libsurvive", @@ -34,4 +32,4 @@ "can_be_built": true, "editable": true, "pull_on_build": true -} \ No newline at end of file +}