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; } }