FCLauncher/FCLauncher.old/src-tauri/src/modpack.rs

325 lines
10 KiB
Rust

use crate::https;
use crate::java;
use crate::system_dirs::{
get_data_directory, get_java_executable, get_local_data_directory, get_prism_executable,
};
use crate::util;
use reqwest::IntoUrl;
use serde::de::value::Error;
use serde::Deserialize;
use serde::Serialize;
use serde_json::Value;
use std::fs;
use std::fs::File;
use std::io::{Read, Seek, Write};
use std::process::Command;
use std::time::Duration;
use std::{env, thread};
use std::{io::Cursor, path::PathBuf};
#[derive(Serialize, Deserialize, Clone)]
pub struct ModpackEntry {
pub name: String,
pub id: String,
pub last_updated: String,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct VersionEntry {
pub Version: String,
pub File: String,
pub Date: String,
}
async fn get_modpack_name(id: String) -> String {
let modpacks = get_modpacks().await;
let mut instance_name = String::new();
for pack in modpacks {
if pack.id == id {
instance_name = pack.name;
}
}
return instance_name;
}
async fn check_modpack_needs_update(id: String) -> bool {
let mut instance_name = get_modpack_name(id.clone()).await;
if !get_local_data_directory()
.join("prism")
.join("instances")
.join(&mut instance_name)
.exists()
{
return true;
}
let versions = get_versions(id).await;
if !versions.is_ok() {
return false;
}
let versions = versions.unwrap();
let latest = versions[versions.len() - 1].Version.clone();
let mut file = File::open(
get_local_data_directory()
.join("prism")
.join("instances")
.join(instance_name)
.join(".minecraft")
.join("version.txt"),
)
.unwrap();
let mut current = String::new();
file.read_to_string(&mut current);
if latest != current {
return true;
}
return false;
}
#[tauri::command]
pub async fn launch_modpack(window: tauri::AppHandle, id: String) {
if check_modpack_needs_update(id.clone()).await {
install_modpack(window, id.clone()).await;
}
// Launch
let mut child = Command::new(
get_local_data_directory()
.join("prism")
.join(get_prism_executable()),
)
.arg("-l")
.arg(get_modpack_name(id).await)
.spawn()
.unwrap();
}
async fn install_modpack(window: tauri::AppHandle, id: String) {
let versions = get_versions(id.clone()).await.unwrap();
let path = env::temp_dir().join(format!("{}.mrpack", get_modpack_name(id.clone()).await));
let mut file = File::create(path.clone()).unwrap();
let ftp_path = PathBuf::new()
.join(id.clone())
.join(versions[versions.len() - 1].File.clone().as_str());
println!("Downloading file {}", ftp_path.to_str().unwrap());
//ftp::ftp_retr(Some(window.clone()), ftp_path, &mut file, |window, data, size| util::download_callback(name.clone(), window, data, size)).unwrap();
https::download(
Some(window.clone()),
format!(
"https://gitea.piwalker.net/fclauncher/{}/{}",
id.clone(),
versions[versions.len() - 1].File.clone()
),
&mut file,
get_modpack_name(id.clone()).await,
)
.await;
let mut child = Command::new(
get_local_data_directory()
.join("prism")
.join(get_prism_executable()),
)
.arg("-I")
.arg(path)
.spawn()
.unwrap();
loop {
let version_path = get_local_data_directory()
.join("prism")
.join("instances")
.join(get_modpack_name(id.clone()).await)
.join(".minecraft")
.join("version.txt");
if version_path.clone().exists() {
let mut ver_file = File::open(version_path).unwrap();
let mut buf = String::new();
ver_file.read_to_string(&mut buf).unwrap();
if buf == versions[versions.len() - 1].Version.clone().as_str() {
break;
}
}
thread::sleep(Duration::from_secs(3));
}
thread::sleep(Duration::from_secs(1));
child.kill();
let info_path = get_local_data_directory()
.join("prism")
.join("instances")
.join(get_modpack_name(id.clone()).await)
.join("mmc-pack.json");
let mut info_file = File::open(info_path.clone()).unwrap();
let info_json: Value = serde_json::from_reader(info_file).unwrap();
let mut mc_version = "0.0";
for component in info_json["components"].as_array().unwrap() {
if component["uid"] == "net.minecraft" {
mc_version = component["version"].as_str().unwrap();
}
}
let java = get_java_version(mc_version);
java::install_java(java, window.clone()).await;
let option_path = get_local_data_directory()
.join("prism")
.join("instances")
.join(get_modpack_name(id.clone()).await)
.join("instance.cfg");
let mut option_file = File::open(option_path.clone()).unwrap();
let mut buf = String::new();
option_file.read_to_string(&mut buf);
let mut option_file = File::create(option_path).unwrap();
let mut set = false;
for line in buf.lines() {
if line.starts_with("JavaPath=") {
option_file.write_all(
format!(
"JavaPath={}/java-{}-{}/bin/{}\n",
get_local_data_directory()
.join("java")
.into_os_string()
.to_str()
.unwrap()
.replace("\\", "/"),
java,
if env::consts::OS == "windows" {
"win"
} else {
"lin"
},
get_java_executable()
)
.as_bytes(),
);
set = true;
} else {
option_file.write_all(format!("{}\n", line).as_bytes());
}
}
if !set {
option_file.write_all(
format!(
"JavaPath={}/java-{}-{}/bin/{}\n",
get_local_data_directory()
.join("java")
.into_os_string()
.to_str()
.unwrap()
.replace("\\", "/"),
java,
if env::consts::OS == "windows" {
"win"
} else {
"lin"
},
get_java_executable()
)
.as_bytes(),
);
option_file.write_all("OverrideJavaLocation=true\n".as_bytes());
option_file.write_all("OverrideJava=true\n".as_bytes());
}
}
#[tauri::command]
pub async fn get_modpacks() -> Vec<ModpackEntry> {
//unsafe{
let mut modpacks: Vec<ModpackEntry> = Vec::new();
//if modpacks.is_empty() {
let mut buf = Cursor::new(vec![]);
//ftp::ftp_retr(None, PathBuf::new().join("modpacks.json"), &mut buf, |_, _, _| return);
https::download(
None,
format!("https://gitea.piwalker.net/fclauncher/modpacks.json"),
&mut buf,
format!("modpacks.json"),
)
.await;
buf.rewind();
let res = serde_json::from_reader(buf);
if !res.is_ok() {
println!("Result not ok!");
let paths =
fs::read_dir(get_local_data_directory().join("prism").join("instances")).unwrap();
for path in paths {
let path = path.unwrap();
if fs::metadata(path.path()).unwrap().is_file() {
continue;
}
let name = path.file_name().into_string().unwrap();
if name.starts_with(".") {
continue;
}
modpacks.push(ModpackEntry {
name: name.clone(),
id: name,
last_updated: format!(""),
})
}
return modpacks.clone();
}
let modpacks: Vec<ModpackEntry> = res.unwrap();
//println!("{}", v[0].name);
//for pack in v.as_array().unwrap() {
//modpacks.push(ModpackEntry{name: pack["name"].as_str().unwrap().to_string(), id: pack["id"].as_str().unwrap().to_string(), last_updated: pack["last-updated"].as_str().unwrap().to_string()});
//}
//}
return modpacks.clone();
//}
}
#[tauri::command]
pub async fn get_versions(id: String) -> Result<Vec<VersionEntry>, String> {
let mut versions: Vec<VersionEntry> = Vec::new();
let mut buf = Cursor::new(vec![]);
//ftp::ftp_retr(None, PathBuf::new().join(id).join("versions.json"), &mut buf, |_, _, _| return);
https::download(
None,
format!(
"https://gitea.piwalker.net/fclauncher/{}/versions.json",
id.clone()
),
&mut buf,
format!("{}/versions.json", id.clone()),
)
.await;
buf.rewind();
let versions: Vec<VersionEntry> =
serde_json::from_reader(buf).or(Err(format!("Unable to parse json")))?;
//for version in v.as_array().unwrap() {
//versions.push(VersionEntry{version: version["Version"].as_str().unwrap().to_string(), file: version["File"].as_str().unwrap().to_string(), date: version["Date"].as_str().unwrap().to_string()});
//}
return Ok(versions.clone());
}
fn get_java_version(mc_version: &str) -> u8 {
let components: Vec<&str> = mc_version.split(".").collect();
let mut java = 8;
if components[1] == "17" {
java = 17
} else if components[1] == "18" || components[1] == "19" {
java = 17
} else if components[1].parse::<i32>().unwrap() > 19 {
if components[1] == "20" && components[1].parse::<i32>().unwrap() < 5 {
java = 17
} else {
java = 21
}
}
return java;
}
#[tauri::command]
pub async fn get_latest_version(id: String) -> Result<String, String> {
let versions = get_versions(id).await.unwrap();
if (versions.len() == 0) {
return Ok(format!(""));
}
Ok(versions[versions.len() - 1].Version.clone())
}
//pub fn create_json(modpacks: Vec<ModpackEntry>) -> Result<serde_json::Value, String> {
//}