@@ -176,7 +176,7 @@ public static SupportStatus getServerSupportStatus() {
176176 }
177177 }
178178
179- if (!supportedVersions . contains (getServerBukkitVersion ())) {
179+ if (!isSupportedVersion (getServerBukkitVersion ())) {
180180 return supportStatus = SupportStatus .OUTDATED ;
181181 }
182182
@@ -189,15 +189,39 @@ public static String getSupportStatusClass() {
189189 return supportStatusClass ;
190190 }
191191
192+ /**
193+ * Checks if a version is considered supported, either by exact match in the
194+ * supported versions set, or by matching the base version (major.minor.patch)
195+ * of a supported version. This handles both the new PaperMC versioning scheme
196+ * (which omits the Bukkit revision suffix) and development builds that report
197+ * versions like {@code 26.1-rc-3.build.8-alpha}.
198+ */
199+ private static boolean isSupportedVersion (final BukkitVersion version ) {
200+ if (supportedVersions .contains (version )) {
201+ return true ;
202+ }
203+ // Check if this version matches a supported base version.
204+ // This covers Paper versions (no -R0.1-SNAPSHOT suffix) and
205+ // dev variants (snapshot/pre-release/RC/Paper builds).
206+ for (final BukkitVersion supported : supportedVersions ) {
207+ if (version .equalsBaseVersion (supported )) {
208+ return true ;
209+ }
210+ }
211+ return false ;
212+ }
213+
192214 public static final class BukkitVersion implements Comparable <BukkitVersion > {
193- private static final Pattern VERSION_PATTERN = Pattern .compile ("^(\\ d+)\\ .(\\ d+)\\ .?([0-9]*)?(?:-snapshot-(\\ d+))?(?:-pre-?(\\ d+))?(?:-rc-?(\\ d+))?(?:-?R?([\\ d.]+))?(?:-SNAPSHOT)?" );
215+ private static final Pattern VERSION_PATTERN = Pattern .compile ("^(\\ d+)\\ .(\\ d+)\\ .?([0-9]*)?(?:-snapshot-(\\ d+))?(?:-pre-?(\\ d+))?(?:-rc-?(\\ d+))?(?:\\ .build \\ .( \\ d+)(?:-([a-z]+))?)?(?: -?R?([\\ d.]+))?(?:-SNAPSHOT)?" );
194216 private static final Pattern LEGACY_SNAPSHOT_PATTERN = Pattern .compile ("^(\\ d{2})w(\\ d{2})([a-z])(?:-?R?([\\ d.]+))?(?:-SNAPSHOT)?" );
195217
196218 private final int major ;
197219 private final int minor ;
198220 private final int snapshotRelease ;
199221 private final int preRelease ;
200222 private final int releaseCandidate ;
223+ private final int paperBuild ;
224+ private final String releaseChannel ;
201225 private final int patch ;
202226 private final double revision ;
203227
@@ -206,21 +230,23 @@ public static final class BukkitVersion implements Comparable<BukkitVersion> {
206230 private final int snapshotWeek ;
207231 private final char snapshotLetter ;
208232
209- private BukkitVersion (final int major , final int minor , final int patch , final double revision , final int snapshotRelease , final int preRelease , final int releaseCandidate ) {
233+ private BukkitVersion (final int major , final int minor , final int patch , final double revision , final int snapshotRelease , final int preRelease , final int releaseCandidate , final int paperBuild , final String releaseChannel ) {
210234 this .major = major ;
211235 this .minor = minor ;
212236 this .patch = patch ;
213237 this .revision = revision ;
214238 this .snapshotRelease = snapshotRelease ;
215239 this .preRelease = preRelease ;
216240 this .releaseCandidate = releaseCandidate ;
241+ this .paperBuild = paperBuild ;
242+ this .releaseChannel = releaseChannel ;
217243 this .snapshot = false ;
218244 this .snapshotYear = -1 ;
219245 this .snapshotWeek = -1 ;
220246 this .snapshotLetter = '\0' ;
221247 }
222248
223- private BukkitVersion (final int major , final int minor , final int patch , final double revision , final int snapshotRelease , final int preRelease , final int releaseCandidate ,
249+ private BukkitVersion (final int major , final int minor , final int patch , final double revision , final int snapshotRelease , final int preRelease , final int releaseCandidate , final int paperBuild , final String releaseChannel ,
224250 final boolean snapshot , final int snapshotYear , final int snapshotWeek , final char snapshotLetter ) {
225251 this .major = major ;
226252 this .minor = minor ;
@@ -229,6 +255,8 @@ private BukkitVersion(final int major, final int minor, final int patch, final d
229255 this .snapshotRelease = snapshotRelease ;
230256 this .preRelease = preRelease ;
231257 this .releaseCandidate = releaseCandidate ;
258+ this .paperBuild = paperBuild ;
259+ this .releaseChannel = releaseChannel ;
232260 this .snapshot = snapshot ;
233261 this .snapshotYear = snapshotYear ;
234262 this .snapshotWeek = snapshotWeek ;
@@ -241,7 +269,7 @@ public static BukkitVersion fromString(final String string) {
241269 // Try standard release format first
242270 Matcher matcher = VERSION_PATTERN .matcher (string );
243271 if (matcher .matches ()) {
244- return from (matcher .group (1 ), matcher .group (2 ), matcher .group (3 ), matcher .group (7 ), matcher .group (4 ), matcher .group (5 ), matcher .group (6 ));
272+ return from (matcher .group (1 ), matcher .group (2 ), matcher .group (3 ), matcher .group (9 ), matcher .group (4 ), matcher .group (5 ), matcher .group (6 ), matcher . group ( 7 ), matcher . group ( 8 ));
245273 }
246274
247275 // Try snapshot format (e.g., 25w32a-R0.1-SNAPSHOT)
@@ -263,26 +291,29 @@ public static BukkitVersion fromString(final String string) {
263291 }
264292 matcher = VERSION_PATTERN .matcher (v1_16_1_R01 .toString ());
265293 Preconditions .checkArgument (matcher .matches (), string + " is not in valid version format. e.g. 1.8.8-R0.1" );
266- return from (matcher .group (1 ), matcher .group (2 ), matcher .group (3 ), matcher .group (7 ), matcher .group (4 ), matcher .group (5 ), matcher .group (6 ));
294+ return from (matcher .group (1 ), matcher .group (2 ), matcher .group (3 ), matcher .group (9 ), matcher .group (4 ), matcher .group (5 ), matcher .group (6 ), matcher . group ( 7 ), matcher . group ( 8 ));
267295 }
268296
269- private static BukkitVersion from (final String major , final String minor , String patch , String revision , String snapshotRelease , String preRelease , String releaseCandidate ) {
297+ private static BukkitVersion from (final String major , final String minor , String patch , String revision , String snapshotRelease , String preRelease , String releaseCandidate , String paperBuild , final String releaseChannel ) {
270298 if (patch == null || patch .isEmpty ()) patch = "0" ;
271299 if (revision == null || revision .isEmpty ()) revision = "0" ;
272300 if (snapshotRelease == null || snapshotRelease .isEmpty ()) snapshotRelease = "-1" ;
273301 if (preRelease == null || preRelease .isEmpty ()) preRelease = "-1" ;
274302 if (releaseCandidate == null || releaseCandidate .isEmpty ()) releaseCandidate = "-1" ;
303+ if (paperBuild == null || paperBuild .isEmpty ()) paperBuild = "-1" ;
275304 return new BukkitVersion (Integer .parseInt (major ),
276305 Integer .parseInt (minor ),
277306 Integer .parseInt (patch ),
278307 Double .parseDouble (revision ),
279308 Integer .parseInt (snapshotRelease ),
280309 Integer .parseInt (preRelease ),
281- Integer .parseInt (releaseCandidate ));
310+ Integer .parseInt (releaseCandidate ),
311+ Integer .parseInt (paperBuild ),
312+ releaseChannel );
282313 }
283314
284315 private static BukkitVersion fromSnapshot (final int year , final int week , final char letter , final double revision ) {
285- return new BukkitVersion (-1 , -1 , -1 , revision , -1 , -1 , -1 , true , year , week , letter );
316+ return new BukkitVersion (-1 , -1 , -1 , revision , -1 , -1 , -1 , - 1 , null , true , year , week , letter );
286317 }
287318
288319 public boolean isHigherThan (final BukkitVersion o ) {
@@ -329,10 +360,35 @@ public int getSnapshotRelease() {
329360 return snapshotRelease ;
330361 }
331362
363+ public int getPaperBuild () {
364+ return paperBuild ;
365+ }
366+
367+ public String getReleaseChannel () {
368+ return releaseChannel ;
369+ }
370+
332371 public boolean isSnapshot () {
333372 return snapshot ;
334373 }
335374
375+ /**
376+ * Checks if this version has the same base version (major, minor, and patch)
377+ * as the given version, ignoring development specifiers (snapshot release, pre-release,
378+ * release candidate, paper build numbers) and Bukkit metadata (revision).
379+ * Revision is ignored because Paper versions do not include the Bukkit revision
380+ * suffix (e.g. {@code -R0.1-SNAPSHOT}).
381+ * This is used to match development builds against their target release version.
382+ */
383+ public boolean equalsBaseVersion (final BukkitVersion other ) {
384+ if (this .snapshot || other .snapshot ) {
385+ return false ;
386+ }
387+ return this .major == other .major &&
388+ this .minor == other .minor &&
389+ this .patch == other .patch ;
390+ }
391+
336392 @ Override
337393 public boolean equals (final Object o ) {
338394 if (this == o ) {
@@ -379,10 +435,16 @@ public String toString() {
379435 sb .append ("-snapshot-" ).append (snapshotRelease );
380436 }
381437 if (preRelease != -1 ) {
382- sb .append ("-pre" ).append (preRelease );
438+ sb .append ("-pre- " ).append (preRelease );
383439 }
384440 if (releaseCandidate != -1 ) {
385- sb .append ("-rc" ).append (releaseCandidate );
441+ sb .append ("-rc-" ).append (releaseCandidate );
442+ }
443+ if (paperBuild != -1 ) {
444+ sb .append (".build." ).append (paperBuild );
445+ if (releaseChannel != null ) {
446+ sb .append ("-" ).append (releaseChannel );
447+ }
386448 }
387449 return sb .append ("-R" ).append (revision ).toString ();
388450 }
@@ -437,7 +499,13 @@ public int compareTo(final BukkitVersion o) {
437499 } else if (releaseCandidate > o .releaseCandidate ) {
438500 return 1 ;
439501 } else { // equal release candidate
440- return Double .compare (revision , o .revision );
502+ if (paperBuild < o .paperBuild ) {
503+ return -1 ;
504+ } else if (paperBuild > o .paperBuild ) {
505+ return 1 ;
506+ } else { // equal paper build
507+ return Double .compare (revision , o .revision );
508+ }
441509 }
442510 }
443511 }
0 commit comments