Unlucky Launcher v0.0.1-alpha
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s

Rust 原生单文件 Minecraft 启动器:CLI 完整可用(install/launch/accounts/java/diagnose/agent),
MCP server 接入外部 Agent 工具,GUI 开发中。
This commit is contained in:
AskaEth committed 2026-10-31 21:54:10 +08:00
commit bc41dfcf7d
517 files changed
+92844

No files matched your search

+124
View File
@@ -0,0 +1,124 @@
//! `core::game` 的错误类型。
//!
//! 采用手写 `Display`/`Error` 而不用 `thiserror`:core 的依赖面越窄越好(D3 模块纪律),
//! 且这里的变体数量固定、不需要派生宏的收益。
use std::fmt;
use std::path::PathBuf;
/// `core::game` 的失败集合。
#[derive(Debug)]
pub enum GameError {
/// JSON 解析/序列化失败(版本清单、版本 JSON、profiles)。
Json {
/// 出错的文档种类,用于给用户看上下文(如 `version_manifest_v2`)。
context: String,
/// 底层 serde_json 错误。
source: serde_json::Error,
},
/// 清单或版本 JSON 缺少必需的 `id`。
MissingVersionId,
/// `inheritsFrom` 指向的父版本在本仓库中不存在。
MissingParent {
/// 缺失的父版本 id。
parent: String,
/// 发起继承的子版本 id。
required_by: String,
},
/// `inheritsFrom` 成环。
CircularInheritance {
/// 从根到环的 id 链(首尾为同一个 id)。
chain: Vec<String>,
},
/// Maven 坐标(`group:artifact:version[:classifier][@ext]`)不合法。
InvalidCoordinate {
/// 原始字符串。
raw: String,
/// 不合法的原因。
reason: &'static str,
},
/// 资源对象哈希不合法(长度不足以做两级分片)。
InvalidAssetHash {
/// 原始哈希。
hash: String,
},
/// 文件系统错误。
Io {
/// 出错的路径。
path: PathBuf,
/// 底层 IO 错误。
source: std::io::Error,
},
/// 已有草稿持有写权,同一仓库同时只允许一个写会话。
DraftBusy,
/// 实例隔离档位是 `custom`,但没有可用的自定义目录(不猜默认值)。
CustomIsolationWithoutDir {
/// 实例 id(可能为空:调用方没给实例上下文)。
instance: String,
},
}
impl fmt::Display for GameError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Json { context, source } => write!(f, "解析 {context} 失败: {source}"),
Self::MissingVersionId => write!(f, "版本 JSON 缺少 id"),
Self::MissingParent {
parent,
required_by,
} => write!(
f,
"版本 {required_by} 继承的父版本 {parent} 不存在(缺失前置版本)"
),
Self::CircularInheritance { chain } => {
write!(f, "版本继承成环: {}", chain.join(" -> "))
}
Self::InvalidCoordinate { raw, reason } => {
write!(f, "Maven 坐标不合法({reason}): {raw}")
}
Self::InvalidAssetHash { hash } => {
write!(f, "资源哈希不合法(短于两个字符): {hash}")
}
Self::Io { path, source } => write!(f, "IO 失败 {}: {source}", path.display()),
Self::DraftBusy => write!(f, "已有草稿持有写权(单写者约束)"),
Self::CustomIsolationWithoutDir { instance } => {
if instance.is_empty() {
write!(f, "隔离档位为 custom,但没有指定自定义运行目录")
} else {
write!(
f,
"实例 {instance} 的隔离档位为 custom,但没有指定自定义运行目录"
)
}
}
}
}
}
impl std::error::Error for GameError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Json { source, .. } => Some(source),
Self::Io { source, .. } => Some(source),
_ => None,
}
}
}
impl GameError {
/// 包装 serde_json 错误并带上文档上下文。
pub fn json(context: impl Into<String>, source: serde_json::Error) -> Self {
Self::Json {
context: context.into(),
source,
}
}
/// 包装 IO 错误并带上路径。
pub fn io(path: impl Into<PathBuf>, source: std::io::Error) -> Self {
Self::Io {
path: path.into(),
source,
}
}
}