You've already forked AstralRinth
forked from didirus/AstralRinth
Added modpack creation and file adding
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -46,6 +46,17 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38de00daab4eac7d753e97697066238d67ce9d7e2d823ab4f72fe14af29f3f33"
|
checksum = "38de00daab4eac7d753e97697066238d67ce9d7e2d823ab4f72fe14af29f3f33"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.51"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -1022,6 +1033,7 @@ name = "theseus"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argh",
|
"argh",
|
||||||
|
"async-trait",
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"daedalus",
|
"daedalus",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
async-trait = "0.1.51"
|
||||||
|
|
||||||
daedalus = "0.1.6"
|
daedalus = "0.1.6"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@@ -11,7 +12,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
pub const DEFAULT_FORMAT_VERSION: u32 = 1;
|
pub const DEFAULT_FORMAT_VERSION: u32 = 1;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Manifest<'a> {
|
pub struct Manifest<'a> {
|
||||||
pub format_version: u32,
|
pub format_version: u32,
|
||||||
@@ -32,7 +33,7 @@ impl TryFrom<Manifest<'_>> for pack::Modpack {
|
|||||||
.files
|
.files
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(pack::ModpackFile::try_from)
|
.map(pack::ModpackFile::try_from)
|
||||||
.collect::<ModpackResult<Vec<pack::ModpackFile>>>()?;
|
.collect::<ModpackResult<HashSet<pack::ModpackFile>>>()?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name: String::from(manifest.name),
|
name: String::from(manifest.name),
|
||||||
@@ -60,7 +61,7 @@ fn get_loader_version(loader: ModLoader, version: &str) -> ModpackResult<String>
|
|||||||
.iter()
|
.iter()
|
||||||
.find(|&it| it.id == version)
|
.find(|&it| it.id == version)
|
||||||
.ok_or(ModpackError::VersionError(format!(
|
.ok_or(ModpackError::VersionError(format!(
|
||||||
"No versions of {:?} exist for Minecraft {}",
|
"No versions of modloader {:?} exist for Minecraft {}",
|
||||||
loader, version
|
loader, version
|
||||||
)))?
|
)))?
|
||||||
.loaders[&LoaderType::Latest]
|
.loaders[&LoaderType::Latest]
|
||||||
@@ -94,7 +95,7 @@ impl<'a> TryFrom<&'a pack::Modpack> for Manifest<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ManifestFile<'a> {
|
pub struct ManifestFile<'a> {
|
||||||
#[serde(borrow)]
|
#[serde(borrow)]
|
||||||
@@ -134,7 +135,7 @@ impl<'a> From<&'a pack::ModpackFile> for ManifestFile<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq)]
|
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)]
|
||||||
pub struct ManifestHashes<'a> {
|
pub struct ManifestHashes<'a> {
|
||||||
pub sha1: &'a str,
|
pub sha1: &'a str,
|
||||||
}
|
}
|
||||||
@@ -153,7 +154,7 @@ impl<'a> From<&'a pack::ModpackFileHashes> for ManifestHashes<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq)]
|
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)]
|
||||||
pub struct ManifestEnvs {
|
pub struct ManifestEnvs {
|
||||||
pub client: ManifestEnv,
|
pub client: ManifestEnv,
|
||||||
pub server: ManifestEnv,
|
pub server: ManifestEnv,
|
||||||
@@ -208,7 +209,7 @@ impl From<pack::ModpackEnv> for ManifestEnvs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
// HACK: I've tried for hours to get this working zero-copy, but I'm beat. If someone else wants to
|
// HACK: I've tried for hours to get this working zero-copy, but I'm beat. If someone else wants to
|
||||||
// go through the #<!! of implementing it, be my guest.
|
// go through the #<!! of implementing it, be my guest.
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ use zip::ZipArchive;
|
|||||||
use self::{manifest::Manifest, pack::Modpack};
|
use self::{manifest::Manifest, pack::Modpack};
|
||||||
|
|
||||||
pub mod pack;
|
pub mod pack;
|
||||||
mod manifest;
|
pub mod manifest;
|
||||||
|
pub mod modrinth_api;
|
||||||
|
|
||||||
pub const MANIFEST_PATH: &'static str = "index.json";
|
pub const MANIFEST_PATH: &'static str = "index.json";
|
||||||
pub const OVERRIDES_PATH: &'static str = "overrides/";
|
pub const OVERRIDES_PATH: &'static str = "overrides/";
|
||||||
@@ -45,8 +46,11 @@ pub enum ModpackError {
|
|||||||
#[error("Error joining futures: {0}")]
|
#[error("Error joining futures: {0}")]
|
||||||
JoinError(#[from] tokio::task::JoinError),
|
JoinError(#[from] tokio::task::JoinError),
|
||||||
|
|
||||||
#[error("Error fetching modloader version: {0}")]
|
#[error("Versioning Error: {0}")]
|
||||||
VersionError(String),
|
VersionError(String),
|
||||||
|
|
||||||
|
#[error("Error downloading file: {0}")]
|
||||||
|
FetchError(#[from] reqwest::Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModpackResult<T> = Result<T, ModpackError>;
|
type ModpackResult<T> = Result<T, ModpackError>;
|
||||||
|
|||||||
176
theseus/src/modpack/modrinth_api.rs
Normal file
176
theseus/src/modpack/modrinth_api.rs
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
use std::{
|
||||||
|
collections::HashSet,
|
||||||
|
convert::TryFrom,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::launcher::ModLoader;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
manifest::{ManifestEnv, ManifestEnvs, ManifestHashes},
|
||||||
|
pack::{ModpackEnv, ModpackFile, ModpackFileHashes, ModpackGame},
|
||||||
|
ModpackError, ModpackResult,
|
||||||
|
};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use bytes::Bytes;
|
||||||
|
use futures::future::try_join_all;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use tokio::try_join;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait ModrinthAPI {
|
||||||
|
async fn get_latest_version(
|
||||||
|
&self,
|
||||||
|
project: &str,
|
||||||
|
channel: &str,
|
||||||
|
game: &ModpackGame,
|
||||||
|
) -> ModpackResult<HashSet<ModpackFile>>;
|
||||||
|
async fn get_version(&self, version: &str) -> ModpackResult<HashSet<ModpackFile>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ModrinthV1(pub String);
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct ModrinthV1Project<'a> {
|
||||||
|
title: &'a str,
|
||||||
|
client_side: &'a str,
|
||||||
|
server_side: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct ModrinthV1ProjectVersion<'a> {
|
||||||
|
#[serde(borrow)]
|
||||||
|
dependencies: HashSet<&'a str>,
|
||||||
|
#[serde(borrow)]
|
||||||
|
game_versions: HashSet<&'a str>,
|
||||||
|
version_type: &'a str,
|
||||||
|
files: Vec<ModrinthV1ProjectVersionFile<'a>>,
|
||||||
|
#[serde(borrow)]
|
||||||
|
loaders: HashSet<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
struct ModrinthV1ProjectVersionFile<'a> {
|
||||||
|
hashes: ManifestHashes<'a>,
|
||||||
|
url: &'a str,
|
||||||
|
filename: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ModrinthV1ProjectVersionFile<'_>> for ModpackFile {
|
||||||
|
fn from(file: ModrinthV1ProjectVersionFile<'_>) -> Self {
|
||||||
|
Self {
|
||||||
|
hashes: ModpackFileHashes::from(file.hashes),
|
||||||
|
downloads: {
|
||||||
|
let mut downloads: HashSet<String> = HashSet::new();
|
||||||
|
downloads.insert(String::from(file.url));
|
||||||
|
downloads
|
||||||
|
},
|
||||||
|
path: PathBuf::from(file.filename),
|
||||||
|
// WARNING: Since the sidedness of version 1 API requests is unknown, the environemnt is
|
||||||
|
// set here as both.
|
||||||
|
env: ModpackEnv::Both,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl ModrinthAPI for ModrinthV1 {
|
||||||
|
async fn get_latest_version(
|
||||||
|
&self,
|
||||||
|
project: &str,
|
||||||
|
channel: &str,
|
||||||
|
game: &ModpackGame,
|
||||||
|
) -> ModpackResult<HashSet<ModpackFile>> {
|
||||||
|
// Fetch metadata
|
||||||
|
let (project_json, versions_json): (Bytes, Bytes) = try_join!(
|
||||||
|
try_get_json(format!("{}/api/v1/mod/{}", self.0, project)),
|
||||||
|
try_get_json(format!("{}/api/v1/mod/{}/version", self.0, project)),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let (mut project_deserializer, mut versions_deserializer) = (
|
||||||
|
serde_json::Deserializer::from_slice(&project_json),
|
||||||
|
serde_json::Deserializer::from_slice(&versions_json),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (project, versions) = (
|
||||||
|
ModrinthV1Project::deserialize(&mut project_deserializer)?,
|
||||||
|
Vec::deserialize(&mut versions_deserializer)?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (game_version, loader) = match game {
|
||||||
|
ModpackGame::Minecraft(_, ModLoader::Vanilla) => Err(ModpackError::VersionError(
|
||||||
|
String::from("Modrinth V1 does not support vanilla projects"),
|
||||||
|
)),
|
||||||
|
ModpackGame::Minecraft(ref version, ref loader) => Ok((version, loader)),
|
||||||
|
_ => Err(ModpackError::VersionError(String::from(
|
||||||
|
"Attempted to use Modrinth API V1 to install a non-Minecraft project!",
|
||||||
|
))),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let version: ModrinthV1ProjectVersion = versions
|
||||||
|
.into_iter()
|
||||||
|
.find(|it: &ModrinthV1ProjectVersion| {
|
||||||
|
let loader_str = match loader {
|
||||||
|
ModLoader::Fabric => "fabric",
|
||||||
|
ModLoader::Forge => "forge",
|
||||||
|
ModLoader::Vanilla => unreachable!(),
|
||||||
|
};
|
||||||
|
it.version_type == channel
|
||||||
|
&& it.game_versions.contains(&game_version.as_str())
|
||||||
|
&& it.loaders.contains(&loader_str)
|
||||||
|
})
|
||||||
|
.ok_or(ModpackError::VersionError(format!(
|
||||||
|
"Unable to find compatible version of mod {}",
|
||||||
|
project.title
|
||||||
|
)))?;
|
||||||
|
|
||||||
|
// Project fields
|
||||||
|
let envs = ModpackEnv::try_from(ManifestEnvs {
|
||||||
|
client: serde_json::from_str(project.client_side)?,
|
||||||
|
server: serde_json::from_str(project.server_side)?,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Conversions
|
||||||
|
let files = version
|
||||||
|
.files
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(ModpackFile::from)
|
||||||
|
.collect::<HashSet<ModpackFile>>();
|
||||||
|
|
||||||
|
let dep_futures = version.dependencies.iter().map(|it| self.get_version(&it));
|
||||||
|
let deps = try_join_all(dep_futures)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect::<HashSet<ModpackFile>>();
|
||||||
|
|
||||||
|
Ok(files
|
||||||
|
.into_iter()
|
||||||
|
.chain(deps.into_iter())
|
||||||
|
.map(|mut it| {
|
||||||
|
it.env = envs;
|
||||||
|
it
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_version(&self, version: &str) -> ModpackResult<HashSet<ModpackFile>> {
|
||||||
|
let version_json = try_get_json(format!("{}/api/v1/version/{}", self.0, version)).await?;
|
||||||
|
let mut version_deserializer = serde_json::Deserializer::from_slice(&version_json);
|
||||||
|
let version = ModrinthV1ProjectVersion::deserialize(&mut version_deserializer)?;
|
||||||
|
let base_path = PathBuf::from("mods/");
|
||||||
|
|
||||||
|
Ok(version
|
||||||
|
.files
|
||||||
|
.into_iter()
|
||||||
|
.map(ModpackFile::from)
|
||||||
|
.collect::<HashSet<ModpackFile>>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
async fn try_get_json(url: String) -> ModpackResult<Bytes> {
|
||||||
|
Ok(reqwest::get(url).await?.error_for_status()?.bytes().await?)
|
||||||
|
}
|
||||||
@@ -1,18 +1,25 @@
|
|||||||
use std::path::{Path, PathBuf};
|
|
||||||
use daedalus::download_file_mirrors;
|
use daedalus::download_file_mirrors;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
|
use std::{
|
||||||
|
collections::HashSet,
|
||||||
|
hash::Hash,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
modrinth_api::{self, ModrinthV1},
|
||||||
|
ModpackResult,
|
||||||
|
};
|
||||||
use crate::launcher::ModLoader;
|
use crate::launcher::ModLoader;
|
||||||
use super::ModpackResult;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Modpack {
|
pub struct Modpack {
|
||||||
pub game: ModpackGame,
|
pub game: ModpackGame,
|
||||||
pub version: String,
|
pub version: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub summary: Option<String>,
|
pub summary: Option<String>,
|
||||||
pub files: Vec<ModpackFile>,
|
pub files: HashSet<ModpackFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Modpack {
|
impl Modpack {
|
||||||
@@ -31,22 +38,84 @@ impl Modpack {
|
|||||||
// TODO Integrate instance format to save other metadata
|
// TODO Integrate instance format to save other metadata
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new(game: ModpackGame, version: &str, name: &str, summary: Option<&str>) -> Self {
|
||||||
|
Self {
|
||||||
|
game,
|
||||||
|
version: String::from(version),
|
||||||
|
name: String::from(name),
|
||||||
|
summary: summary.map(String::from),
|
||||||
|
files: HashSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn add_project(
|
||||||
|
&mut self,
|
||||||
|
project: &str,
|
||||||
|
base_path: &Path,
|
||||||
|
source: Option<&dyn modrinth_api::ModrinthAPI>,
|
||||||
|
channel: Option<&str>,
|
||||||
|
) -> ModpackResult<()> {
|
||||||
|
let default_api = ModrinthV1(String::from("https://api.modrinth.com"));
|
||||||
|
let channel = channel.unwrap_or("release");
|
||||||
|
let source = source.unwrap_or(&default_api);
|
||||||
|
|
||||||
|
let files = source
|
||||||
|
.get_latest_version(project, channel, &self.game)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|mut it: ModpackFile| {
|
||||||
|
it.path = base_path.join(it.path);
|
||||||
|
it
|
||||||
|
});
|
||||||
|
|
||||||
|
self.files.extend(files);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn add_version(
|
||||||
|
&mut self,
|
||||||
|
version: &str,
|
||||||
|
base_path: &Path,
|
||||||
|
source: Option<&dyn modrinth_api::ModrinthAPI>,
|
||||||
|
) -> ModpackResult<()> {
|
||||||
|
let default_api = ModrinthV1(String::from("https://api.modrinth.com"));
|
||||||
|
let source = source.unwrap_or(&default_api);
|
||||||
|
|
||||||
|
let files = source
|
||||||
|
.get_version(version)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|mut it: ModpackFile| {
|
||||||
|
it.path = base_path.join(it.path);
|
||||||
|
it
|
||||||
|
});
|
||||||
|
|
||||||
|
self.files.extend(files);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum ModpackGame {
|
pub enum ModpackGame {
|
||||||
// TODO: Currently, the launcher does not support specifying mod loader versions, so I just
|
// TODO: Currently, the launcher does not support specifying mod loader versions, so I just
|
||||||
// store the loader here.
|
// store the loader here.
|
||||||
Minecraft(String, ModLoader),
|
Minecraft(String, ModLoader),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct ModpackFile {
|
pub struct ModpackFile {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub hashes: ModpackFileHashes,
|
pub hashes: ModpackFileHashes,
|
||||||
pub env: ModpackEnv,
|
pub env: ModpackEnv,
|
||||||
pub downloads: Vec<String>,
|
pub downloads: HashSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for ModpackFile {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.hashes.sha1.hash(state);
|
||||||
|
self.path.hash(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModpackFile {
|
impl ModpackFile {
|
||||||
@@ -76,13 +145,19 @@ impl ModpackFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum ModpackEnv {
|
pub enum ModpackEnv {
|
||||||
ClientOnly,
|
ClientOnly,
|
||||||
ServerOnly,
|
ServerOnly,
|
||||||
Both,
|
Both,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ModpackSide {
|
||||||
|
Client,
|
||||||
|
Server,
|
||||||
|
}
|
||||||
|
|
||||||
impl ModpackEnv {
|
impl ModpackEnv {
|
||||||
pub fn supports(&self, side: ModpackSide) -> bool {
|
pub fn supports(&self, side: ModpackSide) -> bool {
|
||||||
match self {
|
match self {
|
||||||
@@ -93,14 +168,59 @@ impl ModpackEnv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum ModpackSide {
|
|
||||||
Client, Server,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct ModpackFileHashes {
|
pub struct ModpackFileHashes {
|
||||||
pub sha1: String,
|
pub sha1: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{
|
||||||
|
collections::HashSet,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::launcher::ModLoader;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn add_version() -> ModpackResult<()> {
|
||||||
|
const TEST_VERSION: &'static str = "TpnSObJ7";
|
||||||
|
let mut test_pack = Modpack::new(
|
||||||
|
ModpackGame::Minecraft(String::from("1.16.5"), ModLoader::Fabric),
|
||||||
|
"0.1.0",
|
||||||
|
"Example Modpack",
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
test_pack
|
||||||
|
.add_version(TEST_VERSION, Path::new("mods/"), None)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
test_pack,
|
||||||
|
Modpack {
|
||||||
|
game: ModpackGame::Minecraft(String::from("1.16.5"), ModLoader::Fabric),
|
||||||
|
version: String::from("0.1.0"),
|
||||||
|
name: String::from("Example Modpack"),
|
||||||
|
summary: None,
|
||||||
|
files: {
|
||||||
|
let mut files = HashSet::new();
|
||||||
|
files.insert(ModpackFile {
|
||||||
|
path: PathBuf::from("mods/gravestones-v1.9.jar"),
|
||||||
|
hashes: ModpackFileHashes {
|
||||||
|
sha1: String::from("3f0f6d523d218460310b345be03ab3f1d294e04d"),
|
||||||
|
},
|
||||||
|
env: ModpackEnv::Both,
|
||||||
|
downloads: {
|
||||||
|
let mut downloads = HashSet::new();
|
||||||
|
downloads.insert(String::from("https://cdn.modrinth.com/data/ssUbhMkL/versions/v1.9/gravestones-v1.9.jar"));
|
||||||
|
downloads
|
||||||
|
}
|
||||||
|
});
|
||||||
|
files
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user