Skip to content

Commit

Permalink
feat(setting): change global launch and download options (#31)
Browse files Browse the repository at this point in the history
* feat(game_data): show saves and mods

* feat(launch): change global launch options

* feat(download): limit connection or speed
  • Loading branch information
Broken-Deer authored Aug 22, 2024
1 parent 059b4ef commit 53ee227
Show file tree
Hide file tree
Showing 33 changed files with 1,066 additions and 374 deletions.
13 changes: 10 additions & 3 deletions core/src/config/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ pub struct InstanceLaunchConfig {
pub(crate) fullscreen: Option<bool>,

/// User custom additional java virtual machine command line arguments.
pub(crate) extra_jvm_args: Option<Vec<String>>,
pub(crate) extra_jvm_args: Option<String>,

/// User custom additional minecraft command line arguments.
pub(crate) extra_mc_args: Option<Vec<String>>,
pub(crate) extra_mc_args: Option<String>,

pub(crate) is_demo: Option<bool>,
/// Game process priority, invalid on windows
Expand All @@ -77,9 +77,16 @@ pub struct InstanceLaunchConfig {
pub(crate) ignore_patch_discrepancies: Option<bool>,

/// Add extra classpath
pub(crate) extra_class_paths: Option<Vec<String>>,
pub(crate) extra_class_paths: Option<String>,

pub(crate) gc: Option<GC>,

pub(crate) launcher_name: Option<String>,
pub wrap_command: Option<String>,

pub execute_before_launch: Option<String>,

pub execute_after_launch: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
Expand Down
31 changes: 18 additions & 13 deletions core/src/config/launch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ pub struct LaunchConfig {
pub(crate) fullscreen: bool,

/// User custom additional java virtual machine command line arguments.
pub(crate) extra_jvm_args: Vec<String>,
pub(crate) extra_jvm_args: String,

/// User custom additional minecraft command line arguments.
pub(crate) extra_mc_args: Vec<String>,
pub(crate) extra_mc_args: String,

pub(crate) is_demo: bool,
/// Game process priority, invalid on windows
Expand All @@ -67,34 +67,39 @@ pub struct LaunchConfig {
pub(crate) ignore_patch_discrepancies: bool,

/// Add extra classpath
pub(crate) extra_class_paths: Vec<String>,
pub(crate) extra_class_paths: String,

pub(crate) gc: GC,

pub(crate) launcher_name: String,
pub wrap_command: String,

pub execute_before_launch: String,

pub execute_after_launch: String,
}

impl Default for LaunchConfig {
fn default() -> Self {
Self {
min_memory: 0,
max_memory: 1024,
max_memory: 2048,
server: None,
width: 854,
height: 480,
fullscreen: false,
extra_jvm_args: vec![],
extra_mc_args: vec![],
extra_jvm_args: String::new(),
extra_mc_args: String::new(),
is_demo: false,
process_priority: ProcessPriority::Normal,
ignore_invalid_minecraft_certificates: false,
ignore_patch_discrepancies: false,
extra_class_paths: vec![],
extra_class_paths: String::new(),
gc: GC::G1,
launcher_name: "Amethyst_Launcher".to_string(),
wrap_command: String::new(),
execute_after_launch: String::new(),
execute_before_launch: String::new(),
}
}
}

impl LaunchConfig {
pub fn get() -> Self {
Self::default()
}
}
47 changes: 47 additions & 0 deletions core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,52 @@
// Copyright 2022-2024 Broken-Deer and contributors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-only

use serde::{Deserialize, Serialize};

use crate::{Storage, DATA_LOCATION};

pub mod instance;
pub mod launch;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Hash)]
pub struct Config {
pub launch: launch::LaunchConfig,
pub max_connection: usize,
pub max_download_speed: usize,
}

impl Default for Config {
fn default() -> Self {
Self {
launch: launch::LaunchConfig::default(),
max_connection: 100,
max_download_speed: 0,
}
}
}

#[tauri::command]
pub fn save_config(storage: tauri::State<'_, Storage>) {
let data = toml::to_string_pretty(&storage.config.lock().unwrap().clone()).unwrap();
let path = DATA_LOCATION.get().unwrap().root.join(".aml.toml");
std::fs::write(path, data).unwrap();
}

#[tauri::command]
pub fn read_config_file() -> Config {
let path = DATA_LOCATION.get().unwrap().root.join(".aml.toml");
if !path.exists() {
let default_config = Config::default();
let data = toml::to_string_pretty(&default_config).unwrap();
std::fs::write(&path, data).unwrap();
return default_config;
}
let data = std::fs::read(path).unwrap();
toml::from_str::<Config>(String::from_utf8(data).unwrap().as_ref()).unwrap()
}

#[tauri::command]
pub fn update_config(storage: tauri::State<'_, Storage>, config: Config) {
let mut storage_config = storage.config.lock().unwrap();
*storage_config = config
}
55 changes: 51 additions & 4 deletions core/src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ fn calculate_sha1_from_read<R: Read>(source: &mut R) -> String {
hasher.digest().to_string()
}

pub async fn download_files(downloads: Vec<Download>, send_progress: bool, send_error: bool) {
pub async fn download_files(
downloads: Vec<Download>,
send_progress: bool,
send_error: bool,
max_connections: usize,
max_download_speed: usize,
) {
let main_window = MAIN_WINDOW.get().unwrap();
if send_progress {
main_window
Expand Down Expand Up @@ -107,11 +113,30 @@ pub async fn download_files(downloads: Vec<Download>, send_progress: bool, send_
let client = HTTP_CLIENT.get().unwrap();
let speed_counter: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));
let speed_counter_clone = speed_counter.clone();
let running_counter: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));
let running_counter_clone = running_counter.clone();
let (tx, rx) = mpsc::channel();
let (tx2, rx2) = mpsc::channel();
let running_counter_thread = thread::spawn(move || {
let running_counter = running_counter_clone;
loop {
let message = rx.try_recv();
if message == Ok("terminate") {
break;
}
main_window
.emit(
"running_download_task",
running_counter.load(Ordering::SeqCst),
)
.unwrap();
thread::sleep(Duration::from_millis(100))
}
});
let speed_thread = thread::spawn(move || {
let counter = speed_counter_clone;
loop {
let message = rx.try_recv();
let message = rx2.try_recv();
if message == Ok("terminate") {
break;
}
Expand All @@ -123,13 +148,26 @@ pub async fn download_files(downloads: Vec<Download>, send_progress: bool, send_
}
});
let error = Arc::new(AtomicBool::new(false));
main_window
.emit(
"install_progress",
Progress {
completed: 0,
total,
step: 3,
},
)
.unwrap();
futures::stream::iter(downloads)
.map(|task| {
let counter = counter.clone();
let speed_counter = speed_counter.clone();
let error = error.clone();
let running_counter = running_counter.clone();
async move {
let error = error;
let running_counter = running_counter;
running_counter.fetch_add(1, Ordering::SeqCst);
if error.load(Ordering::SeqCst) {
return;
}
Expand All @@ -138,7 +176,7 @@ pub async fn download_files(downloads: Vec<Download>, send_progress: bool, send_
loop {
retried += 1;
let speed_counter = speed_counter.clone();
if download_file(client, &task, &counter, &speed_counter)
if download_file(client, &task, &counter, &speed_counter, max_download_speed)
.await
.is_ok()
{
Expand All @@ -159,10 +197,11 @@ pub async fn download_files(downloads: Vec<Download>, send_progress: bool, send_
}
}
})
.buffer_unordered(100)
.buffer_unordered(max_connections)
.for_each_concurrent(None, |_| async {
let counter = counter.clone().load(Ordering::SeqCst);
// println!("Progress: {counter} / {total}");
running_counter.fetch_sub(1, Ordering::SeqCst);
if send_progress {
main_window
.emit(
Expand All @@ -178,14 +217,17 @@ pub async fn download_files(downloads: Vec<Download>, send_progress: bool, send_
})
.await;
tx.send("terminate").unwrap();
tx2.send("terminate").unwrap();
speed_thread.join().unwrap();
running_counter_thread.join().unwrap();
}

pub async fn download_file(
client: &reqwest::Client,
task: &Download,
counter: &Arc<AtomicUsize>,
speed_counter: &Arc<AtomicUsize>,
max_download_speed: usize,
) -> anyhow::Result<()> {
let file_path = task.file.clone();
tokio::fs::create_dir_all(file_path.parent().ok_or(anyhow::Error::msg(
Expand All @@ -195,6 +237,11 @@ pub async fn download_file(
let mut response = client.get(task.url.clone()).send().await?;
let mut file = tokio::fs::File::create(&file_path).await?;
while let Some(chunk) = response.chunk().await? {
if max_download_speed > 1024 {
while speed_counter.load(Ordering::SeqCst) > max_download_speed {
tokio::time::sleep(Duration::from_millis(100)).await;
}
}
file.write_all(&chunk).await?;
speed_counter.fetch_add(chunk.len(), Ordering::SeqCst);
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/folder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl MinecraftLocation {
}

pub fn get_natives_root<P: AsRef<Path>>(&self, version: P) -> PathBuf {
self.get_version_root(version).join("cvl-natives")
self.get_version_root(version).join("aml-natives")
}

pub fn get_version_root<P: AsRef<Path>>(&self, version: P) -> PathBuf {
Expand Down
46 changes: 46 additions & 0 deletions core/src/game_data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use base64::{engine::general_purpose, Engine};
use mods::ResolvedMod;
use resourcepack::Resourcepack;
use saves::level::LevelData;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -142,3 +143,48 @@ pub async fn scan_saves_folder(
Err(_) => Err(()),
}
}

#[tauri::command(async)]
pub async fn scan_resourcepack_folder(
storage: tauri::State<'_, Storage>,
) -> Result<Vec<Resourcepack>, ()> {
let instance_name = storage.current_instance.lock().unwrap().clone();
async fn scan(
instance_name: String,
storage: tauri::State<'_, Storage>,
) -> anyhow::Result<Vec<Resourcepack>> {
let data_location = DATA_LOCATION.get().unwrap();
let resourcespacks_root = data_location.get_resourcespacks_root(&instance_name);

tokio::fs::create_dir_all(&resourcespacks_root).await?;

let mut folder_entries = tokio::fs::read_dir(resourcespacks_root).await?;
let mut results = Vec::new();
while let Some(entry) = folder_entries.next_entry().await? {
let file_type = match entry.file_type().await {
Err(_) => continue,
Ok(file_type) => file_type,
};
let active_instance = storage.current_instance.lock().unwrap().clone();
if active_instance != instance_name {
return Err(anyhow::anyhow!("stopped")); // if user change the active instance, stop scanning
}
if !file_type.is_file() {
continue;
}
let path = entry.path();
if path.metadata().is_err() {
continue;
}
results.push(match resourcepack::parse_resourcepack(&path) {
Err(_) => continue,
Ok(result) => result,
});
}
Ok(results)
}
match scan(instance_name, storage).await {
Ok(x) => Ok(x),
Err(_) => Err(()),
}
}
Loading

0 comments on commit 53ee227

Please sign in to comment.