mirror of
https://github.com/djibux/BoilR.git
synced 2026-09-01 05:53:41 +02:00
Update cargo toml and refactor uplay (#347)
* 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 <github@ofacy.com> --------- Co-authored-by: Ofacy <github@ofacy.com>
This commit is contained in:
co-authored by
Ofacy
parent
c092ffba88
commit
d5f038a2fa
Generated
+588
-429
File diff suppressed because it is too large
Load Diff
+5
-5
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "boilr"
|
||||
version = "1.7.22"
|
||||
version = "1.8.0"
|
||||
|
||||
[dependencies]
|
||||
base64 = "^0.21.0"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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]
|
||||
|
||||
+1734
-1279
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+120
-91
@@ -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};
|
||||
|
||||
@@ -37,7 +33,6 @@ impl NeedsPorton<UplayPlatform> for UplayGame {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn get_uplay_games() -> eyre::Result<Vec<UplayGame>> {
|
||||
#[cfg(target_family = "unix")]
|
||||
{
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct GameConfig<'a> {
|
||||
icon_image: &'a str,
|
||||
shortcut_name: &'a str,
|
||||
register: &'a str,
|
||||
launch_id: usize,
|
||||
}
|
||||
|
||||
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:") {
|
||||
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 {
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+5
-11
@@ -151,8 +151,9 @@ fn try_get_rename_map() -> Result<HashMap<u32, String>, Box<dyn Error>> {
|
||||
Ok(deserialized)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
#[derive(PartialEq, Clone, Default)]
|
||||
enum Menues {
|
||||
#[default]
|
||||
Import,
|
||||
Settings,
|
||||
Images,
|
||||
@@ -160,12 +161,6 @@ enum Menues {
|
||||
Disconnect,
|
||||
}
|
||||
|
||||
impl Default for Menues {
|
||||
fn default() -> Menues {
|
||||
Menues::Import
|
||||
}
|
||||
}
|
||||
|
||||
fn create_games_to_sync(rt: &mut Runtime, platforms: &[Box<dyn GamesPlatform>]) -> GamesToSync {
|
||||
let mut to_sync = vec![];
|
||||
for platform in platforms {
|
||||
@@ -367,15 +362,14 @@ pub fn run_ui(args: Vec<String>) -> eyre::Result<()>{
|
||||
vsync: !no_v_sync,
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
let run_result = eframe::run_native(
|
||||
"BoilR",
|
||||
native_options,
|
||||
Box::new(|cc| {
|
||||
setup(&cc.egui_ctx);
|
||||
Box::new(app)
|
||||
}),
|
||||
);
|
||||
Ok(())
|
||||
}));
|
||||
run_result.map_err(|e| eyre::eyre!("Could not initialize: {:?}", e))
|
||||
}
|
||||
|
||||
fn is_fullscreen(args: &[String]) -> bool {
|
||||
|
||||
Reference in New Issue
Block a user