From 224634d8d27c2b17bb4557a700f8776a6a48e16b Mon Sep 17 00:00:00 2001 From: Josh Roy <10731363+JRoy@users.noreply.github.com> Date: Tue, 19 Jan 2021 07:40:05 -0500 Subject: [PATCH] Improve VersionUtil version checks (#3812) Co-authored-by: Dylan Xaldin Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com> --- .../com/earth2me/essentials/Essentials.java | 10 +++ .../commands/Commandessentials.java | 10 +++ .../essentials/utils/VersionUtil.java | 80 ++++++++++++++++--- .../src/main/resources/messages.properties | 5 +- .../main/java/net/ess3/nms/refl/ReflUtil.java | 7 +- 5 files changed, 98 insertions(+), 14 deletions(-) diff --git a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java index 902599bcd..bcf785f58 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java @@ -201,6 +201,12 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { Console.setInstance(this); switch (VersionUtil.getServerSupportStatus()) { + case NMS_CLEANROOM: + getLogger().severe(tl("serverUnsupportedCleanroom")); + break; + case DANGEROUS_FORK: + getLogger().severe(tl("serverUnsupportedDangerous")); + break; case UNSTABLE: getLogger().severe(tl("serverUnsupportedMods")); break; @@ -212,6 +218,10 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { break; } + if (VersionUtil.getSupportStatusClass() != null) { + getLogger().info(tl("serverUnsupportedClass", VersionUtil.getSupportStatusClass())); + } + final PluginManager pm = getServer().getPluginManager(); for (final Plugin plugin : pm.getPlugins()) { if (plugin.getDescription().getName().startsWith("Essentials") && !plugin.getDescription().getVersion().equals(this.getDescription().getVersion()) && !plugin.getDescription().getName().equals("EssentialsAntiCheat")) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandessentials.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandessentials.java index dccf76220..2005c7ba3 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandessentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandessentials.java @@ -372,6 +372,12 @@ public class Commandessentials extends EssentialsCommand { } switch (supportStatus) { + case NMS_CLEANROOM: + sender.sendMessage(tl("serverUnsupportedCleanroom")); + break; + case DANGEROUS_FORK: + sender.sendMessage(tl("serverUnsupportedDangerous")); + break; case UNSTABLE: sender.sendMessage(tl("serverUnsupportedMods")); break; @@ -382,6 +388,10 @@ public class Commandessentials extends EssentialsCommand { sender.sendMessage(tl("serverUnsupportedLimitedApi")); break; } + + if (VersionUtil.getSupportStatusClass() != null) { + sender.sendMessage(tl("serverUnsupportedClass", VersionUtil.getSupportStatusClass())); + } } @Override diff --git a/Essentials/src/main/java/com/earth2me/essentials/utils/VersionUtil.java b/Essentials/src/main/java/com/earth2me/essentials/utils/VersionUtil.java index fa0d94189..8672a143b 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/utils/VersionUtil.java +++ b/Essentials/src/main/java/com/earth2me/essentials/utils/VersionUtil.java @@ -2,10 +2,13 @@ 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.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -16,7 +19,6 @@ public final class VersionUtil { 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_R01 = BukkitVersion.fromString("1.10-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"); @@ -28,12 +30,48 @@ public final class VersionUtil { 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_2_R01 = BukkitVersion.fromString("1.16.2-R0.1-SNAPSHOT"); public static final BukkitVersion v1_16_5_R01 = BukkitVersion.fromString("1.16.5-R0.1-SNAPSHOT"); private static final Set 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); + private static final Map unsupportedServerClasses; + + static { + final ImmutableMap.Builder 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); + + // KibblePatcher - Dangerous bytecode editor snakeoil whose only use is to break plugins + builder.put("net.kibblelands.server.FastMath", SupportStatus.DANGEROUS_FORK); + + // AirplaneLite - Yatopia sidestream; + // * Attempts unsafe chunk concurrency + builder.put("gg.airplane.structs.ChunkMapMap", SupportStatus.DANGEROUS_FORK); + builder.put("gg.airplane.structs.ConcLong2ObjectOpenHashMap", 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 + 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() { } @@ -46,17 +84,35 @@ public final class VersionUtil { } public static SupportStatus getServerSupportStatus() { - try { - Class.forName("net.minecraftforge.common.MinecraftForge"); - return SupportStatus.UNSTABLE; - } catch (final ClassNotFoundException ignored) { - } + if (supportStatus == null) { + for (Map.Entry entry : unsupportedServerClasses.entrySet()) { + final boolean inverted = entry.getKey().contains("!"); + final String clazz = entry.getKey().replace("!", ""); + try { + Class.forName(clazz); + 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.OUTDATED; - } + if (!supportedVersions.contains(getServerBukkitVersion())) { + return supportStatus = SupportStatus.OUTDATED; + } - return PaperLib.isPaper() ? SupportStatus.FULL : SupportStatus.LIMITED; + return supportStatus = PaperLib.isPaper() ? SupportStatus.FULL : SupportStatus.LIMITED; + } + return supportStatus; + } + + public static String getSupportStatusClass() { + return supportStatusClass; } public static boolean isServerSupported() { @@ -207,6 +263,8 @@ public final class VersionUtil { public enum SupportStatus { FULL(true), LIMITED(true), + DANGEROUS_FORK(false), + NMS_CLEANROOM(false), UNSTABLE(false), OUTDATED(false) ; diff --git a/Essentials/src/main/resources/messages.properties b/Essentials/src/main/resources/messages.properties index a7eaef9a4..8d39e5920 100644 --- a/Essentials/src/main/resources/messages.properties +++ b/Essentials/src/main/resources/messages.properties @@ -708,8 +708,11 @@ serverFull=Server is full\! serverReloading=There's a good chance you're reloading your server right now. If that's the case, why do you hate yourself? Expect no support from the EssentialsX team when using /reload. serverTotal=\u00a76Server Total\:\u00a7c {0} serverUnsupported=You are running an unsupported server version! +serverUnsupportedClass=Status determining class\: {0} +serverUnsupportedCleanroom=You are running a server that does not properly support Bukkit plugins that rely on internal Mojang code. Consider using an Essentials replacement for your server software. +serverUnsupportedDangerous=You are running a server fork that is known to be extremely dangerous and lead to data loss. It is strongly recommended you switch to a more stable, high-performing server software, like Paper or Tuinity. serverUnsupportedLimitedApi=You are running a server with limited API functionality. EssentialsX will still work, but certain features may be disabled. -serverUnsupportedMods=You are running a server that does not properly support Bukkit plugins. Bukkit plugins should not be used with Forge mods! Consider using ForgeEssentials, or SpongeForge + Nucleus. +serverUnsupportedMods=You are running a server that does not properly support Bukkit plugins. Bukkit plugins should not be used with Forge/Fabric mods! For Forge: Consider using ForgeEssentials, or SpongeForge + Nucleus. setBal=\u00a7aYour balance was set to {0}. setBalOthers=\u00a7aYou set {0}\u00a7a''s balance to {1}. setSpawner=\u00a76Changed spawner type to\u00a7c {0}\u00a76. diff --git a/providers/NMSReflectionProvider/src/main/java/net/ess3/nms/refl/ReflUtil.java b/providers/NMSReflectionProvider/src/main/java/net/ess3/nms/refl/ReflUtil.java index 30aa79e1b..7515c3e8f 100644 --- a/providers/NMSReflectionProvider/src/main/java/net/ess3/nms/refl/ReflUtil.java +++ b/providers/NMSReflectionProvider/src/main/java/net/ess3/nms/refl/ReflUtil.java @@ -17,7 +17,6 @@ import java.util.regex.Pattern; public final class ReflUtil { public static final NMSVersion V1_12_R1 = NMSVersion.fromString("v1_12_R1"); - public static final NMSVersion V1_8_R1 = NMSVersion.fromString("v1_8_R1"); public static final NMSVersion V1_9_R1 = NMSVersion.fromString("v1_9_R1"); public static final NMSVersion V1_11_R1 = NMSVersion.fromString("v1_11_R1"); private static final Map> classCache = new HashMap<>(); @@ -36,7 +35,11 @@ public final class ReflUtil { if (nmsVersion == null) { final String name = Bukkit.getServer().getClass().getName(); final String[] parts = name.split("\\."); - nmsVersion = parts[3]; + if (parts.length > 3) { + return nmsVersion = parts[3]; + } + // We're not on craftbukkit, return an empty string so we can silently fail + return nmsVersion = ""; } return nmsVersion; }