Almost finished with new launcher
@@ -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"
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.6 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 249 KiB |
@@ -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 = "";
|
||||
}
|
||||
@@ -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")]
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
"active": true,
|
||||
"targets": "dmg",
|
||||
"macOS": {
|
||||
"minimumSystemVersion": "12.7.4"
|
||||
"minimumSystemVersion": "13.7.8"
|
||||
},
|
||||
"resources": {
|
||||
"./mac-resources/*": ""
|
||||
}
|
||||
"icon": [
|
||||
"icons/icon.icns"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||