From 5b4cfda2b97b1ee8abac87635ba27868b5848109 Mon Sep 17 00:00:00 2001 From: Aelshi-nui Date: Tue, 8 Sep 2026 14:42:10 +0000 Subject: [PATCH] fix: compare versions numerically so 26.x is detected version.contains("1.21.1") matches nothing on 26.1 and up, so the head detector reported itself irrelevant on the versions that still have the bug. versionUtil now parses versions into numbers and exposes isAtLeast, which orders 1.x and the year based drops correctly. --- .../PlayerHeadIncompatibilityDetector.java | 61 +--------- .../signshop/util/versionUtil.java | 107 ++++++++++++++---- 2 files changed, 89 insertions(+), 79 deletions(-) diff --git a/src/main/java/org/wargamer2010/signshop/incompatibility/detectors/PlayerHeadIncompatibilityDetector.java b/src/main/java/org/wargamer2010/signshop/incompatibility/detectors/PlayerHeadIncompatibilityDetector.java index a208966..b226934 100644 --- a/src/main/java/org/wargamer2010/signshop/incompatibility/detectors/PlayerHeadIncompatibilityDetector.java +++ b/src/main/java/org/wargamer2010/signshop/incompatibility/detectors/PlayerHeadIncompatibilityDetector.java @@ -1,6 +1,5 @@ package org.wargamer2010.signshop.incompatibility.detectors; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -9,6 +8,7 @@ import org.wargamer2010.signshop.SignShop; import org.wargamer2010.signshop.incompatibility.IncompatibilityDetector; import org.wargamer2010.signshop.incompatibility.IncompatibilityType; +import org.wargamer2010.signshop.util.versionUtil; import java.util.NoSuchElementException; @@ -144,30 +144,19 @@ public IncompatibilityType detect(ItemStack item) { /** * Checks if this incompatibility affects the current Spigot version. * - *

Logic:

- * + *

Affects 1.21.10 and everything after it. Minecraft dropped the leading "1." in 2026, + * so the drops after 1.21.11 are 26.1, 26.1.1, 26.1.2, 26.2 and so on. Comparing the parts + * numerically keeps those in the right order, since 26 is greater than 1.

* * @return true if current Spigot version is affected by this incompatibility */ @Override public boolean isRelevantForCurrentVersion() { - String version = Bukkit.getVersion(); - - // If there's a known fix version, check if we're past it - if (FIXED_IN_VERSION != null && isVersionGreaterOrEqual(version)) { + if (FIXED_IN_VERSION != null && versionUtil.isAtLeast(FIXED_IN_VERSION)) { return false; // Issue is fixed in this version } - // Check if we're on an affected version (1.21.10+) - // This is a simplified check - in production you'd want proper version parsing - return version.contains("1.21.1") || // 1.21.10-1.21.19 - version.contains("1.21.2") || // 1.21.20+ - version.contains("1.22") || // Future versions - version.contains("1.23"); // Future versions + return versionUtil.isAtLeast(FIRST_AFFECTED_VERSION); } /** @@ -184,44 +173,6 @@ public String getFixedInVersion() { // Helper Methods // ======================================== - /** - * Simplified version comparison. - * - *

NOTE: This is a basic implementation. For production use, consider - * a more robust version comparison library.

- * - * @param current Current version string - * @return true if current >= target - */ - private boolean isVersionGreaterOrEqual(String current) { - // Extract version numbers (simplified - doesn't handle all edge cases) - try { - String currentClean = current.replaceAll("[^0-9.]", ""); - String targetClean = PlayerHeadIncompatibilityDetector.FIXED_IN_VERSION.replaceAll("[^0-9.]", ""); - - String[] currentParts = currentClean.split("\\."); - String[] targetParts = targetClean.split("\\."); - - int maxLength = Math.max(currentParts.length, targetParts.length); - - for (int i = 0; i < maxLength; i++) { - int currentPart = i < currentParts.length ? - Integer.parseInt(currentParts[i]) : 0; - int targetPart = i < targetParts.length ? - Integer.parseInt(targetParts[i]) : 0; - - if (currentPart > targetPart) return true; - if (currentPart < targetPart) return false; - } - - return true; // Equal - - } catch (NumberFormatException e) { - // If parsing fails, assume version is relevant (safer) - return false; - } - } - /** * Logs debug messages when debugging is enabled. * diff --git a/src/main/java/org/wargamer2010/signshop/util/versionUtil.java b/src/main/java/org/wargamer2010/signshop/util/versionUtil.java index 94be13c..1268f34 100644 --- a/src/main/java/org/wargamer2010/signshop/util/versionUtil.java +++ b/src/main/java/org/wargamer2010/signshop/util/versionUtil.java @@ -1,11 +1,9 @@ - package org.wargamer2010.signshop.util; import org.bukkit.Bukkit; import org.wargamer2010.signshop.SignShop; import java.util.logging.Level; -import java.util.regex.Pattern; /** * Bukkit/Spigot version detection and compatibility checking. @@ -19,10 +17,17 @@ *
  • Post145: Bukkit 1.4.5-R0.3+ (modern API with ItemMeta)
  • * * + *

    Two numbering schemes

    + *

    Minecraft numbered releases 1.0 up to 1.21.11, then switched to a year based + * scheme starting with 26.1 (26.1, 26.1.1, 26.1.2, 26.2, ...). Both look the same to + * the comparison below: the parts are compared as numbers, and since 26 > 1 every + * year based release sorts above every 1.x release.

    + * * @see SSBukkitVersion */ public class versionUtil { private static SSBukkitVersion cachedVersion = SSBukkitVersion.TBD; + private static int[] cachedServerVersion = null; private versionUtil() { @@ -35,18 +40,19 @@ private versionUtil() { public static SSBukkitVersion getBukkitVersionType() { if(cachedVersion == SSBukkitVersion.TBD) { String bukkitversion = Bukkit.getServer().getBukkitVersion(); - String[] versionbits = new String[1]; - if(bukkitversion.contains("-")) - versionbits = bukkitversion.split("-"); - if(versionbits.length < 2) - return SSBukkitVersion.Unknown; + String[] versionbits = bukkitversion.split("-"); + if(versionbits.length < 2) { + cachedVersion = SSBukkitVersion.Unknown; + SignShop.log("Could not determine Bukkit compatibility from this string: " + bukkitversion, Level.SEVERE); + return cachedVersion; + } - int cmp = versionUtil.compare(versionbits[0], "1.4.5"); + int cmp = compare(versionbits[0], "1.4.5"); if(cmp < 0) // < 1.4.5 cachedVersion = SSBukkitVersion.Pre145; else if(cmp == 0) { // == 1.4.5 - if(versionUtil.compare(versionbits[1], "R0.3") < 0) { // < 1.4.5-R0.3 + if(compare(versionbits[1], "R0.3") < 0) { // < 1.4.5-R0.3 cachedVersion = SSBukkitVersion.Pre145; // It didn't have support for ItemMeta so pre-Major-Overhaul } else { // >= 1.4.5-R0.3 cachedVersion = SSBukkitVersion.Post145; @@ -56,12 +62,36 @@ else if(cmp == 0) { // == 1.4.5 cachedVersion = SSBukkitVersion.Post145; } - if(cachedVersion == SSBukkitVersion.Unknown) - SignShop.log("Could not determine Bukkit compatibility from this string: " + Bukkit.getServer().getBukkitVersion(), Level.SEVERE); - return cachedVersion; } + /** + * The Minecraft version this server runs, split into its numeric parts. + * "26.1.2-R0.1-SNAPSHOT" gives {26, 1, 2}, "1.21.11-R0.1-SNAPSHOT" gives {1, 21, 11}. + * + * @return the version parts, or an empty array if the version string made no sense + */ + public static int[] getServerVersion() { + if(cachedServerVersion == null) + cachedServerVersion = parse(Bukkit.getServer().getBukkitVersion()); + + return cachedServerVersion.clone(); + } + + /** + * Checks whether the running server is at least the given Minecraft version. + * Works across both numbering schemes, so isAtLeast("1.21.10") is also true on 26.1 and up. + * + * @param version version to check against, e.g. "1.21.10" or "26.1" + * @return true if the server is that version or newer, false if it is older or unreadable + */ + public static boolean isAtLeast(String version) { + int[] server = getServerVersion(); + if(server.length == 0) + return false; + + return compare(server, parse(version)) >= 0; + } /** * Compare v1 with v2 and returns the result as an int @@ -70,22 +100,51 @@ else if(cmp == 0) { // == 1.4.5 * @param v2 Version string #2 * @return {@literal Returns < 0 if v1 < v2, > 0 if v1 > v2, 0 if v1 == v2} */ - private static int compare(String v1, String v2) { - String s1 = normalisedVersion(v1); - String s2 = normalisedVersion(v2); - return s1.compareTo(s2); + public static int compare(String v1, String v2) { + return compare(parse(v1), parse(v2)); } - private static String normalisedVersion(String version) { - return normalisedVersion(version, ".", 4); + private static int compare(int[] v1, int[] v2) { + for(int i = 0; i < Math.max(v1.length, v2.length); i++) { + int left = i < v1.length ? v1[i] : 0; + int right = i < v2.length ? v2[i] : 0; + + if(left != right) + return left < right ? -1 : 1; + } + + return 0; } - private static String normalisedVersion(String version, String sep, int maxWidth) { - String[] split = Pattern.compile(sep, Pattern.LITERAL).split(version); - StringBuilder sb = new StringBuilder((version.length() * 4)); // * 4 since we'll be adding chars - for (String s : split) { - sb.append(String.format("%" + maxWidth + 's', s)); + /** + * Pulls the numbers out of a version string. Anything that isn't a number is dropped, + * so "1.21.11-R0.1-SNAPSHOT" stops at the dash and "R0.3" reads as {0, 3}. + */ + private static int[] parse(String version) { + if(version == null || version.isEmpty()) + return new int[0]; + + String[] parts = version.split("-")[0].split("\\."); + int[] numbers = new int[parts.length]; + int found = 0; + + for(String part : parts) { + String digits = part.replaceAll("[^0-9]", ""); + if(digits.isEmpty()) + break; + + try { + numbers[found++] = Integer.parseInt(digits); + } catch(NumberFormatException e) { + break; // Absurdly long number, nothing sensible left to compare + } } - return sb.toString(); + + if(found == numbers.length) + return numbers; + + int[] trimmed = new int[found]; + System.arraycopy(numbers, 0, trimmed, 0, found); + return trimmed; } }