mirror of
https://github.com/modrinth/code.git
synced 2026-08-31 03:55:59 +00:00
wip: app-side logic
This commit is contained in:
@@ -269,16 +269,31 @@ provideInstallationSettings({
|
|||||||
debug('resolveLoaderVersions: no manifest', { loader, gameVersion })
|
debug('resolveLoaderVersions: no manifest', { loader, gameVersion })
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
if (loader === 'fabric' || loader === 'quilt') {
|
const entry = manifest.gameVersions?.find((item) => item.id === gameVersion)
|
||||||
const result = manifest.gameVersions[0]?.loaders ?? []
|
if (entry?.versionGroup) {
|
||||||
debug('resolveLoaderVersions: fabric/quilt result', {
|
const result =
|
||||||
|
manifest.versionGroups?.find((group) => group.id === entry.versionGroup)?.loaders ?? []
|
||||||
|
debug('resolveLoaderVersions: version group result', {
|
||||||
|
loader,
|
||||||
|
gameVersion,
|
||||||
|
versionGroup: entry.versionGroup,
|
||||||
|
count: result.length,
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
const placeholder = manifest.gameVersions?.find((item) => item.id === '${modrinth.gameVersion}')
|
||||||
|
if (placeholder) {
|
||||||
|
const result = manifest.gameVersions?.some((item) => item.id === gameVersion)
|
||||||
|
? placeholder.loaders
|
||||||
|
: []
|
||||||
|
debug('resolveLoaderVersions: placeholder result', {
|
||||||
loader,
|
loader,
|
||||||
gameVersion,
|
gameVersion,
|
||||||
count: result.length,
|
count: result.length,
|
||||||
})
|
})
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
const result = manifest.gameVersions?.find((item) => item.id === gameVersion)?.loaders ?? []
|
const result = entry?.loaders ?? []
|
||||||
debug('resolveLoaderVersions: result', { loader, gameVersion, count: result.length })
|
debug('resolveLoaderVersions: result', { loader, gameVersion, count: result.length })
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
|
|||||||
+7
@@ -133,11 +133,18 @@ type Hooks = {
|
|||||||
|
|
||||||
type Manifest = {
|
type Manifest = {
|
||||||
gameVersions: ManifestGameVersion[]
|
gameVersions: ManifestGameVersion[]
|
||||||
|
versionGroups?: ManifestVersionGroup[]
|
||||||
}
|
}
|
||||||
|
|
||||||
type ManifestGameVersion = {
|
type ManifestGameVersion = {
|
||||||
id: string
|
id: string
|
||||||
stable: boolean
|
stable: boolean
|
||||||
|
versionGroup?: string
|
||||||
|
loaders: ManifestLoaderVersion[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type ManifestVersionGroup = {
|
||||||
|
id: string
|
||||||
loaders: ManifestLoaderVersion[]
|
loaders: ManifestLoaderVersion[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,16 +3,25 @@ export namespace LauncherMeta {
|
|||||||
export namespace v0 {
|
export namespace v0 {
|
||||||
export type LoaderVersion = {
|
export type LoaderVersion = {
|
||||||
id: string
|
id: string
|
||||||
|
url: string
|
||||||
stable: boolean
|
stable: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GameVersionEntry = {
|
export type GameVersionEntry = {
|
||||||
|
id: string
|
||||||
|
stable: boolean
|
||||||
|
versionGroup?: string
|
||||||
|
loaders: LoaderVersion[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type VersionGroup = {
|
||||||
id: string
|
id: string
|
||||||
loaders: LoaderVersion[]
|
loaders: LoaderVersion[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Manifest = {
|
export type Manifest = {
|
||||||
gameVersions: GameVersionEntry[]
|
gameVersions: GameVersionEntry[]
|
||||||
|
versionGroups?: VersionGroup[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,13 @@ export class LauncherMetaManifestV0Module extends AbstractModule {
|
|||||||
*
|
*
|
||||||
* @param loader - Loader platform (fabric, forge, quilt, neo)
|
* @param loader - Loader platform (fabric, forge, quilt, neo)
|
||||||
*/
|
*/
|
||||||
public async getManifest(loader: string): Promise<LauncherMeta.Manifest.v0.Manifest> {
|
public async getManifest(
|
||||||
|
loader: string,
|
||||||
|
formatVersion = 0,
|
||||||
|
): Promise<LauncherMeta.Manifest.v0.Manifest> {
|
||||||
return this.client.request<LauncherMeta.Manifest.v0.Manifest>('/manifest.json', {
|
return this.client.request<LauncherMeta.Manifest.v0.Manifest>('/manifest.json', {
|
||||||
api: LAUNCHER_META_BASE_URL,
|
api: LAUNCHER_META_BASE_URL,
|
||||||
version: `${loader}/v0`,
|
version: `${loader}/v${formatVersion}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
skipAuth: true,
|
skipAuth: true,
|
||||||
headers: { 'Content-Type': '' },
|
headers: { 'Content-Type': '' },
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ pub async fn get_minecraft_versions() -> crate::Result<VersionManifest> {
|
|||||||
// #[tracing::instrument]
|
// #[tracing::instrument]
|
||||||
pub async fn get_loader_versions(loader: &str) -> crate::Result<Manifest> {
|
pub async fn get_loader_versions(loader: &str) -> crate::Result<Manifest> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
|
let cache_key =
|
||||||
|
daedalus::modded::loader_manifest_metadata(loader).cache_key;
|
||||||
let loaders = CachedEntry::get_loader_manifest(
|
let loaders = CachedEntry::get_loader_manifest(
|
||||||
loader,
|
&cache_key,
|
||||||
None,
|
None,
|
||||||
&state.pool,
|
&state.pool,
|
||||||
&state.api_semaphore,
|
&state.api_semaphore,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use crate::{State, get_resource_file, process};
|
|||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use daedalus as d;
|
use daedalus as d;
|
||||||
use daedalus::minecraft::{LoggingSide, RuleAction, VersionInfo};
|
use daedalus::minecraft::{LoggingSide, RuleAction, VersionInfo};
|
||||||
use daedalus::modded::LoaderVersion;
|
use daedalus::modded::{LoaderVersion, Manifest};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
@@ -175,19 +175,18 @@ pub async fn get_loader_version_from_profile(
|
|||||||
let versions =
|
let versions =
|
||||||
crate::api::metadata::get_loader_versions(loader.as_meta_str()).await?;
|
crate::api::metadata::get_loader_versions(loader.as_meta_str()).await?;
|
||||||
|
|
||||||
let loaders = versions.game_versions.into_iter().find(|x| {
|
if let Some(loaders) =
|
||||||
x.id.replace(daedalus::modded::DUMMY_REPLACE_STRING, game_version)
|
loader_versions_for_game_version(&versions, game_version)
|
||||||
== game_version
|
{
|
||||||
});
|
let loader_version =
|
||||||
|
loaders
|
||||||
if let Some(loaders) = loaders {
|
.iter()
|
||||||
let loader_version = loaders.loaders.iter().find(|x| filter(x)).or(
|
.find(|x| filter(x))
|
||||||
if version == "stable" {
|
.or(if version == "stable" {
|
||||||
loaders.loaders.first()
|
loaders.first()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
Ok(loader_version.cloned())
|
Ok(loader_version.cloned())
|
||||||
} else {
|
} else {
|
||||||
@@ -195,6 +194,26 @@ pub async fn get_loader_version_from_profile(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn loader_versions_for_game_version<'a>(
|
||||||
|
manifest: &'a Manifest,
|
||||||
|
game_version: &str,
|
||||||
|
) -> Option<&'a [LoaderVersion]> {
|
||||||
|
let version = manifest.game_versions.iter().find(|x| {
|
||||||
|
x.id.replace(daedalus::modded::DUMMY_REPLACE_STRING, game_version)
|
||||||
|
== game_version
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if let Some(version_group) = &version.version_group {
|
||||||
|
manifest
|
||||||
|
.version_groups
|
||||||
|
.iter()
|
||||||
|
.find(|group| group.id == *version_group)
|
||||||
|
.map(|group| group.loaders.as_slice())
|
||||||
|
} else {
|
||||||
|
Some(version.loaders.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolves the Minecraft version manifest and finds the index for the given
|
/// Resolves the Minecraft version manifest and finds the index for the given
|
||||||
/// game version. If the version isn't found in the cache, forces a manifest
|
/// game version. If the version isn't found in the cache, forces a manifest
|
||||||
/// refresh to pick up newly-released versions.
|
/// refresh to pick up newly-released versions.
|
||||||
|
|||||||
@@ -1396,19 +1396,25 @@ impl CachedEntry {
|
|||||||
let fetch_urls = keys
|
let fetch_urls = keys
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
|
let metadata =
|
||||||
|
daedalus::modded::loader_manifest_metadata_from_cache_key(
|
||||||
|
&x.key().to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
x.key().to_string(),
|
metadata.cache_key,
|
||||||
|
metadata.loader,
|
||||||
format!(
|
format!(
|
||||||
"{}{}/v0/manifest.json",
|
"{}{}",
|
||||||
env!("MODRINTH_LAUNCHER_META_URL"),
|
env!("MODRINTH_LAUNCHER_META_URL"),
|
||||||
x.key()
|
metadata.path,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
futures::future::try_join_all(fetch_urls.iter().map(
|
futures::future::try_join_all(fetch_urls.iter().map(
|
||||||
|(_, url)| {
|
|(_, _, url)| {
|
||||||
fetch_json(
|
fetch_json(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
url,
|
url,
|
||||||
@@ -1424,14 +1430,15 @@ impl CachedEntry {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, metadata)| {
|
.map(|(index, metadata)| {
|
||||||
(
|
let mut entry =
|
||||||
CacheValue::LoaderManifest(CachedLoaderManifest {
|
CacheValue::LoaderManifest(CachedLoaderManifest {
|
||||||
loader: fetch_urls[index].0.to_string(),
|
loader: fetch_urls[index].1.to_string(),
|
||||||
manifest: metadata,
|
manifest: metadata,
|
||||||
})
|
})
|
||||||
.get_entry(),
|
.get_entry();
|
||||||
true,
|
entry.id.clone_from(&fetch_urls[index].0);
|
||||||
)
|
|
||||||
|
(entry, true)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-7
@@ -370,11 +370,13 @@ const gameVersionOptions = computed<ComboboxOption<string>[]>(() => {
|
|||||||
const manifest = ctx.loaderVersionsCache.value[apiLoader]
|
const manifest = ctx.loaderVersionsCache.value[apiLoader]
|
||||||
if (!manifest) return []
|
if (!manifest) return []
|
||||||
|
|
||||||
const hasPlaceholder = manifest.some((x) => x.id === '${modrinth.gameVersion}')
|
const hasPlaceholder = manifest.gameVersions.some((x) => x.id === '${modrinth.gameVersion}')
|
||||||
const supportedVersions = new Set(
|
const supportedVersions = new Set(
|
||||||
manifest
|
manifest.gameVersions
|
||||||
.filter(
|
.filter(
|
||||||
(x) => x.id !== '${modrinth.gameVersion}' && (hasPlaceholder || x.loaders.length > 0),
|
(x) =>
|
||||||
|
x.id !== '${modrinth.gameVersion}' &&
|
||||||
|
(hasPlaceholder || x.loaders.length > 0 || !!x.versionGroup),
|
||||||
)
|
)
|
||||||
.map((x) => x.id),
|
.map((x) => x.id),
|
||||||
)
|
)
|
||||||
@@ -466,14 +468,14 @@ function getLoaderVersionsForGameVersion(
|
|||||||
apiLoader,
|
apiLoader,
|
||||||
gameVersion,
|
gameVersion,
|
||||||
hasManifest: !!manifest,
|
hasManifest: !!manifest,
|
||||||
manifestLength: manifest?.length,
|
manifestLength: manifest?.gameVersions.length,
|
||||||
})
|
})
|
||||||
if (!manifest) return []
|
if (!manifest) return []
|
||||||
|
|
||||||
// Some loaders (e.g. Fabric) list all versions under a placeholder entry
|
// Some loaders (e.g. Fabric) list all versions under a placeholder entry
|
||||||
const placeholder = manifest.find((x) => x.id === '${modrinth.gameVersion}')
|
const placeholder = manifest.gameVersions.find((x) => x.id === '${modrinth.gameVersion}')
|
||||||
if (placeholder) {
|
if (placeholder) {
|
||||||
if (!manifest.some((x) => x.id === gameVersion)) return []
|
if (!manifest.gameVersions.some((x) => x.id === gameVersion)) return []
|
||||||
debug(
|
debug(
|
||||||
'getLoaderVersionsForGameVersion: using placeholder, loaders:',
|
'getLoaderVersionsForGameVersion: using placeholder, loaders:',
|
||||||
placeholder.loaders.length,
|
placeholder.loaders.length,
|
||||||
@@ -481,7 +483,20 @@ function getLoaderVersionsForGameVersion(
|
|||||||
return placeholder.loaders
|
return placeholder.loaders
|
||||||
}
|
}
|
||||||
|
|
||||||
const entry = manifest.find((x) => x.id === gameVersion)
|
const entry = manifest.gameVersions.find((x) => x.id === gameVersion)
|
||||||
|
if (entry?.versionGroup) {
|
||||||
|
const loaders =
|
||||||
|
manifest.versionGroups?.find((group) => group.id === entry.versionGroup)?.loaders ?? []
|
||||||
|
debug(
|
||||||
|
'getLoaderVersionsForGameVersion: version group for',
|
||||||
|
gameVersion,
|
||||||
|
':',
|
||||||
|
entry.versionGroup,
|
||||||
|
loaders.length + ' loaders',
|
||||||
|
)
|
||||||
|
return loaders
|
||||||
|
}
|
||||||
|
|
||||||
debug(
|
debug(
|
||||||
'getLoaderVersionsForGameVersion: entry for',
|
'getLoaderVersionsForGameVersion: entry for',
|
||||||
gameVersion,
|
gameVersion,
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export type Gamemode = 'survival' | 'creative' | 'hardcore'
|
|||||||
export type Difficulty = 'peaceful' | 'easy' | 'normal' | 'hard'
|
export type Difficulty = 'peaceful' | 'easy' | 'normal' | 'hard'
|
||||||
export type LoaderVersionType = 'stable' | 'latest' | 'other'
|
export type LoaderVersionType = 'stable' | 'latest' | 'other'
|
||||||
export type GeneratorSettingsMode = 'default' | 'flat' | 'custom'
|
export type GeneratorSettingsMode = 'default' | 'flat' | 'custom'
|
||||||
export type LoaderManifestResolver = (loader: string) => Promise<LauncherMeta.Manifest.v0.Manifest>
|
export type LoaderManifest = LauncherMeta.Manifest.v0.Manifest
|
||||||
|
export type LoaderManifestResolver = (loader: string) => Promise<LoaderManifest>
|
||||||
export interface LoaderVersionEntry {
|
export interface LoaderVersionEntry {
|
||||||
id: string
|
id: string
|
||||||
stable: boolean
|
stable: boolean
|
||||||
@@ -160,7 +161,7 @@ export interface CreationFlowContextValue {
|
|||||||
hideLoaderChips: ComputedRef<boolean>
|
hideLoaderChips: ComputedRef<boolean>
|
||||||
hideLoaderVersion: ComputedRef<boolean>
|
hideLoaderVersion: ComputedRef<boolean>
|
||||||
showSnapshots: Ref<boolean>
|
showSnapshots: Ref<boolean>
|
||||||
loaderVersionsCache: Ref<Record<string, { id: string; loaders: LoaderVersionEntry[] }[]>>
|
loaderVersionsCache: Ref<Record<string, LoaderManifest>>
|
||||||
paperSupportedVersions: Ref<Set<string> | null>
|
paperSupportedVersions: Ref<Set<string> | null>
|
||||||
purpurSupportedVersions: Ref<Set<string> | null>
|
purpurSupportedVersions: Ref<Set<string> | null>
|
||||||
|
|
||||||
@@ -295,9 +296,7 @@ export function createCreationFlowContext(
|
|||||||
const loaderVersionType = ref<LoaderVersionType>('stable')
|
const loaderVersionType = ref<LoaderVersionType>('stable')
|
||||||
const selectedLoaderVersion = ref<string | null>(null)
|
const selectedLoaderVersion = ref<string | null>(null)
|
||||||
const showSnapshots = ref(false)
|
const showSnapshots = ref(false)
|
||||||
const loaderVersionsCache = ref<Record<string, { id: string; loaders: LoaderVersionEntry[] }[]>>(
|
const loaderVersionsCache = ref<Record<string, LoaderManifest>>({})
|
||||||
{},
|
|
||||||
)
|
|
||||||
const paperSupportedVersions = ref<Set<string> | null>(null)
|
const paperSupportedVersions = ref<Set<string> | null>(null)
|
||||||
const purpurSupportedVersions = ref<Set<string> | null>(null)
|
const purpurSupportedVersions = ref<Set<string> | null>(null)
|
||||||
|
|
||||||
@@ -364,11 +363,11 @@ export function createCreationFlowContext(
|
|||||||
(await client.launchermeta.manifest_v0.getManifest(apiLoader)),
|
(await client.launchermeta.manifest_v0.getManifest(apiLoader)),
|
||||||
staleTime: Infinity,
|
staleTime: Infinity,
|
||||||
})
|
})
|
||||||
loaderVersionsCache.value[apiLoader] = data.gameVersions
|
loaderVersionsCache.value[apiLoader] = data
|
||||||
debug('fetchLoaderManifest: loaded', apiLoader, 'gameVersions:', data.gameVersions.length)
|
debug('fetchLoaderManifest: loaded', apiLoader, 'gameVersions:', data.gameVersions.length)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
debug('fetchLoaderManifest: failed', apiLoader, error)
|
debug('fetchLoaderManifest: failed', apiLoader, error)
|
||||||
loaderVersionsCache.value[apiLoader] = []
|
loaderVersionsCache.value[apiLoader] = { gameVersions: [] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -376,12 +376,17 @@ function getLoaderVersionsForGameVersion(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const manifest = manifestQuery.data.value?.gameVersions
|
const manifest = manifestQuery.data.value?.gameVersions
|
||||||
|
const versionGroups = manifestQuery.data.value?.versionGroups
|
||||||
if (!manifest) return []
|
if (!manifest) return []
|
||||||
|
|
||||||
const placeholder = manifest.find((x) => x.id === '${modrinth.gameVersion}')
|
const placeholder = manifest.find((x) => x.id === '${modrinth.gameVersion}')
|
||||||
if (placeholder) return placeholder.loaders
|
if (placeholder) return placeholder.loaders
|
||||||
|
|
||||||
const entry = manifest.find((x) => x.id === gameVersion)
|
const entry = manifest.find((x) => x.id === gameVersion)
|
||||||
|
if (entry?.versionGroup) {
|
||||||
|
return versionGroups?.find((group) => group.id === entry.versionGroup)?.loaders ?? []
|
||||||
|
}
|
||||||
|
|
||||||
return entry?.loaders ?? []
|
return entry?.loaders ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +510,9 @@ provideInstallationSettings({
|
|||||||
const hasPlaceholder = manifest.some((x) => x.id === '${modrinth.gameVersion}')
|
const hasPlaceholder = manifest.some((x) => x.id === '${modrinth.gameVersion}')
|
||||||
if (!hasPlaceholder) {
|
if (!hasPlaceholder) {
|
||||||
const supportedVersions = new Set(
|
const supportedVersions = new Set(
|
||||||
manifest.filter((x) => x.loaders.length > 0).map((x) => x.id),
|
manifest
|
||||||
|
.filter((x) => x.loaders.length > 0 || !!x.versionGroup)
|
||||||
|
.map((x) => x.id),
|
||||||
)
|
)
|
||||||
return versions
|
return versions
|
||||||
.filter((v) => supportedVersions.has(v.version))
|
.filter((v) => supportedVersions.has(v.version))
|
||||||
@@ -547,7 +554,9 @@ provideInstallationSettings({
|
|||||||
if (hasPlaceholder) {
|
if (hasPlaceholder) {
|
||||||
return tags.gameVersions.value.some((v) => v.version_type !== 'release')
|
return tags.gameVersions.value.some((v) => v.version_type !== 'release')
|
||||||
}
|
}
|
||||||
const supportedVersions = new Set(manifest.filter((x) => x.loaders.length > 0).map((x) => x.id))
|
const supportedVersions = new Set(
|
||||||
|
manifest.filter((x) => x.loaders.length > 0 || !!x.versionGroup).map((x) => x.id),
|
||||||
|
)
|
||||||
const supported = tags.gameVersions.value.filter((v) => supportedVersions.has(v.version))
|
const supported = tags.gameVersions.value.filter((v) => supportedVersions.has(v.version))
|
||||||
return supported.some((v) => v.version_type !== 'release')
|
return supported.some((v) => v.version_type !== 'release')
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user