From fb14f96eea517a37b9fd889f3c59b93780db2530 Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Thu, 28 Mar 2024 22:08:04 +0100 Subject: [PATCH] refactor: Lots of stuff refactored --- onelauncher/src/error.rs | 2 +- onelauncher/src/game/client.rs | 228 +----------------- onelauncher/src/game/client_manager.rs | 203 ++++++++++++++++ onelauncher/src/game/clients/mod.rs | 27 +++ onelauncher/src/game/{ => clients}/vanilla.rs | 34 +-- onelauncher/src/game/java.rs | 2 +- onelauncher/src/game/minecraft.rs | 8 +- onelauncher/src/game/mod.rs | 3 +- onelauncher/src/utils/http.rs | 41 ++-- src-tauri/build.rs | 1 + .../permissions/onelauncher/default.toml | 1 + src-tauri/src/api/game.rs | 12 +- src-tauri/src/api/mod.rs | 3 +- src/bridge/auth.ts | 5 - src/bridge/game.ts | 21 +- src/ui/pages/Home.tsx | 29 ++- 16 files changed, 326 insertions(+), 294 deletions(-) create mode 100644 onelauncher/src/game/client_manager.rs create mode 100644 onelauncher/src/game/clients/mod.rs rename onelauncher/src/game/{ => clients}/vanilla.rs (81%) diff --git a/onelauncher/src/error.rs b/onelauncher/src/error.rs index bf77a290..ad5812a6 100644 --- a/onelauncher/src/error.rs +++ b/onelauncher/src/error.rs @@ -65,7 +65,7 @@ pub enum ErrorKind { /// Wrapper around [`crate::game::client::ClientManagerError`] to handle directory errors. #[error("failed to manage clients: {0}")] - ClientManagerError(#[from] crate::game::client::ClientManagerError), + ClientManagerError(#[from] crate::game::client_manager::ClientManagerError), } #[derive(Debug)] diff --git a/onelauncher/src/game/client.rs b/onelauncher/src/game/client.rs index 68c6af43..79e01c26 100644 --- a/onelauncher/src/game/client.rs +++ b/onelauncher/src/game/client.rs @@ -1,27 +1,21 @@ -use std::{collections::HashMap, fs, path::PathBuf}; +use std::path::PathBuf; -use anyhow::anyhow; use async_trait::async_trait; use chrono::{DateTime, Local}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::utils::dirs; - -use super::{ - minecraft::{MinecraftManifest, ReleaseType}, - vanilla::{self, VanillaClientProps}, -}; +use super::{clients::ClientType, minecraft::{MinecraftManifest, ReleaseType}}; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct Version { - id: String, - url: String, +pub struct MinecraftVersion { + pub id: String, + pub url: String, #[serde(default)] - release_type: ReleaseType, + pub release_type: ReleaseType, #[serde(default)] - release_time: chrono::DateTime, + pub release_time: chrono::DateTime, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -41,30 +35,6 @@ pub struct Cluster { pub client: ClientType, } -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "type")] -pub enum ClientType { - Vanilla(VanillaClientProps), -} - -impl ClientType { - pub async fn get_versions(&self, file: Option<&PathBuf>) -> crate::Result> { - match self { - ClientType::Vanilla(_) => vanilla::get_versions(file).await, - } - } -} - -pub fn get_impl<'a>( - client: &'a ClientType, - cluster: &'a Cluster, - manifest: &'a Manifest, -) -> Box + 'a> { - Box::new(match client { - ClientType::Vanilla(_) => vanilla::VanillaClient::new(cluster, manifest), - }) -} - #[async_trait] pub trait ClientTrait<'a>: Send + Sync { fn new(cluster: &'a Cluster, manifest: &'a Manifest) -> Self @@ -122,184 +92,4 @@ macro_rules! impl_game_client { self.manifest } }; -} - -#[derive(Debug, thiserror::Error)] -pub enum ClientManagerError { - #[error("Cluster not found")] - ClusterNotFound, - #[error("Manifest not found")] - ManifestNotFound, -} - -pub struct ClientManager { - clusters: HashMap, - manifests: HashMap, -} - -impl ClientManager { - pub fn new() -> crate::Result { - let clusters = load_and_serialize::(&dirs::clusters_dir()?)?; - - let manifests = load_and_serialize::(&dirs::manifests_dir()?)?; - - Ok(Self { - clusters, - manifests, - }) - } - - pub fn get_impl_uuid<'a>(&'a self, uuid: Uuid) -> crate::Result + 'a>> { - let cluster = self.get_cluster(uuid)?; - let manifest = self.get_manifest(uuid)?; - - Ok(get_impl(&cluster.client, &cluster, &manifest)) - } - - pub fn get_clusters(&self) -> Vec<&Cluster> { - self.clusters.values().collect() - } - - pub fn get_clusters_owned(&self) -> Vec { - self.clusters.values().cloned().collect() - } - - pub fn get_cluster(&self, uuid: Uuid) -> crate::Result<&Cluster> { - self.clusters - .get(&uuid) - .ok_or(ClientManagerError::ClusterNotFound.into()) - } - - pub fn get_cluster_mut(&mut self, uuid: Uuid) -> crate::Result<&mut Cluster> { - self.clusters - .get_mut(&uuid) - .ok_or(ClientManagerError::ClusterNotFound.into()) - } - - pub fn get_manifest(&self, uuid: Uuid) -> crate::Result<&Manifest> { - self.manifests - .get(&uuid) - .ok_or(ClientManagerError::ManifestNotFound.into()) - } - - pub fn get_manifest_mut(&mut self, uuid: Uuid) -> crate::Result<&mut Manifest> { - self.manifests - .get_mut(&uuid) - .ok_or(ClientManagerError::ManifestNotFound.into()) - } - - pub async fn create_cluster( - &mut self, - name: String, - version: String, - cover: Option, - group: Option, - client: ClientType, - ) -> crate::Result { - let version_cache = dirs::app_config_dir()?.join("versions_cache.json"); - let versions = client.get_versions(Some(&version_cache)).await?; - let url = &versions - .iter() - .find(|v| v.id == version) - .ok_or(anyhow!("Version not found"))? - .url; - - let uuid = Uuid::new_v4(); - - // Save the manifest - let minecraft_manifest = vanilla::retrieve_version_manifest(url).await?; - let manifest = Manifest { - id: uuid, - manifest: minecraft_manifest, - }; - - save( - &dirs::manifests_dir()?.join(format!("{}.json", uuid)), - &manifest, - )?; - self.manifests.insert(uuid, manifest); - - // Save the cluster - let cluster = Cluster { - id: uuid, - created_at: Local::now(), - name, - cover, - group, - client, - }; - - save( - &dirs::clusters_dir()?.join(format!("{}.json", uuid)), - &cluster, - )?; - self.clusters.insert(uuid, cluster); - - Ok(uuid) - } -} - -fn save(path: &PathBuf, object: T) -> crate::Result<()> -where - T: Serialize, -{ - if !path.exists() { - fs::create_dir_all( - path.parent() - .expect("Couldn't get parent of path whilst saving object. 'client.rs'"), - )?; - } - - let content = serde_json::to_string(&object)?; - fs::write(path, content)?; - Ok(()) -} - -fn load_and_serialize(dir: &PathBuf) -> crate::Result> -where - T: DeserializeOwned, -{ - let mut result = HashMap::::new(); - - if !dir.exists() { - fs::create_dir_all(dir)?; - return Ok(result); - } - - for file in fs::read_dir(dir)? { - let file = file?; - let file_name = file.file_name(); - let file_name = file_name - .to_str() - .ok_or(anyhow!("Couldn't convert OsStr to str"))? - .replace(".json", ""); - let uuid = match Uuid::parse_str(&file_name) { - Ok(uuid) => uuid, - Err(_) => { - eprintln!("Couldn't parse file name as UUID: '{:?}'", file_name); - continue; - } - }; - - let path = file.path(); - let content = match fs::read_to_string(&path) { - Ok(content) => content, - Err(_) => { - eprintln!("Couldn't read file: '{:?}'", path); - continue; - } - }; - - let parsed = match serde_json::from_str::(&content) { - Ok(parsed) => parsed, - Err(_) => { - eprintln!("Couldn't parse file '{}' content as JSON", path.display()); - continue; - } - }; - - result.insert(uuid, parsed); - } - - Ok(result) -} +} \ No newline at end of file diff --git a/onelauncher/src/game/client_manager.rs b/onelauncher/src/game/client_manager.rs new file mode 100644 index 00000000..1aa42388 --- /dev/null +++ b/onelauncher/src/game/client_manager.rs @@ -0,0 +1,203 @@ +use std::{collections::HashMap, fs, path::PathBuf}; + +use anyhow::anyhow; +use chrono::Local; +use serde::{de::DeserializeOwned, Serialize}; +use uuid::Uuid; + +use crate::utils::dirs; + +use super::{client::{ClientTrait, Cluster, Manifest}, clients::{self, vanilla, ClientType}}; + +#[derive(Debug, thiserror::Error)] +pub enum ClientManagerError { + #[error("Cluster not found")] + ClusterNotFound, + #[error("Manifest not found")] + ManifestNotFound, +} + +pub struct ClientManager { + clusters: HashMap, + manifests: HashMap, +} + +impl ClientManager { + pub fn new() -> crate::Result { + let clusters = load_and_serialize::(&dirs::clusters_dir()?)?; + + let manifests = load_and_serialize::(&dirs::manifests_dir()?)?; + + Ok(Self { + clusters, + manifests, + }) + } + + pub fn get_impl_uuid<'a>(&'a self, uuid: Uuid) -> crate::Result + 'a>> { + let cluster = self.get_cluster(uuid)?; + let manifest = self.get_manifest(uuid)?; + + Ok(clients::get_impl(&cluster.client, &cluster, &manifest)) + } + + pub fn get_clusters(&self) -> Vec<&Cluster> { + self.clusters.values().collect() + } + + pub fn get_clusters_owned(&self) -> Vec { + self.clusters.values().cloned().collect() + } + + pub fn get_cluster(&self, uuid: Uuid) -> crate::Result<&Cluster> { + self.clusters + .get(&uuid) + .ok_or(ClientManagerError::ClusterNotFound.into()) + } + + pub fn get_cluster_mut(&mut self, uuid: Uuid) -> crate::Result<&mut Cluster> { + self.clusters + .get_mut(&uuid) + .ok_or(ClientManagerError::ClusterNotFound.into()) + } + + pub fn get_manifest(&self, uuid: Uuid) -> crate::Result<&Manifest> { + self.manifests + .get(&uuid) + .ok_or(ClientManagerError::ManifestNotFound.into()) + } + + pub fn get_manifest_mut(&mut self, uuid: Uuid) -> crate::Result<&mut Manifest> { + self.manifests + .get_mut(&uuid) + .ok_or(ClientManagerError::ManifestNotFound.into()) + } +} + +impl ClientManager { + pub async fn launch_cluster( + &mut self, + uuid: Uuid, + ) -> crate::Result<()> { + let client = self.get_impl_uuid(uuid)?; + client.setup().await?; + client.launch().await?; + Ok(()) + } + + pub async fn create_cluster( + &mut self, + name: String, + version: String, + cover: Option, + group: Option, + client: ClientType, + ) -> crate::Result { + let version_cache = dirs::app_config_dir()?.join("versions_cache.json"); + let versions = clients::get_versions(&client, Some(&version_cache)).await?; + let url = &versions + .iter() + .find(|v| v.id == version) + .ok_or(anyhow!("Version not found"))? + .url; + + let uuid = Uuid::new_v4(); + + // Save the manifest + // TODO: Is this correct? + let minecraft_manifest = vanilla::retrieve_version_manifest(url).await?; + let manifest = Manifest { + id: uuid, + manifest: minecraft_manifest, + }; + + save( + &dirs::manifests_dir()?.join(format!("{}.json", uuid)), + &manifest, + )?; + self.manifests.insert(uuid, manifest); + + // Save the cluster + let cluster = Cluster { + id: uuid, + created_at: Local::now(), + name, + cover, + group, + client, + }; + + save( + &dirs::clusters_dir()?.join(format!("{}.json", uuid)), + &cluster, + )?; + self.clusters.insert(uuid, cluster); + + Ok(uuid) + } +} + +fn save(path: &PathBuf, object: T) -> crate::Result<()> +where + T: Serialize, +{ + if !path.exists() { + fs::create_dir_all( + path.parent() + .expect("Couldn't get parent of path whilst saving object. 'client.rs'"), + )?; + } + + let content = serde_json::to_string(&object)?; + fs::write(path, content)?; + Ok(()) +} + +fn load_and_serialize(dir: &PathBuf) -> crate::Result> +where + T: DeserializeOwned, +{ + let mut result = HashMap::::new(); + + if !dir.exists() { + fs::create_dir_all(dir)?; + return Ok(result); + } + + for file in fs::read_dir(dir)? { + let file = file?; + let file_name = file.file_name(); + let file_name = file_name + .to_str() + .ok_or(anyhow!("Couldn't convert OsStr to str"))? + .replace(".json", ""); + let uuid = match Uuid::parse_str(&file_name) { + Ok(uuid) => uuid, + Err(_) => { + eprintln!("Couldn't parse file name as UUID: '{:?}'", file_name); + continue; + } + }; + + let path = file.path(); + let content = match fs::read_to_string(&path) { + Ok(content) => content, + Err(_) => { + eprintln!("Couldn't read file: '{:?}'", path); + continue; + } + }; + + let parsed = match serde_json::from_str::(&content) { + Ok(parsed) => parsed, + Err(_) => { + eprintln!("Couldn't parse file '{}' content as JSON", path.display()); + continue; + } + }; + + result.insert(uuid, parsed); + } + + Ok(result) +} diff --git a/onelauncher/src/game/clients/mod.rs b/onelauncher/src/game/clients/mod.rs new file mode 100644 index 00000000..1f42aef6 --- /dev/null +++ b/onelauncher/src/game/clients/mod.rs @@ -0,0 +1,27 @@ +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; + +use self::vanilla::VanillaClientProps; + +use super::client::{ClientTrait, Cluster, Manifest, MinecraftVersion}; + +pub mod vanilla; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type")] +pub enum ClientType { + Vanilla(VanillaClientProps), +} + +pub async fn get_versions(client: &ClientType, file: Option<&PathBuf>) -> crate::Result> { + match client { + ClientType::Vanilla(_) => vanilla::get_versions(file).await, + } +} + +pub fn get_impl<'a>(client: &'a ClientType, cluster: &'a Cluster, manifest: &'a Manifest) -> Box + 'a> { + Box::new(match client { + ClientType::Vanilla(_) => vanilla::VanillaClient::new(cluster, manifest), + }) +} \ No newline at end of file diff --git a/onelauncher/src/game/vanilla.rs b/onelauncher/src/game/clients/vanilla.rs similarity index 81% rename from onelauncher/src/game/vanilla.rs rename to onelauncher/src/game/clients/vanilla.rs index 97b7f4c4..70362414 100644 --- a/onelauncher/src/game/vanilla.rs +++ b/onelauncher/src/game/clients/vanilla.rs @@ -1,11 +1,9 @@ -use super::{ - client::{ClientTrait, Cluster, Manifest, Version}, - minecraft::MinecraftManifest, -}; use crate::{ - constants::MINECRAFT_VERSIONS_MANIFEST, - create_game_client, impl_game_client, - utils::{dirs, file, http}, + constants::MINECRAFT_VERSIONS_MANIFEST, + create_game_client, + game::{client::{ClientTrait, Cluster, Manifest, MinecraftVersion}, minecraft::MinecraftManifest}, + impl_game_client, + utils::{dirs, http} }; use anyhow::anyhow; use async_trait::async_trait; @@ -31,6 +29,8 @@ impl<'a> ClientTrait<'a> for VanillaClient<'a> { } async fn setup(&self) -> crate::Result<()> { + let client_path = self.install_game().await?; + println!("{:?}", client_path); Ok(()) } @@ -42,17 +42,7 @@ impl<'a> ClientTrait<'a> for VanillaClient<'a> { fs::create_dir_all(&file)?; let artifact = &manifest.downloads.client; - http::download_file(&artifact.url, &file).await?; - let file_hash = file::file_sha1(&file)?; - - println!("Downloaded: '{}' | '{}'", file_hash, artifact.sha1); - if file_hash != artifact.sha1 { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - "Hashes do not match", - ) - .into()); - } + http::download_file_sha1_check(&artifact.url, &file, &artifact.sha1).await?; } Ok(file) @@ -73,16 +63,16 @@ impl<'a> ClientTrait<'a> for VanillaClient<'a> { #[derive(Clone, Serialize, Deserialize)] struct VersionList { - versions: Vec, + versions: Vec, } #[derive(Serialize, Deserialize)] struct CachedVersions { last_updated: i64, - versions: Vec, + versions: Vec, } -pub async fn get_versions(file: Option<&PathBuf>) -> crate::Result> { +pub async fn get_versions(file: Option<&PathBuf>) -> crate::Result> { if let Some(file) = file { if file.exists() && file.is_file() { if let Some(versions) = get_cached_versions(file).await? { @@ -110,7 +100,7 @@ pub async fn get_versions(file: Option<&PathBuf>) -> crate::Result> Ok(response.versions) } -async fn get_cached_versions(file: &PathBuf) -> crate::Result>> { +async fn get_cached_versions(file: &PathBuf) -> crate::Result>> { let cached = serde_json::from_str::(&fs::read_to_string(file)?)?; let head_request = http::create_client()? .head(MINECRAFT_VERSIONS_MANIFEST) diff --git a/onelauncher/src/game/java.rs b/onelauncher/src/game/java.rs index 483ee249..304ba616 100644 --- a/onelauncher/src/game/java.rs +++ b/onelauncher/src/game/java.rs @@ -104,7 +104,7 @@ async fn download( let latest = response.as_array().unwrap().first().unwrap(); let download_url = latest.get("download_url").unwrap().as_str().unwrap(); - if let Err(err) = http::download_file(download_url, archive.as_path()).await { + if let Err(err) = http::download_file(download_url, archive).await { return Err(ErrorKind::JavaError(JavaDownloadError::DownloadError(err.to_string())).into()); }; diff --git a/onelauncher/src/game/minecraft.rs b/onelauncher/src/game/minecraft.rs index 079f23d6..bb49ecb0 100644 --- a/onelauncher/src/game/minecraft.rs +++ b/onelauncher/src/game/minecraft.rs @@ -30,8 +30,8 @@ pub struct MinecraftManifest { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ModernArguments { - game: Vec, - jvm: Vec, + pub game: Vec, + pub jvm: Vec, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -46,11 +46,11 @@ pub enum ModernArgumentsItem { #[serde(rename_all = "camelCase")] pub struct ArgumentRule { #[serde(skip_serializing_if = "Vec::is_empty")] - rules: Vec, + pub rules: Vec, #[serde(skip_serializing_if = "Vec::is_empty")] #[serde(deserialize_with = "string_or_seq")] - value: Vec, + pub value: Vec, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/onelauncher/src/game/mod.rs b/onelauncher/src/game/mod.rs index af961ef6..075903dd 100644 --- a/onelauncher/src/game/mod.rs +++ b/onelauncher/src/game/mod.rs @@ -1,4 +1,5 @@ pub mod client; pub mod java; pub mod minecraft; -pub mod vanilla; +pub mod clients; +pub mod client_manager; diff --git a/onelauncher/src/utils/http.rs b/onelauncher/src/utils/http.rs index 0524ecf9..19630399 100644 --- a/onelauncher/src/utils/http.rs +++ b/onelauncher/src/utils/http.rs @@ -1,34 +1,39 @@ use std::{ fs::File, io::{self, Cursor}, - path::Path, + path::PathBuf, }; use reqwest::{Client, ClientBuilder}; use crate::{constants::USER_AGENT, ErrorKind}; +use super::file::file_sha1; + pub fn create_client() -> crate::Result { - Ok(ClientBuilder::new() - .user_agent(USER_AGENT) - .build() - .map_err(|err| ErrorKind::HTTPError(err))?) + Ok(ClientBuilder::new().user_agent(USER_AGENT).build()?) } -// can we not make mapping the errors automatic, isnt that the whole point -pub async fn download_file(url: &str, path: &Path) -> crate::Result<()> { - let response = create_client()? - .get(url) - .send() - .await - .map_err(|err| ErrorKind::HTTPError(err))?; +pub async fn download_file_sha1_check(url: &str, path: &PathBuf, sha1: &str) -> crate::Result<()> { + download_file(url, path).await?; + + let file_hash = file_sha1(path)?; + if file_hash != sha1 { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Hashes do not match", + ).into()); + } + + Ok(()) +} + +pub async fn download_file(url: &str, path: &PathBuf) -> crate::Result<()> { + let response = create_client()?.get(url).send().await?; let mut file = File::create(path).map_err(|err| ErrorKind::IOError(err))?; - let mut content = Cursor::new( - response - .bytes() - .await - .map_err(|err| ErrorKind::HTTPError(err))?, - ); + let mut content = Cursor::new(response.bytes().await?); + io::copy(&mut content, &mut file).map_err(|err| ErrorKind::IOError(err))?; + Ok(()) } diff --git a/src-tauri/build.rs b/src-tauri/build.rs index 6ccf4925..e55f42e2 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -6,6 +6,7 @@ fn main() { InlinedPlugin::new().commands(&[ "login_msa", "refresh_client_manager", + "launch_cluster", "create_cluster", "get_clusters", "get_cluster", diff --git a/src-tauri/permissions/onelauncher/default.toml b/src-tauri/permissions/onelauncher/default.toml index 1361f0e9..df2bea2d 100644 --- a/src-tauri/permissions/onelauncher/default.toml +++ b/src-tauri/permissions/onelauncher/default.toml @@ -2,6 +2,7 @@ description = "Default permissions for the plugin" permissions = [ "allow-refresh-client-manager", + "allow-launch-cluster", "allow-create-cluster", "allow-get-clusters", "allow-get-cluster", diff --git a/src-tauri/src/api/game.rs b/src-tauri/src/api/game.rs index c72a65be..c395c782 100644 --- a/src-tauri/src/api/game.rs +++ b/src-tauri/src/api/game.rs @@ -1,4 +1,4 @@ -use onelauncher::game::client::{ClientType, Cluster, Manifest}; +use onelauncher::game::{client::{Cluster, Manifest}, clients::ClientType}; use tauri::State; use tokio::sync::Mutex; use uuid::Uuid; @@ -39,6 +39,16 @@ pub async fn get_cluster( Ok(instance.clone()) } +#[tauri::command] +pub async fn launch_cluster( + state: State<'_, Mutex>, + uuid: Uuid, +) -> Result<(), String> { + let manager = &mut state.lock().await.client_manager; + manager.launch_cluster(uuid).await?; // TODO: Change how this works + Ok(()) +} + #[tauri::command] pub async fn get_manifest( state: State<'_, Mutex>, diff --git a/src-tauri/src/api/mod.rs b/src-tauri/src/api/mod.rs index 485e6a53..f81d57fd 100644 --- a/src-tauri/src/api/mod.rs +++ b/src-tauri/src/api/mod.rs @@ -1,4 +1,4 @@ -use onelauncher::game::client::ClientManager; +use onelauncher::game::client_manager::ClientManager; use tauri::{plugin::TauriPlugin, Manager, State}; use tokio::sync::Mutex; @@ -27,6 +27,7 @@ pub fn init() -> TauriPlugin { game::get_clusters, game::get_cluster, game::get_manifest, + game::launch_cluster, refresh_client_manager, ]) .build() diff --git a/src/bridge/auth.ts b/src/bridge/auth.ts index d7a25ac8..78bf43da 100644 --- a/src/bridge/auth.ts +++ b/src/bridge/auth.ts @@ -19,8 +19,3 @@ export async function getUuidHeadSrc(uuid: string): Promise { // TODO implement some kind of caching + fallback return `https://crafatar.com/avatars/${uuid}?size=32`; } - -export default { - loginMicrosoft, - getUuidHeadSrc, -}; diff --git a/src/bridge/game.ts b/src/bridge/game.ts index 2e726cc6..258d5f9f 100644 --- a/src/bridge/game.ts +++ b/src/bridge/game.ts @@ -1,15 +1,17 @@ import { invoke } from '@tauri-apps/api/core'; export async function getCluster(uuid: string): Promise { - return await invoke('plugin:onelauncher|get_cluster', { - uuid, - }); + return await invoke( + 'plugin:onelauncher|get_cluster', + { uuid }, + ); } export async function getManifest(uuid: string): Promise { - return await invoke('plugin:onelauncher|get_manifest', { - uuid, - }); + return await invoke( + 'plugin:onelauncher|get_manifest', + { uuid }, + ); } export async function getClustersWithManifests(): Promise { @@ -58,3 +60,10 @@ export async function createCluster(cluster: Omit { return await invoke('plugin:onelauncher|refresh_client_manager'); } + +export async function launchCluster(uuid: string): Promise { + return await invoke( + 'plugin:onelauncher|launch_cluster', + { uuid }, + ); +} diff --git a/src/ui/pages/Home.tsx b/src/ui/pages/Home.tsx index 9799fc22..da25dbe5 100644 --- a/src/ui/pages/Home.tsx +++ b/src/ui/pages/Home.tsx @@ -10,12 +10,12 @@ import type { Accessor, Setter } from 'solid-js'; import { For, Show, createResource, createSignal } from 'solid-js'; import { useNavigate } from '@solidjs/router'; import image from '../../assets/images/header.png'; +import defaultCover from '../../assets/images/default_instance_cover.jpg'; +import ContextMenu from '../components/overlay/ContextMenu'; +import { createCluster, getClustersGrouped, launchCluster } from '../../bridge/game'; import Button from '../components/base/Button'; import Tag from '../components/base/Tag'; import TextField from '../components/base/TextField'; -import defaultCover from '../../assets/images/default_instance_cover.jpg'; -import ContextMenu from '../components/overlay/ContextMenu'; -import { createCluster, getClustersGrouped } from '../../bridge/game'; // TODO: Replace this into it's own component // possibly with the core ui lirbary with autogenerated and optimized svgs pls @@ -71,6 +71,14 @@ interface ClusterCardContextMenuProps { function ClusterCardContextMenu(props: ClusterCardContextMenuProps) { const navigate = useNavigate(); + function viewCluster() { + navigate(`/clusters/?id=${props.id}`); + } + + function launch() { + launchCluster(props.id); + } + return ( } text="View" - onClick={() => { - navigate(`/clusters/?id=${props.id}`); - }} + onClick={() => viewCluster()} /> @@ -90,20 +96,12 @@ function ClusterCardContextMenu(props: ClusterCardContextMenuProps) { } text="Launch" + onClick={() => launch()} /> ); } -declare module 'solid-js' { - // eslint-disable-next-line ts/no-namespace - namespace JSX { - interface Directives { - sortable: any; - } - } -} - function ClusterCard(props: Core.ClusterWithManifest) { const navigate = useNavigate(); const [pos, setPos] = createSignal({ x: 0, y: 0 }); @@ -160,6 +158,7 @@ function ClusterCard(props: Core.ClusterWithManifest) { +