-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add BukkitVersions to simplify parsing MC/CB versions
Bit of a mess, but I think it's about the best I can do.
- Loading branch information
Showing
3 changed files
with
211 additions
and
0 deletions.
There are no files selected for viewing
107 changes: 107 additions & 0 deletions
107
src/main/java/com/github/jikoo/planarwrappers/util/version/BukkitVersions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package com.github.jikoo.planarwrappers.util.version; | ||
|
||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import org.bukkit.Bukkit; | ||
import org.bukkit.Server; | ||
import org.jetbrains.annotations.Contract; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.VisibleForTesting; | ||
|
||
public final class BukkitVersions { | ||
|
||
/** | ||
* The Minecraft version. | ||
*/ | ||
public static final Version MINECRAFT; | ||
/** | ||
* The {@link Version} of Craftbukkit's package. Do not confuse with {@link #MINECRAFT}! | ||
* | ||
* <p>The major and minor version correspond to Minecraft's major and minor version. The patch | ||
* version is an internal version that is intended to be bumped whenever the Minecraft mappings | ||
* version ({@code org.bukkit.craftbukkit.util.CraftMagicNumbers#getMappingsVersion}) changes. | ||
* | ||
* <p>Note that if you are writing a plugin using NMS, you should prefer checking against the | ||
* mappings version. Spigot has been very unreliable about bumping the minor version, claiming | ||
* that the mappings version is the ultimate way to check if your NMS usage is guaranteed to be | ||
* compatible. This is true, but only because they're unreliable about bumping it. If they | ||
* actually kept up with bumping it (which could have been scripted) it would be just as reliable | ||
* and much more human-friendly. | ||
* @deprecated Prefer {@code org.bukkit.craftbukkit.util.CraftMagicNumbers#getMappingsVersion} | ||
*/ | ||
@Deprecated | ||
public static final Version CRAFTBUKKIT_PACKAGE; | ||
|
||
static { | ||
Server server = Bukkit.getServer(); | ||
// Note: we use Bukkit version and not server version because server version includes prefixes | ||
// (such as implementation name and commit hashes of build version) that are not presented in | ||
// valid SemVer format. | ||
// Bukkit version should be a (mostly) SemVer-compliant version including Minecraft's version. | ||
String bukkitVersion = server.getBukkitVersion(); | ||
MINECRAFT = parseMinecraftVersion(bukkitVersion); | ||
|
||
String packageString = server.getClass().getPackage().toString(); | ||
CRAFTBUKKIT_PACKAGE = parseCraftbukkitVersion(packageString); | ||
} | ||
|
||
@VisibleForTesting | ||
@Contract("_ -> new") | ||
static @NotNull Version parseMinecraftVersion(@NotNull String bukkitVersion) { | ||
Pattern semVerRelease = Pattern.compile("^(\\d+)\\.(\\d+)(\\.(\\d+))?-.*$"); | ||
Matcher matcher = semVerRelease.matcher(bukkitVersion); | ||
|
||
if (matcher.find()) { | ||
String patch = matcher.group(3); | ||
return new IntVersion( | ||
Integer.parseInt(matcher.group(1)), | ||
Integer.parseInt(matcher.group(2)), | ||
patch == null || patch.isEmpty() ? 0 : Integer.parseInt(matcher.group(4)) | ||
); | ||
} | ||
|
||
// If Bukkit version has been modified (oh boy) fall through to using whatever Version selects | ||
// with extra SemVer details stripped. Spigot hasn't ever cut a Bukkit release, so | ||
// the pre-release data only will serve to cause comparison confusion. | ||
return Version.of(stripExtraData(bukkitVersion)); | ||
} | ||
|
||
@VisibleForTesting | ||
static @NotNull Version parseCraftbukkitVersion(@NotNull String craftbukkitPackage) { | ||
Pattern packageVer = Pattern.compile("^org\\.bukkit\\.craftbukkit\\.v(\\d+)_(\\d+)_R?(\\d+)"); | ||
Matcher matcher = packageVer.matcher(craftbukkitPackage); | ||
|
||
if (matcher.find()) { | ||
return new IntVersion( | ||
Integer.parseInt(matcher.group(1)), | ||
Integer.parseInt(matcher.group(2)), | ||
Integer.parseInt(matcher.group(3)) | ||
); | ||
} | ||
|
||
// Ancient/unknown version; package is not versioned. Best bet is to use the Minecraft version. | ||
return MINECRAFT; | ||
} | ||
|
||
private static @NotNull String stripExtraData(@NotNull String version) { | ||
int preReleaseStart = version.indexOf('-'); | ||
int metadataStart = version.indexOf('+'); | ||
if (preReleaseStart > -1) { | ||
if (metadataStart > -1) { | ||
return version.substring(0, Math.min(preReleaseStart, metadataStart)); | ||
} else { | ||
return version.substring(0, preReleaseStart); | ||
} | ||
} else { | ||
if (metadataStart > -1) { | ||
return version.substring(0, metadataStart); | ||
} | ||
} | ||
return version; | ||
} | ||
|
||
private BukkitVersions() { | ||
throw new IllegalStateException("Cannot instantiate static utility classes!"); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
src/test/java/com/github/jikoo/planarwrappers/util/version/BukkitVersionsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package com.github.jikoo.planarwrappers.util.version; | ||
|
||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.hamcrest.Matchers.is; | ||
import static org.mockito.Mockito.doReturn; | ||
|
||
import com.github.jikoo.planarwrappers.mock.ServerMocks; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import org.bukkit.Bukkit; | ||
import org.bukkit.Server; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.TestInstance; | ||
import org.junit.jupiter.api.TestInstance.Lifecycle; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
import org.junit.jupiter.params.provider.ValueSource; | ||
|
||
@TestInstance(Lifecycle.PER_CLASS) | ||
class BukkitVersionsTest { | ||
|
||
@BeforeAll | ||
void beforeAll() { | ||
Server server = ServerMocks.newServer(); | ||
doReturn("1.19.4-R0.1-SNAPSHOT").when(server).getBukkitVersion(); | ||
Bukkit.setServer(server); | ||
} | ||
|
||
@Test | ||
void basicParse() { | ||
assertThat(BukkitVersions.MINECRAFT, is(new IntVersion(1, 19, 4))); | ||
assertThat(BukkitVersions.CRAFTBUKKIT_PACKAGE, is(BukkitVersions.MINECRAFT)); | ||
} | ||
|
||
@ParameterizedTest | ||
@ValueSource(strings = { | ||
"org.bukkit.craftbukkit.v1_5_RV", | ||
"org.bukkit.craftbukkit.1_4_5", | ||
"invalid string", | ||
"1.4.5-R1.0" | ||
}) | ||
void invalidCbPackage(String packageName) { | ||
assertThat( | ||
"Invalid package must return Minecraft version", | ||
BukkitVersions.parseCraftbukkitVersion(packageName), | ||
is(BukkitVersions.MINECRAFT)); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("getMcVersions") | ||
void parseMcVersion(String version, Version expected) { | ||
assertThat( | ||
"Version must be parsed from Bukkit version", | ||
BukkitVersions.parseMinecraftVersion(version), | ||
is(expected)); | ||
} | ||
|
||
private static Collection<Arguments> getMcVersions() { | ||
return List.of( | ||
Arguments.of("1.4.5-R1.0", new IntVersion(1, 4, 5)), | ||
Arguments.of("1.19.4-R0.1-SNAPSHOT", new IntVersion(1, 19, 4)), | ||
Arguments.of("1.20-R0.1-SNAPSHOT", new IntVersion(1, 20, 0)), | ||
Arguments.of("unknown-format+1.10.3-R01 Cool Server Edition", new StringVersion("unknown")), | ||
Arguments.of("1.10.3+coolserver-R0.1-SNAPSHOT", new IntVersion(1, 10, 3)), | ||
Arguments.of("weirdserver+1.10.3-R0.1-SNAPSHOT", new StringVersion("weirdserver")), | ||
Arguments.of("weirdserver-1.10.3-R0.1-SNAPSHOT", new StringVersion("weirdserver")), | ||
Arguments.of("weirdserver+1.10.3", new StringVersion("weirdserver")), | ||
Arguments.of("weirdserver1_10_R3", new StringVersion("weirdserver1_10_R3")) | ||
); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("getCbVersions") | ||
void parseCbVersion(String version, Version expected) { | ||
assertThat( | ||
"Version must be parsed from Craftbukkit package", | ||
BukkitVersions.parseCraftbukkitVersion(version), | ||
is(expected)); | ||
} | ||
|
||
private static Collection<Arguments> getCbVersions() { | ||
return List.of( | ||
Arguments.of("org.bukkit.craftbukkit.v1_5_R1.other.package", new IntVersion(1, 5, 1)), | ||
Arguments.of("org.bukkit.craftbukkit.v1_5_R1", new IntVersion(1, 5, 1)), | ||
Arguments.of("org.bukkit.craftbukkit.v18_19_R50", new IntVersion(18, 19, 50)), | ||
Arguments.of("org.bukkit.craftbukkit.v1_20_R2", new IntVersion(1, 20, 2)) | ||
); | ||
} | ||
|
||
} |