1use std::{
3 cmp::Ordering,
4 fmt::{Display, Formatter},
5 str::FromStr,
6};
7
8use nom::*;
9
10#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
14pub enum MinecraftVersion {
15 Release(u32, u32, u32),
17 Snapshot(u32, u32, char),
19 Custom(String),
21}
22
23impl Default for MinecraftVersion {
24 fn default() -> Self {
25 Self::Custom("".into())
26 }
27}
28
29impl FromStr for MinecraftVersion {
30 type Err = ();
31 fn from_str(s: &str) -> Result<Self, Self::Err> {
32 parse_version(s).map(|a| a.1).or(Err(()))
33 }
34}
35
36impl Display for MinecraftVersion {
37 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
38 match self {
39 MinecraftVersion::Release(a, b, c) => {
40 if c == &0 {
41 write!(f, "{a}.{b}")
42 } else {
43 write!(f, "{a}.{b}.{c}")
44 }
45 }
46 MinecraftVersion::Snapshot(a, b, c) => write!(f, "{a:02}w{b:02}{c}"),
47 Self::Custom(c) => write!(f, "{c}"),
48 }
49 }
50}
51
52impl MinecraftVersion {
53 pub fn required_java_version(&self) -> u8 {
56 if let Self::Release(mayor, minor, _) = *self {
57 if mayor >= 1 && minor >= 17 {
58 16
59 } else {
60 8
61 }
62 } else {
63 8
64 }
65 }
66
67 pub fn should_forge_use_override_installiation(&self) -> bool {
73 if let Self::Release(a, b, c) = self {
74 match a.cmp(&1) {
75 Ordering::Greater => false,
76 Ordering::Equal => match b.cmp(&1) {
77 Ordering::Greater => false,
78 Ordering::Equal => *c < 2,
79 Ordering::Less => true,
80 },
81 Ordering::Less => true,
82 }
83 } else {
84 true
85 }
86 }
87
88 pub fn should_forge_use_client_or_universal(&self) -> bool {
94 if let Self::Release(a, b, c) = self {
95 match a.cmp(&1) {
96 Ordering::Greater => false,
97 Ordering::Equal => match b.cmp(&2) {
98 Ordering::Greater => false,
99 Ordering::Equal => *c <= 5,
100 Ordering::Less => true,
101 },
102 Ordering::Less => true,
103 }
104 } else {
105 true
106 }
107 }
108}
109
110pub fn parse_version(input: &str) -> IResult<&str, MinecraftVersion> {
112 let (input, first_number) = character::complete::digit1(input)?;
113 let first_number = first_number.parse::<u32>().unwrap();
114 let (input, s) = character::complete::one_of(".w")(input)?;
115 match s {
116 '.' => {
117 let (input, second_number) = character::complete::digit1(input)?;
119 let second_number = second_number.parse::<u32>().unwrap();
120 if input.is_empty() {
121 return Ok((
122 input,
123 MinecraftVersion::Release(first_number, second_number, 0),
124 ));
125 }
126 let (input, _) = character::complete::char('.')(input)?;
127 let (input, third_number) = character::complete::digit1(input)?;
128 let third_number = third_number.parse::<u32>().unwrap();
129 Ok((
130 input,
131 MinecraftVersion::Release(first_number, second_number, third_number),
132 ))
133 }
134 'w' => {
135 let (input, second_number) = character::complete::digit1(input)?;
137 let second_number = second_number.parse::<u32>().unwrap();
138 let (input, tag_alpha) = character::complete::anychar(input)?;
139 Ok((
140 input,
141 MinecraftVersion::Snapshot(first_number, second_number, tag_alpha),
142 ))
143 }
144 _ => {
145 panic!("Version dot is not correct!")
146 }
147 }
148}
149
150#[test]
151fn parse_version_test() {
152 assert_eq!(
153 parse_version("1.16.5").unwrap().1,
154 MinecraftVersion::Release(1, 16, 5)
155 );
156 assert_eq!(
157 parse_version("1.8").unwrap().1,
158 MinecraftVersion::Release(1, 8, 0)
159 );
160 assert_eq!(
161 parse_version("21w08b").unwrap().1,
162 MinecraftVersion::Snapshot(21, 8, 'b')
163 );
164 assert_eq!(
165 "1.16.5".parse::<MinecraftVersion>().unwrap(),
166 MinecraftVersion::Release(1, 16, 5)
167 );
168 assert_eq!(
169 "1.8".parse::<MinecraftVersion>().unwrap(),
170 MinecraftVersion::Release(1, 8, 0)
171 );
172 assert_eq!(
173 "21w08b".parse::<MinecraftVersion>().unwrap(),
174 MinecraftVersion::Snapshot(21, 8, 'b')
175 );
176 assert_eq!(&MinecraftVersion::Release(1, 16, 5).to_string(), "1.16.5");
177 assert_eq!(&MinecraftVersion::Release(1, 8, 0).to_string(), "1.8");
178 assert_eq!(
179 &MinecraftVersion::Snapshot(21, 8, 'b').to_string(),
180 "21w08b"
181 );
182 assert!(MinecraftVersion::Release(1, 16, 5).required_java_version() >= 8);
183 assert!(MinecraftVersion::Release(1, 17, 1).required_java_version() >= 16);
184 assert!(MinecraftVersion::Release(1, 17, 0).required_java_version() >= 16);
185}