Add a warning message when ProtocolLib is started on untested version.

May decide to simply stop ProtocolLib unless this feature is
specifically disabled.
This commit is contained in:
Kristian S. Stangeland 2012-12-09 04:23:26 +01:00
parent 6b5ecd7309
commit 7ca3e916a5
5 changed files with 239 additions and 20 deletions

View File

@ -0,0 +1,153 @@
package com.comphenix.protocol;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Server;
import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
/**
* Determine the current Minecraft version.
*
* @author Kristian
*/
class MinecraftVersion implements Comparable<MinecraftVersion> {
/**
* Regular expression used to parse version strings.
*/
private static final String VERSION_PATTERN = ".*\\(MC:\\s*((?:\\d+\\.)*\\d)\\s*\\)";
private final int major;
private final int minor;
private final int build;
/**
* Determine the current Minecraft version.
* @param server - the Bukkit server that will be used to examine the MC version.
*/
public MinecraftVersion(Server server) {
this(extractVersion(server.getVersion()));
}
/**
* Construct a version object from the format major.minor.build.
* @param versionOnly - the version in text form.
*/
public MinecraftVersion(String versionOnly) {
int[] numbers = parseVersion(versionOnly);
this.major = numbers[0];
this.minor = numbers[1];
this.build = numbers[2];
}
/**
* Construct a version object directly.
* @param major - major version number.
* @param minor - minor version number.
* @param build - build version number.
*/
public MinecraftVersion(int major, int minor, int build) {
this.major = major;
this.minor = minor;
this.build = build;
}
private int[] parseVersion(String version) {
String[] elements = version.split("\\.");
int[] numbers = new int[3];
// Make sure it's even a valid version
if (elements.length < 1)
throw new IllegalStateException("Corrupt MC version: " + version);
// The String 1 or 1.2 is interpreted as 1.0.0 and 1.2.0 respectively.
for (int i = 0; i < Math.min(numbers.length, elements.length); i++)
numbers[i] = Integer.parseInt(elements[i].trim());
return numbers;
}
/**
* Major version number
* @return Current major version number.
*/
public int getMajor() {
return major;
}
/**
* Minor version number
* @return Current minor version number.
*/
public int getMinor() {
return minor;
}
/**
* Build version number
* @return Current build version number.
*/
public int getBuild() {
return build;
}
@Override
public int compareTo(MinecraftVersion o) {
if (o == null)
return 1;
return ComparisonChain.start().
compare(major, o.major).
compare(minor, o.minor).
compare(build, o.build).
result();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (obj instanceof MinecraftVersion) {
MinecraftVersion other = (MinecraftVersion) obj;
return major == other.major &&
minor == other.minor &&
build == other.build;
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(major, minor, build);
}
@Override
public String toString() {
// Convert to a String that we can parse back again
return String.format("(MC: %s.%s.%s)", major, minor, build);
}
/**
* Extract the Minecraft version from CraftBukkit itself.
* @param server - the server object representing CraftBukkit.
* @return The underlying MC version.
* @throws IllegalStateException If we could not parse the version string.
*/
public static String extractVersion(String text) {
Pattern versionPattern = Pattern.compile(VERSION_PATTERN);
Matcher version = versionPattern.matcher(text);
if (version.matches() && version.group(1) != null) {
return version.group(1);
} else {
throw new IllegalStateException("Cannot parse version String '" + text + "'");
}
}
}

View File

@ -18,6 +18,8 @@ class ProtocolConfig {
private static final String METRICS_ENABLED = "metrics";
private static final String IGNORE_VERSION_CHECK = "ignore version check";
private static final String BACKGROUND_COMPILER_ENABLED = "background compiler";
private static final String UPDATER_NOTIFY = "notify";
@ -149,6 +151,26 @@ class ProtocolConfig {
return updater.getLong(UPDATER_LAST_TIME, 0);
}
/**
* The version of Minecraft to ignore the built-in safety feature.
* @return The version to ignore ProtocolLib's satefy.
*/
public String getIgnoreVersionCheck() {
return global.getString(IGNORE_VERSION_CHECK, "");
}
/**
* Sets under which version of Minecraft the version safety feature will be ignored.
* <p>
* This is useful if a server operator has tested and verified that a version of ProtocolLib works,
* but doesn't want or can't upgrade to a newer version.
*
* @param ignoreVersion - the version of Minecraft where the satefy will be disabled.
*/
public void setIgnoreVersionCheck(String ignoreVersion) {
global.set(IGNORE_VERSION_CHECK, ignoreVersion);
}
/**
* Retrieve whether or not metrics is enabled.
* @return TRUE if metrics is enabled, FALSE otherwise.

View File

@ -43,6 +43,15 @@ import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
* @author Kristian
*/
public class ProtocolLibrary extends JavaPlugin {
/**
* The minimum version ProtocolLib has been tested with.
*/
private static final String MINIMUM_MINECRAFT_VERSION = "1.0.0";
/**
* The maximum version ProtocolLib has been tested with,
*/
private static final String MAXIMUM_MINECRAFT_VERSION = "1.4.5";
/**
* The number of milliseconds per second.
@ -188,13 +197,13 @@ public class ProtocolLibrary extends JavaPlugin {
logger.info("Structure compiler thread has been disabled.");
}
// Handle unexpected Minecraft versions
verifyMinecraftVersion();
// Set up command handlers
registerCommand(CommandProtocol.NAME, commandProtocol);
registerCommand(CommandPacket.NAME, commandPacket);
// Notify server managers of incompatible plugins
checkForIncompatibility(manager);
// Player login and logout events
protocolManager.registerEvents(manager, this);
@ -220,6 +229,26 @@ public class ProtocolLibrary extends JavaPlugin {
}
}
// Used to check Minecraft version
private void verifyMinecraftVersion() {
try {
MinecraftVersion minimum = new MinecraftVersion(MINIMUM_MINECRAFT_VERSION);
MinecraftVersion maximum = new MinecraftVersion(MAXIMUM_MINECRAFT_VERSION);
MinecraftVersion current = new MinecraftVersion(getServer());
// Skip certain versions
if (!config.getIgnoreVersionCheck().equals(current.toString())) {
// We'll just warn the user for now
if (current.compareTo(minimum) < 0)
reporter.reportWarning(this, "Version " + current + " is lower than the minimum " + minimum);
if (current.compareTo(maximum) > 0)
reporter.reportWarning(this, "Version " + current + " has not yet been tested! Proceed with caution.");
}
} catch (Exception e) {
reporter.reportWarning(this, "Unable to retrieve current Minecraft version.", e);
}
}
private void registerCommand(String name, CommandExecutor executor) {
try {
if (executor == null)
@ -296,18 +325,6 @@ public class ProtocolLibrary extends JavaPlugin {
}
}
private void checkForIncompatibility(PluginManager manager) {
// Plugin authors: Notify me to remove these
String[] incompatiblePlugins = {};
for (String plugin : incompatiblePlugins) {
if (manager.getPlugin(plugin) != null) {
// Check for versions, ect.
reporter.reportWarning(this, "Detected incompatible plugin: " + plugin);
}
}
}
@Override
public void onDisable() {
// Disable compiler

View File

@ -26,7 +26,7 @@ public class MinecraftReflection {
/**
* The package name of all the classes that belongs to the native code in Minecraft.
*/
private static String MINECRAFT_SERVER_PACKAGE = "net.minecraft.server";
private static String MINECRAFT_PREFIX_PACKAGE = "net.minecraft.server";
private static String MINECRAFT_FULL_PACKAGE = null;
private static String CRAFTBUKKIT_PACKAGE = null;
@ -74,7 +74,7 @@ public class MinecraftReflection {
}
} else {
throw new IllegalStateException("Cannot find Bukkit. Is it running?");
throw new IllegalStateException("Could not find Bukkit. Is it running?");
}
}
@ -117,7 +117,7 @@ public class MinecraftReflection {
throw new IllegalArgumentException("Cannot determine the type of a null object.");
// Doesn't matter if we don't check for the version here
return obj.getClass().getName().startsWith(MINECRAFT_SERVER_PACKAGE);
return obj.getClass().getName().startsWith(MINECRAFT_PREFIX_PACKAGE);
}
/**
@ -131,7 +131,7 @@ public class MinecraftReflection {
throw new IllegalArgumentException("Cannot determine the type of a null object.");
String javaName = obj.getClass().getName();
return javaName.startsWith(MINECRAFT_SERVER_PACKAGE) && javaName.endsWith(className);
return javaName.startsWith(MINECRAFT_PREFIX_PACKAGE) && javaName.endsWith(className);
}
/**

View File

@ -0,0 +1,27 @@
package com.comphenix.protocol;
import static org.junit.Assert.*;
import org.junit.Test;
public class MinecraftVersionTest {
@Test
public void testComparision() {
MinecraftVersion within = new MinecraftVersion(1, 2, 5);
MinecraftVersion outside = new MinecraftVersion(1, 7, 0);
MinecraftVersion lower = new MinecraftVersion(1, 0, 0);
MinecraftVersion highest = new MinecraftVersion(1, 4, 5);
// Make sure this is valid
assertTrue(lower.compareTo(within) < 0 && within.compareTo(highest) < 0);
assertFalse(outside.compareTo(within) < 0 && outside.compareTo(highest) < 0);
}
public void testParsing() {
assertEquals(MinecraftVersion.extractVersion("CraftBukkit R3.0 (MC: 1.4.3)"), "1.4.3");
assertEquals(MinecraftVersion.extractVersion("CraftBukkit Test Beta 1 (MC: 1.10.01 )"), "1.10.01");
assertEquals(MinecraftVersion.extractVersion("Hello (MC: 2.3.4 ) "), "2.3.4");
}
}