Merge commit 'dbde3c4669af10dd577590ed6980e5bd4552d13c' into feature-clean

This commit is contained in:
2025-06-19 03:45:56 +03:00
364 changed files with 8892 additions and 7026 deletions

View File

@@ -166,9 +166,8 @@ pub async fn test_jre(
path: PathBuf,
major_version: u32,
) -> crate::Result<bool> {
let jre = match jre::check_java_at_filepath(&path).await {
Some(jre) => jre,
None => return Ok(false),
let Some(jre) = jre::check_java_at_filepath(&path).await else {
return Ok(false);
};
let (major, _) = extract_java_majorminor_version(&jre.version)?;
Ok(major == major_version)

View File

@@ -97,12 +97,15 @@ pub struct ATLauncherMod {
// Check if folder has a instance.json that parses
pub async fn is_valid_atlauncher(instance_folder: PathBuf) -> bool {
let instance: String =
io::read_to_string(&instance_folder.join("instance.json"))
.await
.unwrap_or("".to_string());
let instance: Result<ATInstance, serde_json::Error> =
serde_json::from_str::<ATInstance>(&instance);
let instance = serde_json::from_str::<ATInstance>(
&io::read_any_encoding_to_string(
&instance_folder.join("instance.json"),
)
.await
.unwrap_or(("".into(), encoding_rs::UTF_8))
.0,
);
if let Err(e) = instance {
tracing::warn!(
"Could not parse instance.json at {}: {}",
@@ -124,14 +127,17 @@ pub async fn import_atlauncher(
) -> crate::Result<()> {
let atlauncher_instance_path = atlauncher_base_path
.join("instances")
.join(instance_folder.clone());
.join(&instance_folder);
// Load instance.json
let atinstance: String =
io::read_to_string(&atlauncher_instance_path.join("instance.json"))
.await?;
let atinstance: ATInstance =
serde_json::from_str::<ATInstance>(&atinstance)?;
let atinstance = serde_json::from_str::<ATInstance>(
&io::read_any_encoding_to_string(
&atlauncher_instance_path.join("instance.json"),
)
.await
.unwrap_or(("".into(), encoding_rs::UTF_8))
.0,
)?;
// Icon path should be {instance_folder}/instance.png if it exists,
// Second possibility is ATLauncher/configs/images/{safe_pack_name}.png (safe pack name is alphanumeric lowercase)

View File

@@ -36,13 +36,15 @@ pub struct InstalledModpack {
// Check if folder has a minecraftinstance.json that parses
pub async fn is_valid_curseforge(instance_folder: PathBuf) -> bool {
let minecraftinstance: String =
io::read_to_string(&instance_folder.join("minecraftinstance.json"))
.await
.unwrap_or("".to_string());
let minecraftinstance: Result<MinecraftInstance, serde_json::Error> =
serde_json::from_str::<MinecraftInstance>(&minecraftinstance);
minecraftinstance.is_ok()
let minecraft_instance = serde_json::from_str::<MinecraftInstance>(
&io::read_any_encoding_to_string(
&instance_folder.join("minecraftinstance.json"),
)
.await
.unwrap_or(("".into(), encoding_rs::UTF_8))
.0,
);
minecraft_instance.is_ok()
}
pub async fn import_curseforge(
@@ -50,19 +52,20 @@ pub async fn import_curseforge(
profile_path: &str, // path to profile
) -> crate::Result<()> {
// Load minecraftinstance.json
let minecraft_instance: String = io::read_to_string(
&curseforge_instance_folder.join("minecraftinstance.json"),
)
.await?;
let minecraft_instance: MinecraftInstance =
serde_json::from_str::<MinecraftInstance>(&minecraft_instance)?;
let override_title: Option<String> = minecraft_instance.name.clone();
let minecraft_instance = serde_json::from_str::<MinecraftInstance>(
&io::read_any_encoding_to_string(
&curseforge_instance_folder.join("minecraftinstance.json"),
)
.await
.unwrap_or(("".into(), encoding_rs::UTF_8))
.0,
)?;
let override_title = minecraft_instance.name;
let backup_name = format!(
"Curseforge-{}",
curseforge_instance_folder
.file_name()
.map(|a| a.to_string_lossy().to_string())
.unwrap_or("Unknown".to_string())
.map_or("Unknown".to_string(), |a| a.to_string_lossy().to_string())
);
let state = State::get().await?;

View File

@@ -25,12 +25,12 @@ pub struct GDLauncherLoader {
// Check if folder has a config.json that parses
pub async fn is_valid_gdlauncher(instance_folder: PathBuf) -> bool {
let config: String =
io::read_to_string(&instance_folder.join("config.json"))
let config = serde_json::from_str::<GDLauncherConfig>(
&io::read_any_encoding_to_string(&instance_folder.join("config.json"))
.await
.unwrap_or("".to_string());
let config: Result<GDLauncherConfig, serde_json::Error> =
serde_json::from_str::<GDLauncherConfig>(&config);
.unwrap_or(("".into(), encoding_rs::UTF_8))
.0,
);
config.is_ok()
}
@@ -39,18 +39,20 @@ pub async fn import_gdlauncher(
profile_path: &str, // path to profile
) -> crate::Result<()> {
// Load config.json
let config: String =
io::read_to_string(&gdlauncher_instance_folder.join("config.json"))
.await?;
let config: GDLauncherConfig =
serde_json::from_str::<GDLauncherConfig>(&config)?;
let override_title: Option<String> = config.loader.source_name.clone();
let config = serde_json::from_str::<GDLauncherConfig>(
&io::read_any_encoding_to_string(
&gdlauncher_instance_folder.join("config.json"),
)
.await
.unwrap_or(("".into(), encoding_rs::UTF_8))
.0,
)?;
let override_title = config.loader.source_name;
let backup_name = format!(
"GDLauncher-{}",
gdlauncher_instance_folder
.file_name()
.map(|a| a.to_string_lossy().to_string())
.unwrap_or("Unknown".to_string())
.map_or("Unknown".to_string(), |a| a.to_string_lossy().to_string())
);
// Re-cache icon

View File

@@ -26,6 +26,7 @@ enum MMCInstanceEnum {
struct MMCInstanceGeneral {
pub general: MMCInstance,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct MMCInstance {
@@ -144,9 +145,9 @@ pub async fn is_valid_mmc(instance_folder: PathBuf) -> bool {
let instance_cfg = instance_folder.join("instance.cfg");
let mmc_pack = instance_folder.join("mmc-pack.json");
let mmc_pack = match io::read_to_string(&mmc_pack).await {
Ok(mmc_pack) => mmc_pack,
Err(_) => return false,
let Ok((mmc_pack, _)) = io::read_any_encoding_to_string(&mmc_pack).await
else {
return false;
};
load_instance_cfg(&instance_cfg).await.is_ok()
@@ -155,7 +156,7 @@ pub async fn is_valid_mmc(instance_folder: PathBuf) -> bool {
#[tracing::instrument]
pub async fn get_instances_subpath(config: PathBuf) -> Option<String> {
let launcher = io::read_to_string(&config).await.ok()?;
let launcher = io::read_any_encoding_to_string(&config).await.ok()?.0;
let launcher: MMCLauncherEnum = serde_ini::from_str(&launcher).ok()?;
match launcher {
MMCLauncherEnum::General(p) => Some(p.general.instance_dir),
@@ -165,10 +166,9 @@ pub async fn get_instances_subpath(config: PathBuf) -> Option<String> {
// Loading the INI (instance.cfg) file
async fn load_instance_cfg(file_path: &Path) -> crate::Result<MMCInstance> {
let instance_cfg: String = io::read_to_string(file_path).await?;
let instance_cfg_enum: MMCInstanceEnum =
serde_ini::from_str::<MMCInstanceEnum>(&instance_cfg)?;
match instance_cfg_enum {
match serde_ini::from_str::<MMCInstanceEnum>(
&io::read_any_encoding_to_string(file_path).await?.0,
)? {
MMCInstanceEnum::General(instance_cfg) => Ok(instance_cfg.general),
MMCInstanceEnum::Instance(instance_cfg) => Ok(instance_cfg),
}
@@ -183,9 +183,13 @@ pub async fn import_mmc(
let mmc_instance_path =
mmc_base_path.join("instances").join(instance_folder);
let mmc_pack =
io::read_to_string(&mmc_instance_path.join("mmc-pack.json")).await?;
let mmc_pack: MMCPack = serde_json::from_str::<MMCPack>(&mmc_pack)?;
let mmc_pack = serde_json::from_str::<MMCPack>(
&io::read_any_encoding_to_string(
&mmc_instance_path.join("mmc-pack.json"),
)
.await?
.0,
)?;
let instance_cfg =
load_instance_cfg(&mmc_instance_path.join("instance.cfg")).await?;
@@ -230,7 +234,7 @@ pub async fn import_mmc(
// Kept separate as we may in the future want to add special handling for modrinth managed packs
import_mmc_unmanaged(profile_path, minecraft_folder, "Imported Modrinth Modpack".to_string(), description, mmc_pack).await?;
}
Some(MMCManagedPackType::Flame) | Some(MMCManagedPackType::ATLauncher) => {
Some(MMCManagedPackType::Flame | MMCManagedPackType::ATLauncher) => {
// For flame/atlauncher managed packs
// Treat as unmanaged, but with 'minecraft' folder instead of '.minecraft'
import_mmc_unmanaged(profile_path, minecraft_folder, "Imported Modpack".to_string(), description, mmc_pack).await?;
@@ -243,7 +247,7 @@ pub async fn import_mmc(
_ => return Err(crate::ErrorKind::InputError("Instance is managed, but managed pack type not specified in instance.cfg".to_string()).into())
}
} else {
// Direclty import unmanaged pack
// Directly import unmanaged pack
import_mmc_unmanaged(
profile_path,
minecraft_folder,

View File

@@ -357,9 +357,7 @@ pub async fn set_profile_information(
}
}
let game_version = if let Some(game_version) = game_version {
game_version
} else {
let Some(game_version) = game_version else {
return Err(crate::ErrorKind::InputError(
"Pack did not specify Minecraft version".to_string(),
)
@@ -393,10 +391,7 @@ pub async fn set_profile_information(
locked: if !ignore_lock {
true
} else {
prof.linked_data
.as_ref()
.map(|x| x.locked)
.unwrap_or(true)
prof.linked_data.as_ref().is_none_or(|x| x.locked)
},
})
}

View File

@@ -152,8 +152,7 @@ pub async fn install_zipped_mrpack_files(
if let Some(env) = project.env {
if env
.get(&EnvType::Client)
.map(|x| x == &SideType::Unsupported)
.unwrap_or(false)
.is_some_and(|x| x == &SideType::Unsupported)
{
return Ok(());
}

View File

@@ -586,7 +586,7 @@ pub async fn get_pack_export_candidates(
.await
.map_err(|e| IOError::with_path(e, &profile_base_dir))?
{
let path: PathBuf = entry.path();
let path = entry.path();
if path.is_dir() {
// Two layers of files/folders if its a folder
let mut read_dir = io::read_dir(&path).await?;
@@ -595,10 +595,10 @@ pub async fn get_pack_export_candidates(
.await
.map_err(|e| IOError::with_path(e, &profile_base_dir))?
{
let path: PathBuf = entry.path();
path_list
.push(pack_get_relative_path(&profile_base_dir, &path)?);
path_list.push(pack_get_relative_path(
&profile_base_dir,
&entry.path(),
)?);
}
} else {
// One layer of files/folders if its a file
@@ -644,7 +644,6 @@ pub async fn run(
/// Run Minecraft using a profile, and credentials for authentication
/// Returns Arc pointer to RwLock to Child
#[tracing::instrument(skip(credentials))]
pub async fn run_credentials(
path: &str,
credentials: &Credentials,
@@ -662,14 +661,15 @@ pub async fn run_credentials(
.hooks
.pre_launch
.as_ref()
.or(settings.hooks.pre_launch.as_ref());
.or(settings.hooks.pre_launch.as_ref())
.filter(|hook_command| !hook_command.is_empty());
if let Some(hook) = pre_launch_hooks {
// TODO: hook parameters
let mut cmd = hook.split(' ');
if let Some(command) = cmd.next() {
let full_path = get_full_path(&profile.path).await?;
let result = Command::new(command)
.args(cmd.collect::<Vec<&str>>())
.args(cmd)
.current_dir(&full_path)
.spawn()
.map_err(|e| IOError::with_path(e, &full_path))?
@@ -692,7 +692,12 @@ pub async fn run_credentials(
.clone()
.unwrap_or(settings.extra_launch_args);
let wrapper = profile.hooks.wrapper.clone().or(settings.hooks.wrapper);
let wrapper = profile
.hooks
.wrapper
.clone()
.or(settings.hooks.wrapper)
.filter(|hook_command| !hook_command.is_empty());
let memory = profile.memory.unwrap_or(settings.memory);
let resolution =
@@ -704,8 +709,12 @@ pub async fn run_credentials(
.unwrap_or(settings.custom_env_vars);
// Post post exit hooks
let post_exit_hook =
profile.hooks.post_exit.clone().or(settings.hooks.post_exit);
let post_exit_hook = profile
.hooks
.post_exit
.clone()
.or(settings.hooks.post_exit)
.filter(|hook_command| !hook_command.is_empty());
// Any options.txt settings that we want set, add here
let mut mc_set_options: Vec<(String, String)> = vec![];
@@ -872,15 +881,12 @@ pub async fn create_mrpack_json(
env.insert(EnvType::Client, SideType::Required);
env.insert(EnvType::Server, SideType::Required);
let primary_file =
if let Some(primary_file) = version.files.first() {
primary_file
} else {
return Some(Err(crate::ErrorKind::OtherError(
format!("No primary file found for mod at: {path}"),
)
.as_error()));
};
let Some(primary_file) = version.files.first() else {
return Some(Err(crate::ErrorKind::OtherError(format!(
"No primary file found for mod at: {path}"
))
.as_error()));
};
let file_size = primary_file.size;
let downloads = vec![primary_file.url.clone()];

View File

@@ -255,7 +255,7 @@ async fn get_all_worlds_in_profile(
AttachedWorldData::get_all_for_instance(profile_path, &state.pool)
.await?;
if !attached_data.is_empty() {
for world in worlds.iter_mut() {
for world in &mut worlds {
if let Some(data) = attached_data
.get(&(world.world_type(), world.world_id().to_owned()))
{

View File

@@ -139,9 +139,7 @@ pub async fn edit_loading(
// increment refers to by what relative increment to the loading struct's total to update
// message is the message to display on the loading bar- if None, use the loading bar's default one
// By convention, fraction is the fraction of the progress bar that is filled
#[allow(unused_variables)]
#[tracing::instrument(level = "debug")]
pub fn emit_loading(
key: &LoadingBarId,
increment_frac: f64,
@@ -149,22 +147,13 @@ pub fn emit_loading(
) -> crate::Result<()> {
let event_state = crate::EventState::get()?;
let mut loading_bar = match event_state.loading_bars.get_mut(&key.0) {
Some(f) => f,
None => {
return Err(EventError::NoLoadingBar(key.0).into());
}
let Some(mut loading_bar) = event_state.loading_bars.get_mut(&key.0) else {
return Err(EventError::NoLoadingBar(key.0).into());
};
// Tick up loading bar
loading_bar.current += increment_frac;
let display_frac = loading_bar.current / loading_bar.total;
let opt_display_frac = if display_frac >= 1.0 {
None // by convention, when its done, we submit None
// any further updates will be ignored (also sending None)
} else {
Some(display_frac)
};
if f64::abs(display_frac - loading_bar.last_sent) > 0.005 {
// Emit event to indicatif progress bar
@@ -187,7 +176,12 @@ pub fn emit_loading(
.emit(
"loading",
LoadingPayload {
fraction: opt_display_frac,
fraction: if display_frac >= 1.0 {
None // by convention, when its done, we submit None
// any further updates will be ignored (also sending None)
} else {
Some(display_frac)
},
message: message
.unwrap_or(&loading_bar.message)
.to_string(),
@@ -197,6 +191,9 @@ pub fn emit_loading(
)
.map_err(EventError::from)?;
#[cfg(not(any(feature = "cli", feature = "tauri")))]
let _ = message;
loading_bar.last_sent = display_frac;
}
@@ -204,8 +201,6 @@ pub fn emit_loading(
}
// emit_warning(message)
#[allow(dead_code)]
#[allow(unused_variables)]
pub async fn emit_warning(message: &str) -> crate::Result<()> {
#[cfg(feature = "tauri")]
{
@@ -227,8 +222,6 @@ pub async fn emit_warning(message: &str) -> crate::Result<()> {
// emit_command(CommandPayload::Something { something })
// ie: installing a pack, opening an .mrpack, etc
// Generally used for url deep links and file opens that we want to handle in the frontend
#[allow(dead_code)]
#[allow(unused_variables)]
pub async fn emit_command(command: CommandPayload) -> crate::Result<()> {
tracing::debug!("Command: {}", serde_json::to_string(&command)?);
#[cfg(feature = "tauri")]

View File

@@ -87,9 +87,9 @@ pub fn get_lib_path(
lib: &str,
allow_not_exist: bool,
) -> crate::Result<String> {
let mut path = libraries_path.to_path_buf();
path.push(get_path_from_artifact(lib)?);
let path = libraries_path
.to_path_buf()
.join(get_path_from_artifact(lib)?);
if !path.exists() && allow_not_exist {
return Ok(path.to_string_lossy().to_string());

View File

@@ -37,12 +37,7 @@ pub async fn download_minecraft(
let assets_index =
download_assets_index(st, version, Some(loading_bar), force).await?;
let amount = if version
.processors
.as_ref()
.map(|x| !x.is_empty())
.unwrap_or(false)
{
let amount = if version.processors.as_ref().is_some_and(|x| !x.is_empty()) {
25.0
} else {
40.0

View File

@@ -15,9 +15,10 @@ use daedalus as d;
use daedalus::minecraft::{LoggingSide, RuleAction, VersionInfo};
use daedalus::modded::LoaderVersion;
use rand::seq::SliceRandom; // AstralRinth
use regex::Regex;
use serde::Deserialize;
use st::Profile;
use std::collections::HashMap;
use std::fmt::Write;
use std::path::PathBuf;
use tokio::process::Command;
@@ -139,8 +140,7 @@ pub async fn get_java_version_from_profile(
let key = version_info
.java_version
.as_ref()
.map(|it| it.major_version)
.unwrap_or(8);
.map_or(8, |it| it.major_version);
let state = State::get().await?;
@@ -255,8 +255,7 @@ pub async fn install_minecraft(
let loader_version_id = loader_version.clone();
crate::api::profile::edit(&profile.path, |prof| {
prof.loader_version =
loader_version_id.clone().map(|x| x.id.clone());
prof.loader_version = loader_version_id.clone().map(|x| x.id);
async { Ok(()) }
})
@@ -281,8 +280,7 @@ pub async fn install_minecraft(
let key = version_info
.java_version
.as_ref()
.map(|it| it.major_version)
.unwrap_or(8);
.map_or(8, |it| it.major_version);
let (java_version, set_java) = if let Some(java_version) =
get_java_version_from_profile(profile, &version_info).await?
{
@@ -355,9 +353,11 @@ pub async fn install_minecraft(
}
}
let cp = wrap_ref_builder!(cp = processor.classpath.clone() => {
cp.push(processor.jar.clone())
});
let cp = {
let mut cp = processor.classpath.clone();
cp.push(processor.jar.clone());
cp
};
let child = Command::new(&java_version.path)
.arg("-cp")
@@ -580,7 +580,9 @@ pub async fn launch_minecraft(
let args = version_info.arguments.clone().unwrap_or_default();
let mut command = match wrapper {
Some(hook) => {
wrap_ref_builder!(it = Command::new(hook) => {it.arg(&java_version.path)})
let mut command = Command::new(hook);
command.arg(&java_version.path);
command
}
None => Command::new(&java_version.path),
};
@@ -629,8 +631,7 @@ pub async fn launch_minecraft(
.as_ref()
.and_then(|x| x.get(&LoggingSide::Client)),
)?
.into_iter()
.collect::<Vec<_>>(),
.into_iter(),
)
.arg(version_info.main_class.clone())
.args(
@@ -648,8 +649,7 @@ pub async fn launch_minecraft(
&java_version.architecture,
quick_play_type,
)?
.into_iter()
.collect::<Vec<_>>(),
.into_iter(),
)
.current_dir(instance_path.clone());
@@ -665,20 +665,35 @@ pub async fn launch_minecraft(
// Overwrites the minecraft options.txt file with the settings from the profile
// Uses 'a:b' syntax which is not quite yaml
use regex::Regex;
if !mc_set_options.is_empty() {
let options_path = instance_path.join("options.txt");
let mut options_string = String::new();
if options_path.exists() {
options_string = io::read_to_string(&options_path).await?;
let (mut options_string, input_encoding) = if options_path.exists() {
io::read_any_encoding_to_string(&options_path).await?
} else {
(String::new(), encoding_rs::UTF_8)
};
// UTF-16 encodings may be successfully detected and read, but we cannot encode
// them back, and it's technically possible that the game client strongly expects
// such encoding
if input_encoding != input_encoding.output_encoding() {
return Err(crate::ErrorKind::LauncherError(format!(
"The instance options.txt file uses an unsupported encoding: {}. \
Please either turn off instance options that need to modify this file, \
or convert the file to an encoding that both the game and this app support, \
such as UTF-8.",
input_encoding.name()
))
.into());
}
for (key, value) in mc_set_options {
let re = Regex::new(&format!(r"(?m)^{}:.*$", regex::escape(key)))?;
// 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}"));
write!(&mut options_string, "\n{key}:{value}").unwrap();
} else {
let replaced_string = re
.replace_all(&options_string, &format!("{key}:{value}"))
@@ -687,7 +702,8 @@ pub async fn launch_minecraft(
}
}
io::write(&options_path, options_string).await?;
io::write(&options_path, input_encoding.encode(&options_string).0)
.await?;
}
crate::api::profile::edit(&profile.path, |prof| {
@@ -697,31 +713,6 @@ pub async fn launch_minecraft(
})
.await?;
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(
credentials.access_token.clone(),
"{MINECRAFT_ACCESS_TOKEN}".to_string(),
);
censor_strings.insert(
credentials.username.clone(),
"{MINECRAFT_USERNAME}".to_string(),
);
censor_strings.insert(
credentials.id.as_simple().to_string(),
"{MINECRAFT_UUID}".to_string(),
);
censor_strings.insert(
credentials.id.as_hyphenated().to_string(),
"{MINECRAFT_UUID}".to_string(),
);
// If in tauri, and the 'minimize on launch' setting is enabled, minimize the window
#[cfg(feature = "tauri")]
{

View File

@@ -461,8 +461,7 @@ impl CacheValue {
CacheValue::Team(members) => members
.iter()
.next()
.map(|x| x.team_id.as_str())
.unwrap_or(DEFAULT_ID)
.map_or(DEFAULT_ID, |x| x.team_id.as_str())
.to_string(),
CacheValue::Organization(org) => org.id.clone(),
CacheValue::File(file) => file.hash.clone(),
@@ -556,7 +555,6 @@ macro_rules! impl_cache_methods {
$(
paste::paste! {
#[tracing::instrument(skip(pool, fetch_semaphore))]
#[allow(dead_code)]
pub async fn [<get_ $variant:snake>](
id: &str,
cache_behaviour: Option<CacheBehaviour>,
@@ -568,7 +566,6 @@ macro_rules! impl_cache_methods {
}
#[tracing::instrument(skip(pool, fetch_semaphore))]
#[allow(dead_code)]
pub async fn [<get_ $variant:snake _many>](
ids: &[&str],
cache_behaviour: Option<CacheBehaviour>,
@@ -597,7 +594,6 @@ macro_rules! impl_cache_method_singular {
$(
paste::paste! {
#[tracing::instrument(skip(pool, fetch_semaphore))]
#[allow(dead_code)]
pub async fn [<get_ $variant:snake>] (
cache_behaviour: Option<CacheBehaviour>,
pool: &SqlitePool,
@@ -735,18 +731,13 @@ impl CachedEntry {
remaining_keys.retain(|x| {
x != &&*row.id
&& !row
.alias
.as_ref()
.map(|y| {
if type_.case_sensitive_alias().unwrap_or(true)
{
x == y
} else {
y.to_lowercase() == x.to_lowercase()
}
})
.unwrap_or(false)
&& !row.alias.as_ref().is_some_and(|y| {
if type_.case_sensitive_alias().unwrap_or(true) {
x == y
} else {
y.to_lowercase() == x.to_lowercase()
}
})
});
if let Some(data) = parsed_data {
@@ -991,7 +982,7 @@ impl CachedEntry {
let key = key.to_string();
if let Some(position) = teams.iter().position(|x| {
x.first().map(|x| x.team_id == key).unwrap_or(false)
x.first().is_some_and(|x| x.team_id == key)
}) {
let team = teams.remove(position);

View File

@@ -47,9 +47,8 @@ impl DirectoryInfo {
))
})?;
let config_dir = config_dir
.map(PathBuf::from)
.unwrap_or_else(|| settings_dir.clone());
let config_dir =
config_dir.map_or_else(|| settings_dir.clone(), PathBuf::from);
Ok(Self {
settings_dir,
@@ -198,8 +197,7 @@ impl DirectoryInfo {
let move_dir = settings
.custom_dir
.as_ref()
.map(PathBuf::from)
.unwrap_or_else(|| app_dir.clone());
.map_or_else(|| app_dir.clone(), PathBuf::from);
async fn is_dir_writeable(
new_config_dir: &Path,
@@ -225,7 +223,7 @@ impl DirectoryInfo {
let disks = sysinfo::Disks::new_with_refreshed_list();
for disk in disks.iter() {
for disk in &disks {
if path.starts_with(disk.mount_point()) {
return Ok(Some(disk.available_space()));
}

View File

@@ -174,7 +174,7 @@ impl FriendsSocket {
ServerToClientMessage::FriendRequest { from } => {
let _ = emit_friend(FriendPayload::FriendRequest { from }).await;
}
ServerToClientMessage::FriendRequestRejected { .. } => todo!(),
ServerToClientMessage::FriendRequestRejected { .. } => {}, // TODO
ServerToClientMessage::FriendSocketListening { .. } => {}, // TODO
ServerToClientMessage::FriendSocketStoppedListening { .. } => {}, // TODO

View File

@@ -29,9 +29,7 @@ where
return Ok(());
};
let old_launcher_root = if let Some(dir) = default_settings_dir() {
dir
} else {
let Some(old_launcher_root) = default_settings_dir() else {
return Ok(());
};
let old_launcher_root_str = old_launcher_root.to_string_lossy().to_string();
@@ -177,12 +175,10 @@ where
let profile_path = entry.path().join("profile.json");
let profile = if let Ok(profile) =
let Ok(profile) =
read_json::<LegacyProfile>(&profile_path, &io_semaphore)
.await
{
profile
} else {
else {
continue;
};
@@ -285,7 +281,7 @@ where
TeamMember {
team_id: x.team_id,
user: user.clone(),
user,
is_owner: x.role == "Owner",
role: x.role,
ordering: x.ordering,

View File

@@ -1177,12 +1177,10 @@ fn get_date_header(headers: &HeaderMap) -> DateTime<Utc> {
.get(reqwest::header::DATE)
.and_then(|x| x.to_str().ok())
.and_then(|x| DateTime::parse_from_rfc2822(x).ok())
.map(|x| x.with_timezone(&Utc))
.unwrap_or(Utc::now())
.map_or(Utc::now(), |x| x.with_timezone(&Utc))
}
#[tracing::instrument]
#[allow(clippy::format_collect)]
fn generate_oauth_challenge() -> String {
let mut rng = rand::thread_rng();

View File

@@ -692,7 +692,7 @@ impl Process {
let mut cmd = hook.split(' ');
if let Some(command) = cmd.next() {
let mut command = Command::new(command);
command.args(cmd.collect::<Vec<&str>>()).current_dir(
command.args(cmd).current_dir(
profile::get_full_path(&profile_path).await?,
);
command.spawn().map_err(IOError::from)?;

View File

@@ -1022,8 +1022,10 @@ impl Profile {
file.hash,
file.project_type
.filter(|x| *x != ProjectType::Mod)
.map(|x| x.get_loaders().join("+"))
.unwrap_or_else(|| profile.loader.as_str().to_string()),
.map_or_else(
|| profile.loader.as_str().to_string(),
|x| x.get_loaders().join("+")
),
profile.game_version
)
}

View File

@@ -247,9 +247,13 @@ pub struct WindowSize(pub u16, pub u16);
/// Game initialization hooks
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde_with::serde_as]
pub struct Hooks {
#[serde_as(as = "serde_with::NoneAsEmptyString")]
pub pre_launch: Option<String>,
#[serde_as(as = "serde_with::NoneAsEmptyString")]
pub wrapper: Option<String>,
#[serde_as(as = "serde_with::NoneAsEmptyString")]
pub post_exit: Option<String>,
}

View File

@@ -80,10 +80,9 @@ pub async fn fetch_advanced(
) -> crate::Result<Bytes> {
let _permit = semaphore.0.acquire().await?;
let creds = if !header
let creds = if header
.as_ref()
.map(|x| &*x.0.to_lowercase() == "authorization")
.unwrap_or(false)
.is_none_or(|x| &*x.0.to_lowercase() != "authorization")
&& (url.starts_with("https://cdn.modrinth.com")
|| url.starts_with(MODRINTH_API_URL)
|| url.starts_with(MODRINTH_API_URL_V3))

View File

@@ -35,7 +35,6 @@ impl IOError {
}
}
// dunce canonicalize
pub fn canonicalize(
path: impl AsRef<std::path::Path>,
) -> Result<std::path::PathBuf, IOError> {
@@ -46,7 +45,6 @@ pub fn canonicalize(
})
}
// read_dir
pub async fn read_dir(
path: impl AsRef<std::path::Path>,
) -> Result<tokio::fs::ReadDir, IOError> {
@@ -59,7 +57,6 @@ pub async fn read_dir(
})
}
// create_dir
pub async fn create_dir(
path: impl AsRef<std::path::Path>,
) -> Result<(), IOError> {
@@ -72,7 +69,6 @@ pub async fn create_dir(
})
}
// create_dir_all
pub async fn create_dir_all(
path: impl AsRef<std::path::Path>,
) -> Result<(), IOError> {
@@ -85,7 +81,6 @@ pub async fn create_dir_all(
})
}
// remove_dir_all
pub async fn remove_dir_all(
path: impl AsRef<std::path::Path>,
) -> Result<(), IOError> {
@@ -98,20 +93,37 @@ pub async fn remove_dir_all(
})
}
// read_to_string
pub async fn read_to_string(
/// Reads a text file to a string, automatically detecting its encoding and
/// substituting any invalid characters with the Unicode replacement character.
///
/// This function is best suited for reading Minecraft instance files, whose
/// encoding may vary depending on the platform, launchers, client versions
/// (older Minecraft versions tended to rely on the system's default codepage
/// more on Windows platforms), and mods used, while not being highly sensitive
/// to occasional occurrences of mojibake or character replacements.
pub async fn read_any_encoding_to_string(
path: impl AsRef<std::path::Path>,
) -> Result<String, IOError> {
) -> Result<(String, &'static encoding_rs::Encoding), IOError> {
let path = path.as_ref();
tokio::fs::read_to_string(path)
.await
.map_err(|e| IOError::IOPathError {
source: e,
path: path.to_string_lossy().to_string(),
})
let file_bytes =
tokio::fs::read(path)
.await
.map_err(|e| IOError::IOPathError {
source: e,
path: path.to_string_lossy().to_string(),
})?;
let file_encoding = {
let mut encoding_detector = chardetng::EncodingDetector::new();
encoding_detector.feed(&file_bytes, true);
encoding_detector.guess(None, true)
};
let (file_string, actual_file_encoding, _) =
file_encoding.decode(&file_bytes);
Ok((file_string.to_string(), actual_file_encoding))
}
// read
pub async fn read(
path: impl AsRef<std::path::Path>,
) -> Result<Vec<u8>, IOError> {
@@ -124,7 +136,6 @@ pub async fn read(
})
}
// write
pub async fn write(
path: impl AsRef<std::path::Path>,
data: impl AsRef<[u8]>,
@@ -186,7 +197,6 @@ pub fn is_same_disk(old_dir: &Path, new_dir: &Path) -> Result<bool, IOError> {
}
}
// rename
pub async fn rename_or_move(
from: impl AsRef<std::path::Path>,
to: impl AsRef<std::path::Path>,
@@ -228,7 +238,6 @@ async fn move_recursive(from: &Path, to: &Path) -> Result<(), IOError> {
Ok(())
}
// copy
pub async fn copy(
from: impl AsRef<std::path::Path>,
to: impl AsRef<std::path::Path>,
@@ -243,7 +252,6 @@ pub async fn copy(
})
}
// remove file
pub async fn remove_file(
path: impl AsRef<std::path::Path>,
) -> Result<(), IOError> {
@@ -256,7 +264,6 @@ pub async fn remove_file(
})
}
// open file
pub async fn open_file(
path: impl AsRef<std::path::Path>,
) -> Result<tokio::fs::File, IOError> {
@@ -269,7 +276,6 @@ pub async fn open_file(
})
}
// remove dir
pub async fn remove_dir(
path: impl AsRef<std::path::Path>,
) -> Result<(), IOError> {
@@ -282,7 +288,6 @@ pub async fn remove_dir(
})
}
// metadata
pub async fn metadata(
path: impl AsRef<std::path::Path>,
) -> Result<std::fs::Metadata, IOError> {

View File

@@ -227,13 +227,11 @@ async fn get_all_jre_path() -> HashSet<PathBuf> {
paths.unwrap_or_else(|_| HashSet::new())
}
#[cfg(target_os = "windows")]
#[allow(dead_code)]
pub const JAVA_BIN: &str = "javaw.exe";
#[cfg(not(target_os = "windows"))]
#[allow(dead_code)]
pub const JAVA_BIN: &str = "java";
pub const JAVA_BIN: &str = if cfg!(target_os = "windows") {
"javaw.exe"
} else {
"java"
};
// For each example filepath in 'paths', perform check_java_at_filepath, checking each one concurrently
// and returning a JavaVersion for every valid path that points to a java bin
@@ -249,7 +247,7 @@ pub async fn check_java_at_filepaths(
.collect::<Vec<_>>()
.await;
jres.into_iter().flat_map(|x| x.ok()).flatten().collect()
jres.into_iter().filter_map(|x| x.ok()).flatten().collect()
}
// For example filepath 'path', attempt to resolve it and get a Java version at this path

View File

@@ -5,15 +5,3 @@ pub mod jre;
pub mod platform;
pub mod utils; // AstralRinth
pub mod server_ping;
/// Wrap a builder which uses a mut reference into one which outputs an owned value
macro_rules! wrap_ref_builder {
($id:ident = $init:expr => $transform:block) => {{
let mut it = $init;
{
let $id = &mut it;
$transform;
}
it
}};
}