Skip to content

Commit

Permalink
core: 提高 MSRV 到 1.75.0
Browse files Browse the repository at this point in the history
core: 使用 AFIT 特性取代 async-trait 框架
core: 重新使用更小的 async-h1 请求后端并修正请求失败的问题
core: 更换 User-Agent
core: 增加离线用户 UUID 生成函数接口
scl-gui-widget: 为 DownloadModuleItem 增加可选图片图标
scl-macro: 修正文档
  • Loading branch information
Steve-xmh committed Feb 16, 2024
1 parent 1ed6e05 commit b67e308
Show file tree
Hide file tree
Showing 16 changed files with 147 additions and 56 deletions.
17 changes: 11 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,26 @@

![预览图](https://user-images.githubusercontent.com/39523898/208238006-900bd5fe-f9f7-42a9-b726-da829162fbed.png)

![MSRV 1.75.0](https://img.shields.io/badge/MSRV-1.75.0-orange)

使用 Rust 编程语言编写,内存占用相当之小,性能相当之优秀,针对二进制大小做了力所能及的压缩优化。

原生跨平台,支持 Windows,Linux,MacOS 三大主流操作系统。

- 官网:[https://steve-xmh.github.io/scl](https://steve-xmh.github.io/scl)
- 开发文档:[https://steve-xmh.github.io/scl/scl-docs](https://steve-xmh.github.io/scl/scl-docs)
- 设计图:[https://www.figma.com/file/i2Sl8uD5nKS4dIki0yK29n/Sharp-Craft-Launcher-%E8%AE%BE%E8%AE%A1%E5%9B%BE](https://www.figma.com/file/i2Sl8uD5nKS4dIki0yK29n/Sharp-Craft-Launcher-%E8%AE%BE%E8%AE%A1%E5%9B%BE)
- 介绍/发布贴:[https://www.mcbbs.net/thread-1223867-1-1.html](https://www.mcbbs.net/thread-1223867-1-1.html)
- 介绍/发布贴(MineBBS):[https://www.minebbs.com/resources/sharp-craft-launcher-_-_.7177/](https://www.minebbs.com/resources/sharp-craft-launcher-_-_.7177/)
- 介绍/发布贴(MCBBS):[https://www.mcbbs.net/thread-1223867-1-1.html](https://www.mcbbs.net/thread-1223867-1-1.html)
- 官网源代码分支:[https://github.com/Steve-xmh/scl/tree/site](https://github.com/Steve-xmh/scl/tree/site)

## 源代码架构

- `scl-core`: 启动器核心库,包含了游戏启动,游戏下载,正版登录,模组下载等游戏操作功能
- `scl-webview`: 启动器 WebView 网页浏览器库,提供了用于微软正版登录的浏览器窗口
- `scl-macro`: 启动器过程宏库,包含了部分用于代码生成的过程宏代码,目前包含图标代码生成的简易过程宏
- `scl-gui-animation`: 启动器图形页面动画函数库,包含了一些方便用来制作非线性动画的函数和工具类
- `scl-gui-widgets`: 启动器图形页面组件库,基于 [Druid](https://github.com/linebender/druid) 框架,提供了大量基于 WinUI3 设计规范制作的图形页面组件
- `scl-core`: [![](https://img.shields.io/badge/docs-passing-green)](https://steve-xmh.github.io/scl/scl-doc/scl_core/index.html) 启动器核心库,包含了游戏启动,游戏下载,正版登录,模组下载等游戏操作功能
- `scl-webview`: [![](https://img.shields.io/badge/docs-passing-green)](https://steve-xmh.github.io/scl/scl-doc/scl_webview/index.html) 启动器 WebView 网页浏览器库,提供了用于微软正版登录的浏览器窗口
- `scl-macro`: [![](https://img.shields.io/badge/docs-passing-green)](https://steve-xmh.github.io/scl/scl-doc/scl_macro/index.html) 启动器过程宏库,包含了部分用于代码生成的过程宏代码,目前包含图标代码生成的简易过程宏
- `scl-gui-animation`: [![](https://img.shields.io/badge/docs-passing-green)](https://steve-xmh.github.io/scl/scl-doc/scl_gui_animation/index.html) 启动器图形页面动画函数库,包含了一些方便用来制作非线性动画的函数和工具类
- `scl-gui-widgets`: [![](https://img.shields.io/badge/docs-passing-green)](https://steve-xmh.github.io/scl/scl-doc/scl_gui_widgets/index.html) 启动器图形页面组件库,基于 [Druid](https://github.com/linebender/druid) 框架,提供了大量基于 WinUI3 设计规范制作的图形页面组件

## 关于开源协议和代码协作协议

Expand Down
17 changes: 9 additions & 8 deletions scl-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ license = "LGPL-3.0-only"
readme = "README.md"
authors = ["Steve-xmh <[email protected]>"]
edition = "2021"
rust-version = "1.75"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "^1.0"
base64 = "^0.21"
futures = "^0.3.21"
surf = { version = "^2.3", default-features = false, features = [ "curl-client", "encoding" ] }
surf = { version = "^2.3", default-features = false, features = [ "h1-client", "encoding" ] }
image = { version = "^0.24", default-features = false, features = ["jpeg", "png", "gif", "bmp", "rgb"] }
webp = "^0.2"
nom = "^7.1"
Expand All @@ -25,23 +26,23 @@ serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0"
sha1_smol = { version = "^1.0", features = ["std"] }
shell-words = "^1.0"
smol = "^1.2"
toml = "^0.7"
smol = "^2"
toml = "^0.8"
url = "^2.2"
urlencoding = "^2.1"
uuid = { version = "1.0.0", features = ["v4"] }
concat-string = "^1.0"
md5 = "^0.7"
zip = "^0.6.2"
dirs = "^5.0"
async-trait = "^0.1"
shellwords = "1.1.0"
fs_extra = "1.3.0"
tracing = "0.1.40"
tracing = "^0.1"

[target.'cfg(target_os = "windows")'.dependencies]
winreg = "^0.50"
winreg = "^0.52"

[target.'cfg(target_os = "windows")'.dependencies.windows]
version = "0.48"
version = "0.52"
features = [
"Win32_System_Diagnostics_Debug",
"Win32_Foundation",
Expand Down
25 changes: 25 additions & 0 deletions scl-core/src/auth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,31 @@ pub mod authlib;
pub mod microsoft;
pub mod structs;

/// 根据玩家名称生成一个固定的离线 UUID
///
/// 返回值可以通过传入 `format!("{:x}", uuid)` 来转换为十六进制字符串形式
///
/// 代码参考:
/// ```rust
/// # use scl_core::auth::generate_offline_uuid;
/// # fn main() {
/// assert_eq!(format!("{:x}", generate_offline_uuid("Steve")), "5627dd98e6be3c21b8a8e92344183641");
/// assert_eq!(format!("{:x}", generate_offline_uuid("Alex")), "36532b5ec4423dbba24cc7e55d0f979a");
/// # }
/// ```
/// 生成方式参考: <https://github.com/PrismarineJS/node-minecraft-protocol/blob/21240f8ab2fd41c76f50b64e3b3a945f50b25b5e/src/datatypes/uuid.js#L14>
pub fn generate_offline_uuid(player_name: &str) -> md5::Digest {
let mut ctx = md5::Context::new();
ctx.consume("OfflinePlayer:");
ctx.consume(player_name);
let mut result = ctx.compute().0;

result[6] = (result[6] & 0x0f) | 0x30;
result[8] = (result[8] & 0x3f) | 0x80;

md5::Digest(result)
}

/// 提取一个皮肤位图的正面头部部分,用于 GUI 展示头像
///
/// 传入的皮肤大小必须是 32x64 或 64x64
Expand Down
4 changes: 0 additions & 4 deletions scl-core/src/download/authlib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! 获取 authlib-injector 第三方登录代理 jar

use async_trait::async_trait;

use super::{DownloadSource, Downloader};
use crate::prelude::*;

Expand All @@ -14,15 +12,13 @@ struct LatestData {
/// Authlib 第三方正版登录模块的下载特质
///
/// 你可以通过引入本特质和 [`crate::download::Downloader`] 来下载并安装 Authlib Injector
#[async_trait]
pub trait AuthlibDownloadExt: Sync {
/// 下载最新版本的 Authlib Injector 并存放到指定路径,如果路径的文件夹不存在则会先创建它,如果文件已存在则会被覆盖
async fn download_authlib_injector(&self, dest_path: &str) -> DynResult;
/// 安装最新版本的 Authlib Injector
async fn install_authlib_injector(&self) -> DynResult;
}

#[async_trait]
impl<R: Reporter> AuthlibDownloadExt for Downloader<R> {
async fn download_authlib_injector(&self, dest_path: &str) -> DynResult {
// https://authlib-injector.yushi.moe/
Expand Down
3 changes: 0 additions & 3 deletions scl-core/src/download/fabric.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//! Fabric 下载源数据结构
use async_trait::async_trait;
use serde::Deserialize;

use super::{DownloadSource, Downloader};
Expand Down Expand Up @@ -39,7 +38,6 @@ pub struct LoaderStruct {
/// Fabric 模组加载器的安装特质
///
/// 可以通过引入本特质和使用 [`crate::download::Downloader`] 来安装模组加载器
#[async_trait]
pub trait FabricDownloadExt: Sync {
/// 根据原版版本号获取该版本下可用的 Fabric 模组加载器
async fn get_avaliable_loaders(&self, vanilla_version: &str) -> DynResult<Vec<LoaderMetaItem>>;
Expand All @@ -57,7 +55,6 @@ pub trait FabricDownloadExt: Sync {
async fn download_fabric_post(&self, version_name: &str) -> DynResult;
}

#[async_trait]
impl<R: Reporter> FabricDownloadExt for Downloader<R> {
async fn get_avaliable_loaders(&self, vanilla_version: &str) -> DynResult<Vec<LoaderMetaItem>> {
let mut result = crate::http::retry_get(match self.source {
Expand Down
3 changes: 0 additions & 3 deletions scl-core/src/download/forge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::{
};

use anyhow::Context;
use async_trait::async_trait;
use inner_future::io::{AsyncBufReadExt, AsyncWriteExt};
use serde_json::Value;

Expand All @@ -32,7 +31,6 @@ const CLASS_PATH_SPAREATOR: &str = ":";
/// Forge 模组加载器的安装特质
///
/// 可以通过引入本特质和使用 [`crate::download::Downloader`] 来安装模组加载器
#[async_trait]
pub trait ForgeDownloadExt: Sync {
/// 根据纯净版本号获取当前可用的所有 Forge 版本
async fn get_avaliable_installers(&self, vanilla_version: &str)
Expand Down Expand Up @@ -64,7 +62,6 @@ pub trait ForgeDownloadExt: Sync {
) -> DynResult;
}

#[async_trait]
impl<R: Reporter> ForgeDownloadExt for Downloader<R> {
async fn get_avaliable_installers(
&self,
Expand Down
7 changes: 2 additions & 5 deletions scl-core/src/download/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ pub mod vanilla;
use std::{fmt::Display, path::Path, str::FromStr};

use anyhow::Context;
use async_trait::async_trait;
pub use authlib::AuthlibDownloadExt;
pub use fabric::FabricDownloadExt;
pub use forge::ForgeDownloadExt;
Expand Down Expand Up @@ -246,8 +245,7 @@ impl<R: Reporter> Default for Downloader<R> {
}

/// 一个游戏安装特质,如果你并不需要单独安装其它部件,则可以单独引入这个特质来安装游戏
#[async_trait]
pub trait GameDownload<'a>:
pub trait GameDownload:
FabricDownloadExt + ForgeDownloadExt + VanillaDownloadExt + QuiltMCDownloadExt
{
/// 根据参数安装一个游戏,允许安装模组加载器
Expand All @@ -262,8 +260,7 @@ pub trait GameDownload<'a>:
) -> DynResult;
}

#[async_trait]
impl<R: Reporter> GameDownload<'_> for Downloader<R> {
impl<R: Reporter> GameDownload for Downloader<R> {
async fn download_game(
&self,
version_name: &str,
Expand Down
3 changes: 0 additions & 3 deletions scl-core/src/download/optifine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
//!
//! 因 Optifine 并不提供一个稳定的下载方式,故此处会使用镜像源的额外 API 来获取版本下载信息

use async_trait::async_trait;
use inner_future::io::AsyncWriteExt;

use super::{structs::OptifineVersionMeta, Downloader};
Expand All @@ -18,7 +17,6 @@ const CLASS_PATH_SPAREATOR: &str = ":";
const CLASS_PATH_SPAREATOR: &str = ":";

/// 一个用于下载 Optifine 模组下载安装的扩展特质,可以使用 [`crate::download::Downloader`] 来安装
#[async_trait]
pub trait OptifineDownloadExt: Sync {
/// 根据纯净版本号获取当前可用的所有 Optifine 版本
async fn get_avaliable_installers(
Expand Down Expand Up @@ -46,7 +44,6 @@ pub trait OptifineDownloadExt: Sync {
) -> DynResult;
}

#[async_trait]
impl<R: Reporter> OptifineDownloadExt for Downloader<R> {
async fn get_avaliable_installers(
&self,
Expand Down
3 changes: 0 additions & 3 deletions scl-core/src/download/quiltmc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! QuiltMC 下载源数据结构
use anyhow::Context;
use async_trait::async_trait;
use serde::Deserialize;

use super::Downloader;
Expand Down Expand Up @@ -36,7 +35,6 @@ pub struct LoaderStruct {
/// QuiltMC 模组加载器的安装特质
///
/// 可以通过引入本特质和使用 [`crate::download::Downloader`] 来安装模组加载器
#[async_trait]
pub trait QuiltMCDownloadExt: Sync {
/// 根据原版版本号获取该版本下可用的 QuiltMC 模组加载器
async fn get_avaliable_loaders(&self, vanilla_version: &str) -> DynResult<Vec<LoaderMetaItem>>;
Expand All @@ -54,7 +52,6 @@ pub trait QuiltMCDownloadExt: Sync {
async fn download_quiltmc_post(&self, version_name: &str) -> DynResult;
}

#[async_trait]
impl<R: Reporter> QuiltMCDownloadExt for Downloader<R> {
async fn get_avaliable_loaders(&self, vanilla_version: &str) -> DynResult<Vec<LoaderMetaItem>> {
let mut result = crate::http::retry_get(format!(
Expand Down
3 changes: 0 additions & 3 deletions scl-core/src/download/vanilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use std::{borrow::Cow, collections::HashMap, path::Path};

use anyhow::Context;
use async_trait::async_trait;
use inner_future::{fs::create_dir_all, io::AsyncWriteExt};
use tracing::*;

Expand All @@ -19,7 +18,6 @@ use crate::{
};

/// 一个用于下载安装原版的扩展特质,可以使用 [`crate::download::Downloader`] 来安装
#[async_trait]
pub trait VanillaDownloadExt: Sync {
/// 获取现在所有可下载版本
async fn get_avaliable_vanilla_versions(&self) -> DynResult<VersionManifest>;
Expand Down Expand Up @@ -66,7 +64,6 @@ pub trait VanillaDownloadExt: Sync {
async fn install_vanilla(&self, version_name: &str, version_info: &VersionInfo) -> DynResult;
}

#[async_trait]
impl<R: Reporter> VanillaDownloadExt for Downloader<R> {
async fn get_avaliable_vanilla_versions(&self) -> DynResult<VersionManifest> {
let res = crate::http::retry_get_json(match self.source {
Expand Down
7 changes: 5 additions & 2 deletions scl-core/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,16 @@ fn logger(
}

static GLOBAL_CLIENT: Lazy<Arc<Client>> = Lazy::new(|| {
let scl_version = std::option_env!("SCL_VERSION_TYPE").unwrap_or("0.0.0");
let client = Config::new()
.add_header(
"User-Agent",
"github.com/Steve-xmh/SharpCraftLauncher ([email protected])",
format!("SharpCraftLauncher/{scl_version} (github.com/Steve-xmh/SharpCraftLauncher) ([email protected])"),
)
.unwrap()
.set_timeout(Some(Duration::from_secs(30)));
.set_timeout(Some(Duration::from_secs(30)))
.set_http_keep_alive(false) // async-h1 似乎不兼容使用 Keep Alive,会导致解析响应出错
.set_max_connections_per_host(1024);
let client = if let Ok(mut proxy) = std::env::var("HTTP_PROXY") {
let proxy = if proxy.ends_with('/') {
proxy
Expand Down
1 change: 1 addition & 0 deletions scl-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
*/

#![forbid(missing_docs)]
#![allow(async_fn_in_trait)]

pub mod auth;
pub mod client;
Expand Down
1 change: 0 additions & 1 deletion scl-core/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ pub(crate) use smol as inner_future;
pub(crate) type DynResult<T = ()> = anyhow::Result<T>;
pub(crate) use serde::*;

pub use crate::download::GameDownload;
pub(crate) use crate::progress::*;
Loading

0 comments on commit b67e308

Please sign in to comment.