use std::{
cmp::Ordering,
fmt::{Display, Formatter},
str::FromStr,
};
use nom::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
pub enum MinecraftVersion {
Release(u32, u32, u32),
Snapshot(u32, u32, char),
Custom(String),
}
impl Default for MinecraftVersion {
fn default() -> Self {
Self::Custom("".into())
}
}
impl FromStr for MinecraftVersion {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
parse_version(s).map(|a| a.1).or(Err(()))
}
}
impl Display for MinecraftVersion {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
MinecraftVersion::Release(a, b, c) => {
if c == &0 {
write!(f, "{a}.{b}")
} else {
write!(f, "{a}.{b}.{c}")
}
}
MinecraftVersion::Snapshot(a, b, c) => write!(f, "{a:02}w{b:02}{c}"),
Self::Custom(c) => write!(f, "{c}"),
}
}
}
impl MinecraftVersion {
pub fn required_java_version(&self) -> u8 {
if let Self::Release(mayor, minor, _) = *self {
if mayor >= 1 && minor >= 17 {
16
} else {
8
}
} else {
8
}
}
pub fn should_forge_use_override_installiation(&self) -> bool {
if let Self::Release(a, b, c) = self {
match a.cmp(&1) {
Ordering::Greater => false,
Ordering::Equal => match b.cmp(&1) {
Ordering::Greater => false,
Ordering::Equal => *c < 2,
Ordering::Less => true,
},
Ordering::Less => true,
}
} else {
true
}
}
pub fn should_forge_use_client_or_universal(&self) -> bool {
if let Self::Release(a, b, c) = self {
match a.cmp(&1) {
Ordering::Greater => false,
Ordering::Equal => match b.cmp(&2) {
Ordering::Greater => false,
Ordering::Equal => *c <= 5,
Ordering::Less => true,
},
Ordering::Less => true,
}
} else {
true
}
}
}
pub fn parse_version(input: &str) -> IResult<&str, MinecraftVersion> {
let (input, first_number) = character::complete::digit1(input)?;
let first_number = first_number.parse::<u32>().unwrap();
let (input, s) = character::complete::one_of(".w")(input)?;
match s {
'.' => {
let (input, second_number) = character::complete::digit1(input)?;
let second_number = second_number.parse::<u32>().unwrap();
if input.is_empty() {
return Ok((
input,
MinecraftVersion::Release(first_number, second_number, 0),
));
}
let (input, _) = character::complete::char('.')(input)?;
let (input, third_number) = character::complete::digit1(input)?;
let third_number = third_number.parse::<u32>().unwrap();
Ok((
input,
MinecraftVersion::Release(first_number, second_number, third_number),
))
}
'w' => {
let (input, second_number) = character::complete::digit1(input)?;
let second_number = second_number.parse::<u32>().unwrap();
let (input, tag_alpha) = character::complete::anychar(input)?;
Ok((
input,
MinecraftVersion::Snapshot(first_number, second_number, tag_alpha),
))
}
_ => {
panic!("Version dot is not correct!")
}
}
}
#[test]
fn parse_version_test() {
assert_eq!(
parse_version("1.16.5").unwrap().1,
MinecraftVersion::Release(1, 16, 5)
);
assert_eq!(
parse_version("1.8").unwrap().1,
MinecraftVersion::Release(1, 8, 0)
);
assert_eq!(
parse_version("21w08b").unwrap().1,
MinecraftVersion::Snapshot(21, 8, 'b')
);
assert_eq!(
"1.16.5".parse::<MinecraftVersion>().unwrap(),
MinecraftVersion::Release(1, 16, 5)
);
assert_eq!(
"1.8".parse::<MinecraftVersion>().unwrap(),
MinecraftVersion::Release(1, 8, 0)
);
assert_eq!(
"21w08b".parse::<MinecraftVersion>().unwrap(),
MinecraftVersion::Snapshot(21, 8, 'b')
);
assert_eq!(&MinecraftVersion::Release(1, 16, 5).to_string(), "1.16.5");
assert_eq!(&MinecraftVersion::Release(1, 8, 0).to_string(), "1.8");
assert_eq!(
&MinecraftVersion::Snapshot(21, 8, 'b').to_string(),
"21w08b"
);
assert!(MinecraftVersion::Release(1, 16, 5).required_java_version() >= 8);
assert!(MinecraftVersion::Release(1, 17, 1).required_java_version() >= 16);
assert!(MinecraftVersion::Release(1, 17, 0).required_java_version() >= 16);
}