diff --git a/theseus/src/api/mod.rs b/theseus/src/api/mod.rs index 064c04a33..6e983c8f7 100644 --- a/theseus/src/api/mod.rs +++ b/theseus/src/api/mod.rs @@ -2,6 +2,7 @@ pub mod auth; pub mod profile; pub mod profile_create; +pub mod settings; pub mod data { pub use crate::state::{ @@ -15,6 +16,6 @@ pub mod prelude { auth::{self, Credentials}, data::*, profile::{self, Profile}, - profile_create, State, + profile_create, settings, State, }; } diff --git a/theseus/src/api/profile.rs b/theseus/src/api/profile.rs index 4a9d87fc1..9b08f4416 100644 --- a/theseus/src/api/profile.rs +++ b/theseus/src/api/profile.rs @@ -204,12 +204,15 @@ pub async fn run( let memory = profile.memory.unwrap_or(settings.memory); let resolution = profile.resolution.unwrap_or(settings.game_resolution); + let env_args = &settings.custom_env_args; + let mc_process = crate::launcher::launch_minecraft( &profile.metadata.game_version, &profile.metadata.loader_version, &profile.path, java_install, java_args, + env_args, wrapper, &memory, &resolution, diff --git a/theseus/src/api/settings.rs b/theseus/src/api/settings.rs new file mode 100644 index 000000000..c6a2cf28a --- /dev/null +++ b/theseus/src/api/settings.rs @@ -0,0 +1,24 @@ +//! Theseus profile management interface +pub use crate::{ + state::{ + Hooks, JavaSettings, MemorySettings, Profile, Settings, WindowSize, + }, + State, +}; + +/// Gets entire settings +#[tracing::instrument] +pub async fn get() -> crate::Result { + let state = State::get().await?; + let settings = state.settings.read().await; + Ok(settings.clone()) +} + +/// Sets entire settings +#[tracing::instrument] +pub async fn set(settings: Settings) -> crate::Result<()> { + let state = State::get().await?; + // Replaces the settings struct in the RwLock with the passed argument + *state.settings.write().await = settings; + Ok(()) +} \ No newline at end of file diff --git a/theseus/src/launcher/mod.rs b/theseus/src/launcher/mod.rs index bbb7e6a29..51de34229 100644 --- a/theseus/src/launcher/mod.rs +++ b/theseus/src/launcher/mod.rs @@ -53,6 +53,7 @@ pub async fn launch_minecraft( instance_path: &Path, java_install: &Path, java_args: &[String], + env_args: &[(String, String)], wrapper: &Option, memory: &st::MemorySettings, resolution: &st::WindowSize, @@ -173,6 +174,8 @@ pub async fn launch_minecraft( None => Command::new(String::from(java_install.to_string_lossy())), }; + let env_args = Vec::from(env_args); + command .args( args::get_jvm_arguments( @@ -213,6 +216,7 @@ pub async fn launch_minecraft( ) .current_dir(instance_path.clone()) .env_clear() + .envs(env_args) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()); diff --git a/theseus/src/state/settings.rs b/theseus/src/state/settings.rs index ae688d514..cbdb2f937 100644 --- a/theseus/src/state/settings.rs +++ b/theseus/src/state/settings.rs @@ -17,6 +17,7 @@ pub struct Settings { pub memory: MemorySettings, pub game_resolution: WindowSize, pub custom_java_args: Vec, + pub custom_env_args: Vec<(String, String)>, pub java_8_path: Option, pub java_17_path: Option, pub default_user: Option, @@ -31,6 +32,7 @@ impl Default for Settings { memory: MemorySettings::default(), game_resolution: WindowSize::default(), custom_java_args: Vec::new(), + custom_env_args: Vec::new(), java_8_path: None, java_17_path: None, default_user: None, diff --git a/theseus_gui/src-tauri/src/api/mod.rs b/theseus_gui/src-tauri/src/api/mod.rs index 7d3880db0..422cb5b7e 100644 --- a/theseus_gui/src-tauri/src/api/mod.rs +++ b/theseus_gui/src-tauri/src/api/mod.rs @@ -6,6 +6,7 @@ pub mod auth; pub mod profile; pub mod profile_create; +pub mod settings; pub type Result = std::result::Result; diff --git a/theseus_gui/src-tauri/src/api/settings.rs b/theseus_gui/src-tauri/src/api/settings.rs new file mode 100644 index 000000000..765f9b41f --- /dev/null +++ b/theseus_gui/src-tauri/src/api/settings.rs @@ -0,0 +1,17 @@ +use crate::api::Result; +use theseus::prelude::*; + +// Get full settings +// invoke('settings_get') +#[tauri::command] +pub async fn settings_get() -> Result { + Ok(settings::get().await?) +} + +// Set full settings +// invoke('settings_set', settings) +#[tauri::command] +pub async fn settings_set(settings: Settings) -> Result<()> { + settings::set(settings).await?; + Ok(()) +} diff --git a/theseus_gui/src-tauri/src/main.rs b/theseus_gui/src-tauri/src/main.rs index 82b2c0613..0a00734ab 100644 --- a/theseus_gui/src-tauri/src/main.rs +++ b/theseus_gui/src-tauri/src/main.rs @@ -38,6 +38,8 @@ fn main() { api::auth::auth_has_user, api::auth::auth_users, api::auth::auth_get_user, + api::settings::settings_get, + api::settings::settings_set, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/theseus_gui/src/helpers/auth.js b/theseus_gui/src/helpers/auth.js index e85720e4e..1d75e18c3 100644 --- a/theseus_gui/src/helpers/auth.js +++ b/theseus_gui/src/helpers/auth.js @@ -14,7 +14,8 @@ import { invoke } from '@tauri-apps/api/tauri' // } /// Authenticate a user with Hydra - part 1 -/// This begins the authentication flow quasi-synchronously, returning a URL to visit (that the user will sign in at) +/// This begins the authentication flow quasi-synchronously +/// This returns a URL to be opened in a browser export async function authenticate_begin_flow() { return await invoke('auth_authenticate_begin_flow') } @@ -22,30 +23,34 @@ export async function authenticate_begin_flow() { /// Authenticate a user with Hydra - part 2 /// This completes the authentication flow quasi-synchronously, returning the sign-in credentials /// (and also adding the credentials to the state) +/// This returns a Credentials object export async function authenticate_await_completion() { return await invoke('auth_authenticate_await_completion') } /// Refresh some credentials using Hydra, if needed -// user is UUID -// update_name is bool +/// user is UUID +/// update_name is bool +/// Returns a Credentials object export async function refresh(user, update_name) { - return await invoke('auth_refresh', user, update_name) + return await invoke('auth_refresh', { user, update_name }) } /// Remove a user account from the database -// user is UUID +/// user is UUID export async function remove_user(user) { - return await invoke('auth_remove_user', user) + return await invoke('auth_remove_user', { user }) } // Add a path as a profile in-memory // user is UUID +/// Returns a bool export async function has_user(user) { - return await invoke('auth_has_user', user) + return await invoke('auth_has_user', { user }) } -// Remove a profile +/// Returns a list of users +/// Returns an Array of Credentials export async function users() { return await invoke('auth_users') } @@ -53,6 +58,7 @@ export async function users() { // Get a user by UUID // Prefer to use refresh() instead of this because it will refresh the credentials // user is UUID +// Returns Credentials (of user) export async function get_user(user) { - return await invoke('auth_get_user', user) + return await invoke('auth_get_user', { user }) } diff --git a/theseus_gui/src/helpers/profile.js b/theseus_gui/src/helpers/profile.js index 51376a3a4..d1594f2a9 100644 --- a/theseus_gui/src/helpers/profile.js +++ b/theseus_gui/src/helpers/profile.js @@ -10,42 +10,47 @@ export async function addDefaultInstance() { return await invoke('profile_create_empty') } -// Add empty default instance +/// Add empty default instance +/// Returns a path to the profile created export async function create() { return await invoke('profile_create') } // Add a profile to the in-memory state export async function add(profile) { - return await invoke('profile_add', profile) + return await invoke('profile_add', { profile }) } // Add a path as a profile in-memory export async function add_path(path) { - return await invoke('profile_add_path', path) + return await invoke('profile_add_path', { path }) } // Remove a profile export async function remove(path) { - return await invoke('profile_remove', path) + return await invoke('profile_remove', { path }) } // Get a profile by path +// Returns a Profile export async function get(path) { - return await invoke('profile_get', path) + return await invoke('profile_get', { path }) } // Check if a pathed profile is already managed by Theseus +// Returns bool export async function is_managed(path) { - return await invoke('profile_is_managed', path) + return await invoke('profile_is_managed', { path }) } // Check if a pathed profile is loaded +// Returns bool export async function is_loaded(path) { - return await invoke('profile_is_loaded', path) + return await invoke('profile_is_loaded', { path }) } // Get a copy of the profile set +// Returns hashmap of path -> Profile export async function list() { return await invoke('profile_list') } @@ -53,21 +58,21 @@ export async function list() { // Run Minecraft using a pathed profile // Returns PID of child export async function run(path, credentials) { - return await invoke('profile_run', path, credentials) + return await invoke('profile_run', { path, credentials }) } // Run Minecraft using a pathed profile // Waits for end export async function run_wait(path, credentials) { - return await invoke('run_wait', path, credentials) + return await invoke('profile_run_wait', { path, credentials }) } // Tries to kill a running minecraft process (if PID is still stored) export async function kill(child_pid) { - return await invoke('profile_kill', child_pid) + return await invoke('profile_kill', { child_pid }) } // Wait for a running minecraft process (a Child) export async function wait_for(child_pid) { - return await invoke('profile_wait_for', child_pid) + return await invoke('profile_wait_for', { child_pid }) } diff --git a/theseus_gui/src/helpers/settings.js b/theseus_gui/src/helpers/settings.js new file mode 100644 index 000000000..a3d727bf3 --- /dev/null +++ b/theseus_gui/src/helpers/settings.js @@ -0,0 +1,53 @@ +/** + * All theseus API calls return serialized values (both return values and errors); + * So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized, + * and deserialized into a usable JS object. + */ +import { invoke } from '@tauri-apps/api/tauri' + +// Settings object +/* + +Settings { + "memory": MemorySettings, + "game_resolution": [int int], + "custom_java_args": [String ...], + "custom_env_args" : [(string, string) ... ]>, + "java_8_path": Path (can be null), + "java_17_path": Path (can be null), + "default_user": Uuid string (can be null), + "hooks": Hooks, + "max_concurrent_downloads": uint, + "version": u32, +} + +Memorysettings { + "min": u32, can be null, + "max": u32, +} + +*/ + +// An example test function for getting/setting settings +export async function test() { + // First, print settings and store them to an object + let settings = await get() + console.log(JSON.stringify(settings)) + + // Then set some random settings in that object + settings.java_8_path = '/example/path' + + // Set the new settings object + await set(settings) + console.log(JSON.stringify(await get())) +} + +// Get full settings object +export async function get() { + return await invoke('settings_get') +} + +// Set full settings object +export async function set(settings) { + return await invoke('settings_set', { settings }) +} diff --git a/theseus_playground/src/main.rs b/theseus_playground/src/main.rs index 6a6dc8902..d9c864741 100644 --- a/theseus_playground/src/main.rs +++ b/theseus_playground/src/main.rs @@ -87,7 +87,7 @@ async fn main() -> theseus::Result<()> { // Attempt to get the default user, if it exists, and refresh their credentials let default_user_uuid = { let settings = st.settings.read().await; - settings.default_user.clone() + settings.default_user }; let credentials = if let Some(uuid) = default_user_uuid { println!("Attempting to refresh existing authentication.");