From 5655e1591d49ceca46f9bb60b903946c7a72e566 Mon Sep 17 00:00:00 2001 From: anonymous123-code <61744596+anonymous123-code@users.noreply.github.com> Date: Sun, 23 Jul 2023 23:32:01 +0200 Subject: [PATCH 1/7] Quilt? --- Cargo.lock | 11 +++ Cargo.toml | 1 + helixlauncher-meta/src/util.rs | 18 +++++ src/intermediary.rs | 75 ++++++++++++++++++++ src/main.rs | 65 +++++++++++++++++ src/quilt.rs | 123 +++++++++++++++++++++++++++++++++ 6 files changed, 293 insertions(+) create mode 100644 src/intermediary.rs create mode 100644 src/quilt.rs diff --git a/Cargo.lock b/Cargo.lock index 15f6212..676d846 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,6 +660,7 @@ dependencies = [ "indexmap 2.0.0", "lazy_static", "maven-version-rs", + "quick-xml", "regex", "reqwest", "serde", @@ -1106,6 +1107,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-xml" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quote" version = "1.0.31" diff --git a/Cargo.toml b/Cargo.toml index 215ae8b..99f8ba1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ helixlauncher-meta = {path = "helixlauncher-meta"} indexmap = { version = "2.0.0", features = ["serde"] } lazy_static = "1.4.0" maven-version-rs = "0.1.0" +quick-xml = { version = "0.29.0", features = ["serde", "serialize"] } regex = "1.7.3" reqwest = {version = "0.11", features = ["json"]} serde = {version = "1", features = ["derive"]} diff --git a/helixlauncher-meta/src/util.rs b/helixlauncher-meta/src/util.rs index db29335..c463b34 100644 --- a/helixlauncher-meta/src/util.rs +++ b/helixlauncher-meta/src/util.rs @@ -79,6 +79,24 @@ impl Display for GradleSpecifier { } } +impl GradleSpecifier { + pub fn to_url(&self, base_repo: &str) -> String { + format!( + "{}{}/{}/{}/{}-{}{}.{}", + base_repo, + self.group.replace(".", "/"), + self.artifact, + self.version, + self.artifact, + self.version, + self.classifier + .as_ref() + .map_or("".to_string(), |it| "-".to_string() + &it), + self.extension + ) + } +} + cfg_if::cfg_if! { if #[cfg(windows)] { pub const CURRENT_OS: component::OsName = component::OsName::Windows; diff --git a/src/intermediary.rs b/src/intermediary.rs new file mode 100644 index 0000000..fadbd48 --- /dev/null +++ b/src/intermediary.rs @@ -0,0 +1,75 @@ +use std::{collections::BTreeSet, fs, path::Path, str::FromStr}; + +use anyhow::Result; +use chrono::Utc; +use helixlauncher_meta::{ + component::{Component, ComponentDependency, ConditionalClasspathEntry, Download}, + index::Index, util::GradleSpecifier, +}; +use reqwest::Client; + +use crate::{Metadata, get_hash, get_size}; + +pub async fn process(client: &Client) -> Result<()> { + let out_base = Path::new("out/net.fabricmc.intermediary"); + fs::create_dir_all(out_base)?; + + let mut index: Index = vec![]; + + for version in get_versions(client).await? { + let library = crate::Library { name: GradleSpecifier::from_str(&format!("net.fabricmc:intermediary:{version}")).unwrap(), url: "https://maven.fabricmc.net/".into() }; + let downloads = vec![Download { + name: library.name.clone(), + url: library.url.clone(), + hash: get_hash(client, &library).await?, + size: get_size(client, &library).await?.try_into().unwrap(), + }]; + let classpath = vec![ConditionalClasspathEntry::All(library.name)]; + + let component = Component { + format_version: 1, + assets: None, + conflicts: vec![], + id: "net.fabricmc.intermediary".into(), + jarmods: vec![], + natives: vec![], + release_time: Utc::now(), + version: version.clone(), + traits: BTreeSet::new(), + requires: vec![ComponentDependency { + id: "net.minecraft".into(), + version: Some(version), + }], + game_jar: None, + main_class: None, + game_arguments: vec![], + classpath, + downloads, + }; + + fs::write( + out_base.join(format!("{}.json", component.version)), + serde_json::to_string_pretty(&component)?, + )?; + + index.push(component.into()); + } + + index.sort_by(|x, y| y.release_time.cmp(&x.release_time)); + + fs::write( + out_base.join("index.json"), + serde_json::to_string_pretty(&index)?, + )?; + + Ok(()) +} + +async fn get_versions(client: &Client) -> Result> { + let response = client.get("https://maven.fabricmc.net/net/fabricmc/intermediary/maven-metadata.xml") + .header("User-Agent", "helixlauncher-meta (prototype)") + .send().await? + .text().await?; + let response: Metadata = quick_xml::de::from_str(&response)?; + Ok(response.versioning.versions.version) +} diff --git a/src/main.rs b/src/main.rs index 087c58d..a324a6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,10 +5,17 @@ */ #![deny(rust_2018_idioms)] +use std::{fs, path::Path}; + use anyhow::Result; +use helixlauncher_meta::{component::{Component, Hash}, index::Index, util::GradleSpecifier}; +use reqwest::Client; +use serde::Deserialize; mod forge; +mod intermediary; mod mojang; +mod quilt; #[tokio::main] async fn main() -> Result<()> { @@ -18,5 +25,63 @@ async fn main() -> Result<()> { mojang::process()?; + // forge::process()?; + + quilt::process(&client).await?; + + intermediary::process(&client).await?; + Ok(()) } + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(unused)] +pub(crate) struct Metadata { + artifact_id: String, + group_id: String, + versioning: Versioning, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(unused)] +pub(crate) struct Versioning { + latest: String, + release: String, + versions: VersionList, + last_updated: String, +} + +#[derive(Deserialize)] +pub(crate) struct VersionList { + version: Vec, +} + +pub(crate) async fn get_hash(client: &Client, coord: &Library) -> Result { + Ok(Hash::SHA256( + client + .get(coord.name.to_url(&coord.url) + ".sha256") + .header("User-Agent", "helixlauncher-meta (prototype)") + .send() + .await? + .text() + .await?, + )) +} + +pub(crate) async fn get_size(client: &Client, coord: &Library) -> Result { + Ok(client + .head(coord.name.to_url(&coord.url)) + .header("User-Agent", "helixlauncher-meta (prototype)") + .send() + .await? + .content_length() + .expect("Cannot handle servers returning no content length")) +} + +#[derive(Deserialize, Debug)] +struct Library { + name: GradleSpecifier, + url: String, +} \ No newline at end of file diff --git a/src/quilt.rs b/src/quilt.rs new file mode 100644 index 0000000..a1354f1 --- /dev/null +++ b/src/quilt.rs @@ -0,0 +1,123 @@ +use std::{collections::BTreeSet, fs, path::Path}; + +use anyhow::{Context, Result}; +use chrono::{TimeZone, Utc}; +use helixlauncher_meta::{ + component::{Component, ComponentDependency, ConditionalClasspathEntry, Download}, + index::Index, +}; +use reqwest::Client; +use serde::Deserialize; + +use crate::{Metadata, Library}; +pub async fn process(client: &Client) -> Result<()> { + let out_base = Path::new("out/org.quiltmc.quilt-loader"); + fs::create_dir_all(out_base)?; + + let mut index: Index = vec![]; + + for loader_version in get_loader_versions(client).await? { + let response = client.get(format!("https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-loader/{loader_version}/quilt-loader-{loader_version}.json")) + .header("User-Agent", "helixlauncher-meta (prototype)") + .send().await?; + + let release_time = Utc + .timestamp_millis_opt( + response + .headers() + .get("quilt-last-modified-timestamp") + .context("Error quilt did not provide release date in metadata")? + .to_str()? + .parse()?, + ) + .single() + .context("unable to parse release timestamp")?; + + let response: LoaderMeta = response.json().await?; + let mut downloads = vec![]; + let mut classpath = vec![]; + for library in response.libraries.common { + downloads.push(Download { + name: library.name.clone(), + url: library.url.clone(), + hash: crate::get_hash(client, &library).await?, + size: crate::get_size(client, &library).await?.try_into().unwrap(), + }); + classpath.push(ConditionalClasspathEntry::All(library.name)) + } + + let component = Component { + format_version: 1, + assets: None, + conflicts: vec![], + id: "org.quiltmc.quilt-loader".into(), + jarmods: vec![], + natives: vec![], + release_time, + version: loader_version, + traits: BTreeSet::new(), + requires: vec![ + ComponentDependency { + id: "net.minecraft".into(), + version: None, + }, + ComponentDependency { + id: "net.fabricmc.intermediary".into(), + version: None, + }, + ], + game_jar: None, + main_class: Some(response.mainClass.client), + game_arguments: vec![], + classpath, + downloads, + }; + + fs::write( + out_base.join(format!("{}.json", component.version)), + serde_json::to_string_pretty(&component)?, + )?; + + index.push(component.into()); + } + + index.sort_by(|x, y| y.release_time.cmp(&x.release_time)); + + fs::write( + out_base.join("index.json"), + serde_json::to_string_pretty(&index)?, + )?; + + Ok(()) +} + +async fn get_loader_versions(client: &Client) -> Result> { + let response = client.get("https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-loader/maven-metadata.xml") + .header("User-Agent", "helixlauncher-meta (prototype)") + .send().await? + .text().await?; + let response: Metadata = quick_xml::de::from_str(&response)?; + Ok(response.versioning.versions.version) +} + + +#[derive(Deserialize, Debug)] +struct Libraries { + client: Vec, + common: Vec, + server: Vec, +} + +#[derive(Deserialize, Debug)] +struct MainClass { + client: String, + server: String, + serverLauncher: Option, +} + +#[derive(Deserialize, Debug)] +struct LoaderMeta { + version: i32, + libraries: Libraries, + mainClass: MainClass, +} From 87963e5badc473a877af98ab8ca2c2bce95461aa Mon Sep 17 00:00:00 2001 From: anonymous123-code <61744596+anonymous123-code@users.noreply.github.com> Date: Mon, 24 Jul 2023 00:25:42 +0200 Subject: [PATCH 2/7] Fixes not getting the correct size setting the wrong url (was maven root) Also the first special casing for broken stuff --- src/intermediary.rs | 2 +- src/main.rs | 5 +++-- src/quilt.rs | 6 +++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/intermediary.rs b/src/intermediary.rs index fadbd48..7198a6c 100644 --- a/src/intermediary.rs +++ b/src/intermediary.rs @@ -20,7 +20,7 @@ pub async fn process(client: &Client) -> Result<()> { let library = crate::Library { name: GradleSpecifier::from_str(&format!("net.fabricmc:intermediary:{version}")).unwrap(), url: "https://maven.fabricmc.net/".into() }; let downloads = vec![Download { name: library.name.clone(), - url: library.url.clone(), + url: library.name.to_url(&library.url), hash: get_hash(client, &library).await?, size: get_size(client, &library).await?.try_into().unwrap(), }]; diff --git a/src/main.rs b/src/main.rs index a324a6f..fb367e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,8 +76,9 @@ pub(crate) async fn get_size(client: &Client, coord: &Library) -> Result { .header("User-Agent", "helixlauncher-meta (prototype)") .send() .await? - .content_length() - .expect("Cannot handle servers returning no content length")) + .headers() + .get("content-length") + .expect("Cannot handle servers returning no content length").to_str()?.parse()?) } #[derive(Deserialize, Debug)] diff --git a/src/quilt.rs b/src/quilt.rs index a1354f1..1d27831 100644 --- a/src/quilt.rs +++ b/src/quilt.rs @@ -17,6 +17,10 @@ pub async fn process(client: &Client) -> Result<()> { let mut index: Index = vec![]; for loader_version in get_loader_versions(client).await? { + if loader_version == "0.17.5-beta.4" { // This version's meta is very broken and I hate it + continue; + } + let response = client.get(format!("https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-loader/{loader_version}/quilt-loader-{loader_version}.json")) .header("User-Agent", "helixlauncher-meta (prototype)") .send().await?; @@ -39,7 +43,7 @@ pub async fn process(client: &Client) -> Result<()> { for library in response.libraries.common { downloads.push(Download { name: library.name.clone(), - url: library.url.clone(), + url: library.name.to_url(&library.url), hash: crate::get_hash(client, &library).await?, size: crate::get_size(client, &library).await?.try_into().unwrap(), }); From d9fd594c1001dda9f458fda935c38b7205957f38 Mon Sep 17 00:00:00 2001 From: anonymous123-code <61744596+anonymous123-code@users.noreply.github.com> Date: Mon, 24 Jul 2023 00:39:56 +0200 Subject: [PATCH 3/7] Actually add the loader to downlaods & classpath --- src/quilt.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/quilt.rs b/src/quilt.rs index 1d27831..625656e 100644 --- a/src/quilt.rs +++ b/src/quilt.rs @@ -1,10 +1,10 @@ -use std::{collections::BTreeSet, fs, path::Path}; +use std::{collections::BTreeSet, fs, path::Path, str::FromStr}; use anyhow::{Context, Result}; use chrono::{TimeZone, Utc}; use helixlauncher_meta::{ component::{Component, ComponentDependency, ConditionalClasspathEntry, Download}, - index::Index, + index::Index, util::GradleSpecifier, }; use reqwest::Client; use serde::Deserialize; @@ -38,8 +38,14 @@ pub async fn process(client: &Client) -> Result<()> { .context("unable to parse release timestamp")?; let response: LoaderMeta = response.json().await?; - let mut downloads = vec![]; - let mut classpath = vec![]; + let library = crate::Library { name: GradleSpecifier::from_str(&format!("org.quiltmc:quilt-loader:{loader_version}")).unwrap(), url: "https://maven.quiltmc.org/repository/release/".into() }; + let mut downloads = vec![Download { + name: library.name.clone(), + url: library.name.to_url(&library.url), + hash: crate::get_hash(client, &library).await?, + size: crate::get_size(client, &library).await?.try_into().unwrap(), + }]; + let mut classpath = vec![ConditionalClasspathEntry::All(library.name)]; for library in response.libraries.common { downloads.push(Download { name: library.name.clone(), From 404b8c4f18dbe6dc360a73f0f7f4fe26c192bfad Mon Sep 17 00:00:00 2001 From: anonymous123-code <61744596+anonymous123-code@users.noreply.github.com> Date: Wed, 26 Jul 2023 14:52:01 +0200 Subject: [PATCH 4/7] Use meta instead of maven meta (no xml parsing needed anymore) --- Cargo.lock | 11 ----------- Cargo.toml | 1 - src/intermediary.rs | 45 ++++++++++++++++++++++++++++++--------------- src/main.rs | 34 +++++----------------------------- src/quilt.rs | 45 ++++++++++++++++++++++++++++++--------------- 5 files changed, 65 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 676d846..15f6212 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,7 +660,6 @@ dependencies = [ "indexmap 2.0.0", "lazy_static", "maven-version-rs", - "quick-xml", "regex", "reqwest", "serde", @@ -1107,16 +1106,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quick-xml" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "quote" version = "1.0.31" diff --git a/Cargo.toml b/Cargo.toml index 99f8ba1..215ae8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ helixlauncher-meta = {path = "helixlauncher-meta"} indexmap = { version = "2.0.0", features = ["serde"] } lazy_static = "1.4.0" maven-version-rs = "0.1.0" -quick-xml = { version = "0.29.0", features = ["serde", "serialize"] } regex = "1.7.3" reqwest = {version = "0.11", features = ["json"]} serde = {version = "1", features = ["derive"]} diff --git a/src/intermediary.rs b/src/intermediary.rs index 7198a6c..26d56a3 100644 --- a/src/intermediary.rs +++ b/src/intermediary.rs @@ -4,11 +4,13 @@ use anyhow::Result; use chrono::Utc; use helixlauncher_meta::{ component::{Component, ComponentDependency, ConditionalClasspathEntry, Download}, - index::Index, util::GradleSpecifier, + index::Index, + util::GradleSpecifier, }; use reqwest::Client; +use serde::Deserialize; -use crate::{Metadata, get_hash, get_size}; +use crate::{get_hash, get_size}; pub async fn process(client: &Client) -> Result<()> { let out_base = Path::new("out/net.fabricmc.intermediary"); @@ -17,15 +19,19 @@ pub async fn process(client: &Client) -> Result<()> { let mut index: Index = vec![]; for version in get_versions(client).await? { - let library = crate::Library { name: GradleSpecifier::from_str(&format!("net.fabricmc:intermediary:{version}")).unwrap(), url: "https://maven.fabricmc.net/".into() }; + let library = crate::Library { + name: GradleSpecifier::from_str(&format!("net.fabricmc:intermediary:{version}")) + .unwrap(), + url: "https://maven.fabricmc.net/".into(), + }; let downloads = vec![Download { - name: library.name.clone(), - url: library.name.to_url(&library.url), - hash: get_hash(client, &library).await?, - size: get_size(client, &library).await?.try_into().unwrap(), - }]; + name: library.name.clone(), + url: library.name.to_url(&library.url), + hash: get_hash(client, &library).await?, + size: get_size(client, &library).await?.try_into().unwrap(), + }]; let classpath = vec![ConditionalClasspathEntry::All(library.name)]; - + let component = Component { format_version: 1, assets: None, @@ -66,10 +72,19 @@ pub async fn process(client: &Client) -> Result<()> { } async fn get_versions(client: &Client) -> Result> { - let response = client.get("https://maven.fabricmc.net/net/fabricmc/intermediary/maven-metadata.xml") - .header("User-Agent", "helixlauncher-meta (prototype)") - .send().await? - .text().await?; - let response: Metadata = quick_xml::de::from_str(&response)?; - Ok(response.versioning.versions.version) + let response: Vec = client + .get("https://meta.fabricmc.net/v2/versions/intermediary") + .header("User-Agent", "helixlauncher-meta (prototype)") + .send() + .await? + .json() + .await?; + Ok(response.into_iter().map(|v| v.version).collect()) +} + +#[derive(Deserialize)] +struct IntermediaryVersionData { + maven: GradleSpecifier, + version: String, + stable: bool, } diff --git a/src/main.rs b/src/main.rs index fb367e8..9ef0459 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,10 +5,8 @@ */ #![deny(rust_2018_idioms)] -use std::{fs, path::Path}; - use anyhow::Result; -use helixlauncher_meta::{component::{Component, Hash}, index::Index, util::GradleSpecifier}; +use helixlauncher_meta::{component::Hash, util::GradleSpecifier}; use reqwest::Client; use serde::Deserialize; @@ -34,30 +32,6 @@ async fn main() -> Result<()> { Ok(()) } -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -#[allow(unused)] -pub(crate) struct Metadata { - artifact_id: String, - group_id: String, - versioning: Versioning, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -#[allow(unused)] -pub(crate) struct Versioning { - latest: String, - release: String, - versions: VersionList, - last_updated: String, -} - -#[derive(Deserialize)] -pub(crate) struct VersionList { - version: Vec, -} - pub(crate) async fn get_hash(client: &Client, coord: &Library) -> Result { Ok(Hash::SHA256( client @@ -78,11 +52,13 @@ pub(crate) async fn get_size(client: &Client, coord: &Library) -> Result { .await? .headers() .get("content-length") - .expect("Cannot handle servers returning no content length").to_str()?.parse()?) + .expect("Cannot handle servers returning no content length") + .to_str()? + .parse()?) } #[derive(Deserialize, Debug)] struct Library { name: GradleSpecifier, url: String, -} \ No newline at end of file +} diff --git a/src/quilt.rs b/src/quilt.rs index 625656e..64f8279 100644 --- a/src/quilt.rs +++ b/src/quilt.rs @@ -4,12 +4,13 @@ use anyhow::{Context, Result}; use chrono::{TimeZone, Utc}; use helixlauncher_meta::{ component::{Component, ComponentDependency, ConditionalClasspathEntry, Download}, - index::Index, util::GradleSpecifier, + index::Index, + util::GradleSpecifier, }; use reqwest::Client; use serde::Deserialize; -use crate::{Metadata, Library}; +use crate::Library; pub async fn process(client: &Client) -> Result<()> { let out_base = Path::new("out/org.quiltmc.quilt-loader"); fs::create_dir_all(out_base)?; @@ -17,7 +18,8 @@ pub async fn process(client: &Client) -> Result<()> { let mut index: Index = vec![]; for loader_version in get_loader_versions(client).await? { - if loader_version == "0.17.5-beta.4" { // This version's meta is very broken and I hate it + if loader_version == "0.17.5-beta.4" { + // This version's meta is very broken and I hate it continue; } @@ -38,13 +40,17 @@ pub async fn process(client: &Client) -> Result<()> { .context("unable to parse release timestamp")?; let response: LoaderMeta = response.json().await?; - let library = crate::Library { name: GradleSpecifier::from_str(&format!("org.quiltmc:quilt-loader:{loader_version}")).unwrap(), url: "https://maven.quiltmc.org/repository/release/".into() }; + let library = crate::Library { + name: GradleSpecifier::from_str(&format!("org.quiltmc:quilt-loader:{loader_version}")) + .unwrap(), + url: "https://maven.quiltmc.org/repository/release/".into(), + }; let mut downloads = vec![Download { - name: library.name.clone(), - url: library.name.to_url(&library.url), - hash: crate::get_hash(client, &library).await?, - size: crate::get_size(client, &library).await?.try_into().unwrap(), - }]; + name: library.name.clone(), + url: library.name.to_url(&library.url), + hash: crate::get_hash(client, &library).await?, + size: crate::get_size(client, &library).await?.try_into().unwrap(), + }]; let mut classpath = vec![ConditionalClasspathEntry::All(library.name)]; for library in response.libraries.common { downloads.push(Download { @@ -102,14 +108,23 @@ pub async fn process(client: &Client) -> Result<()> { } async fn get_loader_versions(client: &Client) -> Result> { - let response = client.get("https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-loader/maven-metadata.xml") - .header("User-Agent", "helixlauncher-meta (prototype)") - .send().await? - .text().await?; - let response: Metadata = quick_xml::de::from_str(&response)?; - Ok(response.versioning.versions.version) + let response: Vec = client + .get("https://meta.quiltmc.org/v3/versions/loader") + .header("User-Agent", "helixlauncher-meta (prototype)") + .send() + .await? + .json() + .await?; + Ok(response.into_iter().map(|x| x.version).collect()) } +#[derive(Deserialize, Debug)] +struct LoaderVersionData { + separator: String, + build: i32, + maven: GradleSpecifier, + version: String, +} #[derive(Deserialize, Debug)] struct Libraries { From db535e20728bfac3ad85803bd5d417f709d590c1 Mon Sep 17 00:00:00 2001 From: anonymous123-code <61744596+anonymous123-code@users.noreply.github.com> Date: Wed, 26 Jul 2023 18:16:58 +0200 Subject: [PATCH 5/7] Fix: Intermediary used Utc::now as release date --- src/intermediary.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/intermediary.rs b/src/intermediary.rs index 26d56a3..2074032 100644 --- a/src/intermediary.rs +++ b/src/intermediary.rs @@ -1,7 +1,7 @@ use std::{collections::BTreeSet, fs, path::Path, str::FromStr}; use anyhow::Result; -use chrono::Utc; +use chrono::DateTime; use helixlauncher_meta::{ component::{Component, ComponentDependency, ConditionalClasspathEntry, Download}, index::Index, @@ -30,6 +30,25 @@ pub async fn process(client: &Client) -> Result<()> { hash: get_hash(client, &library).await?, size: get_size(client, &library).await?.try_into().unwrap(), }]; + + let release_time = DateTime::parse_from_rfc2822( + // TODO: This does one more request than necessary, should get_size or get_hash be merged into this? + client + .head(library.name.to_url(&library.url)) + .header("User-Agent", "helixlauncher-meta (prototype)") + .send() + .await? + .headers() + .get("last-modified") + .expect("Cannot handle servers returning no last-modified") + .to_str()?, + ) + .expect(&format!( + "Error parsing last-modified header of {}", + library.name.to_url(&library.url) + )) + .into(); + let classpath = vec![ConditionalClasspathEntry::All(library.name)]; let component = Component { @@ -39,7 +58,7 @@ pub async fn process(client: &Client) -> Result<()> { id: "net.fabricmc.intermediary".into(), jarmods: vec![], natives: vec![], - release_time: Utc::now(), + release_time, version: version.clone(), traits: BTreeSet::new(), requires: vec![ComponentDependency { From aba2899ea8737db48d650c49879d46e0e8ea7ec6 Mon Sep 17 00:00:00 2001 From: anonymous123-code <61744596+anonymous123-code@users.noreply.github.com> Date: Thu, 27 Jul 2023 21:34:45 +0200 Subject: [PATCH 6/7] Update User-Agent header --- src/intermediary.rs | 4 ++-- src/main.rs | 4 ++-- src/quilt.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/intermediary.rs b/src/intermediary.rs index 2074032..7dfa304 100644 --- a/src/intermediary.rs +++ b/src/intermediary.rs @@ -35,7 +35,7 @@ pub async fn process(client: &Client) -> Result<()> { // TODO: This does one more request than necessary, should get_size or get_hash be merged into this? client .head(library.name.to_url(&library.url)) - .header("User-Agent", "helixlauncher-meta (prototype)") + .header("User-Agent", "helixlauncher-meta") .send() .await? .headers() @@ -93,7 +93,7 @@ pub async fn process(client: &Client) -> Result<()> { async fn get_versions(client: &Client) -> Result> { let response: Vec = client .get("https://meta.fabricmc.net/v2/versions/intermediary") - .header("User-Agent", "helixlauncher-meta (prototype)") + .header("User-Agent", "helixlauncher-meta") .send() .await? .json() diff --git a/src/main.rs b/src/main.rs index 9ef0459..99750c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,7 +36,7 @@ pub(crate) async fn get_hash(client: &Client, coord: &Library) -> Result { Ok(Hash::SHA256( client .get(coord.name.to_url(&coord.url) + ".sha256") - .header("User-Agent", "helixlauncher-meta (prototype)") + .header("User-Agent", "helixlauncher-meta") .send() .await? .text() @@ -47,7 +47,7 @@ pub(crate) async fn get_hash(client: &Client, coord: &Library) -> Result { pub(crate) async fn get_size(client: &Client, coord: &Library) -> Result { Ok(client .head(coord.name.to_url(&coord.url)) - .header("User-Agent", "helixlauncher-meta (prototype)") + .header("User-Agent", "helixlauncher-meta") .send() .await? .headers() diff --git a/src/quilt.rs b/src/quilt.rs index 64f8279..1d79c6a 100644 --- a/src/quilt.rs +++ b/src/quilt.rs @@ -24,7 +24,7 @@ pub async fn process(client: &Client) -> Result<()> { } let response = client.get(format!("https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-loader/{loader_version}/quilt-loader-{loader_version}.json")) - .header("User-Agent", "helixlauncher-meta (prototype)") + .header("User-Agent", "helixlauncher-meta") .send().await?; let release_time = Utc @@ -110,7 +110,7 @@ pub async fn process(client: &Client) -> Result<()> { async fn get_loader_versions(client: &Client) -> Result> { let response: Vec = client .get("https://meta.quiltmc.org/v3/versions/loader") - .header("User-Agent", "helixlauncher-meta (prototype)") + .header("User-Agent", "helixlauncher-meta") .send() .await? .json() From 54dbc0e36ccaab132198f6e738889ff91f640c43 Mon Sep 17 00:00:00 2001 From: anonymous123-code <61744596+anonymous123-code@users.noreply.github.com> Date: Fri, 28 Jul 2023 13:16:02 +0200 Subject: [PATCH 7/7] Prepare dependency resolution stuff - add provides field to Component struct - move conflicts and requires into dedicatedd Dependencies struct - add optional dependency --- helixlauncher-meta/src/component.rs | 16 ++++++++++++---- src/forge.rs | 14 +++++++++----- src/intermediary.rs | 20 +++++++++++++------- src/mojang.rs | 6 +++--- src/quilt.rs | 28 ++++++++++++++++------------ 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/helixlauncher-meta/src/component.rs b/helixlauncher-meta/src/component.rs index 364ab26..7a20cba 100644 --- a/helixlauncher-meta/src/component.rs +++ b/helixlauncher-meta/src/component.rs @@ -19,7 +19,7 @@ pub enum OsName { Windows, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)] pub struct ComponentDependency { pub id: String, #[serde(skip_serializing_if = "Option::is_none", default)] @@ -131,6 +131,15 @@ pub enum MinecraftArgument { }, } +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct Dependencies { + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub requires: Vec, + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub conflicts: Vec, + pub optional: Vec, +} + #[skip_serializing_none] #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] @@ -138,13 +147,12 @@ pub struct Component { pub format_version: u32, pub id: String, pub version: String, + pub dependencies: Dependencies, #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub requires: Vec, + pub provides: Vec, #[serde(skip_serializing_if = "BTreeSet::is_empty", default)] pub traits: BTreeSet, pub assets: Option, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub conflicts: Vec, pub downloads: Vec, #[serde(skip_serializing_if = "Vec::is_empty", default)] pub jarmods: Vec, diff --git a/src/forge.rs b/src/forge.rs index 0e73f20..654d67b 100644 --- a/src/forge.rs +++ b/src/forge.rs @@ -99,13 +99,17 @@ fn process_version(file: &fs::DirEntry, out_base: &Path) -> Result Result<()> { let component = Component { format_version: 1, assets: None, - conflicts: vec![], + dependencies: Dependencies { + requires: vec![ComponentDependency { + id: "net.minecraft".into(), + version: Some(version.clone()), + }], + conflicts: vec![], + optional: vec![], + }, + provides: vec![], id: "net.fabricmc.intermediary".into(), jarmods: vec![], natives: vec![], release_time, - version: version.clone(), + version, traits: BTreeSet::new(), - requires: vec![ComponentDependency { - id: "net.minecraft".into(), - version: Some(version), - }], game_jar: None, main_class: None, game_arguments: vec![], diff --git a/src/mojang.rs b/src/mojang.rs index 381e7bd..92d534e 100644 --- a/src/mojang.rs +++ b/src/mojang.rs @@ -12,7 +12,7 @@ use anyhow::{bail, ensure, Context, Result}; use chrono::{DateTime, Utc}; use data_encoding::HEXLOWER; use futures::{StreamExt, TryStreamExt}; -use helix::component::{ConditionFeature, MinecraftArgument}; +use helix::component::{ConditionFeature, MinecraftArgument, Dependencies}; use indexmap::{IndexMap, IndexSet}; use lazy_static::lazy_static; use maven_version::Maven3ArtifactVersion; @@ -657,8 +657,8 @@ pub fn process_version( traits, assets: version.asset_index.map(|a| a.into()), version: version.id.to_owned(), - requires: vec![], // TODO: lwjgl 2 (deal with that later) - conflicts: vec![], + dependencies: Dependencies::default(), // TODO: lwjgl 2 (deal with that later) + provides: vec![], downloads: downloads.into_values().collect(), classpath: classpath.into_iter().collect(), natives: natives.into_iter().collect(), diff --git a/src/quilt.rs b/src/quilt.rs index 1d79c6a..178487d 100644 --- a/src/quilt.rs +++ b/src/quilt.rs @@ -3,7 +3,7 @@ use std::{collections::BTreeSet, fs, path::Path, str::FromStr}; use anyhow::{Context, Result}; use chrono::{TimeZone, Utc}; use helixlauncher_meta::{ - component::{Component, ComponentDependency, ConditionalClasspathEntry, Download}, + component::{Component, ComponentDependency, ConditionalClasspathEntry, Download, Dependencies}, index::Index, util::GradleSpecifier, }; @@ -65,23 +65,27 @@ pub async fn process(client: &Client) -> Result<()> { let component = Component { format_version: 1, assets: None, - conflicts: vec![], + provides: vec![], id: "org.quiltmc.quilt-loader".into(), jarmods: vec![], natives: vec![], release_time, version: loader_version, traits: BTreeSet::new(), - requires: vec![ - ComponentDependency { - id: "net.minecraft".into(), - version: None, - }, - ComponentDependency { - id: "net.fabricmc.intermediary".into(), - version: None, - }, - ], + dependencies: Dependencies { + conflicts: vec![], + optional: vec![], + requires: vec![ + ComponentDependency { + id: "net.minecraft".into(), + version: None, + }, + ComponentDependency { + id: "net.fabricmc.intermediary".into(), + version: None, + }, + ], + }, game_jar: None, main_class: Some(response.mainClass.client), game_arguments: vec![],