Proton support (#64)

Enable proton for heroic games
This commit is contained in:
Philip Kristoffersen
2022-03-31 17:33:33 +02:00
committed by GitHub
parent 704d5b5758
commit b58cbc51e0
24 changed files with 589 additions and 156 deletions
+33 -114
View File
@@ -1,128 +1,51 @@
use super::{HeroicGame, HeroicSettings};
use crate::platform::{Platform, SettingsValidity};
use serde_json::from_str;
use std::collections::HashMap;
use std::error::Error;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
pub struct HeroicPlatform {
pub settings: HeroicSettings,
}
#[cfg(target_family = "unix")]
enum InstallationMode {
FlatPak,
UserBin,
UserBin,
}
#[cfg(target_family = "unix")]
fn get_legendary_location(install_mode: &InstallationMode) -> &'static str {
match install_mode{
InstallationMode::FlatPak => "/var/lib/flatpak/app/com.heroicgameslauncher.hgl/current/active/files/bin/heroic/resources/app.asar.unpacked/build/bin/linux/legendary",
InstallationMode::UserBin => "/opt/Heroic/resources/app.asar.unpacked/build/bin/linux/legendary"
}
}
#[cfg(target_family = "unix")]
fn get_config_folder(install_mode: &InstallationMode) -> Option<String> {
fn get_installed_json_location(install_mode: &InstallationMode) -> PathBuf {
let home_dir = std::env::var("HOME").unwrap_or("".to_string());
match install_mode {
InstallationMode::FlatPak => {
let home_dir = std::env::var("HOME").unwrap_or("".to_string());
Some(
Path::new(&home_dir)
.join(".var/app/com.heroicgameslauncher.hgl/config")
.to_string_lossy()
.to_string(),
)
}
InstallationMode::UserBin => None,
InstallationMode::FlatPak => Path::new(&home_dir)
.join(".var/app/com.heroicgameslauncher.hgl/config/legendary/installed.json"),
InstallationMode::UserBin => Path::new(&home_dir).join(".config/legendary/installed.json"),
}
.to_path_buf()
}
#[cfg(target_os = "windows")]
fn find_legendary_location() -> Option<String> {
match heroic_folder_from_registry().or_else(heroic_folder_from_appdata) {
Some(heroic_folder) => {
let legendary_path = heroic_folder
.join("resources\\app.asar.unpacked\\build\\bin\\win32\\legendary.exe");
if legendary_path.exists() {
Some(legendary_path.to_path_buf().to_string_lossy().to_string())
} else {
None
}
}
None => None,
}
}
#[cfg(target_os = "windows")]
fn heroic_folder_from_registry() -> Option<PathBuf> {
use winreg::enums::*;
use winreg::RegKey;
let hklm = RegKey::predef(HKEY_CURRENT_USER);
if let Ok(launcher) = hklm.open_subkey("Software\\035fb1f9-7381-565b-92bb-ed6b2a3b99ba") {
let path_string: Result<String, _> = launcher.get_value("InstallLocation");
if let Ok(path_string) = path_string {
//.join("resources/app.asar.unpacked/build/bin/win32/legendary.exe")
let path = Path::new(&path_string);
if path.exists() {
return Some(path.to_path_buf());
}
}
}
None
}
#[cfg(target_os = "windows")]
fn heroic_folder_from_appdata() -> Option<PathBuf> {
let key = "APPDATA";
match std::env::var(key) {
Ok(program_data) => {
let path = Path::new(&program_data).join("heroic");
if path.exists() {
Some(path.to_path_buf())
} else {
None
}
}
Err(_err) => None,
}
}
#[cfg(target_family = "unix")]
fn get_shortcuts_from_install_mode(
install_mode: &InstallationMode,
) -> Result<Vec<HeroicGame>, Box<dyn Error>> {
let legendary = get_legendary_location(install_mode);
let config_folder = get_config_folder(install_mode);
get_shortcuts_from_location(config_folder, legendary.to_string())
let installed_path = get_installed_json_location(install_mode);
get_shortcuts_from_location(installed_path)
}
fn get_shortcuts_from_location(
config_folder: Option<String>,
legendary: String,
) -> Result<Vec<HeroicGame>, Box<dyn Error>> {
let output = if let Some(config_folder) = config_folder.clone() {
Command::new(&legendary)
.env("XDG_CONFIG_HOME", config_folder)
.arg("list-installed")
.arg("--json")
.output()?
} else {
Command::new(&legendary)
.arg("list-installed")
.arg("--json")
.output()?
};
let json = String::from_utf8_lossy(&output.stdout);
let mut legendary_ouput: Vec<HeroicGame> = from_str(&json)?;
legendary_ouput.iter_mut().for_each(|mut game| {
game.config_folder = config_folder.clone();
game.legendary_location = Some(legendary.to_string());
});
Ok(legendary_ouput)
fn get_shortcuts_from_location<P: AsRef<Path>>(path: P) -> Result<Vec<HeroicGame>, Box<dyn Error>> {
let installed_json_path = path.as_ref();
if installed_json_path.exists() {
let json = std::fs::read_to_string(installed_json_path)?;
let games_map = serde_json::from_str::<HashMap<String, HeroicGame>>(&json)?;
let mut games = vec![];
for game in games_map.values() {
games.push(game.clone());
}
return Ok(games);
}
return Ok(vec![]);
}
impl Platform<HeroicGame, Box<dyn Error>> for HeroicPlatform {
@@ -133,22 +56,14 @@ impl Platform<HeroicGame, Box<dyn Error>> for HeroicPlatform {
fn name(&self) -> &str {
"Heroic"
}
#[cfg(target_family = "unix")]
fn get_shortcuts(&self) -> Result<Vec<HeroicGame>, Box<dyn Error>> {
fn get_shortcuts(&self) -> Result<Vec<HeroicGame>, Box<dyn Error>> {
let install_modes = vec![InstallationMode::FlatPak, InstallationMode::UserBin];
let first_working_instal = install_modes
let shortcuts = install_modes
.iter()
.find_map(|install_mode| get_shortcuts_from_install_mode(install_mode).ok());
match first_working_instal {
Some(res) => return Ok(res),
None => get_shortcuts_from_install_mode(&install_modes[0]),
}
}
#[cfg(target_os = "windows")]
fn get_shortcuts(&self) -> Result<Vec<HeroicGame>, Box<dyn Error>> {
let legendary = find_legendary_location().unwrap_or("legendary".to_string());
get_shortcuts_from_location(None, legendary)
.filter_map(|install_mode| get_shortcuts_from_install_mode(install_mode).ok())
.flatten()
.collect();
Ok(shortcuts)
}
#[cfg(target_family = "unix")]
@@ -165,4 +80,8 @@ impl Platform<HeroicGame, Box<dyn Error>> for HeroicPlatform {
},
}
}
fn needs_proton(&self, _input: &HeroicGame) -> bool {
return true;
}
}