Merge commit '74cf3f076eff43755bb4bef62f1c1bb3fc0e6c2a' into feature-clean

This commit is contained in:
2025-05-26 17:59:09 +03:00
497 changed files with 15033 additions and 9421 deletions

View File

@@ -1,5 +1,6 @@
//! Minecraft CLI argument logic
use crate::launcher::parse_rules;
use crate::profile::QuickPlayType;
use crate::state::Credentials;
use crate::{
state::{MemorySettings, WindowSize},
@@ -31,7 +32,12 @@ pub fn get_class_paths(
.iter()
.filter_map(|library| {
if let Some(rules) = &library.rules {
if !parse_rules(rules, java_arch, minecraft_updated) {
if !parse_rules(
rules,
java_arch,
&QuickPlayType::None,
minecraft_updated,
) {
return None;
}
}
@@ -111,6 +117,7 @@ pub fn get_jvm_arguments(
memory: MemorySettings,
custom_args: Vec<String>,
java_arch: &str,
quick_play_type: &QuickPlayType,
log_config: Option<&LoggingConfiguration>,
) -> crate::Result<Vec<String>> {
let mut parsed_arguments = Vec::new();
@@ -130,6 +137,7 @@ pub fn get_jvm_arguments(
)
},
java_arch,
quick_play_type,
)?;
} else {
parsed_arguments.push(format!(
@@ -214,6 +222,7 @@ pub fn get_minecraft_arguments(
version_type: &VersionType,
resolution: WindowSize,
java_arch: &str,
quick_play_type: &QuickPlayType,
) -> crate::Result<Vec<String>> {
if let Some(arguments) = arguments {
let mut parsed_arguments = Vec::new();
@@ -233,9 +242,11 @@ pub fn get_minecraft_arguments(
assets_directory,
version_type,
resolution,
quick_play_type,
)
},
java_arch,
quick_play_type,
)?;
Ok(parsed_arguments)
@@ -253,6 +264,7 @@ pub fn get_minecraft_arguments(
assets_directory,
version_type,
resolution,
quick_play_type,
)?);
}
Ok(parsed_arguments)
@@ -273,6 +285,7 @@ fn parse_minecraft_argument(
assets_directory: &Path,
version_type: &VersionType,
resolution: WindowSize,
quick_play_type: &QuickPlayType,
) -> crate::Result<String> {
Ok(argument
.replace("${accessToken}", access_token)
@@ -326,7 +339,21 @@ fn parse_minecraft_argument(
)
.replace("${version_type}", version_type.as_str())
.replace("${resolution_width}", &resolution.0.to_string())
.replace("${resolution_height}", &resolution.1.to_string()))
.replace("${resolution_height}", &resolution.1.to_string())
.replace(
"${quickPlaySingleplayer}",
match quick_play_type {
QuickPlayType::Singleplayer(world) => world,
_ => "",
},
)
.replace(
"${quickPlayMultiplayer}",
match quick_play_type {
QuickPlayType::Server(address) => address,
_ => "",
},
))
}
fn parse_arguments<F>(
@@ -334,6 +361,7 @@ fn parse_arguments<F>(
parsed_arguments: &mut Vec<String>,
parse_function: F,
java_arch: &str,
quick_play_type: &QuickPlayType,
) -> crate::Result<()>
where
F: Fn(&str) -> crate::Result<String>,
@@ -348,7 +376,7 @@ where
}
}
Argument::Ruled { rules, value } => {
if parse_rules(rules, java_arch, true) {
if parse_rules(rules, java_arch, quick_play_type, true) {
match value {
ArgumentValue::Single(arg) => {
parsed_arguments.push(parse_function(
@@ -410,16 +438,14 @@ pub async fn get_processor_main_class(
.map_err(|e| IOError::with_path(e, &path))?;
let mut archive = zip::ZipArchive::new(zipfile).map_err(|_| {
crate::ErrorKind::LauncherError(format!(
"Cannot read processor at {}",
path
"Cannot read processor at {path}"
))
.as_error()
})?;
let file = archive.by_name("META-INF/MANIFEST.MF").map_err(|_| {
crate::ErrorKind::LauncherError(format!(
"Cannot read processor manifest at {}",
path
"Cannot read processor manifest at {path}"
))
.as_error()
})?;

View File

@@ -1,10 +1,11 @@
//! Downloader for Minecraft data
use crate::launcher::parse_rules;
use crate::profile::QuickPlayType;
use crate::{
event::{
emit::{emit_loading, loading_try_for_each_concurrent},
LoadingBarId,
emit::{emit_loading, loading_try_for_each_concurrent},
},
state::State,
util::{fetch::*, io, platform::OsExt},
@@ -295,7 +296,7 @@ pub async fn download_libraries(
stream::iter(libraries.iter())
.map(Ok::<&Library, crate::Error>), None, loading_bar,loading_amount,num_files, None,|library| async move {
if let Some(rules) = &library.rules {
if !parse_rules(rules, java_arch, minecraft_updated) {
if !parse_rules(rules, java_arch, &QuickPlayType::None, minecraft_updated) {
tracing::trace!("Skipped library {}", &library.name);
return Ok(());
}

View File

@@ -4,18 +4,21 @@ use crate::event::emit::{emit_loading, init_or_edit_loading};
use crate::event::{LoadingBarId, LoadingBarType};
use crate::launcher::download::download_log_config;
use crate::launcher::io::IOError;
use crate::profile::QuickPlayType;
use crate::state::{
Credentials, JavaVersion, ProcessMetadata, ProfileInstallStage,
};
use crate::util::io;
use crate::{process, state as st, State};
use crate::{State, process, state as st};
use chrono::Utc;
use daedalus as d;
use daedalus::minecraft::{LoggingSide, RuleAction, VersionInfo};
use daedalus::modded::LoaderVersion;
use rand::seq::SliceRandom;
use rand::seq::SliceRandom; // AstralRinth
use serde::Deserialize;
use st::Profile;
use std::collections::HashMap;
use std::path::PathBuf;
use tokio::process::Command;
mod args;
@@ -31,11 +34,14 @@ use crate::state::ACTIVE_STATE;
pub fn parse_rules(
rules: &[d::minecraft::Rule],
java_version: &str,
quick_play_type: &QuickPlayType,
minecraft_updated: bool,
) -> bool {
let mut x = rules
.iter()
.map(|x| parse_rule(x, java_version, minecraft_updated))
.map(|x| {
parse_rule(x, java_version, quick_play_type, minecraft_updated)
})
.collect::<Vec<Option<bool>>>();
if rules
@@ -56,26 +62,30 @@ pub fn parse_rules(
pub fn parse_rule(
rule: &d::minecraft::Rule,
java_version: &str,
quick_play_type: &QuickPlayType,
minecraft_updated: bool,
) -> Option<bool> {
use d::minecraft::{Rule, RuleAction};
let res = match rule {
Rule {
os: Some(ref os), ..
} => {
Rule { os: Some(os), .. } => {
crate::util::platform::os_rule(os, java_version, minecraft_updated)
}
Rule {
features: Some(ref features),
features: Some(features),
..
} => {
!features.is_demo_user.unwrap_or(true)
|| features.has_custom_resolution.unwrap_or(false)
|| !features.has_quick_plays_support.unwrap_or(true)
|| !features.is_quick_play_multiplayer.unwrap_or(true)
|| (features.is_quick_play_singleplayer.unwrap_or(false)
&& matches!(
quick_play_type,
QuickPlayType::Singleplayer(_)
))
|| (features.is_quick_play_multiplayer.unwrap_or(false)
&& matches!(quick_play_type, QuickPlayType::Server(..)))
|| !features.is_quick_play_realms.unwrap_or(true)
|| !features.is_quick_play_singleplayer.unwrap_or(true)
}
_ => return Some(true),
};
@@ -288,8 +298,7 @@ pub async fn install_minecraft(
.await?
.ok_or_else(|| {
crate::ErrorKind::LauncherError(format!(
"Java path invalid or non-functional: {:?}",
java_version
"Java path invalid or non-functional: {java_version:?}"
))
})?;
@@ -308,12 +317,11 @@ pub async fn install_minecraft(
)
.await?;
let client_path = state
.directories
.version_dir(&version_jar)
.join(format!("{version_jar}.jar"));
if let Some(processors) = &version_info.processors {
let client_path = state
.directories
.version_dir(&version_jar)
.join(format!("{version_jar}.jar"));
let libraries_dir = state.directories.libraries_dir();
if let Some(ref mut data) = version_info.data {
@@ -398,16 +406,18 @@ pub async fn install_minecraft(
&loading_bar,
30.0 / total_length as f64,
Some(&format!(
"Running forge processor {}/{}",
index, total_length
"Running forge processor {index}/{total_length}"
)),
)?;
}
}
}
let protocol_version = read_protocol_version_from_jar(client_path).await?;
crate::api::profile::edit(&profile.path, |prof| {
prof.install_stage = ProfileInstallStage::Installed;
prof.protocol_version = protocol_version;
async { Ok(()) }
})
@@ -417,6 +427,34 @@ pub async fn install_minecraft(
Ok(())
}
pub async fn read_protocol_version_from_jar(
path: PathBuf,
) -> crate::Result<Option<i32>> {
let zip = async_zip::tokio::read::fs::ZipFileReader::new(path).await?;
let Some(entry_index) = zip
.file()
.entries()
.iter()
.position(|x| matches!(x.filename().as_str(), Ok("version.json")))
else {
return Ok(None);
};
#[derive(Deserialize, Debug)]
struct VersionData {
protocol_version: Option<i32>,
}
let mut data = vec![];
zip.reader_with_entry(entry_index)
.await?
.read_to_end_checked(&mut data)
.await?;
let data: VersionData = serde_json::from_slice(&data)?;
Ok(data.protocol_version)
}
#[tracing::instrument(skip_all)]
#[allow(clippy::too_many_arguments)]
pub async fn launch_minecraft(
@@ -429,6 +467,7 @@ pub async fn launch_minecraft(
credentials: &Credentials,
post_exit_hook: Option<String>,
profile: &Profile,
quick_play_type: &QuickPlayType,
) -> crate::Result<ProcessMetadata> {
if profile.install_stage == ProfileInstallStage::PackInstalling
|| profile.install_stage == ProfileInstallStage::MinecraftInstalling
@@ -584,6 +623,7 @@ pub async fn launch_minecraft(
*memory,
Vec::from(java_args),
&java_version.architecture,
quick_play_type,
version_info
.logging
.as_ref()
@@ -606,6 +646,7 @@ pub async fn launch_minecraft(
&version.type_,
*resolution,
&java_version.architecture,
quick_play_type,
)?
.into_iter()
.collect::<Vec<_>>(),
@@ -637,10 +678,10 @@ pub async fn launch_minecraft(
// check if the regex exists in the file
if !re.is_match(&options_string) {
// The key was not found in the file, so append it
options_string.push_str(&format!("\n{}:{}", key, value));
options_string.push_str(&format!("\n{key}:{value}"));
} else {
let replaced_string = re
.replace_all(&options_string, &format!("{}:{}", key, value))
.replace_all(&options_string, &format!("{key}:{value}"))
.to_string();
options_string = replaced_string;
}
@@ -658,12 +699,10 @@ pub async fn launch_minecraft(
let mut censor_strings = HashMap::new();
let username = whoami::username();
censor_strings
.insert(format!("/{username}/"), "/{COMPUTER_USERNAME}/".to_string());
censor_strings.insert(
format!("/{}/", username),
"/{COMPUTER_USERNAME}/".to_string(),
);
censor_strings.insert(
format!("\\{}\\", username),
format!("\\{username}\\"),
"\\{COMPUTER_USERNAME}\\".to_string(),
);
censor_strings.insert(
@@ -712,6 +751,12 @@ pub async fn launch_minecraft(
// This also spawns the process and prepares the subsequent processes
state
.process_manager
.insert_new_process(&profile.path, command, post_exit_hook)
.insert_new_process(
&profile.path,
command,
post_exit_hook,
state.directories.profile_logs_dir(&profile.path),
version_info.logging.is_some(),
)
.await
}