Skip to content

Commit

Permalink
Gamepass (#350)
Browse files Browse the repository at this point in the history
* Initial gamepass platform implementation

* Implement cargo clippy fixes

* Update to version 1.9.0
  • Loading branch information
PhilipK authored Jun 10, 2023
1 parent 8fd1f51 commit 28a952a
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
edition = "2021"
name = "boilr"
version = "1.8.0"
version = "1.9.0"

[dependencies]
base64 = "^0.21.0"
Expand Down
16 changes: 16 additions & 0 deletions src/platforms/gamepass/game_pass_games.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Get-AppxPackage |
Where-Object { -not $_.IsFramework } |
ForEach-Object {
try {
$manifest = Get-AppxPackageManifest $_
$application = $manifest.Package.Applications.Application;
[PSCustomObject]@{
kind = $application.Id
display_name = $manifest.Package.Properties.DisplayName
install_location = $_.InstallLocation
family_name = $_.PackageFamilyName
}
}
catch {}
} |
ConvertTo-Json -depth 5
3 changes: 3 additions & 0 deletions src/platforms/gamepass/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod platform;

pub use platform::*;
154 changes: 154 additions & 0 deletions src/platforms/gamepass/platform.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
use serde::Serialize;

use crate::platforms::{load_settings, FromSettingsString, GamesPlatform};
use serde::Deserialize;
use std::io::Error;
use std::path::{Path, PathBuf};
use std::process::Command;
use steam_shortcuts_util::Shortcut;

use crate::platforms::ShortcutToImport;

#[derive(Clone, Deserialize, Default)]
pub struct GamePassPlatForm {
settings: GamePassSettings,
}

#[derive(Serialize,Deserialize, Default, Clone)]
pub struct GamePassSettings {
enabled: bool,
}


impl GamesPlatform for GamePassPlatForm {
fn name(&self) -> &str {
"Game Pass"
}

fn code_name(&self) -> &str {
"gamepass"
}

fn enabled(&self) -> bool {
self.settings.enabled
}

fn get_shortcut_info(&self) -> eyre::Result<Vec<crate::platforms::ShortcutToImport>> {
let command = include_str!("./game_pass_games.ps1");
let res = run_powershell_command(command)?;
let apps: Vec<AppInfo> = serde_json::from_str(&res)?;
let expanded_search = false;

let windows_dir = std::env::var("WinDir").unwrap_or("C:\\Windows".to_string());
let explorer = Path::new(&windows_dir)
.join("explorer.exe")
.to_string_lossy()
.to_string();
let games_iter = apps
.iter()
.filter(|app| {
app.kind.is_game()
|| (expanded_search
&& (app.display_name.contains("DisplayName")
|| app.display_name.contains("ms-resource")))
})
.filter(|game| game.microsoft_game_path().exists() || game.appx_manifest().exists())
.map(|game| {
let launch_url = format!("shell:AppsFolder\\{}", game.aum_id());
let shortcut = Shortcut::new(
"0",
&game.display_name,
&explorer,
&windows_dir,
"",
"",
&launch_url,
);
ShortcutToImport {
shortcut: shortcut.to_owned(),
needs_proton: false,
needs_symlinks: false,
}
});
Ok(games_iter.collect())
}

fn get_settings_serilizable(&self) -> String {
toml::to_string(&self.settings).unwrap_or_default()
}

fn render_ui(&mut self, ui: &mut egui::Ui) {
ui.heading("Game Pass");
ui.checkbox(&mut self.settings.enabled, "Import from Game Pass");
}
}

#[derive(Deserialize, Debug)]
struct AppInfo {
kind: Kind,
display_name: String,
install_location: String,
family_name: String,
}

#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum Kind {
Null,
Str(String),
Array(Vec<String>),
}

impl AppInfo {
fn aum_id(&self) -> String {
format!("{}!{}", self.family_name, self.kind.as_ref())
}

fn microsoft_game_path(&self) -> PathBuf {
Path::new(&self.install_location).join("MicrosoftGames.config")
}

fn appx_manifest(&self) -> PathBuf {
Path::new(&self.install_location).join("AppxManifest.xml")
}
}

impl AsRef<str> for Kind {
fn as_ref(&self) -> &str {
match self {
Kind::Null => "",
Kind::Str(s) => s.as_ref(),
Kind::Array(array) => array.iter().next().map(|s| s.as_ref()).unwrap_or(""),
}
}
}

impl Kind {
fn is_game(&self) -> bool {
match self {
Kind::Str(string) => string.eq("Game"),
Kind::Array(strings) => strings.iter().any(|s| s == "Game"),
_ => false,
}
}
}

fn run_powershell_command(cmd: &str) -> Result<String, Error> {
let output = Command::new("powershell").arg("/c").arg(cmd).output()?;

match output.status.success() {
true => Ok(String::from_utf8_lossy(&output.stdout).to_string()),
false => Err(Error::new(
std::io::ErrorKind::Other,
String::from_utf8_lossy(&output.stderr).to_string(),
)),
}
}

impl FromSettingsString for GamePassPlatForm {
fn from_settings_string<S: AsRef<str>>(s: S) -> Self {
GamePassPlatForm {
settings: load_settings(s),
}
}
}
4 changes: 4 additions & 0 deletions src/platforms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ mod amazon;
#[cfg(not(target_family = "unix"))]
mod playnite;

#[cfg(not(target_family = "unix"))]
mod gamepass;




mod gog;
Expand Down
5 changes: 4 additions & 1 deletion src/platforms/platforms_load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::collections::HashMap;
use super::GamesPlatform;

use crate::settings::load_setting_sections;
const PLATFORM_NAMES: [&str; 13] = [
const PLATFORM_NAMES: [&str; 14] = [
"amazon",
"bottles",
"epic_games",
Expand All @@ -18,6 +18,7 @@ const PLATFORM_NAMES: [&str; 13] = [
"uplay",
"minigalaxy",
"playnite",
"gamepass"
];

pub type Platforms = Vec<Box<dyn GamesPlatform>>;
Expand All @@ -34,9 +35,11 @@ pub fn load_platform<A: AsRef<str>, B: AsRef<str>>(
//Windows only platforms
use super::amazon::AmazonPlatform;
use super::playnite::PlaynitePlatform;
use super::gamepass::GamePassPlatForm;
match name {
"amazon" => return load::<AmazonPlatform>(s),
"playnite" => return load::<PlaynitePlatform>(s),
"gamepass" => return load::<GamePassPlatForm>(s),
_ => {}
}
}
Expand Down

0 comments on commit 28a952a

Please sign in to comment.