Almost finished with new launcher

This commit is contained in:
2025-10-31 09:33:41 -07:00
parent 3b5bd13b1c
commit df951d90c6
64 changed files with 994 additions and 1424 deletions

View File

@@ -9,29 +9,29 @@ name = "lncvrt_games_launcher_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2.4.1", features = [] }
tauri-build = { version = "2.5.1", features = [] }
[dependencies]
tauri = { version = "2.8.5", features = ["macos-private-api"] }
tauri-plugin-opener = "2.5.0"
tauri = { version = "2.9.2", features = [] }
tauri-plugin-opener = "2.5.2"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.145"
tauri-plugin-os = "2.3.1"
tauri-plugin-os = "2.3.2"
reqwest = { version = "0.12.24", default-features = false, features = ["stream", "rustls-tls"] }
tokio = "1.48.0"
futures-util = { version = "0.3.31", features = ["io"] }
tauri-plugin-decorum = "1.1.1"
tauri-plugin-fs = "2.4.2"
tauri-plugin-fs = "2.4.4"
zip = "6.0.0"
libc = "0.2.177"
tauri-plugin-dialog = "2.4.0"
tauri-plugin-notification = "2.3.1"
tauri-plugin-dialog = "2.4.2"
tauri-plugin-notification = "2.3.3"
sysinfo = "0.37.2"
[target.'cfg(target_os = "linux")'.dependencies]
shlex = "1.3.0"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-single-instance = "2.3.4"
tauri-plugin-single-instance = "2.3.6"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
src-tauri/icons/icon.icns Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

View File

@@ -1,8 +0,0 @@
pub struct Keys;
impl Keys {
pub const SERVER_RECEIVE_TRANSFER_KEY: &str = "";
pub const SERVER_SEND_TRANSFER_KEY: &str = "";
pub const CONFIG_ENCRYPTION_KEY: &str = "";
pub const VERSIONS_ENCRYPTION_KEY: &str = "";
}

View File

@@ -1,10 +1,7 @@
mod keys;
use futures_util::stream::StreamExt;
use keys::Keys;
use std::{
fs::{File, create_dir_all},
io::{BufReader, Write, copy},
io::{BufReader, copy},
path::PathBuf,
process::Command,
time::Duration,
@@ -14,7 +11,7 @@ use tauri::{AppHandle, Emitter, Manager};
use tauri_plugin_dialog::{DialogExt, MessageDialogKind};
use tauri_plugin_opener::OpenerExt;
use tauri_plugin_os::platform;
use tokio::{io::AsyncWriteExt, task::spawn_blocking, time::timeout};
use tokio::{io::AsyncWriteExt, time::timeout};
use zip::ZipArchive;
#[cfg(target_os = "linux")]
@@ -22,8 +19,19 @@ use std::{fs, os::unix::fs::PermissionsExt};
#[cfg(target_os = "windows")]
use tauri_plugin_decorum::WebviewWindowExt;
pub async fn unzip_to_dir(zip_path: PathBuf, out_dir: PathBuf) -> zip::result::ZipResult<()> {
spawn_blocking(move || {
fn is_running_by_path(path: &PathBuf) -> bool {
let sys = System::new_all();
sys.processes().values().any(|proc| {
if let Some(exe) = proc.exe() {
exe == path
} else {
false
}
})
}
async fn unzip_to_dir(zip_path: PathBuf, out_dir: PathBuf) -> String {
let res = tauri::async_runtime::spawn_blocking(move || {
let file = File::open(zip_path)?;
let mut archive = ZipArchive::new(BufReader::new(file))?;
@@ -42,39 +50,23 @@ pub async fn unzip_to_dir(zip_path: PathBuf, out_dir: PathBuf) -> zip::result::Z
}
}
Ok(())
Ok::<(), zip::result::ZipError>(())
})
.await
.map_err(|e| zip::result::ZipError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?
.await;
match res {
Ok(Ok(())) => "1".into(),
_ => "-1".into(),
}
}
fn is_running_by_path(path: &PathBuf) -> bool {
let sys = System::new_all();
sys.processes().values().any(|proc| {
if let Some(exe) = proc.exe() {
exe == path
} else {
false
}
})
}
#[allow(unused_variables)]
#[tauri::command]
async fn download(
app: AppHandle,
url: String,
name: String,
executable: String,
) -> Result<(), String> {
app.emit("download-started", &name).unwrap();
async fn download(app: AppHandle, url: String, name: String, executable: String) -> String {
let client = reqwest::Client::new();
let resp = match client.get(&url).send().await {
Ok(r) => r,
Err(e) => {
app.emit("download-failed", &name).unwrap();
return Err(e.to_string());
Err(_) => {
return "-1".to_string();
}
};
let total_size = resp.content_length().unwrap_or(0);
@@ -102,15 +94,13 @@ async fn download(
while let Ok(Some(chunk_result)) = timeout(Duration::from_secs(5), stream.next()).await {
let chunk = match chunk_result {
Ok(c) => c,
Err(e) => {
app.emit("download-failed", &name).unwrap();
return Err(e.to_string());
Err(_) => {
return "-1".to_string();
}
};
if let Err(e) = file.write_all(&chunk).await {
app.emit("download-failed", &name).unwrap();
return Err(e.to_string());
if let Err(_) = file.write_all(&chunk).await {
return "-1".to_string();
}
downloaded += chunk.len() as u64;
@@ -126,8 +116,7 @@ async fn download(
}
if total_size > 0 && downloaded < total_size {
app.emit("download-failed", &name).unwrap();
return Err("Download incomplete".into());
return "-1".to_string();
}
tokio::fs::rename(
@@ -136,12 +125,13 @@ async fn download(
)
.await
.unwrap();
unzip_to_dir(download_zip_path.clone(), game_path.join(&name))
.await
.map_err(|e| e.to_string())?;
let unzip_res = unzip_to_dir(download_zip_path.clone(), game_path.join(&name)).await;
tokio::fs::remove_file(download_zip_path.clone())
.await
.unwrap();
if unzip_res == "-1" {
return "-1".to_string();
}
#[cfg(target_os = "linux")]
{
@@ -152,7 +142,10 @@ async fn download(
}
#[cfg(target_os = "macos")]
{
let macos_app_path = &game_path
use std::fs;
use std::os::unix::fs::PermissionsExt;
let macos_app_path = game_path
.join(&name)
.join(&executable)
.join("Contents")
@@ -160,21 +153,15 @@ async fn download(
.join(
&executable
.chars()
.take(&executable.chars().count() - 4)
.take(executable.chars().count() - 4)
.collect::<String>(),
);
let _ = Command::new("osascript")
.arg("-e")
.arg(format!(
"do shell script \"chmod 755 \\\"{}\\\"\" with prompt \"Administrator is required to make Berry Dash v{} executable\" with administrator privileges",
macos_app_path.to_string_lossy(),
name
))
.spawn();
}
app.emit("download-done", &name).unwrap();
Ok(())
let mut perms = fs::metadata(&macos_app_path).unwrap().permissions();
perms.set_mode(0o755);
fs::set_permissions(&macos_app_path, perms).unwrap();
}
return "1".to_string();
}
#[allow(unused_variables)]
@@ -246,58 +233,6 @@ fn launch_game(app: AppHandle, name: String, executable: String, wine: bool, win
}
}
#[tauri::command]
fn download_leaderboard(app: AppHandle, content: String) {
app.dialog().file().save_file(move |file_path| {
if let Some(path) = file_path {
let mut path_buf = PathBuf::from(path.to_string());
if path_buf.extension().map(|ext| ext != "csv").unwrap_or(true) {
path_buf.set_extension("csv");
}
let path_str = path_buf.to_string_lossy().to_string();
if path_str.is_empty() {
app.dialog()
.message("No file selected.")
.kind(MessageDialogKind::Error)
.title("Error")
.show(|_| {});
return;
}
let mut file = match File::create(&path_buf) {
Ok(f) => f,
Err(e) => {
app.dialog()
.message(format!("Failed to create file: {}", e))
.kind(MessageDialogKind::Error)
.title("Error")
.show(|_| {});
return;
}
};
if let Err(e) = file.write_all(content.as_bytes()) {
app.dialog()
.message(format!("Failed to write to file: {}", e))
.kind(MessageDialogKind::Error)
.title("Error")
.show(|_| {});
} else {
let _ = app.opener().open_path(path.to_string(), None::<&str>);
}
}
})
}
#[tauri::command]
fn get_keys_config(key: i8) -> String {
match key {
0 => Keys::SERVER_RECEIVE_TRANSFER_KEY.to_string(),
1 => Keys::SERVER_SEND_TRANSFER_KEY.to_string(),
2 => Keys::CONFIG_ENCRYPTION_KEY.to_string(),
3 => Keys::VERSIONS_ENCRYPTION_KEY.to_string(),
_ => "".to_string(),
}
}
#[tauri::command]
async fn uninstall_version(app: AppHandle, name: String) {
let game_path = app
@@ -341,37 +276,6 @@ async fn open_folder(app: AppHandle, name: String) {
}
}
#[allow(unused_variables)]
#[tauri::command]
fn fix_mac_permissions(app: AppHandle, name: String, executable: String) {
#[cfg(target_os = "macos")]
{
let macos_app_path = app
.path()
.app_local_data_dir()
.unwrap()
.join("game")
.join(&name)
.join(&executable)
.join("Contents")
.join("MacOS")
.join(
&executable
.chars()
.take(&executable.chars().count() - 4)
.collect::<String>(),
);
let _ = Command::new("osascript")
.arg("-e")
.arg(format!(
"do shell script \"chmod 755 \\\"{}\\\"\" with prompt \"Administrator is required to make Berry Dash v{} executable\" with administrator privileges",
macos_app_path.to_string_lossy(),
name
))
.spawn();
}
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
#[allow(unused_variables)]
@@ -391,11 +295,8 @@ pub fn run() {
.invoke_handler(tauri::generate_handler![
download,
launch_game,
download_leaderboard,
get_keys_config,
uninstall_version,
open_folder,
fix_mac_permissions,
open_folder
])
.setup(|app| {
#[cfg(target_os = "windows")]

View File

@@ -33,9 +33,7 @@
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
"icons/128x128@2x.png"
]
}
}

View File

@@ -30,10 +30,10 @@
"active": true,
"targets": "dmg",
"macOS": {
"minimumSystemVersion": "12.7.4"
"minimumSystemVersion": "13.7.8"
},
"resources": {
"./mac-resources/*": ""
}
"icon": [
"icons/icon.icns"
]
}
}

View File

@@ -32,10 +32,6 @@
"active": true,
"targets": "msi",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}