Skip to content

Commit

Permalink
Update cargo toml and refactor uplay (#347)
Browse files Browse the repository at this point in the history
* Update dependencies

* Conditional imports for linux

* Fix windows warnings

* Sample testconfiguration for uplay

* Refactor uplay code to remove unsafe blocks

* Update version to 1.8.0

* Update cargo-lock for flatpak

* Update flatpak appdata with realse 1.8.0

* Update src/platforms/uplay/platform.rs

Co-authored-by: Ofacy <[email protected]>

---------

Co-authored-by: Ofacy <[email protected]>
  • Loading branch information
PhilipK and Ofacy authored May 29, 2023
1 parent c092ffb commit d5f038a
Show file tree
Hide file tree
Showing 8 changed files with 8,491 additions and 1,793 deletions.
1,025 changes: 592 additions & 433 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
edition = "2021"
name = "boilr"
version = "1.7.22"
version = "1.8.0"

[dependencies]
base64 = "^0.21.0"
Expand All @@ -15,7 +15,7 @@ serde_json = "^1.0.91"

steam_shortcuts_util = "^1.1.8"
steamgriddb_api = "^0.3.1"
sysinfo = "^0.27.1"
sysinfo = "^0.29.0"
eyre = "^0.6.8"
color-eyre = "^0.6.2"
dyn-clone = "^1.0.10"
Expand All @@ -29,10 +29,10 @@ features = ["serde"]
version = "^5.4.0"

[dependencies.eframe]
version = "^0.20.1"
version = "^0.22.0"

[dependencies.egui]
version = "^0.20.1"
version = "^0.22.0"

[dependencies.futures]
version = "^0.3.25"
Expand Down Expand Up @@ -62,7 +62,7 @@ version = "^0.7.1"
winres = "^0.1.12"

[target."cfg(windows)".dependencies]
winreg = "^0.10.1"
winreg = "^0.50.0"
sqlite = "^0.30.3"

[features]
Expand Down
2,957 changes: 1,706 additions & 1,251 deletions flatpak/cargo-lock.json

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions flatpak/io.github.philipk.boilr.appdata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ https://hughsie.github.io/oars/index.html
-->
<content_rating type="oars-1.1" />
<releases>

<release version="1.8.0" date="2023-05-29">
<description>
<ul>
<li>Update dependencies</li>
<li>Support for UPlay</li>
</ul>
</description>
</release>
<release version="1.7.22" date="2023-05-15">
<description>
<ul>
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/uplay/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub(crate) struct UplayGame {
pub(crate) id: String,
pub(crate) launcher: PathBuf,
pub(crate) launcher_compat_folder: Option<PathBuf>,
pub(crate) launch_id: u8,
pub(crate) launch_id: usize,
}

impl From<UplayGame> for ShortcutOwned {
Expand Down
213 changes: 121 additions & 92 deletions src/platforms/uplay/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
use std::path::Path;
use std::path::PathBuf;

use std::io::Read;
use std::io::BufReader;
use std::fs::File;

use crate::platforms::load_settings;
use crate::platforms::to_shortcuts_simple;
use crate::platforms::FromSettingsString;
use crate::platforms::GamesPlatform;
use crate::platforms::ShortcutToImport;
use crate::platforms::NeedsPorton;
use crate::platforms::ShortcutToImport;

use super::{game::UplayGame, settings::UplaySettings};

Expand All @@ -37,7 +33,6 @@ impl NeedsPorton<UplayPlatform> for UplayGame {
}
}


fn get_uplay_games() -> eyre::Result<Vec<UplayGame>> {
#[cfg(target_family = "unix")]
{
Expand All @@ -54,12 +49,13 @@ struct UplayPathData {
//~/.steam/steam/steamapps/compatdata/X/pfx/drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/upc.exe
exe_path: PathBuf,
//~/.steam/steam/steamapps/compatdata/X/pfx/drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/games/
#[cfg(target_family = "unix")]
games_path: PathBuf,
//~/.steam/steam/steamapps/compatdata/X
#[cfg(target_family = "unix")]
compat_folder: Option<PathBuf>,
}


#[cfg(target_family = "unix")]
fn get_launcher_path() -> eyre::Result<UplayPathData> {
let mut res = UplayPathData::default();
Expand Down Expand Up @@ -99,11 +95,9 @@ fn get_launcher_path() -> eyre::Result<UplayPathData> {
}
}
}
Err(eyre::eyre!(
"Could not find uplay launcher"))
Err(eyre::eyre!("Could not find uplay launcher"))
}


#[cfg(target_os = "windows")]
fn get_launcher_path() -> eyre::Result<UplayPathData> {
let mut res = UplayPathData::default();
Expand Down Expand Up @@ -162,7 +156,7 @@ fn get_games_from_winreg() -> eyre::Result<Vec<UplayGame>> {
id,
launcher: launcher_path.clone(),
launcher_compat_folder: None,
launch_id: 0
launch_id: 0,
})
}
}
Expand All @@ -173,95 +167,107 @@ fn get_games_from_winreg() -> eyre::Result<Vec<UplayGame>> {

#[cfg(target_family = "unix")]
fn get_games_from_proton() -> eyre::Result<Vec<UplayGame>> {
let mut games = vec![];

let launcher_path = get_launcher_path()?;
let parent = launcher_path.exe_path.parent().unwrap_or_else(|| Path::new("/"));
let file = File::open(parent
.join("cache")
.join("configuration")
.join("configurations"))?;
let mut reader = BufReader::new(file);
let mut buffer = Vec::new();

// Read file into vector.
reader.read_to_end(&mut buffer)?;

let mut splits: Vec<String> = Vec::new();

while !buffer.is_empty() {
let game_header = b"version: 2.0";
let foundindex: usize = match buffer.windows(game_header.len()).position(|window| window == game_header) {
Some(index) => {index},
None => {break;},
};
let (mut first, second) = buffer.split_at(foundindex);
if first.len() >= 14usize {
first = first.split_at(first.len()-14).0;
let parent = launcher_path
.exe_path
.parent()
.unwrap_or_else(|| Path::new("/"));
let file = parent
.join("cache")
.join("configuration")
.join("configurations");
let buffer = std::fs::read(file)?;
let splits = get_file_splits(&buffer);
let configurations = splits.iter().filter(|s| is_valid_game_config(s));
let parsed_configurations= configurations.flat_map(|config| parse_game_config(config));
let games = parsed_configurations.map(|game|{
UplayGame{
name:game.shortcut_name.to_string(),
icon: parent.join("data").join("games").join(game.icon_image).to_string_lossy().to_string(),
id : game.register
.strip_prefix("HKEY_LOCAL_MACHINE\\SOFTWARE\\Ubisoft\\Launcher\\Installs\\")
.unwrap_or_default()
.strip_suffix("\\InstallDir")
.unwrap_or_default()
.to_string(),
launcher : launcher_path.exe_path.clone(),
launcher_compat_folder: launcher_path.compat_folder.clone(),
launch_id: game.launch_id
}
splits.push(unsafe {std::str::from_utf8_unchecked(first).to_string()});
buffer = second.split_at("version: 2.0".len()).1.to_vec();
}
});
Ok(games.collect())
}




for gameconfig in splits {
if !gameconfig.contains("executables:") {continue};
if !gameconfig.contains("online:") {continue};
if !gameconfig.contains("shortcut_name:") {continue};
if !gameconfig.contains("register:") {continue};

let mut inonline = false;
let mut shortcut_name: String = "".to_string();
let mut game_id: String = "".to_string();
let mut icon_image: PathBuf = "".into();
let mut launch_id = 0;
for line in gameconfig.split('\n') {
let trimed = line.trim();
if trimed.starts_with("online:") {
inonline = true;
continue;
}
if trimed.starts_with("offline:") {
struct GameConfig<'a> {
icon_image: &'a str,
shortcut_name: &'a str,
register: &'a str,
launch_id: usize,
}

fn parse_game_config(split: &str) -> Vec<GameConfig> {
let mut res = vec![];
let mut icon_image = "";
let mut shortcut_name = "";
let mut register = "";
let mut inonline = false;
let mut launch_id = 0;
for line in split.lines().map(|line| line.trim()) {
if line.starts_with("online:") {
inonline = true;
continue;
}
if line.starts_with("offline:") {
break;
}
if let Some(split) = line.strip_prefix("icon_image: ") {
if split.is_empty() {
break;
}
if trimed.starts_with("icon_image: ") {
let split = trimed.split_at("icon_image: ".len()).1;
if split.is_empty() {break}; // invalid config.
icon_image = parent.join("data").join("games").join(split);
}
if !inonline {continue};
if trimed.starts_with("- shortcut_name:") {
let split = trimed.split_at("- shortcut_name:".len()).1;
if split.is_empty() {break}; // invalid config.
shortcut_name = split.to_string();
continue;
}
}; // invalid config.
icon_image = split;
}
if !inonline {
continue;
};
if let Some(split) = line.strip_prefix("- shortcut_name: ") {
if split.is_empty() {
break;
}; // invalid config.
shortcut_name = split;
continue;
}

if trimed.starts_with("register: ") {
let split = trimed.split_at("register: ".len()).1;
if split.is_empty() {break}; // invalid config.
game_id = split
.strip_prefix("HKEY_LOCAL_MACHINE\\SOFTWARE\\Ubisoft\\Launcher\\Installs\\").unwrap_or_default()
.strip_suffix("\\InstallDir").unwrap_or_default().to_string();
continue;
}
if let Some(split) = line.strip_prefix("register: ") {
if split.is_empty() {
break;
}; // invalid config.
register = split;
continue;
}

if trimed == "denuvo: yes" {
games.push(UplayGame {
name: shortcut_name.clone(),
icon: icon_image.to_string_lossy().to_string(),
id: game_id.clone(),
launcher: launcher_path.exe_path.clone(),
launcher_compat_folder: launcher_path.compat_folder.clone(),
launch_id,
});
launch_id += 1;
}
if line == "denuvo: yes" {
res.push(GameConfig {
icon_image,
shortcut_name,
register,
launch_id,
});
launch_id += 1;
}
}
Ok(games)
res
}

fn is_valid_game_config(config: &str) -> bool {
let requires = ["executables:", "online:", "shortcut_name:", "register:"];
requires.iter().all(|req| config.contains(req))
}

fn get_file_splits(buffer: &[u8]) -> Vec<String> {
let new_string = String::from_utf8_lossy(buffer);
let sections = new_string.split("version: 2.0").map(|s| s.replace('�', ""));
sections.collect()
}

impl FromSettingsString for UplayPlatform {
Expand Down Expand Up @@ -297,4 +303,27 @@ impl GamesPlatform for UplayPlatform {
fn code_name(&self) -> &str {
"uplay"
}
}
}

#[cfg(test)]
mod test {

use super::*;

#[test]
fn can_parse_configuration_file() {
let content = include_bytes!("testconfiguration");
let splits = get_file_splits(content);
assert_eq!(501, splits.len());
}

#[test]
fn can_parse_into_game_config() {
let content = include_bytes!("testconfiguration");
let splits = get_file_splits(content);
let games:Vec<_> = splits.iter().flat_map(|split| parse_game_config(split)).collect();
assert_eq!(2, games.len());
assert_eq!(Some("For Honor"),games.get(0).map(|h|h.shortcut_name));
assert_eq!(Some("WATCH_DOGS® 2"),games.get(1).map(|h|h.shortcut_name));
}
}
Loading

0 comments on commit d5f038a

Please sign in to comment.