mirror of
https://github.com/Drop-OSS/drop.git
synced 2026-07-25 17:24:48 +10:00
feat(games): Added multi-argument game launch and setup support
This commit is contained in:
@@ -57,13 +57,23 @@ pub enum ApplicationTransientStatus {
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct GameVersion {
|
pub struct GameVersion {
|
||||||
pub version_index: usize,
|
pub game_id: String,
|
||||||
pub version_name: String,
|
pub version_name: String,
|
||||||
|
|
||||||
|
pub platform: Platform,
|
||||||
|
|
||||||
pub launch_command: String,
|
pub launch_command: String,
|
||||||
pub launch_args: Vec<String>,
|
pub launch_args: Vec<String>,
|
||||||
|
|
||||||
pub setup_command: String,
|
pub setup_command: String,
|
||||||
pub setup_args: Vec<String>,
|
pub setup_args: Vec<String>,
|
||||||
pub platform: Platform,
|
|
||||||
|
pub only_setup: bool,
|
||||||
|
|
||||||
|
pub version_index: usize,
|
||||||
|
pub delta: bool,
|
||||||
|
|
||||||
|
pub umu_id_override: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ use std::sync::Mutex;
|
|||||||
use tauri::AppHandle;
|
use tauri::AppHandle;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{library_error::LibraryError, remote_access_error::RemoteAccessError},
|
database::db::GameVersion, error::{library_error::LibraryError, remote_access_error::RemoteAccessError}, games::library::{get_current_meta, uninstall_game_logic}, AppState
|
||||||
games::library::{get_current_meta, uninstall_game_logic},
|
|
||||||
AppState,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
library::{
|
library::{
|
||||||
fetch_game_logic, fetch_game_verion_options_logic, fetch_library_logic, FetchGameStruct,
|
fetch_game_logic, fetch_game_verion_options_logic, fetch_library_logic, FetchGameStruct,
|
||||||
Game, GameVersionOption,
|
Game,
|
||||||
},
|
},
|
||||||
state::{GameStatusManager, GameStatusWithTransient},
|
state::{GameStatusManager, GameStatusWithTransient},
|
||||||
};
|
};
|
||||||
@@ -50,6 +48,6 @@ pub fn uninstall_game(game_id: String, app_handle: AppHandle) -> Result<(), Libr
|
|||||||
pub fn fetch_game_verion_options(
|
pub fn fetch_game_verion_options(
|
||||||
game_id: String,
|
game_id: String,
|
||||||
state: tauri::State<'_, Mutex<AppState>>,
|
state: tauri::State<'_, Mutex<AppState>>,
|
||||||
) -> Result<Vec<GameVersionOption>, RemoteAccessError> {
|
) -> Result<Vec<GameVersion>, RemoteAccessError> {
|
||||||
fetch_game_verion_options_logic(game_id, state)
|
fetch_game_verion_options_logic(game_id, state)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,18 +6,16 @@ use log::{debug, error, warn};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::Emitter;
|
use tauri::Emitter;
|
||||||
use tauri::{AppHandle, Manager};
|
use tauri::{AppHandle, Manager};
|
||||||
use urlencoding::encode;
|
|
||||||
|
|
||||||
use crate::database::db::{borrow_db_checked, borrow_db_mut_checked, save_db, GameVersion};
|
use crate::database::db::{borrow_db_checked, borrow_db_mut_checked, save_db, GameVersion};
|
||||||
use crate::database::db::{ApplicationTransientStatus, DatabaseImpls, GameDownloadStatus};
|
use crate::database::db::{ApplicationTransientStatus, GameDownloadStatus};
|
||||||
use crate::download_manager::download_manager::DownloadStatus;
|
use crate::download_manager::download_manager::DownloadStatus;
|
||||||
use crate::download_manager::downloadable_metadata::DownloadableMetadata;
|
use crate::download_manager::downloadable_metadata::DownloadableMetadata;
|
||||||
use crate::error::remote_access_error::RemoteAccessError;
|
use crate::error::remote_access_error::RemoteAccessError;
|
||||||
use crate::games::state::{GameStatusManager, GameStatusWithTransient};
|
use crate::games::state::{GameStatusManager, GameStatusWithTransient};
|
||||||
use crate::process::process_manager::Platform;
|
|
||||||
use crate::remote::auth::generate_authorization_header;
|
use crate::remote::auth::generate_authorization_header;
|
||||||
use crate::remote::requests::make_request;
|
use crate::remote::requests::make_request;
|
||||||
use crate::{AppState, DB};
|
use crate::AppState;
|
||||||
|
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde::Serialize)]
|
||||||
pub struct FetchGameStruct {
|
pub struct FetchGameStruct {
|
||||||
@@ -68,30 +66,6 @@ pub struct StatsUpdateEvent {
|
|||||||
pub time: usize,
|
pub time: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Game version with some fields missing and size information
|
|
||||||
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct GameVersionOption {
|
|
||||||
game_id: String,
|
|
||||||
version_name: String,
|
|
||||||
|
|
||||||
platform: Platform,
|
|
||||||
|
|
||||||
launch_command: String,
|
|
||||||
launch_args: Vec<String>,
|
|
||||||
|
|
||||||
setup_command: String,
|
|
||||||
setup_args: Vec<String>,
|
|
||||||
|
|
||||||
only_setup: bool,
|
|
||||||
|
|
||||||
version_index: usize,
|
|
||||||
delta: bool,
|
|
||||||
|
|
||||||
umu_id_override: Option<String>,
|
|
||||||
// total_size: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fetch_library_logic(app: AppHandle) -> Result<Vec<Game>, RemoteAccessError> {
|
pub fn fetch_library_logic(app: AppHandle) -> Result<Vec<Game>, RemoteAccessError> {
|
||||||
let header = generate_authorization_header();
|
let header = generate_authorization_header();
|
||||||
|
|
||||||
@@ -187,7 +161,7 @@ pub fn fetch_game_logic(
|
|||||||
pub fn fetch_game_verion_options_logic(
|
pub fn fetch_game_verion_options_logic(
|
||||||
game_id: String,
|
game_id: String,
|
||||||
state: tauri::State<'_, Mutex<AppState>>,
|
state: tauri::State<'_, Mutex<AppState>>,
|
||||||
) -> Result<Vec<GameVersionOption>, RemoteAccessError> {
|
) -> Result<Vec<GameVersion>, RemoteAccessError> {
|
||||||
let client = reqwest::blocking::Client::new();
|
let client = reqwest::blocking::Client::new();
|
||||||
|
|
||||||
let response = make_request(
|
let response = make_request(
|
||||||
@@ -204,11 +178,11 @@ pub fn fetch_game_verion_options_logic(
|
|||||||
return Err(RemoteAccessError::InvalidResponse(err));
|
return Err(RemoteAccessError::InvalidResponse(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
let data: Vec<GameVersionOption> = response.json()?;
|
let data: Vec<GameVersion> = response.json()?;
|
||||||
|
|
||||||
let state_lock = state.lock().unwrap();
|
let state_lock = state.lock().unwrap();
|
||||||
let process_manager_lock = state_lock.process_manager.lock().unwrap();
|
let process_manager_lock = state_lock.process_manager.lock().unwrap();
|
||||||
let data: Vec<GameVersionOption> = data
|
let data: Vec<GameVersion> = data
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|v| process_manager_lock.valid_platform(&v.platform).unwrap())
|
.filter(|v| process_manager_lock.valid_platform(&v.platform).unwrap())
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use umu_wrapper_lib::command_builder::UmuCommandBuilder;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
database::db::{
|
database::db::{
|
||||||
borrow_db_mut_checked, ApplicationTransientStatus, GameDownloadStatus, DATA_ROOT_DIR,
|
borrow_db_mut_checked, ApplicationTransientStatus, GameDownloadStatus, GameVersion, DATA_ROOT_DIR
|
||||||
},
|
},
|
||||||
download_manager::downloadable_metadata::{DownloadType, DownloadableMetadata},
|
download_manager::downloadable_metadata::{DownloadType, DownloadableMetadata},
|
||||||
error::process_error::ProcessError,
|
error::process_error::ProcessError,
|
||||||
@@ -66,10 +66,6 @@ impl ProcessManager<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's no easy way to distinguish between an executable name with
|
|
||||||
// spaces and it's arguments.
|
|
||||||
// I think if we just join the install_dir to whatever the user provides us, we'll be alright
|
|
||||||
// In future, we should have a separate field for executable name and it's arguments
|
|
||||||
fn process_command(&self, install_dir: &String, command: Vec<String>) -> (PathBuf, Vec<String>) {
|
fn process_command(&self, install_dir: &String, command: Vec<String>) -> (PathBuf, Vec<String>) {
|
||||||
let root = &command[0];
|
let root = &command[0];
|
||||||
|
|
||||||
@@ -194,11 +190,7 @@ impl ProcessManager<'_> {
|
|||||||
GameDownloadStatus::Installed {
|
GameDownloadStatus::Installed {
|
||||||
version_name,
|
version_name,
|
||||||
install_dir,
|
install_dir,
|
||||||
<<<<<<< Updated upstream
|
|
||||||
} => Some((version_name, install_dir)),
|
|
||||||
=======
|
|
||||||
} => (version_name, install_dir),
|
} => (version_name, install_dir),
|
||||||
>>>>>>> Stashed changes
|
|
||||||
GameDownloadStatus::SetupRequired {
|
GameDownloadStatus::SetupRequired {
|
||||||
version_name,
|
version_name,
|
||||||
install_dir,
|
install_dir,
|
||||||
@@ -222,18 +214,19 @@ impl ProcessManager<'_> {
|
|||||||
version_name: _,
|
version_name: _,
|
||||||
install_dir: _,
|
install_dir: _,
|
||||||
} => {
|
} => {
|
||||||
command.extend_one(game_version.launch_command);
|
command.extend([game_version.launch_command.clone()]);
|
||||||
command.extend(game_version.launch_args);
|
command.extend(game_version.launch_args.clone());
|
||||||
},
|
},
|
||||||
GameDownloadStatus::SetupRequired {
|
GameDownloadStatus::SetupRequired {
|
||||||
version_name: _,
|
version_name: _,
|
||||||
install_dir: _,
|
install_dir: _,
|
||||||
} => {
|
} => {
|
||||||
command.extend_one(game_version.setup_command);
|
command.extend([game_version.setup_command.clone()]);
|
||||||
command.extend(game_version.setup_args);
|
command.extend(game_version.setup_args.clone());
|
||||||
},
|
},
|
||||||
_ => panic!("unreachable code"),
|
_ => panic!("unreachable code"),
|
||||||
};
|
};
|
||||||
|
info!("Command: {:?}", &command);
|
||||||
|
|
||||||
let (command, args) = self.process_command(install_dir, command);
|
let (command, args) = self.process_command(install_dir, command);
|
||||||
|
|
||||||
@@ -283,8 +276,7 @@ impl ProcessManager<'_> {
|
|||||||
let launch_process = game_launcher
|
let launch_process = game_launcher
|
||||||
.launch_process(
|
.launch_process(
|
||||||
&meta,
|
&meta,
|
||||||
command.to_str().unwrap().to_owned(),
|
game_version,
|
||||||
args,
|
|
||||||
target_current_dir,
|
target_current_dir,
|
||||||
log_file,
|
log_file,
|
||||||
error_file,
|
error_file,
|
||||||
@@ -339,8 +331,7 @@ pub trait ProcessHandler: Send + 'static {
|
|||||||
fn launch_process(
|
fn launch_process(
|
||||||
&self,
|
&self,
|
||||||
meta: &DownloadableMetadata,
|
meta: &DownloadableMetadata,
|
||||||
command: String,
|
game_version: &GameVersion,
|
||||||
args: Vec<String>,
|
|
||||||
current_dir: &str,
|
current_dir: &str,
|
||||||
log_file: File,
|
log_file: File,
|
||||||
error_file: File,
|
error_file: File,
|
||||||
@@ -352,17 +343,16 @@ impl ProcessHandler for NativeGameLauncher {
|
|||||||
fn launch_process(
|
fn launch_process(
|
||||||
&self,
|
&self,
|
||||||
_meta: &DownloadableMetadata,
|
_meta: &DownloadableMetadata,
|
||||||
command: String,
|
game_version: &GameVersion,
|
||||||
args: Vec<String>,
|
|
||||||
current_dir: &str,
|
current_dir: &str,
|
||||||
log_file: File,
|
log_file: File,
|
||||||
error_file: File,
|
error_file: File,
|
||||||
) -> Result<Child, Error> {
|
) -> Result<Child, Error> {
|
||||||
Command::new(command)
|
Command::new(game_version.launch_command.clone())
|
||||||
.current_dir(current_dir)
|
.current_dir(current_dir)
|
||||||
.stdout(log_file)
|
.stdout(log_file)
|
||||||
.stderr(error_file)
|
.stderr(error_file)
|
||||||
.args(args)
|
.args(game_version.launch_args.clone())
|
||||||
.spawn()
|
.spawn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,15 +363,14 @@ impl ProcessHandler for UMULauncher {
|
|||||||
fn launch_process(
|
fn launch_process(
|
||||||
&self,
|
&self,
|
||||||
_meta: &DownloadableMetadata,
|
_meta: &DownloadableMetadata,
|
||||||
command: String,
|
game_version: &GameVersion,
|
||||||
args: Vec<String>,
|
|
||||||
_current_dir: &str,
|
_current_dir: &str,
|
||||||
_log_file: File,
|
_log_file: File,
|
||||||
_error_file: File,
|
_error_file: File,
|
||||||
) -> Result<Child, Error> {
|
) -> Result<Child, Error> {
|
||||||
UmuCommandBuilder::new(UMU_LAUNCHER_EXECUTABLE, command)
|
UmuCommandBuilder::new(UMU_LAUNCHER_EXECUTABLE, game_version.launch_command.clone())
|
||||||
.game_id(String::from("0"))
|
.game_id(String::from(game_version.umu_id_override.clone().unwrap_or(game_version.game_id.clone())))
|
||||||
.launch_args(args)
|
.launch_args(game_version.launch_args.clone())
|
||||||
.build()
|
.build()
|
||||||
.spawn()
|
.spawn()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user