100 lines
3.1 KiB
Rust
100 lines
3.1 KiB
Rust
use std::{
|
|
fs::{self, File},
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use serde_json::Value;
|
|
use walkdir::WalkDir;
|
|
|
|
const META_SERVER: &str = "https://meta.fabricmc.net/";
|
|
const MAVEN_SERVER: &str = "https://maven.fabricmc.net/";
|
|
|
|
fn query_meta_json(path: &str) -> Value {
|
|
ureq::get(&format!("{META_SERVER}{path}")).call().unwrap().into_json().unwrap()
|
|
}
|
|
|
|
fn download_maven(url: &str, path: &Path) {
|
|
fs::create_dir_all(path.parent().unwrap()).unwrap();
|
|
let mut file = File::create(path).unwrap();
|
|
if url.starts_with(MAVEN_SERVER) {
|
|
crate::download::download(&format!("{url}"), &mut file).unwrap();
|
|
} else {
|
|
crate::download::download(&format!("{META_SERVER}{url}"), &mut file).unwrap();
|
|
}
|
|
}
|
|
|
|
fn library_from_json(json: &Value) -> Option<(String, String, String)> {
|
|
let name = json.get("name")?.as_str()?;
|
|
let url = json.get("url")?.as_str()?;
|
|
|
|
// Split "group:artifact:version"
|
|
let parts: Vec<&str> = name.splitn(3, ':').collect();
|
|
if parts.len() != 3 {
|
|
return None;
|
|
}
|
|
|
|
let group = parts[0].replace('.', "/");
|
|
let artifact = parts[1];
|
|
let version = parts[2];
|
|
|
|
// Build remote URL (like Java's getURL)
|
|
let jar_name = format!("{artifact}-{version}.jar");
|
|
let remote_path = format!("{}/{}/{}/{jar_name}", group, artifact, version);
|
|
let full_url = format!("{}{}", url, remote_path);
|
|
|
|
// Build local path (like Java's getPath)
|
|
let group_fs = parts[0].replace('.', &std::path::MAIN_SEPARATOR.to_string());
|
|
let local_path = PathBuf::from(group_fs)
|
|
.join(artifact)
|
|
.join(version)
|
|
.join(jar_name)
|
|
.to_string_lossy()
|
|
.replace(' ', "_");
|
|
|
|
Some((name.to_string(), full_url, local_path))
|
|
}
|
|
|
|
pub fn install_fabric(minecraft_path: &Path, minecraft_version: &str, loader_version: &str) -> Result<(), crate::error::Error> {
|
|
let profile_name = format!("{minecraft_version}-fabric");
|
|
let versions_dir = minecraft_path.join("versions");
|
|
let profile_dir = versions_dir.join(&profile_name);
|
|
let profile_json = profile_dir.join(format!("{profile_name}.json"));
|
|
let libs_dir = minecraft_path.join("libraries");
|
|
|
|
let mut libs = WalkDir::new(&libs_dir)
|
|
.into_iter()
|
|
.filter_map(|e| e.ok())
|
|
.filter(|e| e.file_type().is_file());
|
|
|
|
let mut json = query_meta_json(&format!("v2/versions/loader/{minecraft_version}/{loader_version}/profile/json"));
|
|
|
|
*json.get_mut("id").unwrap() = Value::String(profile_name.clone());
|
|
|
|
fs::create_dir_all(&profile_dir).unwrap();
|
|
|
|
fs::write(&profile_json, json.to_string()).unwrap();
|
|
|
|
fs::copy(
|
|
versions_dir.join(minecraft_version).join(format!("{minecraft_version}.jar")),
|
|
profile_dir.join(profile_name + ".jar"),
|
|
)
|
|
.unwrap();
|
|
|
|
for lib_json in json.get("libraries").unwrap().as_array().unwrap() {
|
|
if let Some((name, url, path)) = library_from_json(lib_json) {
|
|
let lib_file = libs_dir.join(path);
|
|
let lib_id = lib_file.parent().unwrap().parent().unwrap(); // Removes the version/lib.jar
|
|
if !libs.any(|e| e.path().starts_with(lib_id)) {
|
|
println!("Installing library '{name}'");
|
|
download_maven(&url, &lib_file);
|
|
} else {
|
|
println!("library '{name}' Already exists, skipping");
|
|
}
|
|
} else {
|
|
eprintln!("Failed to get json from {lib_json}")
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|