Files
game_install_tools/src-tauri/src/gameins.rs
Chaos 345acdee91 feat(success): 添加外部链接打开功能并优化页面样式- 集成 tauri-plugin-opener 插件以支持外部链接打开
- 新增 handleExternalLink 方法处理链接点击事件
- 更新 success 页面样式,增强视觉效果
- 添加 MiSans 字体支持
- 引入最新资源列表展示功能
- 优化按钮交互效果和页面布局
2025-11-13 17:24:07 +08:00

148 lines
4.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// --- 1. 导入所需模块 ---
use thiserror::Error;
use zip::ZipArchive;
use std::fs::{self, File};
use std::io;
use std::path::PathBuf;
use serde::Serialize;
use tauri::Emitter;
// --- 2. (新增) 定义事件的有效负载 (Payload) ---
// 这个结构体将作为事件发送给 Svelte
#[derive(Clone, serde::Serialize)]
struct InstallProgress {
message: String,
percentage: f32, // 0.0 到 100.0
}
// --- 3. 错误定义 ---
#[derive(Debug, Error)]
pub enum InstallError {
#[error("IO 错误: {0}")]
Io(#[from] std::io::Error),
#[error("Zip 解压错误: {0}")]
Zip(#[from] zip::result::ZipError),
#[error("找不到 data.bin 文件: {0}")]
DataFileNotFound(String),
}
impl Serialize for InstallError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.to_string().as_ref())
}
}
#[tauri::command]
// --- 5. (修改) 添加 window 参数 ---
pub async fn install_game(window: tauri::Window, target_dir: String) -> Result<String, InstallError> {
println!("Rust 后端收到命令:目标目录 {}", target_dir);
// --- 6. 核心改动:从文件系统读取 data.bin ---
// --- 6a. (新增) 发送启动事件 ---
window.emit("install_progress", InstallProgress {
message: "安装开始...".into(),
percentage: 0.0
}).ok();
// 1. 获取 app.exe 所在的目录
let exe_path = std::env::current_exe()?;
let exe_dir = exe_path.parent()
.ok_or_else(|| InstallError::Io(io::Error::new(io::ErrorKind::NotFound, "无法获取执行文件所在目录")))?;
// 2. 构造 data.bin 的路径
let data_bin_path = exe_dir.join("data.bin");
println!("正在获取游戏资源包: {:?}", data_bin_path);
window.emit("install_progress", InstallProgress {
message: "正在获取游戏资源包".into(),
percentage: 1.0 // 1%
}).ok();
if !data_bin_path.exists() {
// 返回错误Svelte 的 catch 块会捕获它
return Err(InstallError::DataFileNotFound(
format!("未在 {:?} 找到游戏资源包,请重新下载", data_bin_path)
));
}
// 3. 从硬盘打开文件
let archive_file = File::open(&data_bin_path)?;
println!("成功打开游戏资源包");
window.emit("install_progress", InstallProgress {
message: "成功打开游戏资源包".into(),
percentage: 5.0 // 5%
}).ok();
// 4. ZipArchive 现在读取文件
let mut archive = ZipArchive::new(archive_file)?;
let total_files = archive.len() as f32;
println!("在游戏资源包中找到 {} 个文件。", total_files);
window.emit("install_progress", InstallProgress {
message: format!("包中找到 {} 个文件。", total_files),
percentage: 10.0 // 10%
}).ok();
// --- 7. 解压循环 (核心改动: 添加 emit) ---
let install_path = PathBuf::from(target_dir);
fs::create_dir_all(&install_path)?;
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let outpath = match file.enclosed_name() {
Some(path) => install_path.join(path),
None => continue,
};
// --- 7a. (核心) 计算百分比并发送事件 ---
let current_file_index = i as f32;
let percentage = 10.0 + (current_file_index / total_files) * 85.0; // (10% + 85% = 95%)
let message = format!("安装中 [{}/{}]: {}", i + 1, total_files as u32, file.name());
window.emit("install_progress", InstallProgress { message, percentage })
.ok();
// --- 2. (新增) 关键修复 ---
// 释放线程 1 毫秒,给 Svelte 留出渲染时间
// sleep(Duration::from_millis(1)).await;
if (&*file.name()).ends_with('/') {
fs::create_dir_all(&outpath)?;
} else {
if let Some(p) = outpath.parent() {
if !p.exists() {
fs::create_dir_all(p)?;
}
}
let mut outfile = File::create(&outpath)?;
io::copy(&mut file, &mut outfile)?;
}
} // --- 循环结束 ---
println!("Rust 后端:解压成功。");
window.emit("install_progress", InstallProgress {
message: "安装成功".into(),
percentage: 100.0 // 100%
}).ok();
Ok(format!("成功解压 {} 个文件到指定目录!", total_files as u32))
}