From 9535b920fab8eb6d70f4b9a6ccb40f9046e19e42 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 4 Apr 2026 19:55:19 +0200 Subject: [PATCH] Working launch with auth and version --- src-tauri/src/launcher/mod.rs | 34 +++++++++------ src-tauri/src/lib.rs | 24 +--------- src/App.tsx | 14 +++++- src/components/PlaySection.tsx | 19 +++++--- src/components/layout/AccountDropdown.tsx | 53 +++++++++++++---------- src/components/layout/props.ts | 7 +++ src/lib/launcher.ts | 6 ++- src/lib/saturn.ts | 1 + src/lib/types.ts | 1 + 9 files changed, 89 insertions(+), 70 deletions(-) diff --git a/src-tauri/src/launcher/mod.rs b/src-tauri/src/launcher/mod.rs index 74a0df1..c6182c2 100644 --- a/src-tauri/src/launcher/mod.rs +++ b/src-tauri/src/launcher/mod.rs @@ -1,23 +1,28 @@ +pub mod auth; pub mod downloader; pub mod install; -pub mod auth; use directories::ProjectDirs; -use lyceris::minecraft::{ - config::ConfigBuilder, - emitter::{Emitter, Event}, - launch::launch, - loader::fabric::Fabric, +use lyceris::{ + auth::microsoft::MinecraftAccount, + minecraft::{ + config::ConfigBuilder, + emitter::{Emitter, Event}, + launch::launch, + loader::fabric::Fabric, + }, }; use once_cell::sync::Lazy; +use crate::GameVersion; + pub static LAUNCHER_DIR: Lazy = Lazy::new(|| { ProjectDirs::from("org", "SaturnLauncher", "SaturnLauncher") .expect("Failed to create project directories") }); #[tauri::command] -pub async fn launch_game() -> Result<(), String> { +pub async fn launch_game(version: GameVersion, account: MinecraftAccount) -> Result<(), String> { // Emitter uses `EventEmitter` inside of it // and it uses tokio::Mutex for locking. // That causes emitter methods to be async. @@ -58,14 +63,17 @@ pub async fn launch_game() -> Result<(), String> { let current_dir = LAUNCHER_DIR.data_dir(); let config = ConfigBuilder::new( - current_dir.join("1.21.4"), - "1.21.4".into(), - lyceris::auth::AuthMethod::Offline { - username: "Lyceris".into(), - uuid: None, + current_dir.join(&version.id), + version.id.clone(), + lyceris::auth::AuthMethod::Microsoft { + username: account.username, + xuid: account.xuid, + uuid: account.uuid, + access_token: account.access_token, + refresh_token: account.refresh_token, }, ) - .loader(Fabric("0.18.6".to_string()).into()) + .loader(Fabric(version.loader_version).into()) .build(); println!("Starting installation"); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 92aa0b2..3a14ade 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -21,8 +21,7 @@ pub struct Mod { pub struct GameVersion { pub id: String, pub name: String, - pub release_date: String, - pub r#type: String, // "release" | "snapshot" + pub loader_version: String, } #[derive(Clone, Serialize, Deserialize)] @@ -33,7 +32,6 @@ pub struct LauncherSettings { // --- App State --- pub struct AppState { - pub versions: Vec, pub mods: Vec, pub settings: LauncherSettings, } @@ -41,26 +39,6 @@ pub struct AppState { impl Default for AppState { fn default() -> Self { Self { - versions: vec![ - GameVersion { - id: "1.20.1".into(), - name: "Fabric 1.20.1".into(), - release_date: "2023-06-07".into(), - r#type: "release".into(), - }, - GameVersion { - id: "1.20.4".into(), - name: "Fabric 1.20.4".into(), - release_date: "2023-12-07".into(), - r#type: "release".into(), - }, - GameVersion { - id: "1.21".into(), - name: "Fabric 1.21".into(), - release_date: "2024-06-13".into(), - r#type: "release".into(), - }, - ], mods: vec![ Mod { id: "sodium".into(), diff --git a/src/App.tsx b/src/App.tsx index 6968ca5..baca87b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,6 +6,7 @@ import ModsSection from "./components/ModsSection"; import SettingsSection from "./components/SettingsSection"; import { versions } from "./lib/saturn"; import { GameVersion } from "./lib/types"; +import { MinecraftAccount } from "./lib/auth"; type Section = "play" | "mods" | "settings"; @@ -21,6 +22,11 @@ export default function App() { const versionRef = useRef(null); const accountRef = useRef(null); + const [accounts, setAccounts] = useState([]); + const [activeAccount, setActiveAccount] = useState( + null, + ); + useEffect(() => { function handleClickOutside(event: MouseEvent) { const target = event.target as Node; @@ -62,11 +68,15 @@ export default function App() { setIsAccountDropdownOpen={setIsAccountDropdownOpen} versionRef={versionRef} accountRef={accountRef} + accounts={accounts} + setAccounts={setAccounts} + activeAccount={activeAccount} + setActiveAccount={setActiveAccount} />
- {active === "play" && selectedVersion && ( - + {active === "play" && ( + )} {active === "mods" && selectedVersion && ( diff --git a/src/components/PlaySection.tsx b/src/components/PlaySection.tsx index 9c7b399..7272480 100644 --- a/src/components/PlaySection.tsx +++ b/src/components/PlaySection.tsx @@ -5,12 +5,15 @@ import Bg from "@/assets/bg.png"; import { listen } from "@tauri-apps/api/event"; import { GameVersion } from "@/lib/types"; import { launch } from "@/lib/launcher"; +import { MinecraftAccount } from "@/lib/auth"; +import { cn } from "@/lib/utils"; interface PlaySectionProps { - version: GameVersion; + version: GameVersion | null; + account: MinecraftAccount | null; } -const PlaySection: React.FC = ({ version }) => { +const PlaySection: React.FC = ({ version, account }) => { const [isLaunching, setIsLaunching] = useState(false); const [launchStatus, setLaunchStatus] = useState(""); @@ -44,9 +47,13 @@ const PlaySection: React.FC = ({ version }) => {
diff --git a/src/components/layout/AccountDropdown.tsx b/src/components/layout/AccountDropdown.tsx index 84b03e9..398fe7d 100644 --- a/src/components/layout/AccountDropdown.tsx +++ b/src/components/layout/AccountDropdown.tsx @@ -1,15 +1,16 @@ -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { User, LogOut } from "lucide-react"; import { cn } from "@/lib/utils"; import { Props } from "./props"; -import { authList, authRemove, authCreateLink, authLogin } from "@/lib/auth"; +import { + authList, + authRemove, + authCreateLink, + authLogin, + MinecraftAccount, +} from "@/lib/auth"; import { listen } from "@tauri-apps/api/event"; -interface Account { - uuid: string; - username: string; -} - function UserComponent({ username, uuid, @@ -43,10 +44,11 @@ export default function AccountDropdown({ isAccountDropdownOpen, setIsAccountDropdownOpen, accountRef, + activeAccount, + setActiveAccount, + accounts, + setAccounts, }: Props) { - const [accounts, setAccounts] = useState([]); - const [active, setActive] = useState(null); - // Load accounts useEffect(() => { loadAccounts(); @@ -56,26 +58,26 @@ export default function AccountDropdown({ const accs = await authList(); setAccounts(accs); - if (accs.length && !active) { - setActive(accs[0]); // default + if (accs.length && !activeAccount) { + setActiveAccount(accs[0]); // default } } // Switch account - function switchAccount(acc: Account) { - setActive(acc); + function switchAccount(acc: MinecraftAccount) { + setActiveAccount(acc); setIsAccountDropdownOpen(false); } // Logout (remove account) async function logout() { - if (!active) return; + if (!activeAccount) return; - await authRemove(active.uuid); + await authRemove(activeAccount.uuid); const updated = await authList(); setAccounts(updated); - setActive(updated[0] || null); + setActiveAccount(updated[0] || null); } // Add account (open Microsoft login) @@ -89,7 +91,7 @@ export default function AccountDropdown({ }); } - const otherAccounts = accounts.filter((a) => a.uuid !== active?.uuid); + const otherAccounts = accounts.filter((a) => a.uuid !== activeAccount?.uuid); return (
@@ -102,13 +104,13 @@ export default function AccountDropdown({ onClick={() => setIsAccountDropdownOpen((prev: boolean) => !prev)} >
- {active && ( + {activeAccount && ( )} - {!active && ( + {!activeAccount && (

- {active?.username || "No Account"} + {activeAccount?.username || "No Account"}

@@ -136,8 +138,11 @@ export default function AccountDropdown({ )} > {/* Current account */} - {active && ( - + {activeAccount && ( + )} {/* Other accounts */} diff --git a/src/components/layout/props.ts b/src/components/layout/props.ts index b5f5e45..c2aeed6 100644 --- a/src/components/layout/props.ts +++ b/src/components/layout/props.ts @@ -1,3 +1,4 @@ +import { MinecraftAccount } from "@/lib/auth"; import { GameVersion } from "@/lib/types"; export type SetState = React.Dispatch>; @@ -15,4 +16,10 @@ export interface Props { versionRef: React.RefObject; accountRef: React.RefObject; + + accounts: MinecraftAccount[]; + setAccounts: SetState; + + activeAccount: MinecraftAccount | null; + setActiveAccount: SetState; } diff --git a/src/lib/launcher.ts b/src/lib/launcher.ts index 2dec8bf..2640b83 100644 --- a/src/lib/launcher.ts +++ b/src/lib/launcher.ts @@ -1,8 +1,10 @@ import { invoke } from "@tauri-apps/api/core"; +import { GameVersion } from "./types"; +import { MinecraftAccount } from "./auth"; /** * Launch the game with the selected account and version */ -export async function launch() { - return await invoke("launch_game"); +export async function launch(version: GameVersion, account: MinecraftAccount) { + return await invoke("launch_game", { version, account }); } diff --git a/src/lib/saturn.ts b/src/lib/saturn.ts index 39853be..39b517e 100644 --- a/src/lib/saturn.ts +++ b/src/lib/saturn.ts @@ -6,6 +6,7 @@ export const versions: GameVersion[] = [ { id: "1.21.4", name: "Fabric 1.21.4", + loader_version: "0.18.6", }, ]; diff --git a/src/lib/types.ts b/src/lib/types.ts index b2163e3..f845537 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -12,6 +12,7 @@ export interface Mod { export interface GameVersion { id: string; name: string; + loader_version: string; } export interface LauncherSettings {