339 lines
14 KiB
Java
339 lines
14 KiB
Java
package com.earth2me.essentials.utils;
|
|
|
|
import com.google.common.base.Objects;
|
|
import com.google.common.base.Preconditions;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.collect.ImmutableSet;
|
|
import io.papermc.lib.PaperLib;
|
|
import net.ess3.nms.refl.ReflUtil;
|
|
import org.bukkit.Bukkit;
|
|
|
|
import java.lang.reflect.Method;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
public final class VersionUtil {
|
|
|
|
public static final BukkitVersion v1_14_R01 = BukkitVersion.fromString("1.14-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_8_8_R01 = BukkitVersion.fromString("1.8.8-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_9_R01 = BukkitVersion.fromString("1.9-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_9_4_R01 = BukkitVersion.fromString("1.9.4-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_10_2_R01 = BukkitVersion.fromString("1.10.2-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_11_R01 = BukkitVersion.fromString("1.11-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_11_2_R01 = BukkitVersion.fromString("1.11.2-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_12_0_R01 = BukkitVersion.fromString("1.12.0-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_12_2_R01 = BukkitVersion.fromString("1.12.2-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_13_0_R01 = BukkitVersion.fromString("1.13.0-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_13_2_R01 = BukkitVersion.fromString("1.13.2-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_14_4_R01 = BukkitVersion.fromString("1.14.4-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_15_R01 = BukkitVersion.fromString("1.15-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_15_2_R01 = BukkitVersion.fromString("1.15.2-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_16_1_R01 = BukkitVersion.fromString("1.16.1-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_16_5_R01 = BukkitVersion.fromString("1.16.5-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_17_R01 = BukkitVersion.fromString("1.17-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_17_1_R01 = BukkitVersion.fromString("1.17.1-R0.1-SNAPSHOT");
|
|
public static final BukkitVersion v1_18_R01 = BukkitVersion.fromString("1.18-R0.1-SNAPSHOT");
|
|
|
|
private static final Set<BukkitVersion> supportedVersions = ImmutableSet.of(v1_8_8_R01, v1_9_4_R01, v1_10_2_R01, v1_11_2_R01, v1_12_2_R01, v1_13_2_R01, v1_14_4_R01, v1_15_2_R01, v1_16_5_R01, v1_17_1_R01, v1_18_R01);
|
|
|
|
private static final Map<String, SupportStatus> unsupportedServerClasses;
|
|
|
|
static {
|
|
final ImmutableMap.Builder<String, SupportStatus> builder = new ImmutableMap.Builder<>();
|
|
|
|
// Yatopia - Extremely volatile patch set;
|
|
// * Messes with proxy-forwarded UUIDs
|
|
// * Frequent data corruptions
|
|
builder.put("org.yatopiamc.yatopia.server.YatopiaConfig", SupportStatus.DANGEROUS_FORK);
|
|
builder.put("net.yatopia.api.event.PlayerAttackEntityEvent", SupportStatus.DANGEROUS_FORK);
|
|
builder.put("org.bukkit.plugin.SimplePluginManager#getPluginLoaders", SupportStatus.DANGEROUS_FORK);
|
|
builder.put("org.bukkit.Bukkit#getLastTickTime", SupportStatus.DANGEROUS_FORK);
|
|
builder.put("brand:Yatopia", SupportStatus.DANGEROUS_FORK);
|
|
// Yatopia downstream(s) which attempt to do tricky things :)
|
|
builder.put("brand:Hyalus", SupportStatus.DANGEROUS_FORK);
|
|
|
|
// KibblePatcher - Dangerous bytecode editor snakeoil whose only use is to break plugins
|
|
builder.put("net.kibblelands.server.FastMath", SupportStatus.DANGEROUS_FORK);
|
|
|
|
// Akarin - Dangerous patch history;
|
|
// * Potentially unsafe saving of nms.JsonList
|
|
builder.put("io.akarin.server.Config", SupportStatus.DANGEROUS_FORK);
|
|
|
|
// Forge - Doesn't support Bukkit
|
|
builder.put("net.minecraftforge.common.MinecraftForge", SupportStatus.UNSTABLE);
|
|
|
|
// Fabric - Doesn't support Bukkit
|
|
builder.put("net.fabricmc.loader.launch.knot.KnotServer", SupportStatus.UNSTABLE);
|
|
|
|
// Misc translation layers that do not add NMS will be caught by this
|
|
if (ReflUtil.getNmsVersionObject().isHigherThanOrEqualTo(ReflUtil.V1_17_R1)) {
|
|
builder.put("!net.minecraft.server.MinecraftServer", SupportStatus.NMS_CLEANROOM);
|
|
} else {
|
|
builder.put("!net.minecraft.server." + ReflUtil.getNMSVersion() + ".MinecraftServer", SupportStatus.NMS_CLEANROOM);
|
|
}
|
|
|
|
unsupportedServerClasses = builder.build();
|
|
}
|
|
|
|
private static BukkitVersion serverVersion = null;
|
|
private static SupportStatus supportStatus = null;
|
|
// Used to find the specific class that caused a given support status
|
|
private static String supportStatusClass = null;
|
|
|
|
private VersionUtil() {
|
|
}
|
|
|
|
public static boolean isPaper() {
|
|
return PaperLib.isPaper();
|
|
}
|
|
|
|
public static BukkitVersion getServerBukkitVersion() {
|
|
if (serverVersion == null) {
|
|
serverVersion = BukkitVersion.fromString(Bukkit.getServer().getBukkitVersion());
|
|
}
|
|
return serverVersion;
|
|
}
|
|
|
|
public static SupportStatus getServerSupportStatus() {
|
|
if (supportStatus == null) {
|
|
for (Map.Entry<String, SupportStatus> entry : unsupportedServerClasses.entrySet()) {
|
|
|
|
if (entry.getKey().startsWith("brand:")) {
|
|
if (Bukkit.getName().equalsIgnoreCase(entry.getKey().replaceFirst("brand:", ""))) {
|
|
supportStatusClass = entry.getKey();
|
|
return supportStatus = entry.getValue();
|
|
}
|
|
continue;
|
|
}
|
|
|
|
final boolean inverted = entry.getKey().contains("!");
|
|
final String clazz = entry.getKey().replace("!", "").split("#")[0];
|
|
String method = "";
|
|
if (entry.getKey().contains("#")) {
|
|
method = entry.getKey().split("#")[1];
|
|
}
|
|
try {
|
|
final Class<?> lolClass = Class.forName(clazz);
|
|
|
|
if (!method.isEmpty()) {
|
|
for (final Method mth : lolClass.getDeclaredMethods()) {
|
|
if (mth.getName().equals(method)) {
|
|
if (!inverted) {
|
|
supportStatusClass = entry.getKey();
|
|
return supportStatus = entry.getValue();
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!inverted) {
|
|
supportStatusClass = entry.getKey();
|
|
return supportStatus = entry.getValue();
|
|
}
|
|
} catch (final ClassNotFoundException ignored) {
|
|
if (inverted) {
|
|
supportStatusClass = entry.getKey();
|
|
return supportStatus = entry.getValue();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!supportedVersions.contains(getServerBukkitVersion())) {
|
|
return supportStatus = SupportStatus.OUTDATED;
|
|
}
|
|
|
|
return supportStatus = PaperLib.isPaper() ? SupportStatus.FULL : SupportStatus.LIMITED;
|
|
}
|
|
return supportStatus;
|
|
}
|
|
|
|
public static String getSupportStatusClass() {
|
|
return supportStatusClass;
|
|
}
|
|
|
|
public static boolean isServerSupported() {
|
|
return getServerSupportStatus().isSupported();
|
|
}
|
|
|
|
public static final class BukkitVersion implements Comparable<BukkitVersion> {
|
|
private static final Pattern VERSION_PATTERN = Pattern.compile("^(\\d+)\\.(\\d+)\\.?([0-9]*)?(?:-pre(\\d))?(?:-rc(\\d+))?(?:-?R?([\\d.]+))?(?:-SNAPSHOT)?");
|
|
|
|
private final int major;
|
|
private final int minor;
|
|
private final int preRelease;
|
|
private final int releaseCandidate;
|
|
private final int patch;
|
|
private final double revision;
|
|
|
|
private BukkitVersion(final int major, final int minor, final int patch, final double revision, final int preRelease, final int releaseCandidate) {
|
|
this.major = major;
|
|
this.minor = minor;
|
|
this.patch = patch;
|
|
this.revision = revision;
|
|
this.preRelease = preRelease;
|
|
this.releaseCandidate = releaseCandidate;
|
|
}
|
|
|
|
public static BukkitVersion fromString(final String string) {
|
|
Preconditions.checkNotNull(string, "string cannot be null.");
|
|
Matcher matcher = VERSION_PATTERN.matcher(string);
|
|
if (!matcher.matches()) {
|
|
if (!Bukkit.getName().equals("Essentials Fake Server")) {
|
|
throw new IllegalArgumentException(string + " is not in valid version format. e.g. 1.8.8-R0.1");
|
|
}
|
|
matcher = VERSION_PATTERN.matcher(v1_14_R01.toString());
|
|
Preconditions.checkArgument(matcher.matches(), string + " is not in valid version format. e.g. 1.8.8-R0.1");
|
|
}
|
|
|
|
return from(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(6), matcher.group(4), matcher.group(5));
|
|
}
|
|
|
|
private static BukkitVersion from(final String major, final String minor, String patch, String revision, String preRelease, String releaseCandidate) {
|
|
if (patch == null || patch.isEmpty()) patch = "0";
|
|
if (revision == null || revision.isEmpty()) revision = "0";
|
|
if (preRelease == null || preRelease.isEmpty()) preRelease = "-1";
|
|
if (releaseCandidate == null || releaseCandidate.isEmpty()) releaseCandidate = "-1";
|
|
return new BukkitVersion(Integer.parseInt(major),
|
|
Integer.parseInt(minor),
|
|
Integer.parseInt(patch),
|
|
Double.parseDouble(revision),
|
|
Integer.parseInt(preRelease),
|
|
Integer.parseInt(releaseCandidate));
|
|
}
|
|
|
|
public boolean isHigherThan(final BukkitVersion o) {
|
|
return compareTo(o) > 0;
|
|
}
|
|
|
|
public boolean isHigherThanOrEqualTo(final BukkitVersion o) {
|
|
return compareTo(o) >= 0;
|
|
}
|
|
|
|
public boolean isLowerThan(final BukkitVersion o) {
|
|
return compareTo(o) < 0;
|
|
}
|
|
|
|
public boolean isLowerThanOrEqualTo(final BukkitVersion o) {
|
|
return compareTo(o) <= 0;
|
|
}
|
|
|
|
public int getMajor() {
|
|
return major;
|
|
}
|
|
|
|
public int getMinor() {
|
|
return minor;
|
|
}
|
|
|
|
public int getPatch() {
|
|
return patch;
|
|
}
|
|
|
|
public double getRevision() {
|
|
return revision;
|
|
}
|
|
|
|
public int getPrerelease() {
|
|
return preRelease;
|
|
}
|
|
|
|
public int getReleaseCandidate() {
|
|
return releaseCandidate;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(final Object o) {
|
|
if (this == o) {
|
|
return true;
|
|
}
|
|
if (o == null || getClass() != o.getClass()) {
|
|
return false;
|
|
}
|
|
final BukkitVersion that = (BukkitVersion) o;
|
|
return major == that.major &&
|
|
minor == that.minor &&
|
|
patch == that.patch &&
|
|
revision == that.revision &&
|
|
preRelease == that.preRelease;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return Objects.hashCode(major, minor, patch, revision, preRelease, releaseCandidate);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
final StringBuilder sb = new StringBuilder(major + "." + minor);
|
|
if (patch != 0) {
|
|
sb.append(".").append(patch);
|
|
}
|
|
if (preRelease != -1) {
|
|
sb.append("-pre").append(preRelease);
|
|
}
|
|
if (releaseCandidate != -1) {
|
|
sb.append("-rc").append(releaseCandidate);
|
|
}
|
|
return sb.append("-R").append(revision).toString();
|
|
}
|
|
|
|
@Override
|
|
public int compareTo(final BukkitVersion o) {
|
|
if (major < o.major) {
|
|
return -1;
|
|
} else if (major > o.major) {
|
|
return 1;
|
|
} else { // equal major
|
|
if (minor < o.minor) {
|
|
return -1;
|
|
} else if (minor > o.minor) {
|
|
return 1;
|
|
} else { // equal minor
|
|
if (patch < o.patch) {
|
|
return -1;
|
|
} else if (patch > o.patch) {
|
|
return 1;
|
|
} else { // equal patch
|
|
if (preRelease < o.preRelease) {
|
|
return -1;
|
|
} else if (preRelease > o.preRelease) {
|
|
return 1;
|
|
} else { // equal prerelease
|
|
if (releaseCandidate < o.releaseCandidate) {
|
|
return -1;
|
|
} else if (releaseCandidate > o.releaseCandidate) {
|
|
return 1;
|
|
} else { // equal release candidate
|
|
return Double.compare(revision, o.revision);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum SupportStatus {
|
|
FULL(true),
|
|
LIMITED(true),
|
|
DANGEROUS_FORK(false),
|
|
NMS_CLEANROOM(false),
|
|
UNSTABLE(false),
|
|
OUTDATED(false)
|
|
;
|
|
|
|
private final boolean supported;
|
|
|
|
SupportStatus(final boolean supported) {
|
|
this.supported = supported;
|
|
}
|
|
|
|
public boolean isSupported() {
|
|
return supported;
|
|
}
|
|
}
|
|
}
|