feat: add metadata-related commands

This commit is contained in:
LynithDev 2025-06-10 20:00:41 +02:00
parent cbfb32e991
commit 29813acb5a
9 changed files with 104 additions and 1053 deletions

View file

@ -1,99 +0,0 @@
// This file has been generated by Specta. DO NOT EDIT.
import type { InferCommandOutput } from 'taurpc';
import { createTauRPCProxy as createProxy } from 'taurpc';
type TAURI_CHANNEL<T> = (response: T) => void;
export type ClusterError = { type: 'InvalidVersion'; data: string } | { type: 'MissingJavaVersion'; data: string } | { type: 'ClusterDownloading'; data: string } | { type: 'ClusterAlreadyRunning'; data: string };
export type ClusterStage = 'notready' | 'downloading' | 'repairing' | 'ready';
export interface CreateCluster { name: string; mc_version: string; mc_loader: GameLoader; mc_loader_version: string | null; icon: Icon | null }
export type CryptoError = { type: 'InvalidHash'; data: string } | { type: 'InvalidAlgorithm'; data: string };
export type DaoError = { type: 'NotFound'; data: string } | { type: 'AlreadyExists'; data: string } | { type: 'InvalidValue'; data: string };
export interface DirectoryError { type: 'BaseDir'; data: string }
export type DiscordError = { type: 'MissingClientId'; data: string } | { type: 'ConnectError'; data: string };
export type GameLoader = 'vanilla' | 'forge' | 'neoforge' | 'quilt' | 'fabric' | 'legacyfabric';
export type IOError = { type: 'InvalidAbsolutePath'; data: string } | { type: 'IOErrorWrapper'; data: string } | { type: 'IOError'; data: string } | { type: 'DeserializeError'; data: string } | { type: 'AsyncZipError'; data: string };
export type Icon = string;
export type IncompatiblePackageType = { type: 'McVersion'; data: string } | { type: 'Loader'; data: string };
export interface IngressError { type: 'NotFound'; data: string }
export interface IngressPayload { id: string; message: string; ingress_type: IngressType; percent: number | null; total: number }
export type IngressType = { Download: { file_name: string } } | 'JavaPrepare' | 'JavaCheck' | 'JavaLocate' | 'MinecraftDownload' | { PrepareCluster: { cluster_name: string } };
export type JavaError = { type: 'ParseVersion'; data: string } | { type: 'Execute'; data: string } | { type: 'MissingJava'; data: string };
export type LauncherError = { type: 'DirError'; data: DirectoryError } | { type: 'IOError'; data: IOError } | { type: 'IngressError'; data: IngressError } | { type: 'JavaError'; data: JavaError } | { type: 'CryptoError'; data: CryptoError } | { type: 'DiscordError'; data: DiscordError } | { type: 'MetadataError'; data: MetadataError } | { type: 'ClusterError'; data: ClusterError } | { type: 'MinecraftAuthError'; data: MinecraftAuthError } | { type: 'ProcessError'; data: ProcessError } | { type: 'PackageError'; data: PackageError } | { type: 'DaoError'; data: DaoError } | { type: 'SerdeError'; data: string } | { type: 'AnyhowError'; data: string } | { type: 'DbError'; data: string } | { type: 'ReqwestError'; data: string } | { type: 'InterpulseError'; data: string } | { type: 'RegexError'; data: string } | { type: 'SemaphoreError'; data: string } | { type: 'UrlError'; data: string } | { type: 'TauriError'; data: string };
export type MessageLevel = 'Info' | 'Warn' | 'Error';
export interface MessagePayload { level: MessageLevel; message: string }
export type MetadataError = { type: 'FetchError'; data: string } | { type: 'NotModdedManifest'; data: string } | { type: 'NotVanillaManifest'; data: string } | { type: 'ParseError'; data: string } | { type: 'NoMatchingLoader'; data: string } | { type: 'NoMatchingVersion'; data: string };
export type MinecraftAuthError = { type: 'PublicKeyReading'; data: string } | { type: 'PKCS8Error'; data: string } | { type: 'SerializeError'; data: string } | { type: 'DeserializeError'; data: string } | { type: 'RequestError'; data: string } | { type: 'SigningError'; data: string } | { type: 'HashError'; data: string } | { type: 'SessionIdError'; data: string };
/**
* A structure of all needed Minecraft credentials for logging in and account management.
*/
export interface MinecraftCredentials {
/**
* The uuid of the credentials.
*/
id: string;
/**
* The username of the Minecraft account.
*/
username: string;
/**
* The access token as a String.
*/
access_token: string;
/**
* The refresh token as a string for [`MinecraftState#refresh`].
*/
refresh_token: string;
/**
* The time that the access token expires as a [`DateTime<Utc>`].
*/
expires: string;
}
export interface Model { id: bigint; folder_name: string; stage: ClusterStage; created_at: string; group_id: bigint | null; name: string; mc_version: string; mc_loader: GameLoader; mc_loader_version: string | null; last_played: string | null; overall_played: bigint | null; icon_url: Icon | null; setting_profile_name: string | null; linked_pack_id: string | null; linked_pack_version: string | null }
export type PackageError = { type: 'NoPrimaryFile'; data: string } | { type: 'IsModPack'; data: string } | { type: 'Incompatible'; data: IncompatiblePackageType };
export interface Process { pid: number; started_at: string; cluster_id: bigint; post_hook: string | null; account_id: string }
export type ProcessError = { type: 'HookUnsuccessful'; data: string } | { type: 'NoPid'; data: string };
export type ProcessPayload = { type: 'Starting'; command: string } | { type: 'Started'; process: Process } | { type: 'Stopped'; pid: number; exit_code: number } | { type: 'Output'; pid: number; output: string };
export interface Resolution { width: number; height: number }
export interface SettingProfileModel { name: string; java_id: bigint | null; res: Resolution | null; force_fullscreen: boolean | null; mem_max: number | null; launch_args: string | null; launch_env: string | null; hook_pre: string | null; hook_wrapper: string | null; hook_post: string | null; os_extra: SettingsOsExtra | null }
export interface SettingsOsExtra { enable_gamemode: boolean | null }
const ARGS_MAP = { events: '{"message":["event"],"ingress":["event"],"process":["event"]}', core: '{"getUser":["uuid"],"getDefaultUser":["fallback"],"createCluster":["options"],"getClusters":[],"launchCluster":["id","uuid"],"setDefaultUser":["uuid"],"getGlobalProfile":[],"getProfileOrDefault":["name"],"getUsers":[],"openMsaLogin":[],"removeUser":["uuid"],"removeCluster":["id"],"getClusterById":["id"]}', oneclient: '{"return_error":[],"open_dev_tools":[]}' };
export interface Router {
oneclient: { return_error: () => Promise<null>; open_dev_tools: () => Promise<void> };
core: { getClusters: () => Promise<Array<Model>>; getClusterById: (id: bigint) => Promise<Model | null>; removeCluster: (id: bigint) => Promise<null>; createCluster: (options: CreateCluster) => Promise<Model>; launchCluster: (id: bigint, uuid: string | null) => Promise<null>; getProfileOrDefault: (name: string | null) => Promise<SettingProfileModel>; getGlobalProfile: () => Promise<SettingProfileModel>; getUsers: () => Promise<Array<MinecraftCredentials>>; getUser: (uuid: string) => Promise<MinecraftCredentials | null>; removeUser: (uuid: string) => Promise<null>; getDefaultUser: (fallback: boolean | null) => Promise<MinecraftCredentials | null>; setDefaultUser: (uuid: string | null) => Promise<null>; openMsaLogin: () => Promise<MinecraftCredentials | null> };
events: { ingress: (event: IngressPayload) => Promise<void>; message: (event: MessagePayload) => Promise<void>; process: (event: ProcessPayload) => Promise<void> };
}
export type { InferCommandOutput };
export const createTauRPCProxy = () => createProxy<Router>(ARGS_MAP);

View file

@ -1,147 +0,0 @@
/* eslint-disable */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// This file was automatically generated by TanStack Router.
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
// Import Routes
import { Route as rootRoute } from './routes/__root'
import { Route as TestRouteImport } from './routes/test/route'
import { Route as IndexImport } from './routes/index'
import { Route as TestAppImport } from './routes/test/app'
// Create/Update Routes
const TestRouteRoute = TestRouteImport.update({
id: '/test',
path: '/test',
getParentRoute: () => rootRoute,
} as any)
const IndexRoute = IndexImport.update({
id: '/',
path: '/',
getParentRoute: () => rootRoute,
} as any)
const TestAppRoute = TestAppImport.update({
id: '/app',
path: '/app',
getParentRoute: () => TestRouteRoute,
} as any)
// Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexImport
parentRoute: typeof rootRoute
}
'/test': {
id: '/test'
path: '/test'
fullPath: '/test'
preLoaderRoute: typeof TestRouteImport
parentRoute: typeof rootRoute
}
'/test/app': {
id: '/test/app'
path: '/app'
fullPath: '/test/app'
preLoaderRoute: typeof TestAppImport
parentRoute: typeof TestRouteImport
}
}
}
// Create and export the route tree
interface TestRouteRouteChildren {
TestAppRoute: typeof TestAppRoute
}
const TestRouteRouteChildren: TestRouteRouteChildren = {
TestAppRoute: TestAppRoute,
}
const TestRouteRouteWithChildren = TestRouteRoute._addFileChildren(
TestRouteRouteChildren,
)
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/test': typeof TestRouteRouteWithChildren
'/test/app': typeof TestAppRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/test': typeof TestRouteRouteWithChildren
'/test/app': typeof TestAppRoute
}
export interface FileRoutesById {
__root__: typeof rootRoute
'/': typeof IndexRoute
'/test': typeof TestRouteRouteWithChildren
'/test/app': typeof TestAppRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/test' | '/test/app'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/test' | '/test/app'
id: '__root__' | '/' | '/test' | '/test/app'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
TestRouteRoute: typeof TestRouteRouteWithChildren
}
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
TestRouteRoute: TestRouteRouteWithChildren,
}
export const routeTree = rootRoute
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()
/* ROUTE_MANIFEST_START
{
"routes": {
"__root__": {
"filePath": "__root.tsx",
"children": [
"/",
"/test"
]
},
"/": {
"filePath": "index.tsx"
},
"/test": {
"filePath": "test/route.tsx",
"children": [
"/test/app"
]
},
"/test/app": {
"filePath": "test/app.tsx",
"parent": "/test"
}
}
}
ROUTE_MANIFEST_END */

View file

@ -1,114 +0,0 @@
// This file has been generated by Specta. DO NOT EDIT.
import type { InferCommandOutput } from 'taurpc';
import { createTauRPCProxy as createProxy } from 'taurpc';
type TAURI_CHANNEL<T> = (response: T) => void;
export type ClusterError = { InvalidVersion: string } | 'MissingJavaVersion' | 'ClusterDownloading' | 'ClusterAlreadyRunning';
export type ClusterStage = 'notready' | 'downloading' | 'repairing' | 'ready';
export interface CreateCluster { name: string; mc_version: string; mc_loader: GameLoader; mc_loader_version: string | null; icon: Icon | null }
export type CryptoError = { InvalidHash: { algorithm: HashAlgorithm; expected: string; actual: string } } | 'InvalidAlgorithm';
export type DaoError = 'NotFound' | 'AlreadyExists' | { InvalidValue: [string, string] };
export type DirectoryError = 'BaseDir';
export type DiscordError = 'MissingClientId' | 'ConnectError';
export type GameLoader = 'vanilla' | 'forge' | 'neoforge' | 'quilt' | 'fabric' | 'legacyfabric';
export type HashAlgorithm = 'Sha1' | 'Sha256' | 'Md5';
/**
* A wrapper around generic and unhelpful [`std::io::Error`] messages.
*/
export type IOError = { InvalidAbsolutePath: string } | { IOErrorWrapper: { path: string } } | 'IOError' | 'DeserializeError' | 'AsyncZipError';
export type Icon = string;
export type IncompatiblePackageType = 'McVersion' | 'Loader';
export type IngressError = 'NotFound';
export interface IngressPayload { id: string; message: string; ingress_type: IngressType; percent: number | null; total: number }
export type IngressType = { Download: { file_name: string } } | 'JavaPrepare' | 'JavaCheck' | 'JavaLocate' | 'MinecraftDownload' | { PrepareCluster: { cluster_name: string } };
export type JavaError = { ParseVersion: [string] } | 'Execute' | 'MissingJava';
export type LauncherError = { type: 'DirError'; data: DirectoryError } | { type: 'IOError'; data: IOError } | { type: 'IngressError'; data: IngressError } | { type: 'JavaError'; data: JavaError } | { type: 'CryptoError'; data: CryptoError } | { type: 'DiscordError'; data: DiscordError } | { type: 'MetadataError'; data: MetadataError } | { type: 'ClusterError'; data: ClusterError } | { type: 'MinecraftAuthError'; data: MinecraftAuthError } | { type: 'ProcessError'; data: ProcessError } | { type: 'PackageError'; data: PackageError } | { type: 'DaoError'; data: DaoError } | { type: 'SerdeError' } | { type: 'AnyhowError' } | { type: 'DbError' } | { type: 'ReqwestError' } | { type: 'InterpulseError' } | { type: 'RegexError' } | { type: 'SemaphoreError' } | { type: 'UrlError' } | { type: 'TauriError' };
export type LauncherEvent = { Ingress: IngressPayload } | { Message: MessagePayload } | { Process: ProcessPayload };
export type MessageLevel = 'Info' | 'Warn' | 'Error';
export interface MessagePayload { level: MessageLevel; message: string }
export type MetadataError = 'FetchError' | { NotModdedManifest: GameLoader } | { NotVanillaManifest: GameLoader } | 'ParseError' | 'NoMatchingLoader' | 'NoMatchingVersion';
/**
* Wrapper around all `Error`s that can occur during the Microsoft authentication process.
*/
export type MinecraftAuthError = 'PublicKeyReading' | 'PKCS8Error' | { SerializeError: { step: MinecraftAuthStep } } | { DeserializeError: { step: MinecraftAuthStep; raw: string } } | { RequestError: { step: MinecraftAuthStep } } | { SigningError: { step: MinecraftAuthStep } } | 'HashError' | 'SessionIdError';
/**
* An ordered list of all MSA authentication steps.
*/
export type MinecraftAuthStep = 'DeviceToken' | 'SisuAuthenicate' | 'OAuthToken' | 'RefreshOAuthToken' | 'SisuAuthorize' | 'XstsAuthorize' | 'MinecraftToken' | 'MinecraftEntitlements' | 'MinecraftProfile';
/**
* A structure of all needed Minecraft credentials for logging in and account management.
*/
export interface MinecraftCredentials {
/**
* The uuid of the credentials.
*/
id: string;
/**
* The username of the Minecraft account.
*/
username: string;
/**
* The access token as a String.
*/
access_token: string;
/**
* The refresh token as a string for [`MinecraftState#refresh`].
*/
refresh_token: string;
/**
* The time that the access token expires as a [`DateTime<Utc>`].
*/
expires: string;
}
export interface Model { id: bigint; folder_name: string; stage: ClusterStage; created_at: string; group_id: bigint | null; name: string; mc_version: string; mc_loader: GameLoader; mc_loader_version: string | null; last_played: string | null; overall_played: bigint | null; icon_url: Icon | null; setting_profile_name: string | null; linked_pack_id: string | null; linked_pack_version: string | null }
export type PackageError = 'NoPrimaryFile' | 'IsModPack' | { Incompatible: IncompatiblePackageType };
export interface Process { pid: number; started_at: string; cluster_id: bigint; post_hook: string | null; account_id: string }
export type ProcessError = { HookUnsuccessful: number } | 'NoPid';
export type ProcessPayload = { Starting: { command: string } } | { Started: { process: Process } } | { Stopped: { pid: number; exit_code: number } } | { Output: { pid: number; output: string } };
export interface Resolution { width: number; height: number }
export interface SettingProfileModel { name: string; java_id: bigint | null; res: Resolution | null; force_fullscreen: boolean | null; mem_max: number | null; launch_args: string | null; launch_env: string | null; hook_pre: string | null; hook_wrapper: string | null; hook_post: string | null; os_extra: SettingsOsExtra | null }
export interface SettingsOsExtra { enable_gamemode: boolean | null }
const ARGS_MAP = { 'core': '{"getGlobalProfile":[],"getUsers":[],"removeUser":["uuid"],"getDefaultUser":["fallback"],"getUser":["uuid"],"getClusterById":["id"],"setDefaultUser":["uuid"],"openMsaLogin":[],"removeCluster":["id"],"getProfileOrDefault":["name"],"getClusters":[],"createCluster":["options"]}', 'onelauncher': '{"open_dev_tools":[],"return_error":[]}', '': '{"send_event":["event"]}' };
export interface Router {
'onelauncher': { return_error: () => Promise<null>; open_dev_tools: () => Promise<void> };
'': { send_event: (event: LauncherEvent) => Promise<void> };
'core': { getClusters: () => Promise<Array<Model>>; getClusterById: (id: bigint) => Promise<Model | null>; removeCluster: (id: bigint) => Promise<null>; createCluster: (options: CreateCluster) => Promise<Model>; getProfileOrDefault: (name: string | null) => Promise<SettingProfileModel>; getGlobalProfile: () => Promise<SettingProfileModel>; getUsers: () => Promise<Array<MinecraftCredentials>>; getUser: (uuid: string) => Promise<MinecraftCredentials | null>; removeUser: (uuid: string) => Promise<null>; getDefaultUser: (fallback: boolean | null) => Promise<MinecraftCredentials | null>; setDefaultUser: (uuid: string | null) => Promise<null>; openMsaLogin: () => Promise<MinecraftCredentials | null> };
}
export type { InferCommandOutput };
export const createTauRPCProxy = () => createProxy<Router>(ARGS_MAP);

View file

@ -1,669 +0,0 @@
/* eslint-disable */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// This file was automatically generated by TanStack Router.
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
// Import Routes
import { Route as rootRoute } from './routes/__root'
import { Route as OnboardingRouteImport } from './routes/onboarding/route'
import { Route as AppRouteImport } from './routes/app/route'
import { Route as IndexImport } from './routes/index'
import { Route as OnboardingIndexImport } from './routes/onboarding/index'
import { Route as AppIndexImport } from './routes/app/index'
import { Route as OnboardingSummaryImport } from './routes/onboarding/summary'
import { Route as OnboardingLoginImport } from './routes/onboarding/login'
import { Route as OnboardingLanguageImport } from './routes/onboarding/language'
import { Route as OnboardingImportImport } from './routes/onboarding/import'
import { Route as OnboardingCompleteImport } from './routes/onboarding/complete'
import { Route as AppSettingsRouteImport } from './routes/app/settings/route'
import { Route as AppClusterRouteImport } from './routes/app/cluster/route'
import { Route as AppSettingsIndexImport } from './routes/app/settings/index'
import { Route as AppClusterIndexImport } from './routes/app/cluster/index'
import { Route as AppBrowserIndexImport } from './routes/app/browser/index'
import { Route as AppSettingsMinecraftImport } from './routes/app/settings/minecraft'
import { Route as AppSettingsAppearanceImport } from './routes/app/settings/appearance'
import { Route as AppSettingsAccountsImport } from './routes/app/settings/accounts'
import { Route as AppClusterWorldsImport } from './routes/app/cluster/worlds'
import { Route as AppClusterSettingsImport } from './routes/app/cluster/settings'
import { Route as AppClusterScreenshotsImport } from './routes/app/cluster/screenshots'
// Create/Update Routes
const OnboardingRouteRoute = OnboardingRouteImport.update({
id: '/onboarding',
path: '/onboarding',
getParentRoute: () => rootRoute,
} as any)
const AppRouteRoute = AppRouteImport.update({
id: '/app',
path: '/app',
getParentRoute: () => rootRoute,
} as any)
const IndexRoute = IndexImport.update({
id: '/',
path: '/',
getParentRoute: () => rootRoute,
} as any)
const OnboardingIndexRoute = OnboardingIndexImport.update({
id: '/',
path: '/',
getParentRoute: () => OnboardingRouteRoute,
} as any)
const AppIndexRoute = AppIndexImport.update({
id: '/',
path: '/',
getParentRoute: () => AppRouteRoute,
} as any)
const OnboardingSummaryRoute = OnboardingSummaryImport.update({
id: '/summary',
path: '/summary',
getParentRoute: () => OnboardingRouteRoute,
} as any)
const OnboardingLoginRoute = OnboardingLoginImport.update({
id: '/login',
path: '/login',
getParentRoute: () => OnboardingRouteRoute,
} as any)
const OnboardingLanguageRoute = OnboardingLanguageImport.update({
id: '/language',
path: '/language',
getParentRoute: () => OnboardingRouteRoute,
} as any)
const OnboardingImportRoute = OnboardingImportImport.update({
id: '/import',
path: '/import',
getParentRoute: () => OnboardingRouteRoute,
} as any)
const OnboardingCompleteRoute = OnboardingCompleteImport.update({
id: '/complete',
path: '/complete',
getParentRoute: () => OnboardingRouteRoute,
} as any)
const AppSettingsRouteRoute = AppSettingsRouteImport.update({
id: '/settings',
path: '/settings',
getParentRoute: () => AppRouteRoute,
} as any)
const AppClusterRouteRoute = AppClusterRouteImport.update({
id: '/cluster',
path: '/cluster',
getParentRoute: () => AppRouteRoute,
} as any)
const AppSettingsIndexRoute = AppSettingsIndexImport.update({
id: '/',
path: '/',
getParentRoute: () => AppSettingsRouteRoute,
} as any)
const AppClusterIndexRoute = AppClusterIndexImport.update({
id: '/',
path: '/',
getParentRoute: () => AppClusterRouteRoute,
} as any)
const AppBrowserIndexRoute = AppBrowserIndexImport.update({
id: '/browser/',
path: '/browser/',
getParentRoute: () => AppRouteRoute,
} as any)
const AppSettingsMinecraftRoute = AppSettingsMinecraftImport.update({
id: '/minecraft',
path: '/minecraft',
getParentRoute: () => AppSettingsRouteRoute,
} as any)
const AppSettingsAppearanceRoute = AppSettingsAppearanceImport.update({
id: '/appearance',
path: '/appearance',
getParentRoute: () => AppSettingsRouteRoute,
} as any)
const AppSettingsAccountsRoute = AppSettingsAccountsImport.update({
id: '/accounts',
path: '/accounts',
getParentRoute: () => AppSettingsRouteRoute,
} as any)
const AppClusterWorldsRoute = AppClusterWorldsImport.update({
id: '/worlds',
path: '/worlds',
getParentRoute: () => AppClusterRouteRoute,
} as any)
const AppClusterSettingsRoute = AppClusterSettingsImport.update({
id: '/settings',
path: '/settings',
getParentRoute: () => AppClusterRouteRoute,
} as any)
const AppClusterScreenshotsRoute = AppClusterScreenshotsImport.update({
id: '/screenshots',
path: '/screenshots',
getParentRoute: () => AppClusterRouteRoute,
} as any)
// Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexImport
parentRoute: typeof rootRoute
}
'/app': {
id: '/app'
path: '/app'
fullPath: '/app'
preLoaderRoute: typeof AppRouteImport
parentRoute: typeof rootRoute
}
'/onboarding': {
id: '/onboarding'
path: '/onboarding'
fullPath: '/onboarding'
preLoaderRoute: typeof OnboardingRouteImport
parentRoute: typeof rootRoute
}
'/app/cluster': {
id: '/app/cluster'
path: '/cluster'
fullPath: '/app/cluster'
preLoaderRoute: typeof AppClusterRouteImport
parentRoute: typeof AppRouteImport
}
'/app/settings': {
id: '/app/settings'
path: '/settings'
fullPath: '/app/settings'
preLoaderRoute: typeof AppSettingsRouteImport
parentRoute: typeof AppRouteImport
}
'/onboarding/complete': {
id: '/onboarding/complete'
path: '/complete'
fullPath: '/onboarding/complete'
preLoaderRoute: typeof OnboardingCompleteImport
parentRoute: typeof OnboardingRouteImport
}
'/onboarding/import': {
id: '/onboarding/import'
path: '/import'
fullPath: '/onboarding/import'
preLoaderRoute: typeof OnboardingImportImport
parentRoute: typeof OnboardingRouteImport
}
'/onboarding/language': {
id: '/onboarding/language'
path: '/language'
fullPath: '/onboarding/language'
preLoaderRoute: typeof OnboardingLanguageImport
parentRoute: typeof OnboardingRouteImport
}
'/onboarding/login': {
id: '/onboarding/login'
path: '/login'
fullPath: '/onboarding/login'
preLoaderRoute: typeof OnboardingLoginImport
parentRoute: typeof OnboardingRouteImport
}
'/onboarding/summary': {
id: '/onboarding/summary'
path: '/summary'
fullPath: '/onboarding/summary'
preLoaderRoute: typeof OnboardingSummaryImport
parentRoute: typeof OnboardingRouteImport
}
'/app/': {
id: '/app/'
path: '/'
fullPath: '/app/'
preLoaderRoute: typeof AppIndexImport
parentRoute: typeof AppRouteImport
}
'/onboarding/': {
id: '/onboarding/'
path: '/'
fullPath: '/onboarding/'
preLoaderRoute: typeof OnboardingIndexImport
parentRoute: typeof OnboardingRouteImport
}
'/app/cluster/screenshots': {
id: '/app/cluster/screenshots'
path: '/screenshots'
fullPath: '/app/cluster/screenshots'
preLoaderRoute: typeof AppClusterScreenshotsImport
parentRoute: typeof AppClusterRouteImport
}
'/app/cluster/settings': {
id: '/app/cluster/settings'
path: '/settings'
fullPath: '/app/cluster/settings'
preLoaderRoute: typeof AppClusterSettingsImport
parentRoute: typeof AppClusterRouteImport
}
'/app/cluster/worlds': {
id: '/app/cluster/worlds'
path: '/worlds'
fullPath: '/app/cluster/worlds'
preLoaderRoute: typeof AppClusterWorldsImport
parentRoute: typeof AppClusterRouteImport
}
'/app/settings/accounts': {
id: '/app/settings/accounts'
path: '/accounts'
fullPath: '/app/settings/accounts'
preLoaderRoute: typeof AppSettingsAccountsImport
parentRoute: typeof AppSettingsRouteImport
}
'/app/settings/appearance': {
id: '/app/settings/appearance'
path: '/appearance'
fullPath: '/app/settings/appearance'
preLoaderRoute: typeof AppSettingsAppearanceImport
parentRoute: typeof AppSettingsRouteImport
}
'/app/settings/minecraft': {
id: '/app/settings/minecraft'
path: '/minecraft'
fullPath: '/app/settings/minecraft'
preLoaderRoute: typeof AppSettingsMinecraftImport
parentRoute: typeof AppSettingsRouteImport
}
'/app/browser/': {
id: '/app/browser/'
path: '/browser'
fullPath: '/app/browser'
preLoaderRoute: typeof AppBrowserIndexImport
parentRoute: typeof AppRouteImport
}
'/app/cluster/': {
id: '/app/cluster/'
path: '/'
fullPath: '/app/cluster/'
preLoaderRoute: typeof AppClusterIndexImport
parentRoute: typeof AppClusterRouteImport
}
'/app/settings/': {
id: '/app/settings/'
path: '/'
fullPath: '/app/settings/'
preLoaderRoute: typeof AppSettingsIndexImport
parentRoute: typeof AppSettingsRouteImport
}
}
}
// Create and export the route tree
interface AppClusterRouteRouteChildren {
AppClusterScreenshotsRoute: typeof AppClusterScreenshotsRoute
AppClusterSettingsRoute: typeof AppClusterSettingsRoute
AppClusterWorldsRoute: typeof AppClusterWorldsRoute
AppClusterIndexRoute: typeof AppClusterIndexRoute
}
const AppClusterRouteRouteChildren: AppClusterRouteRouteChildren = {
AppClusterScreenshotsRoute: AppClusterScreenshotsRoute,
AppClusterSettingsRoute: AppClusterSettingsRoute,
AppClusterWorldsRoute: AppClusterWorldsRoute,
AppClusterIndexRoute: AppClusterIndexRoute,
}
const AppClusterRouteRouteWithChildren = AppClusterRouteRoute._addFileChildren(
AppClusterRouteRouteChildren,
)
interface AppSettingsRouteRouteChildren {
AppSettingsAccountsRoute: typeof AppSettingsAccountsRoute
AppSettingsAppearanceRoute: typeof AppSettingsAppearanceRoute
AppSettingsMinecraftRoute: typeof AppSettingsMinecraftRoute
AppSettingsIndexRoute: typeof AppSettingsIndexRoute
}
const AppSettingsRouteRouteChildren: AppSettingsRouteRouteChildren = {
AppSettingsAccountsRoute: AppSettingsAccountsRoute,
AppSettingsAppearanceRoute: AppSettingsAppearanceRoute,
AppSettingsMinecraftRoute: AppSettingsMinecraftRoute,
AppSettingsIndexRoute: AppSettingsIndexRoute,
}
const AppSettingsRouteRouteWithChildren =
AppSettingsRouteRoute._addFileChildren(AppSettingsRouteRouteChildren)
interface AppRouteRouteChildren {
AppClusterRouteRoute: typeof AppClusterRouteRouteWithChildren
AppSettingsRouteRoute: typeof AppSettingsRouteRouteWithChildren
AppIndexRoute: typeof AppIndexRoute
AppBrowserIndexRoute: typeof AppBrowserIndexRoute
}
const AppRouteRouteChildren: AppRouteRouteChildren = {
AppClusterRouteRoute: AppClusterRouteRouteWithChildren,
AppSettingsRouteRoute: AppSettingsRouteRouteWithChildren,
AppIndexRoute: AppIndexRoute,
AppBrowserIndexRoute: AppBrowserIndexRoute,
}
const AppRouteRouteWithChildren = AppRouteRoute._addFileChildren(
AppRouteRouteChildren,
)
interface OnboardingRouteRouteChildren {
OnboardingCompleteRoute: typeof OnboardingCompleteRoute
OnboardingImportRoute: typeof OnboardingImportRoute
OnboardingLanguageRoute: typeof OnboardingLanguageRoute
OnboardingLoginRoute: typeof OnboardingLoginRoute
OnboardingSummaryRoute: typeof OnboardingSummaryRoute
OnboardingIndexRoute: typeof OnboardingIndexRoute
}
const OnboardingRouteRouteChildren: OnboardingRouteRouteChildren = {
OnboardingCompleteRoute: OnboardingCompleteRoute,
OnboardingImportRoute: OnboardingImportRoute,
OnboardingLanguageRoute: OnboardingLanguageRoute,
OnboardingLoginRoute: OnboardingLoginRoute,
OnboardingSummaryRoute: OnboardingSummaryRoute,
OnboardingIndexRoute: OnboardingIndexRoute,
}
const OnboardingRouteRouteWithChildren = OnboardingRouteRoute._addFileChildren(
OnboardingRouteRouteChildren,
)
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/app': typeof AppRouteRouteWithChildren
'/onboarding': typeof OnboardingRouteRouteWithChildren
'/app/cluster': typeof AppClusterRouteRouteWithChildren
'/app/settings': typeof AppSettingsRouteRouteWithChildren
'/onboarding/complete': typeof OnboardingCompleteRoute
'/onboarding/import': typeof OnboardingImportRoute
'/onboarding/language': typeof OnboardingLanguageRoute
'/onboarding/login': typeof OnboardingLoginRoute
'/onboarding/summary': typeof OnboardingSummaryRoute
'/app/': typeof AppIndexRoute
'/onboarding/': typeof OnboardingIndexRoute
'/app/cluster/screenshots': typeof AppClusterScreenshotsRoute
'/app/cluster/settings': typeof AppClusterSettingsRoute
'/app/cluster/worlds': typeof AppClusterWorldsRoute
'/app/settings/accounts': typeof AppSettingsAccountsRoute
'/app/settings/appearance': typeof AppSettingsAppearanceRoute
'/app/settings/minecraft': typeof AppSettingsMinecraftRoute
'/app/browser': typeof AppBrowserIndexRoute
'/app/cluster/': typeof AppClusterIndexRoute
'/app/settings/': typeof AppSettingsIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/onboarding/complete': typeof OnboardingCompleteRoute
'/onboarding/import': typeof OnboardingImportRoute
'/onboarding/language': typeof OnboardingLanguageRoute
'/onboarding/login': typeof OnboardingLoginRoute
'/onboarding/summary': typeof OnboardingSummaryRoute
'/app': typeof AppIndexRoute
'/onboarding': typeof OnboardingIndexRoute
'/app/cluster/screenshots': typeof AppClusterScreenshotsRoute
'/app/cluster/settings': typeof AppClusterSettingsRoute
'/app/cluster/worlds': typeof AppClusterWorldsRoute
'/app/settings/accounts': typeof AppSettingsAccountsRoute
'/app/settings/appearance': typeof AppSettingsAppearanceRoute
'/app/settings/minecraft': typeof AppSettingsMinecraftRoute
'/app/browser': typeof AppBrowserIndexRoute
'/app/cluster': typeof AppClusterIndexRoute
'/app/settings': typeof AppSettingsIndexRoute
}
export interface FileRoutesById {
__root__: typeof rootRoute
'/': typeof IndexRoute
'/app': typeof AppRouteRouteWithChildren
'/onboarding': typeof OnboardingRouteRouteWithChildren
'/app/cluster': typeof AppClusterRouteRouteWithChildren
'/app/settings': typeof AppSettingsRouteRouteWithChildren
'/onboarding/complete': typeof OnboardingCompleteRoute
'/onboarding/import': typeof OnboardingImportRoute
'/onboarding/language': typeof OnboardingLanguageRoute
'/onboarding/login': typeof OnboardingLoginRoute
'/onboarding/summary': typeof OnboardingSummaryRoute
'/app/': typeof AppIndexRoute
'/onboarding/': typeof OnboardingIndexRoute
'/app/cluster/screenshots': typeof AppClusterScreenshotsRoute
'/app/cluster/settings': typeof AppClusterSettingsRoute
'/app/cluster/worlds': typeof AppClusterWorldsRoute
'/app/settings/accounts': typeof AppSettingsAccountsRoute
'/app/settings/appearance': typeof AppSettingsAppearanceRoute
'/app/settings/minecraft': typeof AppSettingsMinecraftRoute
'/app/browser/': typeof AppBrowserIndexRoute
'/app/cluster/': typeof AppClusterIndexRoute
'/app/settings/': typeof AppSettingsIndexRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
| '/app'
| '/onboarding'
| '/app/cluster'
| '/app/settings'
| '/onboarding/complete'
| '/onboarding/import'
| '/onboarding/language'
| '/onboarding/login'
| '/onboarding/summary'
| '/app/'
| '/onboarding/'
| '/app/cluster/screenshots'
| '/app/cluster/settings'
| '/app/cluster/worlds'
| '/app/settings/accounts'
| '/app/settings/appearance'
| '/app/settings/minecraft'
| '/app/browser'
| '/app/cluster/'
| '/app/settings/'
fileRoutesByTo: FileRoutesByTo
to:
| '/'
| '/onboarding/complete'
| '/onboarding/import'
| '/onboarding/language'
| '/onboarding/login'
| '/onboarding/summary'
| '/app'
| '/onboarding'
| '/app/cluster/screenshots'
| '/app/cluster/settings'
| '/app/cluster/worlds'
| '/app/settings/accounts'
| '/app/settings/appearance'
| '/app/settings/minecraft'
| '/app/browser'
| '/app/cluster'
| '/app/settings'
id:
| '__root__'
| '/'
| '/app'
| '/onboarding'
| '/app/cluster'
| '/app/settings'
| '/onboarding/complete'
| '/onboarding/import'
| '/onboarding/language'
| '/onboarding/login'
| '/onboarding/summary'
| '/app/'
| '/onboarding/'
| '/app/cluster/screenshots'
| '/app/cluster/settings'
| '/app/cluster/worlds'
| '/app/settings/accounts'
| '/app/settings/appearance'
| '/app/settings/minecraft'
| '/app/browser/'
| '/app/cluster/'
| '/app/settings/'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
AppRouteRoute: typeof AppRouteRouteWithChildren
OnboardingRouteRoute: typeof OnboardingRouteRouteWithChildren
}
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
AppRouteRoute: AppRouteRouteWithChildren,
OnboardingRouteRoute: OnboardingRouteRouteWithChildren,
}
export const routeTree = rootRoute
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()
/* ROUTE_MANIFEST_START
{
"routes": {
"__root__": {
"filePath": "__root.tsx",
"children": [
"/",
"/app",
"/onboarding"
]
},
"/": {
"filePath": "index.tsx"
},
"/app": {
"filePath": "app/route.tsx",
"children": [
"/app/cluster",
"/app/settings",
"/app/",
"/app/browser/"
]
},
"/onboarding": {
"filePath": "onboarding/route.tsx",
"children": [
"/onboarding/complete",
"/onboarding/import",
"/onboarding/language",
"/onboarding/login",
"/onboarding/summary",
"/onboarding/"
]
},
"/app/cluster": {
"filePath": "app/cluster/route.tsx",
"parent": "/app",
"children": [
"/app/cluster/screenshots",
"/app/cluster/settings",
"/app/cluster/worlds",
"/app/cluster/"
]
},
"/app/settings": {
"filePath": "app/settings/route.tsx",
"parent": "/app",
"children": [
"/app/settings/accounts",
"/app/settings/appearance",
"/app/settings/minecraft",
"/app/settings/"
]
},
"/onboarding/complete": {
"filePath": "onboarding/complete.tsx",
"parent": "/onboarding"
},
"/onboarding/import": {
"filePath": "onboarding/import.tsx",
"parent": "/onboarding"
},
"/onboarding/language": {
"filePath": "onboarding/language.tsx",
"parent": "/onboarding"
},
"/onboarding/login": {
"filePath": "onboarding/login.tsx",
"parent": "/onboarding"
},
"/onboarding/summary": {
"filePath": "onboarding/summary.tsx",
"parent": "/onboarding"
},
"/app/": {
"filePath": "app/index.tsx",
"parent": "/app"
},
"/onboarding/": {
"filePath": "onboarding/index.tsx",
"parent": "/onboarding"
},
"/app/cluster/screenshots": {
"filePath": "app/cluster/screenshots.tsx",
"parent": "/app/cluster"
},
"/app/cluster/settings": {
"filePath": "app/cluster/settings.tsx",
"parent": "/app/cluster"
},
"/app/cluster/worlds": {
"filePath": "app/cluster/worlds.tsx",
"parent": "/app/cluster"
},
"/app/settings/accounts": {
"filePath": "app/settings/accounts.tsx",
"parent": "/app/settings"
},
"/app/settings/appearance": {
"filePath": "app/settings/appearance.tsx",
"parent": "/app/settings"
},
"/app/settings/minecraft": {
"filePath": "app/settings/minecraft.tsx",
"parent": "/app/settings"
},
"/app/browser/": {
"filePath": "app/browser/index.tsx",
"parent": "/app"
},
"/app/cluster/": {
"filePath": "app/cluster/index.tsx",
"parent": "/app/cluster"
},
"/app/settings/": {
"filePath": "app/settings/index.tsx",
"parent": "/app/settings"
}
}
}
ROUTE_MANIFEST_END */

View file

@ -10,11 +10,11 @@ async fn main() -> LauncherResult<()> {
println!("Initialized: {}", metadata.initialized());
println!("Minecraft: {:?}", metadata.get_vanilla_or_fetch().await.is_ok());
println!("Forge: {:?}", metadata.get_modded_or_fetch(GameLoader::Forge).await.is_ok());
println!("Forge: {:?}", metadata.get_modded_or_fetch(&GameLoader::Forge).await.is_ok());
println!("Initialized: {}", metadata.initialized());
println!("NeoForge: {:?}", metadata.get_modded_or_fetch(GameLoader::NeoForge).await.is_ok());
println!("Fabric: {:?}", metadata.get_modded_or_fetch(GameLoader::Fabric).await.is_ok());
println!("Quilt: {:?}", metadata.get_modded_or_fetch(GameLoader::Quilt).await.is_ok());
println!("NeoForge: {:?}", metadata.get_modded_or_fetch(&GameLoader::NeoForge).await.is_ok());
println!("Fabric: {:?}", metadata.get_modded_or_fetch(&GameLoader::Fabric).await.is_ok());
println!("Quilt: {:?}", metadata.get_modded_or_fetch(&GameLoader::Quilt).await.is_ok());
Ok(())
}

View file

@ -386,7 +386,7 @@ pub async fn download_libraries(
Ok(failed)
}
// MARK: Loader Version
// MARK: Get Loader
/// Gets the loader version for a given Minecraft version and loader
/// If `loader_version` is `None`, it will return the latest stable version else
/// it will return the specified version if found
@ -402,7 +402,7 @@ pub async fn get_loader_version(
let state = State::get().await?;
let metadata = state.metadata.read().await;
let manifest = metadata.get_modded(loader)?;
let manifest = metadata.get_modded(&loader)?;
let Some(loaders) = manifest.game_versions.iter().find(|it| {
it.id
@ -422,3 +422,23 @@ pub async fn get_loader_version(
Ok(Some(loader_version))
}
// MARK: Get Versions
/// Gets the list of Minecraft versions from the metadata store
#[tracing::instrument]
pub async fn get_game_versions() -> LauncherResult<Vec<Version>> {
let state = State::get().await?;
let metadata = state.metadata.read().await;
let manifest = metadata.get_vanilla()?;
Ok(manifest.versions.clone())
}
/// Gets the list of modded loaders and their versions from the metadata store
#[tracing::instrument]
pub async fn get_loaders_for_version(mc_version: &str) -> LauncherResult<Vec<GameLoader>> {
let state = State::get().await?;
let mut metadata = state.metadata.write().await;
Ok(metadata.get_loaders_for_version(mc_version).await?)
}

View file

@ -1,3 +1,4 @@
use interpulse::api::minecraft::Version;
use onelauncher_entity::{icon::Icon, loader::GameLoader};
use tauri::{AppHandle, Runtime};
@ -32,6 +33,13 @@ pub trait TauriLauncherApi {
#[taurpc(alias = "getGlobalProfile")]
async fn get_global_profile() -> SettingsProfile;
// Game Metadata
#[taurpc(alias = "getGameVersions")]
async fn get_game_versions() -> LauncherResult<Vec<Version>>;
#[taurpc(alias = "getLoadersForVersion")]
async fn get_loaders_for_version(mc_version: String) -> LauncherResult<Vec<GameLoader>>;
// Users
#[taurpc(alias = "getUsers")]
@ -70,6 +78,8 @@ pub struct TauriLauncherApiImpl;
#[taurpc::resolvers]
impl TauriLauncherApi for TauriLauncherApiImpl {
// Clusters
async fn get_clusters(self) -> LauncherResult<Vec<Cluster>> {
api::cluster::dao::get_all_clusters().await
}
@ -85,13 +95,6 @@ impl TauriLauncherApi for TauriLauncherApiImpl {
async fn create_cluster(self, options: CreateCluster) -> LauncherResult<Cluster> {
let cluster = api::cluster::create_cluster(&options.name, &options.mc_version, options.mc_loader, options.mc_loader_version.as_deref(), options.icon).await?;
// if api::setting_profiles::dao::get_profile_by_name(&options.name).await?.is_none() {
// api::setting_profiles::create_profile(&options.name, async |mut profile| {
// profile.mem_max = sea_orm::ActiveValue::Set(Some(2048));
// Ok(profile)
// }).await?;
// }
Ok(cluster)
}
@ -114,14 +117,28 @@ impl TauriLauncherApi for TauriLauncherApiImpl {
Ok(())
}
async fn get_profile_or_default(self, name: Option<String>) -> LauncherResult<SettingsProfile> {
api::setting_profiles::dao::get_profile_or_default(name.as_ref()).await
}
// Setting Profiles
async fn get_global_profile(self) -> SettingsProfile {
api::setting_profiles::get_global_profile().await
}
async fn get_profile_or_default(self, name: Option<String>) -> LauncherResult<SettingsProfile> {
api::setting_profiles::dao::get_profile_or_default(name.as_ref()).await
}
// Game Metadata
async fn get_loaders_for_version(self, mc_version: String) -> LauncherResult<Vec<GameLoader>> {
api::game::metadata::get_loaders_for_version(&mc_version).await
}
async fn get_game_versions(self) -> LauncherResult<Vec<Version>> {
api::game::metadata::get_game_versions().await
}
// Users
async fn get_users(self) -> LauncherResult<Vec<MinecraftCredentials>> {
api::credentials::get_users().await
}

View file

@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::str::FromStr;
use interpulse::api::minecraft::VersionManifest as VanillaManifest;
@ -8,7 +9,7 @@ use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use crate::constants;
use crate::error::LauncherResult;
use crate::error::{LauncherError, LauncherResult};
use crate::utils::http::fetch_json;
use crate::utils::io;
@ -19,6 +20,7 @@ use super::Dirs;
pub struct Metadata {
initialized: bool,
inner: MetadataInner,
version_loader_cache: HashMap<String, Vec<GameLoader>>
}
#[derive(Debug, Default, Serialize, Deserialize)]
@ -74,9 +76,9 @@ impl Metadata {
}
#[tracing::instrument(skip(self))]
pub async fn get_modded_or_fetch(&mut self, loader: GameLoader) -> LauncherResult<&ModdedManifest> {
pub async fn get_modded_or_fetch(&mut self, loader: &GameLoader) -> LauncherResult<&ModdedManifest> {
if !loader.is_modded() {
return Err(MetadataError::NotModdedManifest(loader).into());
return Err(MetadataError::NotModdedManifest(*loader).into());
}
if !self.initialized() {
@ -90,9 +92,9 @@ impl Metadata {
self.inner.minecraft.as_ref().ok_or_else(|| MetadataError::FetchError.into())
}
pub fn get_modded(&self, loader: GameLoader) -> LauncherResult<&ModdedManifest> {
pub fn get_modded(&self, loader: &GameLoader) -> LauncherResult<&ModdedManifest> {
if !loader.is_modded() {
return Err(MetadataError::NotModdedManifest(loader).into());
return Err(MetadataError::NotModdedManifest(*loader).into());
}
match loader {
@ -219,17 +221,48 @@ impl Metadata {
(quilt, true)
};
}
/// Returns a list of loaders that are compatible with the given Minecraft version.
///
/// WARNING: Can be heavy in certain cases!
pub async fn get_loaders_for_version(&mut self, mc_version: &str) -> LauncherResult<Vec<GameLoader>> {
if !self.initialized() {
self.initialize().await?;
}
if let Some(hit) = self.version_loader_cache.get(mc_version) {
return Ok(hit.clone());
}
let mut loaders = Vec::<GameLoader>::new();
for loader in GameLoader::modded_loaders() {
let manifest = match self.get_modded(loader) {
Ok(manifest) => manifest,
Err(LauncherError::MetadataError(MetadataError::NotModdedManifest(_))) => continue,
Err(e) => return Err(e),
};
let found = manifest.game_versions.iter().find(|it| it.id == mc_version);
if found.is_some() {
loaders.push(*loader);
}
}
self.version_loader_cache.insert(mc_version.to_owned(), loaders.clone());
Ok(loaders)
}
}
pub async fn fetch_vanilla_manifest(loader: GameLoader) -> LauncherResult<VanillaManifest> {
async fn fetch_vanilla_manifest(loader: GameLoader) -> LauncherResult<VanillaManifest> {
fetch_manifest(loader).await
}
pub async fn fetch_modded_manifest(loader: GameLoader) -> LauncherResult<ModdedManifest> {
async fn fetch_modded_manifest(loader: GameLoader) -> LauncherResult<ModdedManifest> {
fetch_manifest(loader).await
}
pub async fn fetch_manifest<T: DeserializeOwned>(loader: GameLoader) -> LauncherResult<T> {
async fn fetch_manifest<T: DeserializeOwned>(loader: GameLoader) -> LauncherResult<T> {
fetch_json::<T>(
Method::GET,
format!(

View file

@ -55,6 +55,16 @@ impl GameLoader {
}
}
pub const fn modded_loaders() -> &'static [Self] {
&[
Self::Forge,
Self::NeoForge,
Self::Quilt,
Self::Fabric,
Self::LegacyFabric,
]
}
}
impl TryFrom<String> for GameLoader {