diff --git a/.idea/discord.xml b/.idea/discord.xml
new file mode 100644
index 000000000..d8e956166
--- /dev/null
+++ b/.idea/discord.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/daedalus/src/fabric.rs b/daedalus/src/fabric.rs
deleted file mode 100644
index d63705a73..000000000
--- a/daedalus/src/fabric.rs
+++ /dev/null
@@ -1,136 +0,0 @@
-use crate::minecraft::{Argument, ArgumentType, Library, VersionInfo, VersionType};
-use crate::{download_file, Error};
-use chrono::{DateTime, Utc};
-use serde::{Deserialize, Serialize};
-use std::collections::HashMap;
-
-/// The latest version of the format the model structs deserialize to
-pub const CURRENT_FORMAT_VERSION: usize = 0;
-
-#[derive(Serialize, Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
-/// A partial version returned by fabric meta
-pub struct PartialVersionInfo {
- /// The version ID of the version
- pub id: String,
- /// The version ID this partial version inherits from
- pub inherits_from: String,
- /// The time that the version was released
- pub release_time: DateTime,
- /// The latest time a file in this version was updated
- pub time: DateTime,
- /// The classpath to the main class to launch the game
- pub main_class: Option,
- /// Arguments passed to the game or JVM
- pub arguments: Option>>,
- /// Libraries that the version depends on
- pub libraries: Vec,
- #[serde(rename = "type")]
- /// The type of version
- pub type_: VersionType,
-}
-
-/// Merges a partial version into a complete one
-pub fn merge_partial_version(partial: PartialVersionInfo, merge: VersionInfo) -> VersionInfo {
- VersionInfo {
- arguments: if let Some(partial_args) = partial.arguments {
- if let Some(merge_args) = merge.arguments {
- Some(partial_args.into_iter().chain(merge_args).collect())
- } else {
- Some(partial_args)
- }
- } else {
- merge.arguments
- },
- asset_index: merge.asset_index,
- assets: merge.assets,
- downloads: merge.downloads,
- id: merge.id,
- libraries: partial
- .libraries
- .into_iter()
- .chain(merge.libraries)
- .collect::>(),
- main_class: if let Some(main_class) = partial.main_class {
- main_class
- } else {
- merge.main_class
- },
- minecraft_arguments: merge.minecraft_arguments,
- minimum_launcher_version: merge.minimum_launcher_version,
- release_time: partial.release_time,
- time: partial.time,
- type_: partial.type_,
- }
-}
-
-/// The default servers for fabric meta
-pub const FABRIC_META_URL: &str = "https://meta.fabricmc.net/v2";
-
-/// Fetches the manifest of a fabric loader version and game version
-pub async fn fetch_fabric_version(
- version_number: &str,
- loader_version: &str,
-) -> Result {
- Ok(serde_json::from_slice(
- &download_file(
- &*format!(
- "{}/versions/loader/{}/{}/profile/json",
- FABRIC_META_URL, version_number, loader_version
- ),
- None,
- )
- .await?,
- )?)
-}
-
-/// Fetches the manifest of a game version's URL
-pub async fn fetch_fabric_game_version(url: &str) -> Result {
- Ok(serde_json::from_slice(&download_file(url, None).await?)?)
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-/// Versions of fabric components
-pub struct FabricVersions {
- /// Versions of Minecraft that fabric supports
- pub game: Vec,
- /// Available versions of the fabric loader
- pub loader: Vec,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-/// A version of Minecraft that fabric supports
-pub struct FabricGameVersion {
- /// The version number of the game
- pub version: String,
- /// Whether the Minecraft version is stable or not
- pub stable: bool,
- /// (Modrinth Provided) The URLs to download this version's profile with a loader
- /// The key of the map is the loader version, and the value is the URL
- pub urls: Option>,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-/// A version of the fabric loader
-pub struct FabricLoaderVersion {
- /// The separator to get the build number
- pub separator: String,
- /// The build number
- pub build: u32,
- /// The maven artifact
- pub maven: String,
- /// The version number of the fabric loader
- pub version: String,
- /// Whether the loader is stable or not
- pub stable: bool,
-}
-/// Fetches the list of fabric versions
-pub async fn fetch_fabric_versions(url: Option<&str>) -> Result {
- Ok(serde_json::from_slice(
- &download_file(
- url.unwrap_or(&*format!("{}/versions", FABRIC_META_URL)),
- None,
- )
- .await?,
- )?)
-}
diff --git a/daedalus/src/forge.rs b/daedalus/src/forge.rs
deleted file mode 100644
index 4381f0307..000000000
--- a/daedalus/src/forge.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use crate::{download_file, Error};
-
-use std::collections::HashMap;
-
-/// The latest version of the format the model structs deserialize to
-pub const CURRENT_FORMAT_VERSION: usize = 0;
-
-const DEFAULT_MAVEN_METADATA_URL: &str =
- "https://files.minecraftforge.net/net/minecraftforge/forge/maven-metadata.json";
-
-/// Fetches the forge maven metadata from the specified URL. If no URL is specified, the default is used.
-/// Returns a hashmap specifying the versions of the forge mod loader
-/// The hashmap key is a Minecraft version, and the value is the loader versions that work on
-/// the specified Minecraft version
-pub async fn fetch_maven_metadata(
- url: Option<&str>,
-) -> Result>, Error> {
- Ok(serde_json::from_slice(
- &download_file(url.unwrap_or(DEFAULT_MAVEN_METADATA_URL), None).await?,
- )?)
-}
diff --git a/daedalus/src/lib.rs b/daedalus/src/lib.rs
index 4f3147553..a4ac00599 100644
--- a/daedalus/src/lib.rs
+++ b/daedalus/src/lib.rs
@@ -4,12 +4,10 @@
#![warn(missing_docs, unused_import_braces, missing_debug_implementations)]
-/// Models and methods for fetching metadata for the Fabric mod loader
-pub mod fabric;
-/// Models and methods for fetching metadata for the Forge mod loader
-pub mod forge;
/// Models and methods for fetching metadata for Minecraft
pub mod minecraft;
+/// Models and methods for fetching metadata for Minecraft mod loaders
+pub mod modded;
#[derive(thiserror::Error, Debug)]
/// An error type representing possible errors when fetching metadata
diff --git a/daedalus/src/modded.rs b/daedalus/src/modded.rs
new file mode 100644
index 000000000..cff051fa6
--- /dev/null
+++ b/daedalus/src/modded.rs
@@ -0,0 +1,115 @@
+use crate::{download_file, Error};
+
+use crate::minecraft::{Argument, ArgumentType, Library, VersionInfo, VersionType};
+use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+
+/// The latest version of the format the fabric model structs deserialize to
+pub const CURRENT_FABRIC_FORMAT_VERSION: usize = 0;
+/// The latest version of the format the fabric model structs deserialize to
+pub const CURRENT_FORGE_FORMAT_VERSION: usize = 0;
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+/// A partial version returned by fabric meta
+pub struct PartialVersionInfo {
+ /// The version ID of the version
+ pub id: String,
+ /// The version ID this partial version inherits from
+ pub inherits_from: String,
+ /// The time that the version was released
+ pub release_time: DateTime,
+ /// The latest time a file in this version was updated
+ pub time: DateTime,
+ /// The classpath to the main class to launch the game
+ pub main_class: Option,
+ /// Arguments passed to the game or JVM
+ pub arguments: Option>>,
+ /// Libraries that the version depends on
+ pub libraries: Vec,
+ #[serde(rename = "type")]
+ /// The type of version
+ pub type_: VersionType,
+}
+
+/// Fetches the version manifest of a game version's URL
+pub async fn fetch_partial_version(url: &str) -> Result {
+ Ok(serde_json::from_slice(&download_file(url, None).await?)?)
+}
+
+/// Merges a partial version into a complete one
+pub fn merge_partial_version(partial: PartialVersionInfo, merge: VersionInfo) -> VersionInfo {
+ VersionInfo {
+ arguments: if let Some(partial_args) = partial.arguments {
+ if let Some(merge_args) = merge.arguments {
+ Some(partial_args.into_iter().chain(merge_args).collect())
+ } else {
+ Some(partial_args)
+ }
+ } else {
+ merge.arguments
+ },
+ asset_index: merge.asset_index,
+ assets: merge.assets,
+ downloads: merge.downloads,
+ id: merge.id,
+ libraries: partial
+ .libraries
+ .into_iter()
+ .chain(merge.libraries)
+ .collect::>(),
+ main_class: if let Some(main_class) = partial.main_class {
+ main_class
+ } else {
+ merge.main_class
+ },
+ minecraft_arguments: merge.minecraft_arguments,
+ minimum_launcher_version: merge.minimum_launcher_version,
+ release_time: partial.release_time,
+ time: partial.time,
+ type_: partial.type_,
+ }
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+/// A manifest containing information about a mod loader's versions
+pub struct Manifest {
+ /// The game versions the mod loader supports
+ pub game_versions: Vec,
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Clone)]
+#[serde(rename_all = "camelCase")]
+/// The version type of the loader
+pub enum LoaderType {
+ /// The latest type is for experimental loader versions that may not be ready for normal use
+ Latest,
+ /// The stable type is for the most stable but recent loader version. For the forge mod loader,
+ /// this is never used
+ Stable,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+/// A game version of Minecraft
+pub struct Version {
+ /// The minecraft version ID
+ pub id: String,
+ /// A map that contains loader versions for the game version
+ pub loaders: HashMap,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+/// A version of a Minecraft mod loader
+pub struct LoaderVersion {
+ /// The version ID of the loader
+ pub id: String,
+ /// The URL of the version's manifest
+ pub url: String,
+}
+
+/// Fetches the manifest of a mod loader
+pub async fn fetch_manifest(url: &str) -> Result {
+ Ok(serde_json::from_slice(&download_file(url, None).await?)?)
+}
diff --git a/daedalus_client/src/fabric.rs b/daedalus_client/src/fabric.rs
index 809ec832e..63f637f40 100644
--- a/daedalus_client/src/fabric.rs
+++ b/daedalus_client/src/fabric.rs
@@ -1,33 +1,47 @@
use crate::{format_url, upload_file_to_bucket, Error};
-use daedalus::fabric::PartialVersionInfo;
+use daedalus::download_file;
use daedalus::minecraft::Library;
-use std::collections::HashMap;
-use std::sync::{Arc};
-use std::time::{Duration, Instant};
+use daedalus::modded::{LoaderType, LoaderVersion, Manifest, PartialVersionInfo, Version};
use futures::lock::Mutex;
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use std::sync::Arc;
+use std::time::{Duration, Instant};
pub async fn retrieve_data() -> Result<(), Error> {
- let mut list = daedalus::fabric::fetch_fabric_versions(None).await?;
+ let mut list = fetch_fabric_versions(None).await?;
+ let old_manifest = daedalus::modded::fetch_manifest(&*format!(
+ "fabric/v{}/manifest.json",
+ daedalus::modded::CURRENT_FABRIC_FORMAT_VERSION,
+ ))
+ .await
+ .ok();
+
+ let versions = Arc::new(Mutex::new(if let Some(old_manifest) = old_manifest {
+ old_manifest.game_versions
+ } else {
+ Vec::new()
+ }));
if let Some(latest) = list.loader.get(0) {
- let loaders_mutex = Arc::new(Mutex::new(Vec::new()));
+ let loaders_mutex = Arc::new(Mutex::new(HashMap::new()));
let visited_artifacts_mutex = Arc::new(Mutex::new(Vec::new()));
{
let mut loaders = loaders_mutex.lock().await;
- loaders.push(latest.version.clone());
+ loaders.insert(LoaderType::Latest, latest.version.clone());
if !latest.stable {
if let Some(stable) = list.loader.iter().find(|x| x.stable) {
- loaders.push(stable.version.clone());
+ loaders.insert(LoaderType::Stable, stable.version.clone());
}
}
list.loader = list
.loader
.into_iter()
- .filter(|x| loaders.contains(&x.version))
+ .filter(|x| loaders.values().any(|val| val == &x.version))
.collect();
}
@@ -35,105 +49,127 @@ pub async fn retrieve_data() -> Result<(), Error> {
for game_version in list.game.iter_mut() {
let visited_artifacts_mutex = Arc::clone(&visited_artifacts_mutex);
- let game_version_mutex = Mutex::new(HashMap::new());
let loaders_mutex = Arc::clone(&loaders_mutex);
+
+ let versions_mutex = Arc::clone(&versions);
version_futures.push(async move {
- let versions = futures::future::try_join_all(loaders_mutex.lock().await.clone().into_iter().map(
- |loader| async {
- let version = daedalus::fabric::fetch_fabric_version(
- &*game_version.version,
- &*loader,
- )
- .await
- .expect(&*format!("{}, {}", game_version.version, loader));
+ let loader_version_mutex = Mutex::new(HashMap::new());
- Ok::<(String, PartialVersionInfo), Error>((loader, version))
- },
- ))
- .await?;
-
- futures::future::try_join_all(versions.into_iter().map(
- |(loader, version)| async {
- let libs = futures::future::try_join_all(
- version.libraries.into_iter().map(|mut lib| async {
+ let versions =
+ futures::future::try_join_all(
+ loaders_mutex.lock().await.clone().into_iter().map(
+ |(type_, loader)| async {
{
- let mut visited_assets = visited_artifacts_mutex.lock().await;
-
- if visited_assets.contains(&lib.name) {
- lib.url = Some(format_url("maven/"));
-
- return Ok(lib);
- } else {
- visited_assets.push(lib.name.clone())
+ if versions_mutex.lock().await.iter().any(|x| {
+ x.id == game_version.version
+ && x.loaders
+ .get(&type_)
+ .map(|x| x.id == loader)
+ .unwrap_or(false)
+ }) {
+ return Ok(None);
}
}
- let artifact_path =
- daedalus::get_path_from_artifact(&*lib.name)?;
+ let version =
+ fetch_fabric_version(&*game_version.version, &*loader).await?;
- let artifact = daedalus::download_file(
- &*format!(
- "{}{}",
- lib.url.unwrap_or_else(|| {
- "https://maven.fabricmc.net/".to_string()
- }),
- artifact_path
- ),
- None,
- )
- .await?;
+ Ok::