|
6 | 6 | import java.util.regex.Matcher; |
7 | 7 | import java.util.regex.Pattern; |
8 | 8 |
|
9 | | -public final class VersionUtil implements Comparable<VersionUtil>{ |
10 | | -/* |
11 | | - private VersionUtil() {} |
12 | | -
|
13 | | - /** |
14 | | - * Returns true if current >= target (by Minecraft version). |
15 | | - * |
16 | | - * current can be: |
17 | | - * - "1.21.10", "1.21.4", "1.21.4-pre1", "1.21.4-SNAPSHOT" (Paper/Folia) |
18 | | - * - "v1_21_R3" (Spigot/Bukkit NMS package) |
19 | | - * |
20 | | - * target should be a normal MC version like "1.21.4". |
21 | | -
|
22 | | - public static boolean isAtLeast(String current, String target) { |
23 | | - String normCurrent = normalize(current); |
24 | | - String normTarget = normalize(target); |
25 | | -
|
26 | | - int[] curParts = parseVersion(normCurrent); |
27 | | - int[] tarParts = parseVersion(normTarget); |
28 | | -
|
29 | | - int len = Math.max(curParts.length, tarParts.length); |
30 | | - for (int i = 0; i < len; i++) { |
31 | | - int c = i < curParts.length ? curParts[i] : 0; |
32 | | - int t = i < tarParts.length ? tarParts[i] : 0; |
33 | | -
|
34 | | - if (c != t) { |
35 | | - return c > t; |
36 | | - } |
37 | | - } |
38 | | - return true; // equal |
39 | | - } |
40 | | -
|
41 | | - /** |
42 | | - * Normalizes: |
43 | | - * - Paper/Folia style "1.21.10", "1.21.10-pre4", "1.21.10-SNAPSHOT" |
44 | | - * - Spigot NMS style "v1_21_R3" |
45 | | - * into a "major.minor.patch" string. |
46 | | -
|
47 | | - private static String normalize(String version) { |
48 | | - if (version == null) return "0.0.0"; |
49 | | - version = version.trim(); |
50 | | -
|
51 | | - // Case A: Spigot NMS "v1_21_RX" |
52 | | - if (version.startsWith("v") && version.contains("_")) { |
53 | | - // Strip leading 'v' |
54 | | - String body = version.substring(1); // e.g. "1_21_R3" |
55 | | - String[] parts = body.split("_"); |
56 | | - if (parts.length >= 3) { |
57 | | - String majorStr = digitsOnly(parts[0]); // "1" |
58 | | - String minorStr = digitsOnly(parts[1]); // "21" |
59 | | - String rStr = digitsOnly(parts[2]); // "3" for R3 |
60 | | -
|
61 | | - int major = parseIntOrZero(majorStr); |
62 | | - int minor = parseIntOrZero(minorStr); |
63 | | - int r = parseIntOrZero(rStr); |
64 | | -
|
65 | | - // Map 1_21_Rx -> minimum MCP version as per wiki |
66 | | - // R1 -> 1.21.0 |
67 | | - // R2 -> 1.21.2 |
68 | | - // R3 -> 1.21.4 |
69 | | - // R4 -> 1.21.5 |
70 | | - // R5 -> 1.21.6 |
71 | | - int patch; |
72 | | - if (major == 1 && minor == 21) { |
73 | | - switch (r) { |
74 | | - case 1: patch = 0; break; |
75 | | - case 2: patch = 2; break; |
76 | | - case 3: patch = 4; break; |
77 | | - case 4: patch = 5; break; |
78 | | - case 5: patch = 6; break; |
79 | | - default: |
80 | | - // Future R versions for 1.21: assume >= 1.21.6 |
81 | | - patch = 6; |
82 | | - break; |
83 | | - } |
84 | | - } else { |
85 | | - // Fallback for other majors/minors if needed |
86 | | - patch = 0; |
87 | | - } |
88 | | -
|
89 | | - return major + "." + minor + "." + patch; |
90 | | - } |
91 | | - } |
92 | | -
|
93 | | - // Case B: Paper/Folia "1.21.10", maybe with suffixes |
94 | | - // Keep only the leading 0-9 and dots |
95 | | - StringBuilder sb = new StringBuilder(); |
96 | | - for (int i = 0; i < version.length(); i++) { |
97 | | - char c = version.charAt(i); |
98 | | - if ((c >= '0' && c <= '9') || c == '.') { |
99 | | - sb.append(c); |
100 | | - } else if (sb.length() > 0) { |
101 | | - break; |
102 | | - } |
103 | | - } |
104 | | -
|
105 | | - if (sb.length() == 0) { |
106 | | - return "0.0.0"; |
107 | | - } |
108 | | -
|
109 | | - String[] nums = sb.toString().split("\\."); |
110 | | - if (nums.length == 1) { |
111 | | - return nums[0] + ".0.0"; |
112 | | - } else if (nums.length == 2) { |
113 | | - return nums[0] + "." + nums[1] + ".0"; |
114 | | - } else { |
115 | | - return sb.toString(); |
116 | | - } |
117 | | - } |
118 | | -
|
119 | | - private static String digitsOnly(String s) { |
120 | | - StringBuilder sb = new StringBuilder(); |
121 | | - for (int i = 0; i < s.length(); i++) { |
122 | | - char c = s.charAt(i); |
123 | | - if (c >= '0' && c <= '9') { |
124 | | - sb.append(c); |
125 | | - } |
126 | | - } |
127 | | - return sb.toString(); |
128 | | - } |
129 | | -
|
130 | | - private static int parseIntOrZero(String s) { |
131 | | - try { |
132 | | - return Integer.parseInt(s); |
133 | | - } catch (NumberFormatException e) { |
134 | | - return 0; |
135 | | - } |
136 | | - } |
137 | | -
|
138 | | - private static int[] parseVersion(String version) { |
139 | | - String[] parts = version.split("\\."); |
140 | | - int[] result = new int[parts.length]; |
141 | | - for (int i = 0; i < parts.length; i++) { |
142 | | - try { |
143 | | - result[i] = Integer.parseInt(parts[i]); |
144 | | - } catch (NumberFormatException e) { |
145 | | - result[i] = 0; |
146 | | - } |
147 | | - } |
148 | | - return result; |
149 | | - }*/ |
| 9 | +public class VersionUtil implements Comparable<VersionUtil> { |
150 | 10 |
|
151 | 11 | private final String version; |
152 | 12 | private static final Pattern SEPARATOR = Pattern.compile("\\."); |
153 | | - private static final Pattern VERSION_NUMBER = Pattern.compile("[0-9]+(" + SEPARATOR + "[0-9]+)*"); |
154 | | - private final String[] versionComponents; |
| 13 | + private static final Pattern VERSION_PATTERN = Pattern.compile("[0-9]+(" + SEPARATOR + "[0-9]+)*"); |
| 14 | + private final String[] components; |
155 | 15 |
|
156 | | - private VersionUtil(String version){ |
| 16 | + private VersionUtil(String version) { |
157 | 17 | this.version = version; |
158 | | - versionComponents = version.split(SEPARATOR.pattern()); |
| 18 | + components = version.split(SEPARATOR.pattern()); |
159 | 19 | } |
160 | 20 |
|
161 | | - public static String fromString(String version){ |
162 | | - if (version == null) |
| 21 | + /** |
| 22 | + * Constructs a Version object from the given string. |
| 23 | + * |
| 24 | + * <p>This method will truncate any extraneous characters found |
| 25 | + * after it matches the first qualified version string.</p> |
| 26 | + * |
| 27 | + * @param version A string that contains a formatted version. |
| 28 | + * @return A new Version instance from the given string. |
| 29 | + */ |
| 30 | + public static VersionUtil fromString(String version) { |
| 31 | + if(version == null) { |
163 | 32 | throw new IllegalArgumentException("Version can not be null"); |
| 33 | + } |
164 | 34 |
|
165 | | - Matcher matcher = VERSION_NUMBER.matcher(version); |
166 | | - |
167 | | - if(!matcher.find()) |
168 | | - throw new IllegalArgumentException("Invalid Version Format: " + version); |
| 35 | + Matcher matcher = VERSION_PATTERN.matcher(version); |
| 36 | + if(!matcher.find()) { |
| 37 | + throw new IllegalArgumentException("Invalid version format: " + version); |
| 38 | + } |
169 | 39 |
|
170 | 40 | return new VersionUtil(matcher.group(0)); |
171 | 41 | } |
172 | 42 |
|
173 | | - public int compareTo(@NotNull VersionUtil that){ |
174 | | - int length = Math.max(versionComponents.length, that.versionComponents.length); |
| 43 | + @Override |
| 44 | + public int compareTo(@NotNull VersionUtil that) { |
| 45 | + int length = Math.max(components.length, that.components.length); |
| 46 | + |
175 | 47 | for(int i = 0; i < length; i++) { |
176 | | - int thisPart = i < versionComponents.length ? Integer.parseInt(versionComponents[i]) : 0; |
177 | | - int thatPart = i < that.versionComponents.length ? Integer.parseInt(that.versionComponents[i]) : 0; |
| 48 | + int thisPart = i < components.length ? Integer.parseInt(components[i]) : 0; |
| 49 | + int thatPart = i < that.components.length ? Integer.parseInt(that.components[i]) : 0; |
178 | 50 |
|
179 | 51 | if (thisPart < thatPart) { |
180 | 52 | return -1; |
@@ -205,20 +77,27 @@ public String toString() { |
205 | 77 | return version; |
206 | 78 | } |
207 | 79 |
|
| 80 | + /** |
| 81 | + * Returns the components of the version separated by .'s |
| 82 | + * |
| 83 | + * @return A string array of the components. |
| 84 | + */ |
208 | 85 | @NotNull |
209 | 86 | public String[] getComponents() { |
210 | | - return versionComponents; |
| 87 | + return components; |
211 | 88 | } |
212 | 89 |
|
213 | | - public boolean isPreRelease() { |
214 | | - try { |
215 | | - return Integer.parseInt(this.versionComponents[versionComponents.length-1]) != 0; |
216 | | - } catch (NumberFormatException e) { |
217 | | - return false; |
218 | | - } |
219 | | - } |
220 | 90 |
|
221 | 91 | public boolean isNewerThanOrEquals(@NotNull VersionUtil other) { |
222 | 92 | return this.compareTo(other) >= 0; |
223 | 93 | } |
| 94 | + |
| 95 | + public boolean isOlderThanOrEquals(@NotNull VersionUtil other) { |
| 96 | + return this.compareTo(other) <= 0; |
| 97 | + } |
| 98 | + public boolean isOlderThan(@NotNull VersionUtil other) { |
| 99 | + return this.compareTo(other) < 0; |
| 100 | + } |
| 101 | + |
| 102 | + |
224 | 103 | } |
0 commit comments