use cobble_core::minecraft::models::{AssetIndex, VersionData, VersionManifest}; use cobble_core::minecraft::{ install_assets, install_client, install_libraries, install_log_config, AssetInstallationUpdate, ClientInstallationUpdate, InstallOptionsBuilder, InstallationUpdate, LibraryInstallationUpdate, LogConfigInstallationUpdate, }; use cobble_core::utils::DownloadProgress; use futures::join; use std::env::temp_dir; use tokio::sync::mpsc::{Receiver, Sender}; use tracing_subscriber::FmtSubscriber; #[tokio::main] async fn main() { FmtSubscriber::builder() .with_env_filter("info,cobble_core=debug") .init(); // Fetch version manifest let version_manifest = VersionManifest::fetch().await.unwrap(); // Get version summary let version_summary = version_manifest .versions .get(&version_manifest.latest.release) .unwrap(); // Fetch version data let version_data = VersionData::fetch(&version_summary.url).await.unwrap(); // Fetch asset_index let asset_index = version_data.asset_index.fetch_index().await.unwrap(); let (tx, rx) = InstallationUpdate::channel(500); join!(install(version_data, asset_index, tx), process_updates(rx)); } async fn install( version_data: VersionData, asset_index: AssetIndex, tx: Sender, ) { let mut libraries_path = temp_dir(); libraries_path.push("cobble-core/libraries"); let mut natives_path = temp_dir(); natives_path.push("cobble-core/natives"); let mut assets_path = temp_dir(); assets_path.push("cobble-core/assets"); let mut log_configs_path = temp_dir(); log_configs_path.push("cobble-core/assets/log_configs"); let mut minecraft_path = temp_dir(); minecraft_path.push("cobble-core/.minecraft"); let options = InstallOptionsBuilder::default() .version_data(version_data) .asset_index(asset_index) .libraries_path(libraries_path) .natives_path(natives_path) .assets_path(assets_path) .log_configs_path(log_configs_path) .minecraft_path(minecraft_path) .parallel_downloads(5) .download_retries(1) .verify_downloads(true) .build() .unwrap(); install_libraries(&options, tx.clone()).await.unwrap(); install_assets(&options, tx.clone()).await.unwrap(); install_log_config(&options, tx.clone()).await.unwrap(); install_client(&options, tx.clone()).await.unwrap(); } async fn process_updates(mut rx: Receiver) { while let Some(update) = rx.recv().await { match update { InstallationUpdate::Library((n, p)) => match p { LibraryInstallationUpdate::Downloading(p) => print_progress(p), LibraryInstallationUpdate::Extracting => { println!("{} extracting...", n); } }, InstallationUpdate::Asset((n, p)) => match p { AssetInstallationUpdate::Downloading(p) => print_progress(p), AssetInstallationUpdate::Symlink => { println!("{} symlink...", n); } }, InstallationUpdate::LogConfig(p) => match p { LogConfigInstallationUpdate::Downloading(p) => print_progress(p), }, InstallationUpdate::Client(p) => match p { ClientInstallationUpdate::Downloading(p) => print_progress(p), }, } } } fn print_progress(p: DownloadProgress) { let name = p.file.file_name().map(|s| s.to_string_lossy()).unwrap(); let percent = p.downloaded_bytes as f64 / p.total_bytes as f64; tracing::info!( "{} ({}/{}): {}% done", name, p.current_file + 1, p.total_files, (percent * 100.0) as u64 ); }