use crate::api::Result; use dashmap::DashMap; use path_util::SafeRelativeUtf8UnixPathBuf; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::{Path, PathBuf}; use tauri::{AppHandle, Manager, Runtime}; use tauri_plugin_fs::FsExt; use tauri_plugin_opener::OpenerExt; use theseus::DownloadReason; use theseus::data::{ AppliedContentSetPatch, ContentItem, Dependency, EditInstance as CoreEditInstance, InstanceInstallCandidate, InstanceInstallTarget, InstanceLaunchOverridesPatch, InstanceLink as CoreInstanceLink, InstanceMetadata, LinkedModpackInfo, SharedInstanceAttachment as CoreSharedInstanceAttachment, SharedInstanceRole, }; use theseus::instance::InstallProjectWithDependenciesRequest; use theseus::instance::QuickPlayType; use theseus::prelude::*; use theseus::server_address::ServerAddress; pub fn init() -> tauri::plugin::TauriPlugin { tauri::plugin::Builder::new("instance") .invoke_handler(tauri::generate_handler![ instance_remove, instance_get, instance_get_many, instance_list, instance_list_groups, instance_create_group, instance_rename_group, instance_delete_group, instance_set_group_order, instance_set_group_memberships, instance_get_projects, instance_get_installed_project_ids, instance_get_install_candidates, instance_content, instance_get_content_items, instance_refresh_content_updates, instance_get_dependencies_as_content_items, instance_get_linked_modpack_info, instance_get_linked_modpack_content, instance_get_optimal_jre_key, instance_get_full_path, instance_get_mod_full_path, instance_list_screenshots, instance_list_all_screenshots, instance_list_synced_screenshots, instance_save_edited_screenshot, instance_list_screenshot_groups, instance_create_screenshot_group, instance_rename_screenshot_group, instance_delete_screenshot_group, instance_set_screenshot_group_memberships, instance_import_screenshot_groups, instance_delete_screenshots, instance_export_screenshots, instance_move_screenshots, instance_open_screenshot, instance_set_synced_option, instance_get_synced_option_join_preview, instance_get_synced_options_overview, instance_get_global_synced_options, instance_set_global_synced_option, instance_get_command_history, instance_set_command_history, instance_open_synced_options_folder, instance_list_synced_servers, instance_update_synced_server, instance_remove_synced_server, instance_rebuild_synced_options, instance_check_installed, instance_update_all, instance_update_project, instance_add_project_from_version, instance_install_project_with_dependencies, instance_switch_project_version_with_dependencies, instance_add_project_from_path, instance_is_file_on_modrinth, instance_toggle_disable_project, instance_set_project_locked, instance_remove_project, instance_update_managed_modrinth_version, instance_repair_managed_modrinth, instance_run, instance_kill, instance_edit, instance_edit_icon, instance_edit_generated_icon, instance_cache_generated_icon, instance_get_recent_icon_configs, instance_share_can_current_user_use, instance_share_get_users, instance_share_invite_users, instance_share_create_invite_link, instance_share_get_invites, instance_share_revoke_invite, instance_share_remove_users, instance_share_get_publish_preview, instance_share_publish, instance_share_unlink, instance_share_unpublish, instance_export_mrpack, instance_get_pack_export_candidates, ]) .build() } #[derive(Serialize, Debug, Clone)] pub struct Instance { pub id: String, pub path: String, pub install_stage: String, pub launcher_feature_version: String, pub name: String, pub icon_path: Option, pub icon_config: Option, pub game_version: String, pub protocol_version: Option, pub loader: ModLoader, pub loader_version: Option, pub group_ids: Vec, pub synced_options: InstanceSyncedOptions, pub link: Option, pub shared_instance: Option, pub quarantined: bool, pub update_channel: ReleaseChannel, pub created: chrono::DateTime, pub modified: chrono::DateTime, pub last_played: Option>, pub submitted_time_played: u64, pub recent_time_played: u64, pub java_path: Option, pub extra_launch_args: Option>, pub custom_env_vars: Option>, pub memory: Option, pub force_fullscreen: Option, pub game_resolution: Option, pub hooks: Hooks, } #[derive(Serialize, Debug, Clone)] pub struct InstanceScreenshot { pub id: String, pub instance_id: String, pub instance_name: String, pub file_name: String, pub created_at: chrono::DateTime, pub modified_at: i64, pub group_id: Option, pub path: PathBuf, pub url: url::Url, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type", rename_all = "snake_case")] pub enum InstanceLink { ModrinthModpack { project_id: String, version_id: String, }, ServerProject { project_id: String, }, ServerProjectModpack { server_project_id: String, content_project_id: Option, content_version_id: String, project_id: Option, version_id: Option, }, ImportedModpack { project_id: Option, version_id: Option, name: Option, version_number: Option, filename: Option, }, ModrinthHosting { server_id: String, instance_ids: Vec, active_instance_id: Option, }, SharedInstance { modpack_project_id: Option, modpack_version_id: Option, }, } #[derive(Serialize, Debug, Clone)] pub struct SharedInstanceAttachment { pub id: String, pub role: SharedInstanceRole, pub manager_id: Option, pub server_manager_name: Option, pub server_manager_icon_url: Option, pub linked_user_id: Option, pub status: String, pub applied_version: Option, pub latest_version: Option, } impl From for SharedInstanceAttachment { fn from(attachment: CoreSharedInstanceAttachment) -> Self { Self { id: attachment.id.to_string(), role: attachment.role, manager_id: attachment.manager_id, server_manager_name: attachment.server_manager_name, server_manager_icon_url: attachment.server_manager_icon_url, linked_user_id: attachment.linked_user_id, status: attachment.status.as_str().to_string(), applied_version: attachment.applied_version, latest_version: attachment.latest_version, } } } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct EditInstance { pub name: Option, pub game_version: Option, pub loader: Option, #[serde( default, skip_serializing_if = "Option::is_none", with = "serde_with::rust::double_option" )] pub loader_version: Option>, pub group_ids: Option>, #[serde( default, skip_serializing_if = "Option::is_none", with = "serde_with::rust::double_option" )] pub link: Option>, pub update_channel: Option, #[serde( default, skip_serializing_if = "Option::is_none", with = "serde_with::rust::double_option" )] pub java_path: Option>, #[serde( default, skip_serializing_if = "Option::is_none", with = "serde_with::rust::double_option" )] pub extra_launch_args: Option>>, #[serde( default, skip_serializing_if = "Option::is_none", with = "serde_with::rust::double_option" )] pub custom_env_vars: Option>>, #[serde( default, skip_serializing_if = "Option::is_none", with = "serde_with::rust::double_option" )] pub memory: Option>, #[serde( default, skip_serializing_if = "Option::is_none", with = "serde_with::rust::double_option" )] pub force_fullscreen: Option>, #[serde( default, skip_serializing_if = "Option::is_none", with = "serde_with::rust::double_option" )] pub game_resolution: Option>, pub hooks: Option, } impl From for Instance { fn from(metadata: InstanceMetadata) -> Self { Self { id: metadata.instance.id, path: metadata.instance.path, install_stage: metadata.instance.install_stage.as_str().to_string(), launcher_feature_version: metadata .instance .launcher_feature_version .as_str() .to_string(), name: metadata.instance.name, icon_path: metadata.instance.icon_path, icon_config: metadata.icon_config, game_version: metadata.applied_content_set.game_version, protocol_version: metadata.applied_content_set.protocol_version, loader: metadata.applied_content_set.loader, loader_version: metadata.applied_content_set.loader_version, group_ids: metadata.group_ids, synced_options: metadata.synced_options, link: InstanceLink::from_core(metadata.link), shared_instance: metadata.shared_instance.map(Into::into), quarantined: metadata.quarantined, update_channel: metadata.instance.update_channel, created: metadata.instance.created, modified: metadata.instance.modified, last_played: metadata.instance.last_played, submitted_time_played: metadata.instance.submitted_time_played, recent_time_played: metadata.instance.recent_time_played, java_path: metadata.launch_overrides.java_path, extra_launch_args: metadata.launch_overrides.extra_launch_args, custom_env_vars: metadata.launch_overrides.custom_env_vars, memory: metadata.launch_overrides.memory, force_fullscreen: metadata.launch_overrides.force_fullscreen, game_resolution: metadata.launch_overrides.game_resolution, hooks: metadata.launch_overrides.hooks, } } } impl InstanceLink { fn from_core(link: CoreInstanceLink) -> Option { match link { CoreInstanceLink::Unmanaged => None, CoreInstanceLink::ModrinthModpack { project_id, version_id, } => Some(Self::ModrinthModpack { project_id, version_id, }), CoreInstanceLink::ServerProject { project_id } => { Some(Self::ServerProject { project_id }) } CoreInstanceLink::ServerProjectModpack { server_project_id, content_project_id, content_version_id, } => Some(Self::ServerProjectModpack { project_id: Some(server_project_id.clone()), version_id: Some(content_version_id.clone()), server_project_id, content_project_id: Some(content_project_id), content_version_id, }), CoreInstanceLink::ImportedModpack { project_id, version_id, name, version_number, filename, } => Some(Self::ImportedModpack { project_id, version_id, name, version_number, filename, }), CoreInstanceLink::ModrinthHosting { server_id, instance_ids, active_instance_id, } => Some(Self::ModrinthHosting { server_id: server_id.to_string(), instance_ids: instance_ids .into_iter() .map(|id| id.to_string()) .collect(), active_instance_id: active_instance_id.map(|id| id.to_string()), }), CoreInstanceLink::SharedInstance { modpack_project_id, modpack_version_id, } => Some(Self::SharedInstance { modpack_project_id, modpack_version_id, }), } } pub(crate) fn into_core(self) -> Result { match self { Self::ModrinthModpack { project_id, version_id, } => Ok(CoreInstanceLink::ModrinthModpack { project_id, version_id, }), Self::ServerProject { project_id } => { Ok(CoreInstanceLink::ServerProject { project_id }) } Self::ServerProjectModpack { server_project_id, content_project_id, content_version_id, .. } => Ok(CoreInstanceLink::ServerProjectModpack { server_project_id, content_project_id: content_project_id.unwrap_or_default(), content_version_id, }), Self::ImportedModpack { project_id, version_id, name, version_number, filename, } => Ok(CoreInstanceLink::ImportedModpack { project_id, version_id, name, version_number, filename, }), Self::ModrinthHosting { server_id, instance_ids, active_instance_id, } => Ok(CoreInstanceLink::ModrinthHosting { server_id: server_id.parse().map_err(|err| { theseus::Error::from(theseus::ErrorKind::InputError( format!("Invalid server id: {err}"), )) })?, instance_ids: instance_ids .into_iter() .map(|id| { id.parse().map_err(|err| { theseus::Error::from( theseus::ErrorKind::InputError(format!( "Invalid hosted instance id: {err}" )), ) }) }) .collect::, _>>()?, active_instance_id: active_instance_id .map(|id| { id.parse().map_err(|err| { theseus::Error::from( theseus::ErrorKind::InputError(format!( "Invalid active instance id: {err}" )), ) }) }) .transpose()?, }), Self::SharedInstance { modpack_project_id, modpack_version_id, } => Ok(CoreInstanceLink::SharedInstance { modpack_project_id, modpack_version_id, }), } } } fn edit_to_core(edit_instance: EditInstance) -> Result { Ok(CoreEditInstance { install_stage: None, launcher_feature_version: None, name: edit_instance.name, icon_path: None, icon_config: None, update_channel: edit_instance.update_channel, group_ids: edit_instance.group_ids, link: edit_instance .link .map(|link| match link { Some(link) => link.into_core(), None => Ok(CoreInstanceLink::Unmanaged), }) .transpose()?, launch_overrides: Some(InstanceLaunchOverridesPatch { java_path: edit_instance.java_path, extra_launch_args: edit_instance.extra_launch_args, custom_env_vars: edit_instance.custom_env_vars, memory: edit_instance.memory, force_fullscreen: edit_instance.force_fullscreen, game_resolution: edit_instance.game_resolution, hooks: edit_instance.hooks, }), content_set_patch: Some(AppliedContentSetPatch { source_kind: None, game_version: edit_instance.game_version, protocol_version: Some(None), loader: edit_instance.loader, loader_version: edit_instance.loader_version, }), last_played: None, submitted_time_played: None, recent_time_played: None, }) } #[tauri::command] pub async fn instance_remove(instance_id: &str) -> Result<()> { theseus::instance::remove(instance_id).await?; Ok(()) } #[tauri::command] pub async fn instance_get(instance_id: &str) -> Result> { Ok(theseus::instance::get(instance_id) .await? .map(Instance::from)) } #[tauri::command] pub async fn instance_get_many( instance_ids: Vec, ) -> Result> { let ids = instance_ids.iter().map(|x| &**x).collect::>(); Ok(theseus::instance::get_many(&ids) .await? .into_iter() .map(Instance::from) .collect()) } #[tauri::command] pub async fn instance_list() -> Result> { Ok(theseus::instance::list() .await? .into_iter() .map(Instance::from) .collect()) } #[tauri::command] pub async fn instance_list_groups() -> Result> { Ok(theseus::instance::list_groups().await?) } #[tauri::command] pub async fn instance_create_group( name: String, ) -> Result { Ok(theseus::instance::create_group(name).await?) } #[tauri::command] pub async fn instance_rename_group( id: String, new_name: String, ) -> Result { Ok(theseus::instance::rename_group(id, new_name).await?) } #[tauri::command] pub async fn instance_delete_group(id: String) -> Result<()> { Ok(theseus::instance::delete_group(id).await?) } #[tauri::command] pub async fn instance_set_group_order(group_ids: Vec) -> Result<()> { Ok(theseus::instance::set_group_order(group_ids).await?) } #[tauri::command] pub async fn instance_set_group_memberships( updates: Vec, ) -> Result<()> { Ok(theseus::instance::set_group_memberships(updates).await?) } #[tauri::command] pub async fn instance_get_projects( instance_id: &str, cache_behaviour: Option, ) -> Result> { Ok(theseus::instance::get_projects(instance_id, cache_behaviour).await?) } #[tauri::command] pub async fn instance_get_installed_project_ids( instance_id: &str, ) -> Result> { Ok(theseus::instance::get_installed_project_ids(instance_id).await?) } #[tauri::command] pub async fn instance_get_install_candidates( project_id: &str, project_type: ProjectType, targets: Vec, ) -> Result> { Ok(theseus::instance::get_install_candidates( project_id, project_type, targets, ) .await?) } #[tauri::command] pub async fn instance_content( instance_id: &str, cache_behaviour: Option, ) -> Result> { instance_get_content_items(instance_id, cache_behaviour).await } #[tauri::command] pub async fn instance_get_content_items( instance_id: &str, cache_behaviour: Option, ) -> Result> { Ok( theseus::instance::get_content_items(instance_id, cache_behaviour) .await?, ) } #[tauri::command] pub async fn instance_refresh_content_updates(instance_id: &str) -> Result<()> { Ok(theseus::instance::refresh_content_updates(instance_id).await?) } #[tauri::command] pub async fn instance_get_dependencies_as_content_items( dependencies: Vec, cache_behaviour: Option, ) -> Result> { Ok(theseus::instance::get_dependencies_as_content_items( dependencies, cache_behaviour, ) .await?) } #[tauri::command] pub async fn instance_get_linked_modpack_info( instance_id: &str, cache_behaviour: Option, ) -> Result> { Ok( theseus::instance::get_linked_modpack_info( instance_id, cache_behaviour, ) .await?, ) } #[tauri::command] pub async fn instance_get_linked_modpack_content( instance_id: &str, cache_behaviour: Option, ) -> Result> { Ok(theseus::instance::get_linked_modpack_content( instance_id, cache_behaviour, ) .await?) } #[tauri::command] pub async fn instance_get_full_path(instance_id: &str) -> Result { Ok(theseus::instance::get_full_path(instance_id).await?) } #[tauri::command] pub async fn instance_get_mod_full_path( instance_id: &str, project_path: &str, ) -> Result { Ok(theseus::instance::get_mod_full_path(instance_id, project_path).await?) } #[tauri::command] pub async fn instance_list_screenshots( app_handle: AppHandle, instance_id: &str, ) -> Result> { let screenshots = theseus::instance::list_screenshots(instance_id).await?; serialize_screenshots(&app_handle, screenshots) } #[tauri::command] pub async fn instance_list_all_screenshots( app_handle: AppHandle, ) -> Result> { let screenshots = theseus::instance::list_all_screenshots().await?; serialize_screenshots(&app_handle, screenshots) } #[tauri::command] pub async fn instance_list_synced_screenshots( app_handle: AppHandle, ) -> Result> { let screenshots = theseus::instance::list_synced_screenshots().await?; serialize_screenshots(&app_handle, screenshots) } #[tauri::command] pub async fn instance_save_edited_screenshot( app_handle: AppHandle, key: theseus::instance::ScreenshotKey, png_bytes: Vec, mode: theseus::instance::ScreenshotEditSaveMode, ) -> Result { let screenshot = theseus::instance::save_edited_screenshot(key, png_bytes, mode).await?; serialize_screenshot(&app_handle, screenshot) } #[tauri::command] pub async fn instance_list_screenshot_groups() -> Result> { Ok(theseus::instance::list_screenshot_groups().await?) } #[tauri::command] pub async fn instance_create_screenshot_group( name: String, screenshot_ids: Vec, ) -> Result { Ok( theseus::instance::create_screenshot_group(name, screenshot_ids) .await?, ) } #[tauri::command] pub async fn instance_rename_screenshot_group( id: String, new_name: String, ) -> Result { Ok(theseus::instance::rename_screenshot_group(id, new_name).await?) } #[tauri::command] pub async fn instance_delete_screenshot_group(id: String) -> Result<()> { Ok(theseus::instance::delete_screenshot_group(id).await?) } #[tauri::command] pub async fn instance_set_screenshot_group_memberships( updates: Vec, ) -> Result<()> { Ok(theseus::instance::set_screenshot_group_memberships(updates).await?) } #[tauri::command] pub async fn instance_import_screenshot_groups( groups: Vec, ) -> Result<()> { Ok(theseus::instance::import_screenshot_groups(groups).await?) } #[tauri::command] pub async fn instance_delete_screenshots( keys: Vec, ) -> Result<()> { Ok(theseus::instance::delete_screenshots(&keys).await?) } #[tauri::command] pub async fn instance_export_screenshots( keys: Vec, export_path: PathBuf, ) -> Result<()> { Ok(theseus::instance::export_screenshots(&keys, export_path).await?) } #[tauri::command] pub async fn instance_move_screenshots( keys: Vec, target_instance_id: &str, ) -> Result> { Ok(theseus::instance::move_screenshots(&keys, target_instance_id).await?) } #[tauri::command] pub async fn instance_open_screenshot( app_handle: AppHandle, key: theseus::instance::ScreenshotKey, ) -> Result<()> { let path = theseus::instance::get_screenshot_path(&key).await?; app_handle .opener() .reveal_item_in_dir(path) .map_err(|error| std::io::Error::other(error.to_string()))?; Ok(()) } #[tauri::command] pub async fn instance_set_synced_option( instance_id: &str, option: InstanceSyncedOption, enabled: bool, resolution: Option, ) -> Result { Ok(Instance::from( theseus::instance::set_synced_option( instance_id, option, enabled, resolution, ) .await?, )) } #[tauri::command] pub async fn instance_get_synced_option_join_preview( instance_id: &str, option: InstanceSyncedOption, ) -> Result { Ok( theseus::instance::get_synced_option_join_preview(instance_id, option) .await?, ) } #[tauri::command] pub async fn instance_get_synced_options_overview( instance_id: &str, ) -> Result { Ok(theseus::instance::get_synced_options_overview(instance_id).await?) } #[tauri::command] pub async fn instance_get_global_synced_options() -> Result { Ok(theseus::instance::get_global_synced_options().await?) } #[tauri::command] pub async fn instance_set_global_synced_option( option: InstanceSyncedOption, enabled: bool, ) -> Result { Ok(theseus::instance::set_global_synced_option(option, enabled).await?) } #[tauri::command] pub async fn instance_get_command_history() -> Result { Ok(theseus::instance::get_command_history().await?) } #[tauri::command] pub async fn instance_set_command_history(contents: &str) -> Result { Ok(theseus::instance::set_command_history(contents).await?) } #[tauri::command] pub async fn instance_open_synced_options_folder( app_handle: AppHandle, ) -> Result<()> { let path = theseus::instance::get_synced_options_folder().await?; app_handle .opener() .open_path(path.to_string_lossy(), None::<&str>) .map_err(|error| std::io::Error::other(error.to_string()))?; Ok(()) } #[tauri::command] pub async fn instance_list_synced_servers() -> Result> { Ok(theseus::instance::list_synced_servers().await?) } #[tauri::command] pub async fn instance_update_synced_server( server: theseus::instance::SyncedServer, ) -> Result<()> { Ok(theseus::instance::update_synced_server(server).await?) } #[tauri::command] pub async fn instance_remove_synced_server(server_id: &str) -> Result<()> { Ok(theseus::instance::remove_synced_server(server_id).await?) } #[tauri::command] pub async fn instance_rebuild_synced_options( instance_id: Option<&str>, ) -> Result<()> { if let Some(instance_id) = instance_id { theseus::instance::reconcile_instance_synced_options(instance_id) .await?; } else { theseus::instance::reconcile_all_synced_options().await?; } Ok(()) } fn serialize_screenshots( app_handle: &AppHandle, screenshots: Vec, ) -> Result> { let mut result = Vec::with_capacity(screenshots.len()); for screenshot in screenshots { result.push(serialize_screenshot(app_handle, screenshot)?); } Ok(result) } fn serialize_screenshot( app_handle: &AppHandle, screenshot: theseus::instance::InstanceScreenshot, ) -> Result { app_handle .asset_protocol_scope() .allow_file(&screenshot.path) .map_err(|error| std::io::Error::other(error.to_string()))?; app_handle .fs_scope() .allow_file(&screenshot.path) .map_err(|error| std::io::Error::other(error.to_string()))?; let mut url = super::utils::tauri_convert_file_src(&screenshot.path)?; url.query_pairs_mut() .append_pair("revision", &screenshot.modified_at.to_string()); Ok(InstanceScreenshot { id: screenshot.id, instance_id: screenshot.instance_id, instance_name: screenshot.instance_name, file_name: screenshot.file_name, created_at: screenshot.created_at, modified_at: screenshot.modified_at, group_id: screenshot.group_id, path: screenshot.path, url, }) } #[tauri::command] pub async fn instance_get_optimal_jre_key( instance_id: &str, ) -> Result> { Ok(theseus::instance::get_optimal_jre_key(instance_id).await?) } #[tauri::command] pub async fn instance_check_installed( instance_id: &str, project_id: &str, ) -> Result { let check_project_id = project_id; if let Ok(projects) = theseus::instance::get_projects(instance_id, None).await { Ok(projects.into_iter().any(|(_, project)| { project .metadata .as_ref() .is_some_and(|metadata| check_project_id == metadata.project_id) })) } else { Ok(false) } } #[tauri::command] pub async fn instance_update_all( instance_id: &str, ) -> Result> { Ok(theseus::instance::update_all_projects(instance_id).await?) } #[tauri::command] pub async fn instance_update_project( instance_id: &str, project_path: &str, ) -> Result { Ok( theseus::instance::update_project(instance_id, project_path, None) .await?, ) } #[tauri::command] pub async fn instance_add_project_from_version( instance_id: &str, version_id: &str, reason: DownloadReason, dependent_on_version_id: Option, ) -> Result { Ok(theseus::instance::add_project_from_version( instance_id, version_id, reason, dependent_on_version_id, ) .await?) } #[tauri::command] pub async fn instance_install_project_with_dependencies( instance_id: &str, request: InstallProjectWithDependenciesRequest, ) -> Result { Ok(theseus::instance::install_project_with_dependencies( instance_id, request, ) .await?) } #[tauri::command] pub async fn instance_switch_project_version_with_dependencies( instance_id: &str, project_path: &str, version_id: &str, ) -> Result { Ok(theseus::instance::switch_project_version_with_dependencies( instance_id, project_path, version_id, ) .await?) } #[tauri::command] pub async fn instance_add_project_from_path( instance_id: &str, project_path: &Path, project_type: Option, ) -> Result { Ok(theseus::instance::add_project_from_path( instance_id, project_path, project_type, ) .await?) } #[tauri::command] pub async fn instance_is_file_on_modrinth(project_path: &Path) -> Result { Ok(theseus::instance::is_file_on_modrinth(project_path).await?) } #[tauri::command] pub async fn instance_toggle_disable_project( instance_id: &str, project_path: &str, desired_enabled: Option, ) -> Result { Ok(theseus::instance::toggle_disable_project( instance_id, project_path, desired_enabled, ) .await?) } #[tauri::command] pub async fn instance_set_project_locked( instance_id: &str, project_path: &str, locked: bool, ) -> Result<()> { theseus::instance::set_project_locked(instance_id, project_path, locked) .await?; Ok(()) } #[tauri::command] pub async fn instance_remove_project( instance_id: &str, project_path: &str, ) -> Result<()> { theseus::instance::remove_project(instance_id, project_path).await?; Ok(()) } #[tauri::command] pub async fn instance_update_managed_modrinth_version( instance_id: String, version_id: String, ) -> Result { Ok(theseus::instance::update_managed_modrinth_version( &instance_id, &version_id, ) .await?) } #[tauri::command] pub async fn instance_repair_managed_modrinth( instance_id: &str, ) -> Result { Ok(theseus::instance::repair_managed_modrinth(instance_id).await?) } #[tauri::command] pub async fn instance_export_mrpack( instance_id: &str, export_location: PathBuf, included_overrides: Vec, excluded_overrides: Vec, version_id: Option, description: Option, name: Option, ) -> Result<()> { theseus::instance::export_mrpack( instance_id, export_location, included_overrides, excluded_overrides, version_id, description, name, ) .await?; Ok(()) } #[tauri::command] pub async fn instance_get_pack_export_candidates( instance_id: &str, parent: Option, ) -> Result> { Ok(theseus::instance::get_pack_export_candidates_for_parent( instance_id, parent, ) .await?) } #[tauri::command] pub async fn instance_run( instance_id: &str, server_address: Option, ) -> Result { let quick_play = match server_address { Some(addr) => QuickPlayType::Server(ServerAddress::Unresolved(addr)), None => QuickPlayType::None, }; Ok(theseus::instance::run(instance_id, quick_play).await?) } #[tauri::command] pub async fn instance_kill(instance_id: &str) -> Result<()> { theseus::instance::kill(instance_id).await?; Ok(()) } #[tauri::command] pub async fn instance_edit( instance_id: &str, edit_instance: EditInstance, ) -> Result<()> { theseus::instance::edit(instance_id, edit_to_core(edit_instance)?).await?; Ok(()) } #[tauri::command] pub async fn instance_edit_icon( instance_id: &str, icon_path: Option<&Path>, ) -> Result<()> { theseus::instance::edit_icon(instance_id, icon_path).await?; Ok(()) } #[tauri::command] pub async fn instance_edit_generated_icon( instance_id: &str, config: theseus::data::InstanceIconConfig, symbol_bytes: Vec, only_if_empty: Option, ) -> Result> { if only_if_empty.unwrap_or(false) { return Ok(theseus::instance::edit_generated_icon_if_empty( instance_id, config, symbol_bytes, ) .await?); } Ok(Some( theseus::instance::edit_generated_icon( instance_id, config, symbol_bytes, ) .await?, )) } #[tauri::command] pub async fn instance_cache_generated_icon( config: theseus::data::InstanceIconConfig, symbol_bytes: Vec, add_to_recents: bool, ) -> Result { Ok(theseus::instance::cache_generated_icon( config, symbol_bytes, add_to_recents, ) .await?) } #[tauri::command] pub async fn instance_get_recent_icon_configs() -> Result> { Ok(theseus::instance::get_recent_icon_configs().await?) } #[tauri::command] pub async fn instance_share_can_current_user_use() -> Result { Ok(theseus::instance::can_active_user_use_shared_instances().await?) } #[tauri::command] pub async fn instance_share_get_users( instance_id: &str, ) -> Result { Ok(theseus::instance::get_shared_instance_users(instance_id).await?) } #[tauri::command] pub async fn instance_share_invite_users( instance_id: &str, user_ids: Vec, ) -> Result { Ok( theseus::instance::invite_shared_instance_users(instance_id, user_ids) .await?, ) } #[tauri::command] pub async fn instance_share_create_invite_link( instance_id: &str, max_age_seconds: Option, max_uses: Option, replace_invite_id: Option, ) -> Result { Ok(theseus::instance::create_shared_instance_invite_link( instance_id, max_age_seconds, max_uses, replace_invite_id, ) .await?) } #[tauri::command] pub async fn instance_share_get_invites( instance_id: &str, ) -> Result> { Ok(theseus::instance::get_shared_instance_invites(instance_id).await?) } #[tauri::command] pub async fn instance_share_revoke_invite( instance_id: &str, invite_id: String, ) -> Result<()> { Ok( theseus::instance::revoke_shared_instance_invite( instance_id, invite_id, ) .await?, ) } #[tauri::command] pub async fn instance_share_remove_users( instance_id: &str, user_ids: Vec, has_pending_recipients: bool, ) -> Result { Ok(theseus::instance::remove_shared_instance_users( instance_id, user_ids, has_pending_recipients, ) .await?) } #[tauri::command] pub async fn instance_share_get_publish_preview( instance_id: &str, ) -> Result> { Ok( theseus::instance::get_shared_instance_publish_preview(instance_id) .await?, ) } #[tauri::command] pub async fn instance_share_publish( instance_id: &str, config_paths: Vec, ) -> Result { Ok( theseus::instance::publish_shared_instance(instance_id, config_paths) .await? .into(), ) } #[tauri::command] pub async fn instance_share_unlink(instance_id: &str) -> Result<()> { theseus::instance::unlink_shared_instance(instance_id).await?; Ok(()) } #[tauri::command] pub async fn instance_share_unpublish(instance_id: &str) -> Result<()> { theseus::instance::unpublish_shared_instance(instance_id).await?; Ok(()) }