diff --git a/.gitignore b/.gitignore index 458382c..3260e5e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target /xcraft /logs -/.vscode \ No newline at end of file +/.vscode +/tmp \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 40e3da1..4c1a16d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,7 @@ dependencies = [ "futures", "java-locator", "log", + "nicotine", "rand 0.9.0", "serde", "serde_json", @@ -1116,7 +1117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1535,8 +1536,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.13.3+wasi-0.2.2", + "wasm-bindgen", "windows-targets 0.52.6", ] @@ -2312,7 +2315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if 1.0.0", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -2401,6 +2404,17 @@ dependencies = [ "crc", ] +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "mac" version = "0.1.1" @@ -2582,6 +2596,14 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nicotine" +version = "0.1.16" +source = "git+https://gitea.awain.net/alterwain/Nicotine.git#c55143440ed00262d3dc2143cca85286dd3b6565" +dependencies = [ + "zip-extract", +] + [[package]] name = "nodrop" version = "0.1.14" @@ -3568,7 +3590,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -3581,7 +3603,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.9.2", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -4174,7 +4196,7 @@ dependencies = [ "getrandom 0.3.1", "once_cell", "rustix 1.0.2", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -4978,7 +5000,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -5514,6 +5536,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + [[package]] name = "yoke" version = "0.7.5" @@ -5643,9 +5674,9 @@ dependencies = [ [[package]] name = "zip" -version = "2.2.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b280484c454e74e5fff658bbf7df8fdbe7a07c6b2de4a53def232c15ef138f3a" +checksum = "938cc23ac49778ac8340e366ddc422b2227ea176edb447e23fc0627608dddadd" dependencies = [ "aes 0.8.4", "arbitrary", @@ -5656,15 +5687,16 @@ dependencies = [ "deflate64", "displaydoc", "flate2", + "getrandom 0.3.1", "hmac 0.12.1", "indexmap 2.8.0", "lzma-rs", "memchr", "pbkdf2", - "rand 0.8.5", "sha1 0.10.6", "thiserror 2.0.12", "time 0.3.39", + "xz2", "zeroize", "zopfli", "zstd", diff --git a/Cargo.toml b/Cargo.toml index aa5f640..bb99f57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,4 +18,5 @@ zip-extract = "0.2.1" java-locator = "0.1.9" log = "0.4.26" env_logger = "0.11.7" -toml = "0.8.20" \ No newline at end of file +toml = "0.8.20" +nicotine = { git = "https://gitea.awain.net/alterwain/Nicotine.git", version = "0.1.16" } \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 7a43165..14b4c7c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,14 +2,14 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct LauncherCredentials { pub uuid: String, pub username: String, pub password: String } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct LauncherServer { pub domain: String, pub port: u16, diff --git a/src/launcher.rs b/src/launcher.rs index a47cbca..a2bf913 100644 --- a/src/launcher.rs +++ b/src/launcher.rs @@ -158,11 +158,10 @@ impl Launcher { p.push("screenshots"); if !p.exists() { continue; } if let Ok(screenshots) = std::fs::read_dir(p) { - for screenshot in screenshots { - if let Ok(screenshot) = screenshot { - if screenshot.file_name().to_str().unwrap().ends_with("png") { - v.push((screenshot.path().to_str().unwrap().to_string(), format!("data:image/png;base64,{}", BASE64_STANDARD.encode(std::fs::read(screenshot.path()).unwrap())))); - } + let tmp = screenshots; + for screenshot in tmp.flatten() { + if screenshot.file_name().to_str().unwrap().ends_with("png") { + v.push((screenshot.path().to_str().unwrap().to_string(), format!("data:image/png;base64,{}", BASE64_STANDARD.encode(std::fs::read(screenshot.path()).unwrap())))); } } } @@ -171,7 +170,13 @@ impl Launcher { v } - pub async fn launch_instance(&self, instance_name: String, username: String, uuid: String, token: String, sender: UnboundedSender) { + pub async fn launch_instance(&self, instance_name: String, mut username: String, mut uuid: String, mut token: String, sender: UnboundedSender, special_server: Option<&LauncherServer> ) { + if let Some(server) = special_server { + username = server.credentials.username.clone(); + uuid = server.credentials.uuid.clone(); + token = server.credentials.password.clone(); + } + let mut instances = self.config.launcher_dir(); instances.push("instances"); instances.push(&instance_name); @@ -186,15 +191,16 @@ impl Launcher { instance_dir.push("instances"); instance_dir.push(&instance_name); instance_dir.push("data"); + let _ = std::fs::create_dir_all(&instance_dir); let mut cmd = Command::new(&self.config.java_path); cmd.current_dir(instance_dir); cmd.stdout(std::process::Stdio::piped()); - cmd.stderr(std::process::Stdio::inherit()); + cmd.stderr(std::process::Stdio::piped()); for arg in JAVA_ARGS { - cmd.arg(arg.to_string()); + cmd.arg(arg); } cmd.arg(["-Xmx", &self.config.ram_amount.to_string(), "M"].concat()); @@ -206,7 +212,7 @@ impl Launcher { cmd.arg(["-Djava.library.path=", natives_path.to_str().unwrap() ].concat()); cmd.arg(["-Dminecraft.client.jar=", client_jar.to_str().unwrap()].concat()); - cmd.arg("-cp".to_string()); + cmd.arg("-cp"); if let Ok(data) = std::fs::read(&instances) { let config: VersionConfig = serde_json::from_slice(&data).unwrap(); @@ -220,17 +226,29 @@ impl Launcher { let rel_path = [libs.to_str().unwrap(), "\\", &rel_path.replace("/", "\\")].concat(); let data = std::fs::read(rel_path).unwrap(); - zip_extract::extract(Cursor::new(data), &natives_path, true); + let _ = zip_extract::extract(Cursor::new(data), &natives_path, true); } } else { let mut libs = self.config.launcher_dir(); libs.push("libraries"); - libs.push(library.to_pathbuf_file()); + libs.push(library.to_pathbuf_file(false)); + if library.name.contains("com.mojang:authlib") { + if let Some(server) = special_server { + let mut patched_auth = self.config.launcher_dir(); + patched_auth.push("libraries"); + patched_auth.push(library.to_pathbuf_file(true)); + let _ = nicotine::patch_jar(libs.to_str().unwrap(), patched_auth.to_str().unwrap(), &["http://", &server.domain, ":", &server.session_server_port.to_string(), "/api/"].concat()); + libraries_cmd.push([patched_auth.to_str().unwrap(), ";"].concat()); + println!("{:?}", patched_auth.to_str().unwrap()); + continue; + } + } libraries_cmd.push([libs.to_str().unwrap(), ";"].concat()); } } libraries_cmd.push(client_jar.to_str().unwrap().to_string()); cmd.arg(libraries_cmd.concat()); + println!("{:?}", libraries_cmd); cmd.arg(config.mainClass.clone()); let mut game_dir = self.config.launcher_dir(); @@ -240,16 +258,37 @@ impl Launcher { let mut assets_dir = self.config.launcher_dir(); assets_dir.push("assets"); - cmd.args(&["--username", &username, "--version", &instance_name, "--gameDir", game_dir.to_str().unwrap(), "--assetsDir", assets_dir.to_str().unwrap(), "--assetIndex", &config.assetIndex.id, "--uuid", &uuid, "--accessToken", &token, "--userProperties", "{}", "--userType", "mojang", "--width", "925", "--height", "530"]); + cmd.args(["--username", &username, "--version", &instance_name, "--gameDir", game_dir.to_str().unwrap(), "--assetsDir", assets_dir.to_str().unwrap(), "--assetIndex", &config.assetIndex.id, "--uuid", &uuid, "--accessToken", &token, "--userProperties", "{}", "--userType", "mojang", "--width", "925", "--height", "530"]); + if let Some(server) = special_server { + cmd.arg("--server"); + cmd.arg(&server.domain); + cmd.arg("--port"); + cmd.arg(server.port.to_string()); + } let mut child = cmd.spawn().unwrap(); tokio::spawn(async move { + if let Some(stdout) = child.stdout.take() { - let reader = BufReader::new(stdout); - let mut lines = reader.lines(); - - while let Ok(Some(line)) = lines.next_line().await { - let _ = sender.send(line); + if let Some(stderr) = child.stderr.take() { + let out_reader = BufReader::new(stdout); + let mut out_lines = out_reader.lines(); + + let err_reader = BufReader::new(stderr); + let mut err_lines = err_reader.lines(); + + loop { + tokio::select! { + Ok(Some(line)) = out_lines.next_line() => { + let _ = sender.send(line); + } + Ok(Some(line)) = err_lines.next_line() => { + let _ = sender.send(line); + } + else => break, + } + } + // end of minecraft launch } } }); @@ -296,7 +335,7 @@ impl Launcher { let mut dl_pp = libraries.clone(); dl_pp.push(library.to_pathbuf_path()); let _ = std::fs::create_dir_all(dl_pp); - dl_path.push(library.to_pathbuf_file()); + dl_path.push(library.to_pathbuf_file(false)); if File::open(dl_path.to_str().unwrap()).await.is_err() { overall_size += artifact.size as usize; let _ = util::download_file(&artifact.url, dl_path.to_str().unwrap(), sx.clone(), "Downloading libraries"); @@ -350,10 +389,10 @@ impl Launcher { let mut single_object_path = assets_path.clone(); single_object_path.push(asset.to_small_path()); - std::fs::create_dir_all(single_object_path); + let _ = std::fs::create_dir_all(single_object_path); if File::open(single_object.to_str().unwrap()).await.is_err() { - util::download_file(&asset.to_url(), single_object.to_str().unwrap(), sx.clone(), "Downloading assets objects"); + let _ = util::download_file(&asset.to_url(), single_object.to_str().unwrap(), sx.clone(), "Downloading assets objects"); cnt += 1; } } @@ -364,9 +403,9 @@ impl Launcher { while let Some((size, status)) = rx.recv().await { current_size += size; current_cnt += 1; - sender.send((((current_size as f32 / overall_size as f32) * 100.0) as u8, status)); + let _ = sender.send((((current_size as f32 / overall_size as f32) * 100.0) as u8, status)); if current_cnt >= cnt { - sender.send((100, "_".to_string())); + let _ = sender.send((100, "_".to_string())); } } }); diff --git a/src/main.rs b/src/main.rs index b83df7a..02fb38c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,17 @@ -use std::sync::{Arc, Mutex}; +use std::sync::Mutex; -use base64::prelude::{BASE64_STANDARD, BASE64_STANDARD_NO_PAD}; -use base64::Engine; -use config::LauncherConfig; use launcher::Launcher; use serde::{Deserialize, Serialize}; use tokio::process::Command; use tokio::runtime::Runtime; -use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; +use tokio::sync::mpsc::{self, UnboundedSender}; use winit::application::ApplicationHandler; -use winit::event_loop::{ControlFlow, EventLoop}; -use winit::event::{Event, WindowEvent}; -use winit::platform::run_on_demand::EventLoopExtRunOnDemand; +use winit::event_loop::EventLoop; +use winit::event::WindowEvent; use winit::window::{Window, WindowId}; use winit::event_loop::ActiveEventLoop; use wry::dpi::LogicalSize; -use wry::http::{version, Request, Response}; +use wry::http::Response; use wry::{RequestAsyncResponder, WebView, WebViewBuilder}; mod config; @@ -57,11 +53,8 @@ impl ApplicationHandler for App { } fn window_event(&mut self, event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent) { - match event { - WindowEvent::CloseRequested => { - event_loop.exit(); - }, - _ => {} + if event == WindowEvent::CloseRequested { + event_loop.exit(); } } } @@ -109,21 +102,17 @@ async fn main() { } } "sign_up" => { - let user_name = params.as_ref().unwrap().params.get(0).unwrap(); + let user_name = params.as_ref().unwrap().params.first().unwrap(); launcher.init_config(user_name.to_string()); responder.respond(Response::new(serde_json::to_vec(&UIMessage { params: vec!["show_add".to_string(), "sidebar_on".to_string()] }).unwrap())); } "fetch_official_versions" => { if let Ok(versions) = crate::minecraft::versions::fetch_versions_list().await { let versions: Vec = versions.versions.iter().filter(|t| { - if !launcher.config.show_alpha && t.r#type == "old_alpha" { - return false; - } else if !launcher.config.show_beta && t.r#type == "old_beta" { - return false; - } else if !launcher.config.show_snapshots && t.r#type == "snapshot" { + if (!launcher.config.show_alpha && t.r#type == "old_alpha") || (!launcher.config.show_beta && t.r#type == "old_beta") || (!launcher.config.show_snapshots && t.r#type == "snapshot") { return false; } - return true; + true }).map(|t| t.id.clone()).collect(); responder.respond(Response::new(serde_json::to_vec(&UIMessage { params: [ vec!["set_downloadable_versions".to_string()], versions ].concat() }).unwrap())); } else { @@ -132,15 +121,11 @@ async fn main() { } "download_vanilla" => { let version = params.unwrap().params[0].clone(); - println!("Version: {}", version); if let Ok(versions) = crate::minecraft::versions::fetch_versions_list().await { - println!("Got versions"); let version = versions.versions.iter().find(|t| t.id.clone() == version); if let Some(version) = version { - println!("Found"); match crate::minecraft::versions::fetch_version_object(version).await { Ok(config ) => { - println!("Config: {}", config.id); responder.respond(Response::new(serde_json::to_vec(&UIMessage { params: vec!["show_loading".to_string(), "sidebar_off".to_string()] }).unwrap())); launcher.new_vanilla_instance(config, version, sx.clone()).await; } @@ -193,7 +178,17 @@ async fn main() { let instance_name = params.unwrap().params[0].clone(); logs_rec.close(); (lx, logs_rec) = mpsc::unbounded_channel(); - launcher.launch_instance(instance_name, launcher.config.user_name().to_string(), util::random_string(32), util::random_string(32), lx.clone()).await; + launcher.launch_instance(instance_name, launcher.config.user_name().to_string(), util::random_string(32), util::random_string(32), lx.clone(), None).await; + } + "run_server_instance" => { + let params = params.unwrap().params; + let instance_name = params[0].clone(); + let domain = params[1].clone(); + let nickname = params[2].clone(); + logs_rec.close(); + (lx, logs_rec) = mpsc::unbounded_channel(); + let s = launcher.config.servers().iter().find(|s| s.domain == domain && s.credentials.username == nickname); + launcher.launch_instance(instance_name, launcher.config.user_name().to_string(), util::random_string(32), util::random_string(32), lx.clone(), s).await; } "locate_java" => { if let Ok(java_path) = java_locator::locate_file("java.exe") { diff --git a/src/minecraft.rs b/src/minecraft.rs index f6907be..27c71f5 100644 --- a/src/minecraft.rs +++ b/src/minecraft.rs @@ -60,7 +60,7 @@ pub mod versions { p } - pub fn to_pathbuf_file(&self) -> PathBuf { + pub fn to_pathbuf_file(&self, is_patched: bool) -> PathBuf { let mut p = PathBuf::new(); let pkg = self.name.clone(); let g = pkg.split(":").collect::>(); @@ -73,7 +73,11 @@ pub mod versions { } p.push(artifact_name); p.push(version); - p.push(vec![artifact_name, "-", version, ".jar"].concat()); + if !is_patched { + p.push([artifact_name, "-", version, ".jar"].concat()); + } else { + p.push([artifact_name, "-", version, "-patch.jar"].concat()); + } p } } @@ -188,7 +192,7 @@ pub mod session { surf::StatusCode::Conflict => Ok(SignUpResponse::UserAlreadyExists), surf::StatusCode::Ok => { let response: ResponseUUID = serde_json::from_slice(&b).unwrap(); - return Ok(SignUpResponse::Registered(response.uuid)) + Ok(SignUpResponse::Registered(response.uuid)) }, _ => Ok(SignUpResponse::ServerError) } diff --git a/src/www/portable.html b/src/www/portable.html index 800c79f..321fde9 100644 --- a/src/www/portable.html +++ b/src/www/portable.html @@ -76,7 +76,7 @@
  • @@ -362,13 +362,6 @@