Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/daedalus_client/src/forge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,9 @@ async fn fetch(
.cloned()
.collect()
}),
java_version: None,
logging: None,
removed_libraries: Vec::new(),
libraries: install_profile
.version_info
.libraries
Expand Down
10 changes: 10 additions & 0 deletions apps/modrinth-minecraft-meta/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ Forge and NeoForge currently import installer metadata and embedded artifacts, a

Forge and NeoForge (henceforth Forgelike) store much of their important info in the installer JAR file, rather than as a JSON file served at some HTTP route.

## Ornithe

Ornithe runs Fabric Loader on game versions up to 1.14.4, with its own intermediary (`net.ornithemc:calamus-intermediary-gen2`). Its profiles look like Fabric's, so it is extracted and exported through the same code, but a single template doesn't work:
- Ornithe adds different libraries depending on the game version (e.g. a newer log4j, or LWJGL builds from Legacy Fabric's Maven), which aren't in its profiles. Game versions are grouped by these libraries, and profiles are downloaded once per group, templated from the group's longest game version. The libraries are added to every profile of their group.
- The LWJGL builds come from Ornithe's copy of each version manifest. They keep their upstream downloads, like Mojang's libraries.
- Ornithe's version manifests also drop some of Mojang's libraries (e.g. `org.ow2.asm:asm-all`). These are listed in the profile's `removedLibraries`, and split groups without changing which profile is downloaded.
- Group IDs are hashed the same way as the legacy daedalus client, so they stay stable when switching over.
- A few game versions are named differently by Ornithe and Mojang (e.g. `1.0.0` and `1.0`). These get a group of their own whose profile isn't templated, since the app would fill the placeholder with Mojang's name.
- Only game versions in Mojang's catalog are exported, so Mojang metadata must be extracted first.

## Fabric and Quilt

Fabric's and Quilt's manifests contain (among other things) two fields:
Expand Down
13 changes: 12 additions & 1 deletion apps/modrinth-minecraft-meta/src/export/fabriclike.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ pub async fn export(
FabriclikeLoader::Quilt => {
format!("quilt/v{format_version}/manifest.json")
}
FabriclikeLoader::Ornithe => {
format!("ornithe/v{format_version}/manifest.json")
}
};
app.public_blobs
.put(&path, &json, ContentType::Json)
Expand Down Expand Up @@ -163,8 +166,11 @@ fn prepare_profile(
mut profile: FabriclikeProfileMetadata,
public_maven: &Url,
) -> FabriclikeProfileMetadata {
// libraries with their own downloads are served from upstream
for library in &mut profile.libraries {
library.url = Some(public_maven.to_string());
if library.downloads.is_none() {
library.url = Some(public_maven.to_string());
}
}
profile
}
Expand Down Expand Up @@ -232,6 +238,7 @@ fn profile_path(
let loader = match loader {
FabriclikeLoader::Fabric => "fabric",
FabriclikeLoader::Quilt => "quilt",
FabriclikeLoader::Ornithe => "ornithe",
};
match group {
None => format!("{loader}/v{format_version}/versions/{version}.json"),
Expand Down Expand Up @@ -335,6 +342,10 @@ mod tests {
profile_base_url: "https://meta.example.com/versions/loader/"
.parse()
.unwrap(),
templated: true,
extra_libraries: Vec::new(),
removed_libraries: Vec::new(),
java_version: None,
}
}

Expand Down
12 changes: 12 additions & 0 deletions apps/modrinth-minecraft-meta/src/export/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod fabric;
mod fabriclike;
mod forgelike;
mod mojang;
mod ornithe;
mod quilt;

pub async fn run(app: AppState, upstreams: Upstreams) -> Result<()> {
Expand Down Expand Up @@ -48,6 +49,17 @@ pub async fn run(app: AppState, upstreams: Upstreams) -> Result<()> {
.ok();
}

if upstreams.ornithe {
ornithe::export(&app)
.context(info_span!("exporting Ornithe artifacts"))
.await
.inspect_err(|err| {
warn!("error: {err:?}");
failed.push("Ornithe");
})
.ok();
}

if upstreams.forge || upstreams.neoforge {
forgelike::export(&app, upstreams)
.context(info_span!("exporting Forge-like artifacts"))
Expand Down
9 changes: 9 additions & 0 deletions apps/modrinth-minecraft-meta/src/export/ornithe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use anyhow::Result;

use crate::{AppState, export::fabriclike, model::FabriclikeLoader};

pub const FORMAT_VERSION: u32 = 0;

pub async fn export(app: &AppState) -> Result<()> {
fabriclike::export(app, FabriclikeLoader::Ornithe, FORMAT_VERSION).await
}
50 changes: 45 additions & 5 deletions apps/modrinth-minecraft-meta/src/import/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use tracing_anyhow::FutureContext;

use crate::{
AppState,
import::{fabric, forge, mojang, neoforge, quilt},
import::{fabric, forge, mojang, neoforge, ornithe, quilt},
model::{self, DownloadRunId},
store::BlobCas,
upstream::Upstreams,
Expand Down Expand Up @@ -61,6 +61,7 @@ pub async fn download_from_upstreams(
forge: false,
neoforge: false,
quilt: false,
ornithe: false,
};

if upstreams.mojang {
Expand Down Expand Up @@ -98,6 +99,15 @@ pub async fn download_from_upstreams(
completed.quilt = download_succeeded(result, &cx.errors, errors_before);
}

if upstreams.ornithe {
let errors_before = cx.errors.len();
let result = ornithe::download(&mut cx)
.context(info_span!("downloading Ornithe upstream"))
.await;
completed.ornithe =
download_succeeded(result, &cx.errors, errors_before);
}

// do Forge last since we have to download a lot of installers
if upstreams.forge {
let errors_before = cx.errors.len();
Expand Down Expand Up @@ -162,11 +172,41 @@ impl<'cx> DownloadRunContext<'cx> {
url: impl IntoUrl,
) -> Result<(T, Sha256)> {
let url = url.into_url().context("converting to URL")?;
let response = self
.http
.get(url.clone())
.send()
.context(info_span!("fetching text"))
.await?;
self.store_json(url, response).await
}

/// Like [`Self::download_json`], but returns [`None`] if the server
/// responds with 404 Not Found.
pub async fn download_json_if_found<T: DeserializeOwned>(
&self,
url: impl IntoUrl,
) -> Result<Option<(T, Sha256)>> {
let url = url.into_url().context("converting to URL")?;
let response = self
.http
.get(url.clone())
.send()
.context(info_span!("fetching text"))
.await?;
if response.status() == reqwest::StatusCode::NOT_FOUND {
return Ok(None);
}
self.store_json(url, response).await.map(Some)
}

async fn store_json<T: DeserializeOwned>(
&self,
url: reqwest::Url,
response: reqwest::Response,
) -> Result<(T, Sha256)> {
let text = async {
self.http
.get(url.clone())
.send()
.await?
response
.error_for_status_ext()
.await?
.text()
Expand Down
4 changes: 4 additions & 0 deletions apps/modrinth-minecraft-meta/src/import/extract/fabric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ pub async fn extract(app: &AppState) -> Result<()> {
"{}/loader/",
fabric::CATALOG_URL
))?,
templated: true,
extra_libraries: Vec::new(),
removed_libraries: Vec::new(),
java_version: None,
};

fabriclike::extract_catalogs(
Expand Down
Loading
Loading