323 lines
8.8 KiB
Rust
323 lines
8.8 KiB
Rust
use std::fmt::Display;
|
|
use std::str::FromStr;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
use strum::{Display as StrumDisplay, EnumIter, FromRepr};
|
|
|
|
#[derive(
|
|
Debug,
|
|
Clone,
|
|
Copy,
|
|
PartialEq,
|
|
Eq,
|
|
Hash,
|
|
Serialize,
|
|
Deserialize,
|
|
EnumIter,
|
|
FromRepr,
|
|
StrumDisplay,
|
|
)]
|
|
#[repr(u8)]
|
|
pub enum ContentType {
|
|
#[serde(rename = "mod")]
|
|
Mod = 0,
|
|
#[serde(rename = "resourcepack")]
|
|
ResourcePack = 1,
|
|
#[serde(rename = "shader")]
|
|
Shader = 2,
|
|
#[serde(rename = "datapack")]
|
|
DataPack = 3,
|
|
#[serde(rename = "world")]
|
|
World = 4,
|
|
#[serde(rename = "modpack")]
|
|
Modpack = 5,
|
|
}
|
|
|
|
impl ContentType {
|
|
pub fn modrinth_type(self) -> &'static str {
|
|
match self {
|
|
Self::Mod => "mod",
|
|
Self::ResourcePack => "resourcepack",
|
|
Self::Shader => "shader",
|
|
Self::DataPack => "datapack",
|
|
Self::World => "world",
|
|
Self::Modpack => "modpack",
|
|
}
|
|
}
|
|
|
|
pub fn folder_name(self) -> &'static str {
|
|
match self {
|
|
Self::Mod => "mods",
|
|
Self::ResourcePack => "resourcepacks",
|
|
Self::Shader => "shaderpacks",
|
|
Self::DataPack => "datapacks",
|
|
Self::World => "worlds",
|
|
Self::Modpack => "modpacks",
|
|
}
|
|
}
|
|
|
|
// installed once for the whole launcher rather than per cluster
|
|
#[must_use]
|
|
pub const fn is_global(self) -> bool {
|
|
matches!(self, Self::ResourcePack | Self::Shader)
|
|
}
|
|
|
|
#[must_use]
|
|
pub const fn reloads_in_game(self) -> bool {
|
|
matches!(self, Self::ResourcePack | Self::Shader)
|
|
}
|
|
|
|
pub fn from_folder_name(name: &str) -> Option<Self> {
|
|
match name.to_lowercase().as_str() {
|
|
"mods" | "mod" => Some(Self::Mod),
|
|
"resourcepacks" | "resourcepack" => Some(Self::ResourcePack),
|
|
"shaderpacks" | "shaders" | "shader" => Some(Self::Shader),
|
|
"datapacks" | "datapack" => Some(Self::DataPack),
|
|
"worlds" | "world" | "saves" => Some(Self::World),
|
|
"modpacks" | "modpack" => Some(Self::Modpack),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&str> for ContentType {
|
|
fn from(value: &str) -> Self {
|
|
Self::from_folder_name(value).unwrap_or(Self::Mod)
|
|
}
|
|
}
|
|
|
|
#[derive(
|
|
Debug,
|
|
Clone,
|
|
Copy,
|
|
PartialEq,
|
|
Eq,
|
|
Hash,
|
|
Serialize,
|
|
Deserialize,
|
|
EnumIter,
|
|
FromRepr,
|
|
StrumDisplay,
|
|
)]
|
|
#[repr(u8)]
|
|
pub enum ProviderId {
|
|
Modrinth = 0,
|
|
CurseForge = 1,
|
|
Local = 2,
|
|
}
|
|
|
|
impl ProviderId {
|
|
pub const REMOTE_PROVIDERS: &[Self] = &[Self::Modrinth, Self::CurseForge];
|
|
pub const REMOTE_PROVIDERS_STR: &[&str] = &["Modrinth", "CurseForge"];
|
|
|
|
pub fn dir_name(self) -> &'static str {
|
|
match self {
|
|
Self::Modrinth => "modrinth",
|
|
Self::CurseForge => "curseforge",
|
|
Self::Local => "local",
|
|
}
|
|
}
|
|
|
|
pub fn website(self) -> &'static str {
|
|
match self {
|
|
Self::Modrinth => "https://modrinth.com/",
|
|
Self::CurseForge => "https://www.curseforge.com/",
|
|
Self::Local => "",
|
|
}
|
|
}
|
|
|
|
pub const fn remote_providers() -> &'static [Self] {
|
|
&[Self::Modrinth, Self::CurseForge]
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum HashAlgorithm {
|
|
Sha1,
|
|
}
|
|
|
|
/// Applies only to browser-installed packages bundles have their own update flow
|
|
/// The check always runs regardless of variant so "out of date" markers stay populated
|
|
#[derive(
|
|
Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, EnumIter, StrumDisplay,
|
|
)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum PackageUpdateMode {
|
|
Automatic,
|
|
Skip,
|
|
#[default]
|
|
Prompt,
|
|
}
|
|
|
|
impl PackageUpdateMode {
|
|
/// Display order defaulting variant first
|
|
pub const ALL: &[Self] = &[Self::Prompt, Self::Automatic, Self::Skip];
|
|
|
|
#[must_use]
|
|
pub const fn label(self) -> &'static str {
|
|
match self {
|
|
Self::Automatic => "Automatically update",
|
|
Self::Skip => "Always skip auto updates",
|
|
Self::Prompt => "Show the modal",
|
|
}
|
|
}
|
|
|
|
/// The value stored in the `setting_profiles.browser_update_mode` column
|
|
#[must_use]
|
|
pub const fn as_str(self) -> &'static str {
|
|
match self {
|
|
Self::Automatic => "automatic",
|
|
Self::Skip => "skip",
|
|
Self::Prompt => "prompt",
|
|
}
|
|
}
|
|
|
|
#[must_use]
|
|
pub fn parse(value: &str) -> Option<Self> {
|
|
match value {
|
|
"automatic" => Some(Self::Automatic),
|
|
"skip" => Some(Self::Skip),
|
|
"prompt" => Some(Self::Prompt),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, FromRepr)]
|
|
#[repr(u8)]
|
|
pub enum GameLoader {
|
|
#[default]
|
|
#[serde(rename = "minecraft")]
|
|
Vanilla = 0,
|
|
Forge = 1,
|
|
NeoForge = 2,
|
|
Quilt = 3,
|
|
Fabric = 4,
|
|
Ornithe = 5,
|
|
}
|
|
|
|
impl GameLoader {
|
|
pub const fn is_modded(self) -> bool {
|
|
!matches!(self, Self::Vanilla)
|
|
}
|
|
|
|
pub const fn get_format_version(self) -> usize {
|
|
match self {
|
|
Self::Vanilla => interfrost::api::minecraft::CURRENT_FORMAT_VERSION,
|
|
Self::Forge => interfrost::api::modded::CURRENT_FORGE_FORMAT_VERSION,
|
|
Self::NeoForge => interfrost::api::modded::CURRENT_NEOFORGE_FORMAT_VERSION,
|
|
Self::Quilt => interfrost::api::modded::CURRENT_QUILT_FORMAT_VERSION,
|
|
Self::Fabric => interfrost::api::modded::CURRENT_FABRIC_FORMAT_VERSION,
|
|
Self::Ornithe => interfrost::api::modded::CURRENT_ORNITHE_FORMAT_VERSION,
|
|
}
|
|
}
|
|
|
|
pub fn get_format_name(self) -> String {
|
|
match self {
|
|
Self::Vanilla => String::from("minecraft"),
|
|
Self::NeoForge => String::from("neo"),
|
|
Self::Ornithe => String::from("ornithe"),
|
|
_ => self.to_string().to_lowercase().replace(['_', '.', ' '], ""),
|
|
}
|
|
}
|
|
|
|
pub const fn modded_loaders() -> &'static [Self] {
|
|
&[
|
|
Self::Forge,
|
|
Self::NeoForge,
|
|
Self::Quilt,
|
|
Self::Fabric,
|
|
Self::Ornithe,
|
|
]
|
|
}
|
|
|
|
pub fn compatible_with(self, other: Self) -> bool {
|
|
match self {
|
|
Self::Vanilla => other == Self::Vanilla,
|
|
Self::Forge => other == Self::Forge,
|
|
Self::NeoForge => other == Self::NeoForge,
|
|
Self::Quilt => matches!(other, Self::Quilt | Self::Fabric),
|
|
Self::Fabric => other == Self::Fabric,
|
|
Self::Ornithe => other == Self::Ornithe,
|
|
}
|
|
}
|
|
|
|
pub fn modrinth_name(self) -> &'static str {
|
|
match self {
|
|
Self::Vanilla => "minecraft",
|
|
Self::Forge => "forge",
|
|
Self::NeoForge => "neoforge",
|
|
Self::Quilt => "quilt",
|
|
Self::Fabric => "fabric",
|
|
Self::Ornithe => "ornithe",
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FromStr for GameLoader {
|
|
type Err = String;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
Ok(
|
|
match s.to_lowercase().replace(['_', '.', ' '], "").as_str() {
|
|
"vanilla" | "minecraft" => Self::Vanilla,
|
|
"forge" => Self::Forge,
|
|
"neoforge" | "neo" => Self::NeoForge,
|
|
"quilt" | "quiltloader" => Self::Quilt,
|
|
"fabric" | "fabricloader" => Self::Fabric,
|
|
"ornithe" => Self::Ornithe,
|
|
_ => return Err(format!("'{s}' is not a valid game loader")),
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Display for GameLoader {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str(match self {
|
|
Self::Vanilla => "Vanilla",
|
|
Self::Forge => "Forge",
|
|
Self::NeoForge => "NeoForge",
|
|
Self::Quilt => "Quilt",
|
|
Self::Fabric => "Fabric",
|
|
Self::Ornithe => "Fabric",
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Shared by the settings profile (which stores it) and the launch-argument
|
|
/// builder (which turns it into `--width`/`--height`)
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct Resolution {
|
|
pub width: u32,
|
|
pub height: u32,
|
|
}
|
|
|
|
impl Default for Resolution {
|
|
fn default() -> Self {
|
|
Self::new(854, 480)
|
|
}
|
|
}
|
|
|
|
impl Resolution {
|
|
#[must_use]
|
|
pub const fn new(width: u32, height: u32) -> Self {
|
|
Self { width, height }
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn a_display_name_is_not_a_metadata_path() {
|
|
assert_eq!(GameLoader::Ornithe.to_string(), "Fabric");
|
|
assert_eq!(GameLoader::Ornithe.get_format_name(), "ornithe");
|
|
assert_eq!(GameLoader::Vanilla.get_format_name(), "minecraft");
|
|
assert_eq!(GameLoader::NeoForge.get_format_name(), "neo");
|
|
assert_eq!(GameLoader::Fabric.get_format_name(), "fabric");
|
|
assert_eq!(GameLoader::Quilt.get_format_name(), "quilt");
|
|
assert_eq!(GameLoader::Forge.get_format_name(), "forge");
|
|
}
|
|
}
|