Refactor the report system. Allow identification of report messages.
All warnings and error messages will now be identified using fields in the sender classes, to avoid depending on the format of the error or warning messages directly. This decoupling will make it possible to filter out certain irrelevant messages.
Dieser Commit ist enthalten in:
Ursprung
7e18207a2b
Commit
40a3abf5b9
@ -24,6 +24,8 @@ import java.util.List;
|
|||||||
|
|
||||||
import com.comphenix.protocol.async.AsyncListenerHandler;
|
import com.comphenix.protocol.async.AsyncListenerHandler;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||||
@ -51,6 +53,9 @@ import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class CleanupStaticMembers {
|
class CleanupStaticMembers {
|
||||||
|
// Reports
|
||||||
|
public final static ReportType REPORT_CANNOT_RESET_FIELD = new ReportType("Unable to reset field %s: %s");
|
||||||
|
public final static ReportType REPORT_CANNOT_UNLOAD_CLASS = new ReportType("Unable to unload class %s.");
|
||||||
|
|
||||||
private ClassLoader loader;
|
private ClassLoader loader;
|
||||||
private ErrorReporter reporter;
|
private ErrorReporter reporter;
|
||||||
@ -116,7 +121,9 @@ class CleanupStaticMembers {
|
|||||||
setFinalStatic(field, null);
|
setFinalStatic(field, null);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
// Just inform the player
|
// Just inform the player
|
||||||
reporter.reportWarning(this, "Unable to reset field " + field.getName() + ": " + e.getMessage(), e);
|
reporter.reportWarning(this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_RESET_FIELD).error(e).messageParam(field.getName(), e.getMessage())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +158,7 @@ class CleanupStaticMembers {
|
|||||||
output.add(loader.loadClass(name));
|
output.add(loader.loadClass(name));
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
// Warn the user
|
// Warn the user
|
||||||
reporter.reportWarning(this, "Unable to unload class " + name, e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_UNLOAD_CLASS).error(e).messageParam(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ import org.bukkit.command.CommandExecutor;
|
|||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all our commands.
|
* Base class for all our commands.
|
||||||
@ -30,6 +32,8 @@ import com.comphenix.protocol.error.ErrorReporter;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
abstract class CommandBase implements CommandExecutor {
|
abstract class CommandBase implements CommandExecutor {
|
||||||
|
public static final ReportType REPORT_COMMAND_ERROR = new ReportType("Cannot execute command %s.");
|
||||||
|
public static final ReportType REPORT_UNEXPECTED_COMMAND = new ReportType("Incorrect command assigned to %s.");
|
||||||
|
|
||||||
public static final String PERMISSION_ADMIN = "protocol.admin";
|
public static final String PERMISSION_ADMIN = "protocol.admin";
|
||||||
|
|
||||||
@ -55,7 +59,7 @@ abstract class CommandBase implements CommandExecutor {
|
|||||||
try {
|
try {
|
||||||
// Make sure we're dealing with the correct command
|
// Make sure we're dealing with the correct command
|
||||||
if (!command.getName().equalsIgnoreCase(name)) {
|
if (!command.getName().equalsIgnoreCase(name)) {
|
||||||
reporter.reportWarning(this, "Incorrect command assigned to " + this);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_UNEXPECTED_COMMAND).messageParam(this));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (permission != null && !sender.hasPermission(permission)) {
|
if (permission != null && !sender.hasPermission(permission)) {
|
||||||
@ -72,7 +76,9 @@ abstract class CommandBase implements CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reporter.reportDetailed(this, "Cannot execute command " + name, e, sender, label, args);
|
reporter.reportDetailed(this,
|
||||||
|
Report.newBuilder(REPORT_COMMAND_ERROR).error(e).messageParam(name).callerParam(sender, label, args)
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@ import org.bukkit.plugin.Plugin;
|
|||||||
import com.comphenix.protocol.MultipleLinesPrompt.MultipleConversationCanceller;
|
import com.comphenix.protocol.MultipleLinesPrompt.MultipleConversationCanceller;
|
||||||
import com.comphenix.protocol.concurrency.IntegerSet;
|
import com.comphenix.protocol.concurrency.IntegerSet;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.google.common.collect.DiscreteDomains;
|
import com.google.common.collect.DiscreteDomains;
|
||||||
import com.google.common.collect.Range;
|
import com.google.common.collect.Range;
|
||||||
@ -35,6 +37,12 @@ import com.google.common.collect.Ranges;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class CommandFilter extends CommandBase {
|
public class CommandFilter extends CommandBase {
|
||||||
|
public static final ReportType REPORT_FALLBACK_ENGINE = new ReportType("Falling back to the Rhino engine.");
|
||||||
|
public static final ReportType REPORT_CANNOT_LOAD_FALLBACK_ENGINE = new ReportType("Could not load Rhino either. Please upgrade your JVM or OS.");
|
||||||
|
public static final ReportType REPORT_PACKAGES_UNSUPPORTED_IN_ENGINE = new ReportType("Unable to initialize packages for JavaScript engine.");
|
||||||
|
public static final ReportType REPORT_FILTER_REMOVED_FOR_ERROR = new ReportType("Removing filter %s for causing %s.");
|
||||||
|
public static final ReportType REPORT_CANNOT_HANDLE_CONVERSATION = new ReportType("Cannot handle conversation.");
|
||||||
|
|
||||||
public interface FilterFailedHandler{
|
public interface FilterFailedHandler{
|
||||||
/**
|
/**
|
||||||
* Invoked when a given filter has failed.
|
* Invoked when a given filter has failed.
|
||||||
@ -236,7 +244,7 @@ public class CommandFilter extends CommandBase {
|
|||||||
printPackageWarning(e1);
|
printPackageWarning(e1);
|
||||||
|
|
||||||
if (!config.getScriptEngineName().equals("rhino")) {
|
if (!config.getScriptEngineName().equals("rhino")) {
|
||||||
reporter.reportWarning(this, "Falling back to the Rhino engine.");
|
reporter.reportWarning(this, Report.newBuilder(REPORT_FALLBACK_ENGINE));
|
||||||
config.setScriptEngineName("rhino");
|
config.setScriptEngineName("rhino");
|
||||||
config.saveAll();
|
config.saveAll();
|
||||||
|
|
||||||
@ -244,7 +252,7 @@ public class CommandFilter extends CommandBase {
|
|||||||
initializeEngine();
|
initializeEngine();
|
||||||
|
|
||||||
if (!isInitialized()) {
|
if (!isInitialized()) {
|
||||||
reporter.reportWarning(this, "Could not load Rhino either. Please upgrade your JVM or OS.");
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_FALLBACK_ENGINE));
|
||||||
}
|
}
|
||||||
} catch (ScriptException e2) {
|
} catch (ScriptException e2) {
|
||||||
// And again ..
|
// And again ..
|
||||||
@ -255,7 +263,7 @@ public class CommandFilter extends CommandBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void printPackageWarning(ScriptException e) {
|
private void printPackageWarning(ScriptException e) {
|
||||||
reporter.reportWarning(this, "Unable to initialize packages for JavaScript engine.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_PACKAGES_UNSUPPORTED_IN_ENGINE).error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -288,7 +296,9 @@ public class CommandFilter extends CommandBase {
|
|||||||
@Override
|
@Override
|
||||||
public boolean handle(PacketEvent event, Filter filter, Exception ex) {
|
public boolean handle(PacketEvent event, Filter filter, Exception ex) {
|
||||||
reporter.reportMinimal(plugin, "filterEvent(PacketEvent)", ex, event);
|
reporter.reportMinimal(plugin, "filterEvent(PacketEvent)", ex, event);
|
||||||
reporter.reportWarning(this, "Removing filter " + filter.getName() + " for causing an exception.");
|
reporter.reportWarning(this,
|
||||||
|
Report.newBuilder(REPORT_FILTER_REMOVED_FOR_ERROR).messageParam(filter.getName(), ex.getClass().getSimpleName())
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -398,7 +408,9 @@ public class CommandFilter extends CommandBase {
|
|||||||
whom.sendRawMessage(ChatColor.RED + "Cancelled filter.");
|
whom.sendRawMessage(ChatColor.RED + "Cancelled filter.");
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reporter.reportDetailed(this, "Cannot handle conversation.", e, event);
|
reporter.reportDetailed(this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_HANDLE_CONVERSATION).error(e).callerParam(event)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).
|
}).
|
||||||
|
@ -36,6 +36,8 @@ import org.bukkit.plugin.Plugin;
|
|||||||
|
|
||||||
import com.comphenix.protocol.concurrency.AbstractIntervalTree;
|
import com.comphenix.protocol.concurrency.AbstractIntervalTree;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.events.ConnectionSide;
|
import com.comphenix.protocol.events.ConnectionSide;
|
||||||
import com.comphenix.protocol.events.ListenerPriority;
|
import com.comphenix.protocol.events.ListenerPriority;
|
||||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||||
@ -57,6 +59,7 @@ import com.google.common.collect.Sets;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class CommandPacket extends CommandBase {
|
class CommandPacket extends CommandBase {
|
||||||
|
public static final ReportType REPORT_CANNOT_SEND_MESSAGE = new ReportType("Cannot send chat message.");
|
||||||
|
|
||||||
private interface DetailedPacketListener extends PacketListener {
|
private interface DetailedPacketListener extends PacketListener {
|
||||||
/**
|
/**
|
||||||
@ -166,7 +169,9 @@ class CommandPacket extends CommandBase {
|
|||||||
try {
|
try {
|
||||||
chatter.sendMessageSilently(receiver, message);
|
chatter.sendMessageSilently(receiver, message);
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
reporter.reportDetailed(this, "Cannot send chat message.", e, receiver, message);
|
reporter.reportDetailed(this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_SEND_MESSAGE).error(e).callerParam(receiver, message)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +184,9 @@ class CommandPacket extends CommandBase {
|
|||||||
try {
|
try {
|
||||||
chatter.broadcastMessageSilently(message, permission);
|
chatter.broadcastMessageSilently(message, permission);
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
reporter.reportDetailed(this, "Cannot send chat message.", e, message, permission);
|
reporter.reportDetailed(this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_SEND_MESSAGE).error(e).callerParam(message, permission)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ import org.bukkit.command.CommandSender;
|
|||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.metrics.Updater;
|
import com.comphenix.protocol.metrics.Updater;
|
||||||
import com.comphenix.protocol.metrics.Updater.UpdateResult;
|
import com.comphenix.protocol.metrics.Updater.UpdateResult;
|
||||||
import com.comphenix.protocol.metrics.Updater.UpdateType;
|
import com.comphenix.protocol.metrics.Updater.UpdateType;
|
||||||
@ -40,6 +42,10 @@ class CommandProtocol extends CommandBase {
|
|||||||
*/
|
*/
|
||||||
public static final String NAME = "protocol";
|
public static final String NAME = "protocol";
|
||||||
|
|
||||||
|
public static final ReportType REPORT_HTTP_ERROR = new ReportType("Http error: %s");
|
||||||
|
public static final ReportType REPORT_CANNOT_CHECK_FOR_UPDATES = new ReportType("Cannot check updates for ProtocolLib.");
|
||||||
|
public static final ReportType REPORT_CANNOT_UPDATE_PLUGIN = new ReportType("Cannot update ProtocolLib.");
|
||||||
|
|
||||||
private Plugin plugin;
|
private Plugin plugin;
|
||||||
private Updater updater;
|
private Updater updater;
|
||||||
private ProtocolConfig config;
|
private ProtocolConfig config;
|
||||||
@ -77,9 +83,11 @@ class CommandProtocol extends CommandBase {
|
|||||||
sender.sendMessage(ChatColor.BLUE + "[ProtocolLib] " + result.toString());
|
sender.sendMessage(ChatColor.BLUE + "[ProtocolLib] " + result.toString());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (isHttpError(e)) {
|
if (isHttpError(e)) {
|
||||||
getReporter().reportWarning(this, "Http error: " + e.getCause().getMessage());
|
getReporter().reportWarning(this,
|
||||||
|
Report.newBuilder(REPORT_HTTP_ERROR).messageParam(e.getCause().getMessage())
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
getReporter().reportDetailed(this, "Cannot check updates for ProtocolLib.", e, sender);
|
getReporter().reportDetailed(this, Report.newBuilder(REPORT_CANNOT_CHECK_FOR_UPDATES).error(e).callerParam(sender));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,9 +106,11 @@ class CommandProtocol extends CommandBase {
|
|||||||
sender.sendMessage(ChatColor.BLUE + "[ProtocolLib] " + result.toString());
|
sender.sendMessage(ChatColor.BLUE + "[ProtocolLib] " + result.toString());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (isHttpError(e)) {
|
if (isHttpError(e)) {
|
||||||
getReporter().reportWarning(this, "Http error: " + e.getCause().getMessage());
|
getReporter().reportWarning(this,
|
||||||
|
Report.newBuilder(REPORT_HTTP_ERROR).messageParam(e.getCause().getMessage())
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
getReporter().reportDetailed(this, "Cannot update ProtocolLib.", e, sender);
|
getReporter().reportDetailed(this,Report.newBuilder(REPORT_CANNOT_UPDATE_PLUGIN).error(e).callerParam(sender));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||||||
import com.comphenix.protocol.async.AsyncFilterManager;
|
import com.comphenix.protocol.async.AsyncFilterManager;
|
||||||
import com.comphenix.protocol.error.DetailedErrorReporter;
|
import com.comphenix.protocol.error.DetailedErrorReporter;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.injector.DelayedSingleTask;
|
import com.comphenix.protocol.injector.DelayedSingleTask;
|
||||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||||
@ -51,6 +53,24 @@ import com.comphenix.protocol.utility.MinecraftVersion;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class ProtocolLibrary extends JavaPlugin {
|
public class ProtocolLibrary extends JavaPlugin {
|
||||||
|
// Every possible error or warning report type
|
||||||
|
public static final ReportType REPORT_CANNOT_LOAD_CONFIG = new ReportType("Cannot load configuration");
|
||||||
|
public static final ReportType REPORT_CANNOT_DELETE_CONFIG = new ReportType("Cannot delete old ProtocolLib configuration.");
|
||||||
|
public static final ReportType REPORT_CANNOT_PARSE_INJECTION_METHOD = new ReportType("Cannot parse injection method. Using default.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_PLUGIN_LOAD_ERROR = new ReportType("Cannot load ProtocolLib.");
|
||||||
|
public static final ReportType REPORT_PLUGIN_ENABLE_ERROR = new ReportType("Cannot enable ProtocolLib.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_METRICS_IO_ERROR = new ReportType("Unable to enable metrics due to network problems.");
|
||||||
|
public static final ReportType REPORT_METRICS_GENERIC_ERROR = new ReportType("Unable to enable metrics due to network problems.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_CANNOT_PARSE_MINECRAFT_VERSION = new ReportType("Unable to retrieve current Minecraft version.");
|
||||||
|
public static final ReportType REPORT_CANNOT_DETECT_CONFLICTING_PLUGINS = new ReportType("Unable to detect conflicting plugin versions.");
|
||||||
|
public static final ReportType REPORT_CANNOT_REGISTER_COMMAND = new ReportType("Cannot register command %s: %s");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_CANNOT_CREATE_TIMEOUT_TASK = new ReportType("Unable to create packet timeout task.");
|
||||||
|
public static final ReportType REPORT_CANNOT_UPDATE_PLUGIN = new ReportType("Cannot perform automatic updates.");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The minimum version ProtocolLib has been tested with.
|
* The minimum version ProtocolLib has been tested with.
|
||||||
*/
|
*/
|
||||||
@ -120,13 +140,13 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
try {
|
try {
|
||||||
config = new ProtocolConfig(this);
|
config = new ProtocolConfig(this);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
detailedReporter.reportWarning(this, "Cannot load configuration", e);
|
detailedReporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_CONFIG).error(e));
|
||||||
|
|
||||||
// Load it again
|
// Load it again
|
||||||
if (deleteConfig()) {
|
if (deleteConfig()) {
|
||||||
config = new ProtocolConfig(this);
|
config = new ProtocolConfig(this);
|
||||||
} else {
|
} else {
|
||||||
reporter.reportWarning(this, "Cannot delete old ProtocolLib configuration.");
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_DELETE_CONFIG));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +182,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
protocolManager.setPlayerHook(hook);
|
protocolManager.setPlayerHook(hook);
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
detailedReporter.reportWarning(config, "Cannot parse injection method. Using default.", e);
|
detailedReporter.reportWarning(config, Report.newBuilder(REPORT_CANNOT_PARSE_INJECTION_METHOD).error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize command handlers
|
// Initialize command handlers
|
||||||
@ -174,7 +194,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
setupBroadcastUsers(PERMISSION_INFO);
|
setupBroadcastUsers(PERMISSION_INFO);
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
detailedReporter.reportDetailed(this, "Cannot load ProtocolLib.", e, protocolManager);
|
detailedReporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_LOAD_ERROR).error(e).callerParam(protocolManager));
|
||||||
disablePlugin();
|
disablePlugin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,7 +293,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
createAsyncTask(server);
|
createAsyncTask(server);
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
reporter.reportDetailed(this, "Cannot enable ProtocolLib.", e);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_ENABLE_ERROR).error(e));
|
||||||
disablePlugin();
|
disablePlugin();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -284,9 +304,9 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
statistisc = new Statistics(this);
|
statistisc = new Statistics(this);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
reporter.reportDetailed(this, "Unable to enable metrics.", e, statistisc);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_METRICS_IO_ERROR).error(e).callerParam(statistisc));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
reporter.reportDetailed(this, "Metrics cannot be enabled. Incompatible Bukkit version.", e, statistisc);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_METRICS_GENERIC_ERROR).error(e).callerParam(statistisc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +328,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
return current;
|
return current;
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reporter.reportWarning(this, "Unable to retrieve current Minecraft version.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_PARSE_MINECRAFT_VERSION).error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unknown version
|
// Unknown version
|
||||||
@ -345,7 +365,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reporter.reportWarning(this, "Unable to detect conflicting plugin versions.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_DETECT_CONFLICTING_PLUGINS).error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if the newest version is actually higher
|
// See if the newest version is actually higher
|
||||||
@ -374,7 +394,9 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
throw new RuntimeException("plugin.yml might be corrupt.");
|
throw new RuntimeException("plugin.yml might be corrupt.");
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
reporter.reportWarning(this, "Cannot register command " + name + ": " + e.getMessage());
|
reporter.reportWarning(this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_REGISTER_COMMAND).messageParam(name, e.getMessage()).error(e)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +430,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
if (asyncPacketTask == -1) {
|
if (asyncPacketTask == -1) {
|
||||||
reporter.reportDetailed(this, "Unable to create packet timeout task.", e);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_CREATE_TIMEOUT_TASK).error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -431,7 +453,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
commandProtocol.updateFinished();
|
commandProtocol.updateFinished();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reporter.reportDetailed(this, "Cannot perform automatic updates.", e);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLUGIN).error(e));
|
||||||
updateDisabled = true;
|
updateDisabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import org.apache.commons.lang.builder.ToStringStyle;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.error.Report.ReportBuilder;
|
||||||
import com.comphenix.protocol.events.PacketAdapter;
|
import com.comphenix.protocol.events.PacketAdapter;
|
||||||
import com.comphenix.protocol.reflect.PrettyPrinter;
|
import com.comphenix.protocol.reflect.PrettyPrinter;
|
||||||
import com.google.common.primitives.Primitives;
|
import com.google.common.primitives.Primitives;
|
||||||
@ -44,11 +45,14 @@ import com.google.common.primitives.Primitives;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class DetailedErrorReporter implements ErrorReporter {
|
public class DetailedErrorReporter implements ErrorReporter {
|
||||||
|
/**
|
||||||
|
* Report format for printing the current exception count.
|
||||||
|
*/
|
||||||
|
public static final ReportType REPORT_EXCEPTION_COUNT = new ReportType("Internal exception count: %s!");
|
||||||
|
|
||||||
public static final String SECOND_LEVEL_PREFIX = " ";
|
public static final String SECOND_LEVEL_PREFIX = " ";
|
||||||
public static final String DEFAULT_PREFIX = " ";
|
public static final String DEFAULT_PREFIX = " ";
|
||||||
public static final String DEFAULT_SUPPORT_URL = "http://dev.bukkit.org/server-mods/protocollib/";
|
public static final String DEFAULT_SUPPORT_URL = "http://dev.bukkit.org/server-mods/protocollib/";
|
||||||
public static final String PLUGIN_NAME = "ProtocolLib";
|
|
||||||
|
|
||||||
// Users that are informed about errors in the chat
|
// Users that are informed about errors in the chat
|
||||||
public static final String ERROR_PERMISSION = "protocol.info";
|
public static final String ERROR_PERMISSION = "protocol.info";
|
||||||
@ -68,6 +72,7 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
protected Logger logger;
|
protected Logger logger;
|
||||||
|
|
||||||
protected WeakReference<Plugin> pluginReference;
|
protected WeakReference<Plugin> pluginReference;
|
||||||
|
protected String pluginName;
|
||||||
|
|
||||||
// Whether or not Apache Commons is not present
|
// Whether or not Apache Commons is not present
|
||||||
protected boolean apacheCommonsMissing;
|
protected boolean apacheCommonsMissing;
|
||||||
@ -92,15 +97,6 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
this(plugin, prefix, supportURL, DEFAULT_MAX_ERROR_COUNT, getBukkitLogger());
|
this(plugin, prefix, supportURL, DEFAULT_MAX_ERROR_COUNT, getBukkitLogger());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to get the logger.
|
|
||||||
private static Logger getBukkitLogger() {
|
|
||||||
try {
|
|
||||||
return Bukkit.getLogger();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
return Logger.getLogger("Minecraft");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a central error reporting system.
|
* Create a central error reporting system.
|
||||||
* @param plugin - the plugin owner.
|
* @param plugin - the plugin owner.
|
||||||
@ -114,23 +110,28 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
throw new IllegalArgumentException("Plugin cannot be NULL.");
|
throw new IllegalArgumentException("Plugin cannot be NULL.");
|
||||||
|
|
||||||
this.pluginReference = new WeakReference<Plugin>(plugin);
|
this.pluginReference = new WeakReference<Plugin>(plugin);
|
||||||
|
this.pluginName = plugin.getName();
|
||||||
this.prefix = prefix;
|
this.prefix = prefix;
|
||||||
this.supportURL = supportURL;
|
this.supportURL = supportURL;
|
||||||
this.maxErrorCount = maxErrorCount;
|
this.maxErrorCount = maxErrorCount;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attempt to get the logger.
|
||||||
|
private static Logger getBukkitLogger() {
|
||||||
|
try {
|
||||||
|
return Bukkit.getLogger();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
return Logger.getLogger("Minecraft");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) {
|
public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) {
|
||||||
if (reportMinimalNoSpam(sender, methodName, error)) {
|
if (reportMinimalNoSpam(sender, methodName, error)) {
|
||||||
// Print parameters, if they are given
|
// Print parameters, if they are given
|
||||||
if (parameters != null && parameters.length > 0) {
|
if (parameters != null && parameters.length > 0) {
|
||||||
logger.log(Level.SEVERE, " Parameters:");
|
logger.log(Level.SEVERE, printParameters(parameters));
|
||||||
|
|
||||||
// Print each parameter
|
|
||||||
for (Object parameter : parameters) {
|
|
||||||
logger.log(Level.SEVERE, " " + getStringDescription(parameter));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,14 +159,14 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
|
|
||||||
// See if we should print the full error
|
// See if we should print the full error
|
||||||
if (errorCount < getMaxErrorCount()) {
|
if (errorCount < getMaxErrorCount()) {
|
||||||
logger.log(Level.SEVERE, "[" + PLUGIN_NAME + "] Unhandled exception occured in " +
|
logger.log(Level.SEVERE, "[" + pluginName + "] Unhandled exception occured in " +
|
||||||
methodName + " for " + pluginName, error);
|
methodName + " for " + pluginName, error);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Nope - only print the error count occationally
|
// Nope - only print the error count occationally
|
||||||
if (isPowerOfTwo(errorCount)) {
|
if (isPowerOfTwo(errorCount)) {
|
||||||
logger.log(Level.SEVERE, "[" + PLUGIN_NAME + "] Unhandled exception number " + errorCount + " occured in " +
|
logger.log(Level.SEVERE, "[" + pluginName + "] Unhandled exception number " + errorCount + " occured in " +
|
||||||
methodName + " for " + pluginName, error);
|
methodName + " for " + pluginName, error);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -184,15 +185,36 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reportWarning(Object sender, String message) {
|
public void reportWarning(Object sender, ReportBuilder reportBuilder) {
|
||||||
logger.log(Level.WARNING, "[" + PLUGIN_NAME + "] [" + getSenderName(sender) + "] " + message);
|
if (reportBuilder == null)
|
||||||
|
throw new IllegalArgumentException("reportBuilder cannot be NULL.");
|
||||||
|
|
||||||
|
reportWarning(sender, reportBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reportWarning(Object sender, String message, Throwable error) {
|
public void reportWarning(Object sender, Report report) {
|
||||||
logger.log(Level.WARNING, "[" + PLUGIN_NAME + "] [" + getSenderName(sender) + "] " + message, error);
|
String message = "[" + pluginName + "] [" + getSenderName(sender) + "] " + report.getReportMessage();
|
||||||
|
|
||||||
|
// Print the main warning
|
||||||
|
if (report.getException() != null) {
|
||||||
|
logger.log(Level.WARNING, message, report.getException());
|
||||||
|
} else {
|
||||||
|
logger.log(Level.WARNING, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameters?
|
||||||
|
if (report.hasCallerParameters()) {
|
||||||
|
// Write it
|
||||||
|
logger.log(Level.WARNING, printParameters(report.getCallerParameters()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the name of a sender class.
|
||||||
|
* @param sender - sender object.
|
||||||
|
* @return The name of the sender's class.
|
||||||
|
*/
|
||||||
private String getSenderName(Object sender) {
|
private String getSenderName(Object sender) {
|
||||||
if (sender != null)
|
if (sender != null)
|
||||||
return sender.getClass().getSimpleName();
|
return sender.getClass().getSimpleName();
|
||||||
@ -201,8 +223,12 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reportDetailed(Object sender, String message, Throwable error, Object... parameters) {
|
public void reportDetailed(Object sender, ReportBuilder reportBuilder) {
|
||||||
|
reportDetailed(sender, reportBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reportDetailed(Object sender, Report report) {
|
||||||
final Plugin plugin = pluginReference.get();
|
final Plugin plugin = pluginReference.get();
|
||||||
final int errorCount = internalErrorCount.incrementAndGet();
|
final int errorCount = internalErrorCount.incrementAndGet();
|
||||||
|
|
||||||
@ -211,7 +237,7 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
// Only allow the error count at rare occations
|
// Only allow the error count at rare occations
|
||||||
if (isPowerOfTwo(errorCount)) {
|
if (isPowerOfTwo(errorCount)) {
|
||||||
// Permit it - but print the number of exceptions first
|
// Permit it - but print the number of exceptions first
|
||||||
reportWarning(this, "Internal exception count: " + errorCount + "!");
|
reportWarning(this, Report.newBuilder(REPORT_EXCEPTION_COUNT).messageParam(errorCount).build());
|
||||||
} else {
|
} else {
|
||||||
// NEVER SPAM THE CONSOLE
|
// NEVER SPAM THE CONSOLE
|
||||||
return;
|
return;
|
||||||
@ -222,27 +248,23 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
PrintWriter writer = new PrintWriter(text);
|
PrintWriter writer = new PrintWriter(text);
|
||||||
|
|
||||||
// Helpful message
|
// Helpful message
|
||||||
writer.println("[ProtocolLib] INTERNAL ERROR: " + message);
|
writer.println("[" + pluginName + "] INTERNAL ERROR: " + report.getReportMessage());
|
||||||
writer.println("If this problem hasn't already been reported, please open a ticket");
|
writer.println("If this problem hasn't already been reported, please open a ticket");
|
||||||
writer.println("at " + supportURL + " with the following data:");
|
writer.println("at " + supportURL + " with the following data:");
|
||||||
|
|
||||||
// Now, let us print important exception information
|
// Now, let us print important exception information
|
||||||
writer.println(" ===== STACK TRACE =====");
|
writer.println(" ===== STACK TRACE =====");
|
||||||
|
|
||||||
if (error != null)
|
if (report.getException() != null) {
|
||||||
error.printStackTrace(writer);
|
report.getException().printStackTrace(writer);
|
||||||
|
}
|
||||||
|
|
||||||
// Data dump!
|
// Data dump!
|
||||||
writer.println(" ===== DUMP =====");
|
writer.println(" ===== DUMP =====");
|
||||||
|
|
||||||
// Relevant parameters
|
// Relevant parameters
|
||||||
if (parameters != null && parameters.length > 0) {
|
if (report.hasCallerParameters()) {
|
||||||
writer.println("Parameters:");
|
printParameters(writer, report.getCallerParameters());
|
||||||
|
|
||||||
// We *really* want to get as much information as possible
|
|
||||||
for (Object param : parameters) {
|
|
||||||
writer.println(addPrefix(getStringDescription(param), SECOND_LEVEL_PREFIX));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global parameters
|
// Global parameters
|
||||||
@ -270,7 +292,7 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
// Inform of this occurrence
|
// Inform of this occurrence
|
||||||
if (ERROR_PERMISSION != null) {
|
if (ERROR_PERMISSION != null) {
|
||||||
Bukkit.getServer().broadcast(
|
Bukkit.getServer().broadcast(
|
||||||
String.format("Error %s (%s) occured in %s.", message, error, sender),
|
String.format("Error %s (%s) occured in %s.", report.getReportMessage(), report.getException(), sender),
|
||||||
ERROR_PERMISSION
|
ERROR_PERMISSION
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -280,6 +302,23 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
logger.severe(addPrefix(text.toString(), prefix));
|
logger.severe(addPrefix(text.toString(), prefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String printParameters(Object... parameters) {
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
|
||||||
|
// Print and retrieve the string buffer
|
||||||
|
printParameters(new PrintWriter(writer), parameters);
|
||||||
|
return writer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printParameters(PrintWriter writer, Object[] parameters) {
|
||||||
|
writer.println("Parameters: ");
|
||||||
|
|
||||||
|
// We *really* want to get as much information as possible
|
||||||
|
for (Object param : parameters) {
|
||||||
|
writer.println(addPrefix(getStringDescription(param), SECOND_LEVEL_PREFIX));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given prefix to every line in the text.
|
* Adds the given prefix to every line in the text.
|
||||||
* @param text - text to modify.
|
* @param text - text to modify.
|
||||||
@ -290,6 +329,11 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
return text.replaceAll("(?m)^", prefix);
|
return text.replaceAll("(?m)^", prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a string representation of the given object.
|
||||||
|
* @param value - object to convert.
|
||||||
|
* @return String representation.
|
||||||
|
*/
|
||||||
protected String getStringDescription(Object value) {
|
protected String getStringDescription(Object value) {
|
||||||
|
|
||||||
// We can't only rely on toString.
|
// We can't only rely on toString.
|
||||||
|
@ -19,8 +19,9 @@ package com.comphenix.protocol.error;
|
|||||||
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
public interface ErrorReporter {
|
import com.comphenix.protocol.error.Report.ReportBuilder;
|
||||||
|
|
||||||
|
public interface ErrorReporter {
|
||||||
/**
|
/**
|
||||||
* Prints a small minimal error report about an exception from another plugin.
|
* Prints a small minimal error report about an exception from another plugin.
|
||||||
* @param sender - the other plugin.
|
* @param sender - the other plugin.
|
||||||
@ -41,25 +42,28 @@ public interface ErrorReporter {
|
|||||||
/**
|
/**
|
||||||
* Prints a warning message from the current plugin.
|
* Prints a warning message from the current plugin.
|
||||||
* @param sender - the object containing the caller method.
|
* @param sender - the object containing the caller method.
|
||||||
* @param message - error message.
|
* @param report - an error report to include.
|
||||||
*/
|
*/
|
||||||
public abstract void reportWarning(Object sender, String message);
|
public abstract void reportWarning(Object sender, Report report);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints a warning message from the current plugin.
|
* Prints a warning message from the current plugin.
|
||||||
* @param sender - the object containing the caller method.
|
* @param sender - the object containing the caller method.
|
||||||
* @param message - error message.
|
* @param reportBuilder - an error report builder that will be used to get the report.
|
||||||
* @param error - the exception that was thrown.
|
|
||||||
*/
|
*/
|
||||||
public abstract void reportWarning(Object sender, String message, Throwable error);
|
public abstract void reportWarning(Object sender, ReportBuilder reportBuilder);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints a detailed error report about an unhandled exception.
|
* Prints a detailed error report about an unhandled exception.
|
||||||
* @param sender - the object containing the caller method.
|
* @param sender - the object containing the caller method.
|
||||||
* @param message - an error message to include.
|
* @param report - an error report to include.
|
||||||
* @param error - the exception that was thrown in the caller method.
|
|
||||||
* @param parameters - parameters from the caller method.
|
|
||||||
*/
|
*/
|
||||||
public abstract void reportDetailed(Object sender, String message, Throwable error, Object... parameters);
|
public abstract void reportDetailed(Object sender, Report report);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a detailed error report about an unhandled exception.
|
||||||
|
* @param sender - the object containing the caller method.
|
||||||
|
* @param reportBuilder - an error report builder that will be used to get the report.
|
||||||
|
*/
|
||||||
|
public abstract void reportDetailed(Object sender, ReportBuilder reportBuilder);
|
||||||
}
|
}
|
162
ProtocolLib/src/main/java/com/comphenix/protocol/error/Report.java
Normale Datei
162
ProtocolLib/src/main/java/com/comphenix/protocol/error/Report.java
Normale Datei
@ -0,0 +1,162 @@
|
|||||||
|
package com.comphenix.protocol.error;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a error or warning report.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
public class Report {
|
||||||
|
private final ReportType type;
|
||||||
|
private final Throwable exception;
|
||||||
|
private final Object[] messageParameters;
|
||||||
|
private final Object[] callerParameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be constructed through the factory method in Report.
|
||||||
|
*/
|
||||||
|
public static class ReportBuilder {
|
||||||
|
private ReportType type;
|
||||||
|
private Throwable exception;
|
||||||
|
private Object[] messageParameters;
|
||||||
|
private Object[] callerParameters;
|
||||||
|
|
||||||
|
private ReportBuilder() {
|
||||||
|
// Don't allow
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current report type. Cannot be NULL.
|
||||||
|
* @param type - report type.
|
||||||
|
* @return This builder, for chaining.
|
||||||
|
*/
|
||||||
|
public ReportBuilder type(ReportType type) {
|
||||||
|
if (type == null)
|
||||||
|
throw new IllegalArgumentException("Report type cannot be set to NULL.");
|
||||||
|
this.type = type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current exception that occured.
|
||||||
|
* @param exception - exception that occured.
|
||||||
|
* @return This builder, for chaining.
|
||||||
|
*/
|
||||||
|
public ReportBuilder error(@Nullable Throwable exception) {
|
||||||
|
this.exception = exception;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the message parameters that are used to construct a message text.
|
||||||
|
* @param messageParameters - parameters for the report type.
|
||||||
|
* @return This builder, for chaining.
|
||||||
|
*/
|
||||||
|
public ReportBuilder messageParam(@Nullable Object... messageParameters) {
|
||||||
|
this.messageParameters = messageParameters;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the parameters in the caller method. This is optional.
|
||||||
|
* @param callerParameters - parameters of the caller method.
|
||||||
|
* @return This builder, for chaining.
|
||||||
|
*/
|
||||||
|
public ReportBuilder callerParam(@Nullable Object... callerParameters) {
|
||||||
|
this.callerParameters = callerParameters;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new report with the provided input.
|
||||||
|
* @return A new report.
|
||||||
|
*/
|
||||||
|
public Report build() {
|
||||||
|
return new Report(type, exception, messageParameters, callerParameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new report builder.
|
||||||
|
* @param type - the initial report type.
|
||||||
|
* @return Report builder.
|
||||||
|
*/
|
||||||
|
public static ReportBuilder newBuilder(ReportType type) {
|
||||||
|
return new ReportBuilder().type(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new report with the given type and parameters.
|
||||||
|
* @param exception - exception that occured in the caller method.
|
||||||
|
* @param type - the report type that will be used to construct the message.
|
||||||
|
* @param messageParameters - parameters used to construct the report message.
|
||||||
|
* @param callerParameters - parameters from the caller method.
|
||||||
|
*/
|
||||||
|
protected Report(ReportType type, @Nullable Throwable exception, @Nullable Object[] messageParameters, @Nullable Object[] callerParameters) {
|
||||||
|
if (type == null)
|
||||||
|
throw new IllegalArgumentException("type cannot be NULL.");
|
||||||
|
this.type = type;
|
||||||
|
this.exception = exception;
|
||||||
|
this.messageParameters = messageParameters;
|
||||||
|
this.callerParameters = callerParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the current report type with the provided message parameters.
|
||||||
|
* @return The formated report message.
|
||||||
|
*/
|
||||||
|
public String getReportMessage() {
|
||||||
|
return type.getMessage(messageParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the message parameters that will be used to construc the report message.
|
||||||
|
* <p<
|
||||||
|
* This should not be confused with the method parameters of the caller method.
|
||||||
|
* @return Message parameters.
|
||||||
|
*/
|
||||||
|
public Object[] getMessageParameters() {
|
||||||
|
return messageParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the parameters of the caller method. Optional - may be NULL.
|
||||||
|
* @return Parameters or the caller method.
|
||||||
|
*/
|
||||||
|
public Object[] getCallerParameters() {
|
||||||
|
return callerParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the report type.
|
||||||
|
* @return Report type.
|
||||||
|
*/
|
||||||
|
public ReportType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the associated exception, or NULL if not found.
|
||||||
|
* @return Associated exception, or NULL.
|
||||||
|
*/
|
||||||
|
public Throwable getException() {
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if we have any message parameters.
|
||||||
|
* @return TRUE if there are any message parameters, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public boolean hasMessageParameters() {
|
||||||
|
return messageParameters != null && messageParameters.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if we have any caller parameters.
|
||||||
|
* @return TRUE if there are any caller parameters, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public boolean hasCallerParameters() {
|
||||||
|
return callerParameters != null && callerParameters.length > 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package com.comphenix.protocol.error;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a strongly-typed report. Subclasses should be immutable.
|
||||||
|
* <p>
|
||||||
|
* By convention, a report must be declared as a static field publicly accessible from the sender class.
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
public class ReportType {
|
||||||
|
private final String errorFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new report type.
|
||||||
|
* @param errorFormat - string used to format the underlying report.
|
||||||
|
*/
|
||||||
|
public ReportType(String errorFormat) {
|
||||||
|
this.errorFormat = errorFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the given report to a string, using the provided parameters.
|
||||||
|
* @param parameters - parameters to insert, or NULL to insert nothing.
|
||||||
|
* @return The full report in string format.
|
||||||
|
*/
|
||||||
|
public String getMessage(Object[] parameters) {
|
||||||
|
if (parameters == null || parameters.length == 0)
|
||||||
|
return toString();
|
||||||
|
else
|
||||||
|
return String.format(errorFormat, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return errorFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve all publicly associated reports.
|
||||||
|
* @param clazz - sender class.
|
||||||
|
* @return All associated reports.
|
||||||
|
*/
|
||||||
|
public static ReportType[] getReports(Class<?> clazz) {
|
||||||
|
if (clazz == null)
|
||||||
|
throw new IllegalArgumentException("clazz cannot be NULL.");
|
||||||
|
List<ReportType> result = new ArrayList<ReportType>();
|
||||||
|
|
||||||
|
for (Field field : clazz.getFields()) {
|
||||||
|
if (Modifier.isStatic(field.getModifiers()) &&
|
||||||
|
ReportType.class.isAssignableFrom(field.getDeclaringClass())) {
|
||||||
|
try {
|
||||||
|
result.add((ReportType) field.get(null));
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new FieldAccessException("Unable to access field.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toArray(new ReportType[0]);
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,9 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.injector.PacketConstructor.Unwrapper;
|
import com.comphenix.protocol.injector.PacketConstructor.Unwrapper;
|
||||||
import com.comphenix.protocol.reflect.FieldUtils;
|
import com.comphenix.protocol.reflect.FieldUtils;
|
||||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||||
@ -42,8 +45,32 @@ import com.google.common.primitives.Primitives;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class BukkitUnwrapper implements Unwrapper {
|
public class BukkitUnwrapper implements Unwrapper {
|
||||||
|
public static final ReportType REPORT_ILLEGAL_ARGUMENT = new ReportType("Illegal argument.");
|
||||||
|
public static final ReportType REPORT_SECURITY_LIMITATION = new ReportType("Security limitation.");
|
||||||
|
public static final ReportType REPORT_CANNOT_FIND_UNWRAP_METHOD = new ReportType("Cannot find method.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_CANNOT_READ_FIELD_HANDLE = new ReportType("Cannot read field 'handle'.");
|
||||||
|
|
||||||
private static Map<Class<?>, Unwrapper> unwrapperCache = new ConcurrentHashMap<Class<?>, Unwrapper>();
|
private static Map<Class<?>, Unwrapper> unwrapperCache = new ConcurrentHashMap<Class<?>, Unwrapper>();
|
||||||
|
|
||||||
|
// The current error reporter
|
||||||
|
private final ErrorReporter reporter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new Bukkit unwrapper with ProtocolLib's default error reporter.
|
||||||
|
*/
|
||||||
|
public BukkitUnwrapper() {
|
||||||
|
this(ProtocolLibrary.getErrorReporter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new Bukkit unwrapper with the given error reporter.
|
||||||
|
* @param reporter - the error reporter to use.
|
||||||
|
*/
|
||||||
|
public BukkitUnwrapper(ErrorReporter reporter) {
|
||||||
|
this.reporter = reporter;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public Object unwrapItem(Object wrappedObject) {
|
public Object unwrapItem(Object wrappedObject) {
|
||||||
@ -111,8 +138,9 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
return find.invoke(wrappedObject);
|
return find.invoke(wrappedObject);
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
ProtocolLibrary.getErrorReporter().reportDetailed(
|
reporter.reportDetailed(this,
|
||||||
this, "Illegal argument.", e, wrappedObject, find);
|
Report.newBuilder(REPORT_ILLEGAL_ARGUMENT).error(e).callerParam(wrappedObject, find)
|
||||||
|
);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
// Should not occur either
|
// Should not occur either
|
||||||
return null;
|
return null;
|
||||||
@ -129,7 +157,9 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
return methodUnwrapper;
|
return methodUnwrapper;
|
||||||
|
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
ProtocolLibrary.getErrorReporter().reportDetailed(this, "Security limitation.", e, type.getName());
|
reporter.reportDetailed(this,
|
||||||
|
Report.newBuilder(REPORT_SECURITY_LIMITATION).error(e).callerParam(type)
|
||||||
|
);
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
// Try getting the field unwrapper too
|
// Try getting the field unwrapper too
|
||||||
Unwrapper fieldUnwrapper = getFieldUnwrapper(type);
|
Unwrapper fieldUnwrapper = getFieldUnwrapper(type);
|
||||||
@ -137,7 +167,8 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
if (fieldUnwrapper != null)
|
if (fieldUnwrapper != null)
|
||||||
return fieldUnwrapper;
|
return fieldUnwrapper;
|
||||||
else
|
else
|
||||||
ProtocolLibrary.getErrorReporter().reportDetailed(this, "Cannot find method.", e, type.getName());
|
reporter.reportDetailed(this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_FIND_UNWRAP_METHOD).error(e).callerParam(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default method
|
// Default method
|
||||||
@ -160,8 +191,9 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
try {
|
try {
|
||||||
return FieldUtils.readField(find, wrappedObject, true);
|
return FieldUtils.readField(find, wrappedObject, true);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
ProtocolLibrary.getErrorReporter().reportDetailed(
|
reporter.reportDetailed(this,
|
||||||
this, "Cannot read field 'handle'.", e, wrappedObject, find.getName());
|
Report.newBuilder(REPORT_CANNOT_READ_FIELD_HANDLE).error(e).callerParam(wrappedObject, find)
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,9 +204,9 @@ public class BukkitUnwrapper implements Unwrapper {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Inform about this too
|
// Inform about this too
|
||||||
ProtocolLibrary.getErrorReporter().reportDetailed(
|
reporter.reportDetailed(this,
|
||||||
this, "Could not find field 'handle'.",
|
Report.newBuilder(REPORT_CANNOT_READ_FIELD_HANDLE).callerParam(find)
|
||||||
new Exception("Unable to find 'handle'"), type.getName());
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,8 @@ import com.comphenix.protocol.ProtocolManager;
|
|||||||
import com.comphenix.protocol.async.AsyncFilterManager;
|
import com.comphenix.protocol.async.AsyncFilterManager;
|
||||||
import com.comphenix.protocol.async.AsyncMarker;
|
import com.comphenix.protocol.async.AsyncMarker;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.events.*;
|
import com.comphenix.protocol.events.*;
|
||||||
import com.comphenix.protocol.injector.packet.PacketInjector;
|
import com.comphenix.protocol.injector.packet.PacketInjector;
|
||||||
import com.comphenix.protocol.injector.packet.PacketInjectorBuilder;
|
import com.comphenix.protocol.injector.packet.PacketInjectorBuilder;
|
||||||
@ -67,6 +69,22 @@ import com.google.common.base.Predicate;
|
|||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
public final class PacketFilterManager implements ProtocolManager, ListenerInvoker {
|
public final class PacketFilterManager implements ProtocolManager, ListenerInvoker {
|
||||||
|
public static final ReportType REPORT_CANNOT_LOAD_PACKET_LIST = new ReportType("Cannot load server and client packet list.");
|
||||||
|
public static final ReportType REPORT_CANNOT_INITIALIZE_PACKET_INJECTOR = new ReportType("Unable to initialize packet injector");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_PLUGIN_DEPEND_MISSING =
|
||||||
|
new ReportType("%s doesn't depend on ProtocolLib. Check that its plugin.yml has a 'depend' directive.");
|
||||||
|
|
||||||
|
// Registering packet IDs that are not supported
|
||||||
|
public static final ReportType REPORT_UNSUPPORTED_SERVER_PACKET_ID = new ReportType("[%s] Unsupported server packet ID in current Minecraft version: %s");
|
||||||
|
public static final ReportType REPORT_UNSUPPORTED_CLIENT_PACKET_ID = new ReportType("[%s] Unsupported client packet ID in current Minecraft version: %s");
|
||||||
|
|
||||||
|
// Problems injecting and uninjecting players
|
||||||
|
public static final ReportType REPORT_CANNOT_UNINJECT_PLAYER = new ReportType("Unable to uninject net handler for player.");
|
||||||
|
public static final ReportType REPORT_CANNOT_UNINJECT_OFFLINE_PLAYER = new ReportType("Unable to uninject logged off player.");
|
||||||
|
public static final ReportType REPORT_CANNOT_INJECT_PLAYER = new ReportType("Unable to inject player.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_CANNOT_UNREGISTER_PLUGIN = new ReportType("Unable to handle disabled plugin.");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the inject hook type. Different types allow for maximum compatibility.
|
* Sets the inject hook type. Different types allow for maximum compatibility.
|
||||||
@ -234,11 +252,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
knowsServerPackets = PacketRegistry.getServerPackets() != null;
|
knowsServerPackets = PacketRegistry.getServerPackets() != null;
|
||||||
knowsClientPackets = PacketRegistry.getClientPackets() != null;
|
knowsClientPackets = PacketRegistry.getClientPackets() != null;
|
||||||
} catch (FieldAccessException e) {
|
} catch (FieldAccessException e) {
|
||||||
reporter.reportWarning(this, "Cannot load server and client packet list.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_PACKET_LIST).error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (FieldAccessException e) {
|
} catch (FieldAccessException e) {
|
||||||
reporter.reportWarning(this, "Unable to initialize packet injector.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_INITIALIZE_PACKET_INJECTOR).error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +300,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
private void printPluginWarnings(Plugin plugin) {
|
private void printPluginWarnings(Plugin plugin) {
|
||||||
switch (pluginVerifier.verify(plugin)) {
|
switch (pluginVerifier.verify(plugin)) {
|
||||||
case NO_DEPEND:
|
case NO_DEPEND:
|
||||||
reporter.reportWarning(this, plugin + " doesn't depend on ProtocolLib. Check that its plugin.yml has a 'depend' directive.");
|
reporter.reportWarning(this, Report.newBuilder(REPORT_PLUGIN_DEPEND_MISSING).messageParam(plugin.getName()));
|
||||||
case VALID:
|
case VALID:
|
||||||
// Do nothing
|
// Do nothing
|
||||||
break;
|
break;
|
||||||
@ -510,10 +528,9 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
if (!knowsServerPackets || PacketRegistry.getServerPackets().contains(packetID))
|
if (!knowsServerPackets || PacketRegistry.getServerPackets().contains(packetID))
|
||||||
playerInjection.addPacketHandler(packetID);
|
playerInjection.addPacketHandler(packetID);
|
||||||
else
|
else
|
||||||
reporter.reportWarning(this, String.format(
|
reporter.reportWarning(this,
|
||||||
"[%s] Unsupported server packet ID in current Minecraft version: %s",
|
Report.newBuilder(REPORT_UNSUPPORTED_SERVER_PACKET_ID).messageParam(PacketAdapter.getPluginName(listener), packetID)
|
||||||
PacketAdapter.getPluginName(listener), packetID
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// As above, only for client packets
|
// As above, only for client packets
|
||||||
@ -521,10 +538,9 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
if (!knowsClientPackets || PacketRegistry.getClientPackets().contains(packetID))
|
if (!knowsClientPackets || PacketRegistry.getClientPackets().contains(packetID))
|
||||||
packetInjector.addPacketHandler(packetID);
|
packetInjector.addPacketHandler(packetID);
|
||||||
else
|
else
|
||||||
reporter.reportWarning(this, String.format(
|
reporter.reportWarning(this,
|
||||||
"[%s] Unsupported client packet ID in current Minecraft version: %s",
|
Report.newBuilder(REPORT_UNSUPPORTED_CLIENT_PACKET_ID).messageParam(PacketAdapter.getPluginName(listener), packetID)
|
||||||
PacketAdapter.getPluginName(listener), packetID
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -722,7 +738,9 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
playerInjection.uninjectPlayer(event.getPlayer().getAddress());
|
playerInjection.uninjectPlayer(event.getPlayer().getAddress());
|
||||||
playerInjection.updatePlayer(event.getPlayer());
|
playerInjection.updatePlayer(event.getPlayer());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reporter.reportDetailed(PacketFilterManager.this, "Unable to uninject net handler for player.", e, event);
|
reporter.reportDetailed(PacketFilterManager.this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_UNINJECT_PLAYER).callerParam(event).error(e)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,7 +749,9 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
// This call will be ignored if no listeners are registered
|
// This call will be ignored if no listeners are registered
|
||||||
playerInjection.injectPlayer(event.getPlayer(), ConflictStrategy.OVERRIDE);
|
playerInjection.injectPlayer(event.getPlayer(), ConflictStrategy.OVERRIDE);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reporter.reportDetailed(PacketFilterManager.this, "Unable to inject player.", e, event);
|
reporter.reportDetailed(PacketFilterManager.this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_INJECT_PLAYER).callerParam(event).error(e)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -743,7 +763,9 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
playerInjection.handleDisconnect(player);
|
playerInjection.handleDisconnect(player);
|
||||||
playerInjection.uninjectPlayer(player);
|
playerInjection.uninjectPlayer(player);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reporter.reportDetailed(PacketFilterManager.this, "Unable to uninject logged off player.", e, event);
|
reporter.reportDetailed(PacketFilterManager.this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_UNINJECT_OFFLINE_PLAYER).callerParam(event).error(e)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -754,7 +776,9 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
removePacketListeners(event.getPlugin());
|
removePacketListeners(event.getPlugin());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reporter.reportDetailed(PacketFilterManager.this, "Unable handle disabled plugin.", e, event);
|
reporter.reportDetailed(PacketFilterManager.this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_UNREGISTER_PLUGIN).callerParam(event).error(e)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,8 @@ import java.util.Set;
|
|||||||
import net.sf.cglib.proxy.Factory;
|
import net.sf.cglib.proxy.Factory;
|
||||||
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.FieldUtils;
|
import com.comphenix.protocol.reflect.FieldUtils;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
@ -44,6 +46,11 @@ import com.google.common.collect.ImmutableSet;
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public class PacketRegistry {
|
public class PacketRegistry {
|
||||||
|
public static final ReportType REPORT_CANNOT_CORRECT_TROVE_MAP = new ReportType("Unable to correct no entry value.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_INSUFFICIENT_SERVER_PACKETS = new ReportType("Too few server packets detected: %s");
|
||||||
|
public static final ReportType REPORT_INSUFFICIENT_CLIENT_PACKETS = new ReportType("Too few client packets detected: %s");
|
||||||
|
|
||||||
private static final int MIN_SERVER_PACKETS = 5;
|
private static final int MIN_SERVER_PACKETS = 5;
|
||||||
private static final int MIN_CLIENT_PACKETS = 5;
|
private static final int MIN_CLIENT_PACKETS = 5;
|
||||||
|
|
||||||
@ -118,7 +125,8 @@ public class PacketRegistry {
|
|||||||
}
|
}
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
// Whatever
|
// Whatever
|
||||||
ProtocolLibrary.getErrorReporter().reportWarning(PacketRegistry.class, "Unable to correct no entry value.", e);
|
ProtocolLibrary.getErrorReporter().reportWarning(PacketRegistry.class,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_CORRECT_TROVE_MAP).error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll assume this a Trove map
|
// We'll assume this a Trove map
|
||||||
@ -200,10 +208,12 @@ public class PacketRegistry {
|
|||||||
// Check sizes
|
// Check sizes
|
||||||
if (serverPackets.size() < MIN_SERVER_PACKETS)
|
if (serverPackets.size() < MIN_SERVER_PACKETS)
|
||||||
ProtocolLibrary.getErrorReporter().reportWarning(
|
ProtocolLibrary.getErrorReporter().reportWarning(
|
||||||
PacketRegistry.class, "Too few server packets detected: " + serverPackets.size());
|
PacketRegistry.class, Report.newBuilder(REPORT_INSUFFICIENT_SERVER_PACKETS).messageParam(serverPackets.size())
|
||||||
|
);
|
||||||
if (clientPackets.size() < MIN_CLIENT_PACKETS)
|
if (clientPackets.size() < MIN_CLIENT_PACKETS)
|
||||||
ProtocolLibrary.getErrorReporter().reportWarning(
|
ProtocolLibrary.getErrorReporter().reportWarning(
|
||||||
PacketRegistry.class, "Too few client packets detected: " + clientPackets.size());
|
PacketRegistry.class, Report.newBuilder(REPORT_INSUFFICIENT_CLIENT_PACKETS).messageParam(clientPackets.size())
|
||||||
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new FieldAccessException("Cannot retrieve packet client/server sets.");
|
throw new FieldAccessException("Cannot retrieve packet client/server sets.");
|
||||||
|
@ -22,6 +22,8 @@ import java.lang.reflect.Method;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.google.common.collect.MapMaker;
|
import com.google.common.collect.MapMaker;
|
||||||
@ -30,6 +32,8 @@ import net.sf.cglib.proxy.MethodInterceptor;
|
|||||||
import net.sf.cglib.proxy.MethodProxy;
|
import net.sf.cglib.proxy.MethodProxy;
|
||||||
|
|
||||||
class ReadPacketModifier implements MethodInterceptor {
|
class ReadPacketModifier implements MethodInterceptor {
|
||||||
|
public static final ReportType REPORT_CANNOT_HANDLE_CLIENT_PACKET = new ReportType("Cannot handle client packet.");
|
||||||
|
|
||||||
// A cancel marker
|
// A cancel marker
|
||||||
private static final Object CANCEL_MARKER = new Object();
|
private static final Object CANCEL_MARKER = new Object();
|
||||||
|
|
||||||
@ -122,7 +126,9 @@ class ReadPacketModifier implements MethodInterceptor {
|
|||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// Minecraft cannot handle this error
|
// Minecraft cannot handle this error
|
||||||
reporter.reportDetailed(this, "Cannot handle client packet.", e, args[0]);
|
reporter.reportDetailed(this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_HANDLE_CLIENT_PACKET).callerParam(args[0]).error(e)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
|
@ -24,6 +24,8 @@ import java.util.Set;
|
|||||||
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.injector.ListenerInvoker;
|
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||||
import com.comphenix.protocol.injector.player.NetworkFieldInjector.FakePacket;
|
import com.comphenix.protocol.injector.player.NetworkFieldInjector.FakePacket;
|
||||||
|
|
||||||
@ -38,6 +40,7 @@ import net.sf.cglib.proxy.MethodProxy;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class InjectedArrayList extends ArrayList<Object> {
|
class InjectedArrayList extends ArrayList<Object> {
|
||||||
|
public static final ReportType REPORT_CANNOT_REVERT_CANCELLED_PACKET = new ReportType("Reverting cancelled packet failed.");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Silly Eclipse.
|
* Silly Eclipse.
|
||||||
@ -89,7 +92,7 @@ class InjectedArrayList extends ArrayList<Object> {
|
|||||||
|
|
||||||
// Prefer to report this to the user, instead of risking sending it to Minecraft
|
// Prefer to report this to the user, instead of risking sending it to Minecraft
|
||||||
if (reporter != null) {
|
if (reporter != null) {
|
||||||
reporter.reportDetailed(this, "Reverting cancelled packet failed.", e, packet);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_REVERT_CANCELLED_PACKET).error(e).callerParam(packet));
|
||||||
} else {
|
} else {
|
||||||
System.out.println("[ProtocolLib] Reverting cancelled packet failed.");
|
System.out.println("[ProtocolLib] Reverting cancelled packet failed.");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -27,6 +27,8 @@ import net.sf.cglib.proxy.Factory;
|
|||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
|
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.injector.server.AbstractInputStreamLookup;
|
import com.comphenix.protocol.injector.server.AbstractInputStreamLookup;
|
||||||
import com.comphenix.protocol.reflect.FieldUtils;
|
import com.comphenix.protocol.reflect.FieldUtils;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
@ -40,6 +42,19 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class InjectedServerConnection {
|
class InjectedServerConnection {
|
||||||
|
// A number of things can go wrong ...
|
||||||
|
public static final ReportType REPORT_CANNOT_FIND_MINECRAFT_SERVER = new ReportType("Cannot extract minecraft server from Bukkit.");
|
||||||
|
public static final ReportType REPORT_CANNOT_INJECT_SERVER_CONNECTION = new ReportType("Cannot inject into server connection. Bad things will happen.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_CANNOT_FIND_LISTENER_THREAD = new ReportType("Cannot find listener thread in MinecraftServer.");
|
||||||
|
public static final ReportType REPORT_CANNOT_READ_LISTENER_THREAD = new ReportType("Unable to read the listener thread.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_CANNOT_FIND_SERVER_CONNECTION = new ReportType("Unable to retrieve server connection");
|
||||||
|
public static final ReportType REPORT_UNEXPECTED_THREAD_COUNT = new ReportType("Unexpected number of threads in %s: %s");
|
||||||
|
public static final ReportType REPORT_CANNOT_FIND_NET_HANDLER_THREAD = new ReportType("Unable to retrieve net handler thread.");
|
||||||
|
public static final ReportType REPORT_INSUFFICENT_THREAD_COUNT = new ReportType("Unable to inject %s lists in %s.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_CANNOT_COPY_OLD_TO_NEW = new ReportType("Cannot copy old %s to new.");
|
||||||
|
|
||||||
private static Field listenerThreadField;
|
private static Field listenerThreadField;
|
||||||
private static Field minecraftServerField;
|
private static Field minecraftServerField;
|
||||||
@ -74,7 +89,6 @@ class InjectedServerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void injectList() {
|
public void injectList() {
|
||||||
|
|
||||||
// Only execute this method once
|
// Only execute this method once
|
||||||
if (!hasAttempted)
|
if (!hasAttempted)
|
||||||
hasAttempted = true;
|
hasAttempted = true;
|
||||||
@ -88,7 +102,7 @@ class InjectedServerConnection {
|
|||||||
try {
|
try {
|
||||||
minecraftServer = FieldUtils.readField(minecraftServerField, server, true);
|
minecraftServer = FieldUtils.readField(minecraftServerField, server, true);
|
||||||
} catch (IllegalAccessException e1) {
|
} catch (IllegalAccessException e1) {
|
||||||
reporter.reportWarning(this, "Cannot extract minecraft server from Bukkit.");
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_FIND_MINECRAFT_SERVER));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +121,7 @@ class InjectedServerConnection {
|
|||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Oh damn - inform the player
|
// Oh damn - inform the player
|
||||||
reporter.reportDetailed(this, "Cannot inject into server connection. Bad things will happen.", e);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_INJECT_SERVER_CONNECTION).error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +131,9 @@ class InjectedServerConnection {
|
|||||||
listenerThreadField = FuzzyReflection.fromObject(minecraftServer).
|
listenerThreadField = FuzzyReflection.fromObject(minecraftServer).
|
||||||
getFieldByType("networkListenThread", MinecraftReflection.getNetworkListenThreadClass());
|
getFieldByType("networkListenThread", MinecraftReflection.getNetworkListenThreadClass());
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
reporter.reportDetailed(this, "Cannot find listener thread in MinecraftServer.", e, minecraftServer);
|
reporter.reportDetailed(this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_FIND_LISTENER_THREAD).callerParam(minecraftServer).error(e)
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +143,7 @@ class InjectedServerConnection {
|
|||||||
try {
|
try {
|
||||||
listenerThread = listenerThreadField.get(minecraftServer);
|
listenerThread = listenerThreadField.get(minecraftServer);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reporter.reportWarning(this, "Unable to read the listener thread.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_READ_LISTENER_THREAD).error(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,14 +156,15 @@ class InjectedServerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void injectServerConnection() {
|
private void injectServerConnection() {
|
||||||
|
|
||||||
Object serverConnection = null;
|
Object serverConnection = null;
|
||||||
|
|
||||||
// Careful - we might fail
|
// Careful - we might fail
|
||||||
try {
|
try {
|
||||||
serverConnection = serverConnectionMethod.invoke(minecraftServer);
|
serverConnection = serverConnectionMethod.invoke(minecraftServer);
|
||||||
} catch (Exception ex) {
|
} catch (Exception e) {
|
||||||
reporter.reportDetailed(this, "Unable to retrieve server connection", ex, minecraftServer);
|
reporter.reportDetailed(this,
|
||||||
|
Report.newBuilder(REPORT_CANNOT_FIND_SERVER_CONNECTION).callerParam(minecraftServer).error(e)
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +177,9 @@ class InjectedServerConnection {
|
|||||||
|
|
||||||
// Verify the field count
|
// Verify the field count
|
||||||
if (matches.size() != 1)
|
if (matches.size() != 1)
|
||||||
reporter.reportWarning(this, "Unexpected number of threads in " + serverConnection.getClass().getName());
|
reporter.reportWarning(this,
|
||||||
|
Report.newBuilder(REPORT_UNEXPECTED_THREAD_COUNT).messageParam(serverConnection.getClass(), matches.size())
|
||||||
|
);
|
||||||
else
|
else
|
||||||
dedicatedThreadField = matches.get(0);
|
dedicatedThreadField = matches.get(0);
|
||||||
}
|
}
|
||||||
@ -175,7 +194,7 @@ class InjectedServerConnection {
|
|||||||
injectEveryListField(dedicatedThread, 1);
|
injectEveryListField(dedicatedThread, 1);
|
||||||
}
|
}
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
reporter.reportWarning(this, "Unable to retrieve net handler thread.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_FIND_NET_HANDLER_THREAD).error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
injectIntoList(serverConnection, listField);
|
injectIntoList(serverConnection, listField);
|
||||||
@ -201,7 +220,7 @@ class InjectedServerConnection {
|
|||||||
|
|
||||||
// Warn about unexpected errors
|
// Warn about unexpected errors
|
||||||
if (lists.size() < minimum) {
|
if (lists.size() < minimum) {
|
||||||
reporter.reportWarning(this, "Unable to inject " + minimum + " lists in " + container.getClass().getName());
|
reporter.reportWarning(this, Report.newBuilder(REPORT_INSUFFICENT_THREAD_COUNT).messageParam(minimum, container.getClass()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,8 +260,9 @@ class InjectedServerConnection {
|
|||||||
try {
|
try {
|
||||||
writer.copyTo(inserting, replacement, inserting.getClass());
|
writer.copyTo(inserting, replacement, inserting.getClass());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
reporter.reportDetailed(InjectedServerConnection.this, "Cannot copy old " + inserting +
|
reporter.reportDetailed(InjectedServerConnection.this,
|
||||||
" to new.", e, inserting, replacement);
|
Report.newBuilder(REPORT_CANNOT_COPY_OLD_TO_NEW).messageParam(inserting).callerParam(inserting, replacement).error(e)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ import org.bukkit.Server;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.injector.GamePhase;
|
import com.comphenix.protocol.injector.GamePhase;
|
||||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler.ConflictStrategy;
|
import com.comphenix.protocol.injector.player.PlayerInjectionHandler.ConflictStrategy;
|
||||||
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
|
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
|
||||||
@ -35,6 +37,9 @@ import com.google.common.collect.Maps;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class NetLoginInjector {
|
class NetLoginInjector {
|
||||||
|
public static final ReportType REPORT_CANNOT_HOOK_LOGIN_HANDLER = new ReportType("Unable to hook %s.");
|
||||||
|
public static final ReportType REPORT_CANNOT_CLEANUP_LOGIN_HANDLER = new ReportType("Cannot cleanup %s.");
|
||||||
|
|
||||||
private ConcurrentMap<Object, PlayerInjector> injectedLogins = Maps.newConcurrentMap();
|
private ConcurrentMap<Object, PlayerInjector> injectedLogins = Maps.newConcurrentMap();
|
||||||
|
|
||||||
// Handles every hook
|
// Handles every hook
|
||||||
@ -83,8 +88,12 @@ class NetLoginInjector {
|
|||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// Minecraft can't handle this, so we'll deal with it here
|
// Minecraft can't handle this, so we'll deal with it here
|
||||||
reporter.reportDetailed(this, "Unable to hook " +
|
reporter.reportDetailed(this,
|
||||||
MinecraftReflection.getNetLoginHandlerName() + ".", e, inserting, injectionHandler);
|
Report.newBuilder(REPORT_CANNOT_HOOK_LOGIN_HANDLER).
|
||||||
|
messageParam(MinecraftReflection.getNetLoginHandlerName()).
|
||||||
|
callerParam(inserting, injectionHandler).
|
||||||
|
error(e)
|
||||||
|
);
|
||||||
return inserting;
|
return inserting;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,8 +131,12 @@ class NetLoginInjector {
|
|||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// Don't leak this to Minecraft
|
// Don't leak this to Minecraft
|
||||||
reporter.reportDetailed(this, "Cannot cleanup " +
|
reporter.reportDetailed(this,
|
||||||
MinecraftReflection.getNetLoginHandlerName() + ".", e, removing);
|
Report.newBuilder(REPORT_CANNOT_CLEANUP_LOGIN_HANDLER).
|
||||||
|
messageParam(MinecraftReflection.getNetLoginHandlerName()).
|
||||||
|
callerParam(removing).
|
||||||
|
error(e)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ import org.bukkit.entity.Player;
|
|||||||
|
|
||||||
import com.comphenix.protocol.concurrency.IntegerSet;
|
import com.comphenix.protocol.concurrency.IntegerSet;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.events.PacketListener;
|
import com.comphenix.protocol.events.PacketListener;
|
||||||
import com.comphenix.protocol.injector.GamePhase;
|
import com.comphenix.protocol.injector.GamePhase;
|
||||||
import com.comphenix.protocol.injector.ListenerInvoker;
|
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||||
@ -48,6 +50,11 @@ import com.comphenix.protocol.utility.MinecraftVersion;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class NetworkServerInjector extends PlayerInjector {
|
class NetworkServerInjector extends PlayerInjector {
|
||||||
|
// Disconnected field
|
||||||
|
public static final ReportType REPORT_ASSUMING_DISCONNECT_FIELD = new ReportType("Unable to find 'disconnected' field. Assuming %s.");
|
||||||
|
public static final ReportType REPORT_DISCONNECT_FIELD_MISSING = new ReportType("Cannot find disconnected field. Is ProtocolLib up to date?");
|
||||||
|
public static final ReportType REPORT_DISCONNECT_FIELD_FAILURE = new ReportType("Unable to update disconnected field. Player quit event may be sent twice.");
|
||||||
|
|
||||||
private volatile static CallbackFilter callbackFilter;
|
private volatile static CallbackFilter callbackFilter;
|
||||||
private volatile static boolean foundSendPacket;
|
private volatile static boolean foundSendPacket;
|
||||||
|
|
||||||
@ -309,7 +316,7 @@ class NetworkServerInjector extends PlayerInjector {
|
|||||||
// Assume it's the first ...
|
// Assume it's the first ...
|
||||||
if (disconnectField == null) {
|
if (disconnectField == null) {
|
||||||
disconnectField = FuzzyReflection.fromObject(handler).getFieldByType("disconnected", boolean.class);
|
disconnectField = FuzzyReflection.fromObject(handler).getFieldByType("disconnected", boolean.class);
|
||||||
reporter.reportWarning(this, "Unable to find 'disconnected' field. Assuming " + disconnectField);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_ASSUMING_DISCONNECT_FIELD).messageParam(disconnectField));
|
||||||
|
|
||||||
// Try again
|
// Try again
|
||||||
if (disconnectField != null) {
|
if (disconnectField != null) {
|
||||||
@ -319,10 +326,10 @@ class NetworkServerInjector extends PlayerInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is really bad
|
// This is really bad
|
||||||
reporter.reportDetailed(this, "Cannot find disconnected field. Is ProtocolLib up to date?", e);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_DISCONNECT_FIELD_MISSING).error(e));
|
||||||
|
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
reporter.reportWarning(this, "Unable to update disconnected field. Player quit event may be sent twice.");
|
reporter.reportWarning(this, Report.newBuilder(REPORT_DISCONNECT_FIELD_FAILURE).error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ import org.bukkit.entity.Player;
|
|||||||
|
|
||||||
import com.comphenix.protocol.Packets;
|
import com.comphenix.protocol.Packets;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.comphenix.protocol.events.PacketListener;
|
import com.comphenix.protocol.events.PacketListener;
|
||||||
@ -45,7 +47,21 @@ import com.comphenix.protocol.reflect.VolatileField;
|
|||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||||
|
|
||||||
abstract class PlayerInjector implements SocketInjector {
|
public abstract class PlayerInjector implements SocketInjector {
|
||||||
|
// Disconnect method related reports
|
||||||
|
public static final ReportType REPORT_ASSUME_DISCONNECT_METHOD = new ReportType("Cannot find disconnect method by name. Assuming %s.");
|
||||||
|
public static final ReportType REPORT_INVALID_ARGUMENT_DISCONNECT = new ReportType("Invalid argument passed to disconnect method: %s");
|
||||||
|
public static final ReportType REPORT_CANNOT_ACCESS_DISCONNECT = new ReportType("Unable to access disconnect method.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_CANNOT_CLOSE_SOCKET = new ReportType("Unable to close socket.");
|
||||||
|
public static final ReportType REPORT_ACCESS_DENIED_CLOSE_SOCKET = new ReportType("Insufficient permissions. Cannot close socket.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_DETECTED_CUSTOM_SERVER_HANDLER =
|
||||||
|
new ReportType("Detected server handler proxy type by another plugin. Conflict may occur!");
|
||||||
|
public static final ReportType REPORT_CANNOT_PROXY_SERVER_HANDLER = new ReportType("Unable to load server handler from proxy type.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_CANNOT_UPDATE_PLAYER = new ReportType("Cannot update player in PlayerEvent.");
|
||||||
|
public static final ReportType REPORT_CANNOT_HANDLE_PACKET = new ReportType("Cannot handle server packet.");
|
||||||
|
|
||||||
// Net login handler stuff
|
// Net login handler stuff
|
||||||
private static Field netLoginNetworkField;
|
private static Field netLoginNetworkField;
|
||||||
@ -305,7 +321,7 @@ abstract class PlayerInjector implements SocketInjector {
|
|||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
// Just assume it's the first String method
|
// Just assume it's the first String method
|
||||||
disconnect = FuzzyReflection.fromObject(handler).getMethodByParameters("disconnect", String.class);
|
disconnect = FuzzyReflection.fromObject(handler).getMethodByParameters("disconnect", String.class);
|
||||||
reporter.reportWarning(this, "Cannot find disconnect method by name. Assuming " + disconnect);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_ASSUME_DISCONNECT_METHOD).messageParam(disconnect));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the method for later
|
// Save the method for later
|
||||||
@ -319,9 +335,9 @@ abstract class PlayerInjector implements SocketInjector {
|
|||||||
disconnect.invoke(handler, message);
|
disconnect.invoke(handler, message);
|
||||||
return;
|
return;
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
reporter.reportDetailed(this, "Invalid argument passed to disconnect method: " + message, e, handler);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_INVALID_ARGUMENT_DISCONNECT).error(e).messageParam(message).callerParam(handler));
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
reporter.reportWarning(this, "Unable to access disconnect method.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_ACCESS_DISCONNECT).error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,16 +348,15 @@ abstract class PlayerInjector implements SocketInjector {
|
|||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
reporter.reportDetailed(this, "Unable to close socket.", e, socket);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_CLOSE_SOCKET).error(e).callerParam(socket));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
reporter.reportWarning(this, "Insufficient permissions. Cannot close socket.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_ACCESS_DENIED_CLOSE_SOCKET).error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Field getProxyField(Object notchEntity, Field serverField) {
|
private Field getProxyField(Object notchEntity, Field serverField) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object handler = FieldUtils.readField(serverHandlerField, notchEntity, true);
|
Object handler = FieldUtils.readField(serverHandlerField, notchEntity, true);
|
||||||
|
|
||||||
@ -353,7 +368,7 @@ abstract class PlayerInjector implements SocketInjector {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
hasProxyType = true;
|
hasProxyType = true;
|
||||||
reporter.reportWarning(this, "Detected server handler proxy type by another plugin. Conflict may occur!");
|
reporter.reportWarning(this, Report.newBuilder(REPORT_DETECTED_CUSTOM_SERVER_HANDLER).callerParam(notchEntity, serverField));
|
||||||
|
|
||||||
// No? Is it a Proxy type?
|
// No? Is it a Proxy type?
|
||||||
try {
|
try {
|
||||||
@ -368,7 +383,7 @@ abstract class PlayerInjector implements SocketInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
reporter.reportWarning(this, "Unable to load server handler from proxy type.");
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_PROXY_SERVER_HANDLER).error(e).callerParam(notchEntity, serverField));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nope, just go with it
|
// Nope, just go with it
|
||||||
@ -534,7 +549,7 @@ abstract class PlayerInjector implements SocketInjector {
|
|||||||
try {
|
try {
|
||||||
updatedPlayer = (Player) MinecraftReflection.getBukkitEntity(getEntityPlayer(getNetHandler()));
|
updatedPlayer = (Player) MinecraftReflection.getBukkitEntity(getEntityPlayer(getNetHandler()));
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
reporter.reportDetailed(this, "Cannot update player in PlayerEvent.", e, packet);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLAYER).error(e).callerParam(packet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,7 +574,7 @@ abstract class PlayerInjector implements SocketInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
reporter.reportDetailed(this, "Cannot handle server packet.", e, packet);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_HANDLE_PACKET).error(e).callerParam(packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
return packet;
|
return packet;
|
||||||
|
@ -34,6 +34,8 @@ import com.comphenix.protocol.Packets;
|
|||||||
import com.comphenix.protocol.concurrency.BlockingHashMap;
|
import com.comphenix.protocol.concurrency.BlockingHashMap;
|
||||||
import com.comphenix.protocol.concurrency.IntegerSet;
|
import com.comphenix.protocol.concurrency.IntegerSet;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.events.PacketAdapter;
|
import com.comphenix.protocol.events.PacketAdapter;
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.events.PacketListener;
|
import com.comphenix.protocol.events.PacketListener;
|
||||||
@ -59,6 +61,16 @@ import com.google.common.collect.Maps;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
||||||
|
// Warnings and errors
|
||||||
|
public static final ReportType REPORT_UNSUPPPORTED_LISTENER = new ReportType("Cannot fully register listener for %s: %s");
|
||||||
|
|
||||||
|
// Fallback to older player hook types
|
||||||
|
public static final ReportType REPORT_PLAYER_HOOK_FAILED = new ReportType("Player hook %s failed.");
|
||||||
|
public static final ReportType REPORT_SWITCHED_PLAYER_HOOK = new ReportType("Switching to %s instead.");
|
||||||
|
|
||||||
|
public static final ReportType REPORT_HOOK_CLEANUP_FAILED = new ReportType("Cleaing up after player hook failed.");
|
||||||
|
public static final ReportType REPORT_CANNOT_REVERT_HOOK = new ReportType("Unable to fully revert old injector. May cause conflicts.");
|
||||||
|
|
||||||
// Server connection injection
|
// Server connection injection
|
||||||
private InjectedServerConnection serverInjection;
|
private InjectedServerConnection serverInjection;
|
||||||
|
|
||||||
@ -355,8 +367,9 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
|||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Mark this injection attempt as a failure
|
// Mark this injection attempt as a failure
|
||||||
reporter.reportDetailed(this, "Player hook " + tempHook.toString() + " failed.",
|
reporter.reportDetailed(this,
|
||||||
e, player, injectionPoint, phase);
|
Report.newBuilder(REPORT_PLAYER_HOOK_FAILED).messageParam(tempHook).callerParam(player, injectionPoint, phase).error(e)
|
||||||
|
);
|
||||||
hookFailed = true;
|
hookFailed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,7 +377,7 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
|||||||
tempHook = PlayerInjectHooks.values()[tempHook.ordinal() - 1];
|
tempHook = PlayerInjectHooks.values()[tempHook.ordinal() - 1];
|
||||||
|
|
||||||
if (hookFailed)
|
if (hookFailed)
|
||||||
reporter.reportWarning(this, "Switching to " + tempHook.toString() + " instead.");
|
reporter.reportWarning(this, Report.newBuilder(REPORT_SWITCHED_PLAYER_HOOK).messageParam(tempHook));
|
||||||
|
|
||||||
// Check for UTTER FAILURE
|
// Check for UTTER FAILURE
|
||||||
if (tempHook == PlayerInjectHooks.NONE) {
|
if (tempHook == PlayerInjectHooks.NONE) {
|
||||||
@ -400,7 +413,7 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
|||||||
if (injector != null)
|
if (injector != null)
|
||||||
injector.cleanupAll();
|
injector.cleanupAll();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
reporter.reportDetailed(this, "Cleaing up after player hook failed.", ex, injector);
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_HOOK_CLEANUP_FAILED).callerParam(injector).error(ex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,7 +475,7 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
|||||||
|
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
// Let the user know
|
// Let the user know
|
||||||
reporter.reportWarning(this, "Unable to fully revert old injector. May cause conflicts.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_REVERT_HOOK).error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -646,8 +659,9 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
|||||||
|
|
||||||
// We won't prevent the listener, as it may still have valid packets
|
// We won't prevent the listener, as it may still have valid packets
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
reporter.reportWarning(this, "Cannot fully register listener for " +
|
reporter.reportWarning(this,
|
||||||
PacketAdapter.getPluginName(listener) + ": " + result.toString());
|
Report.newBuilder(REPORT_UNSUPPPORTED_LISTENER).messageParam(PacketAdapter.getPluginName(listener), result)
|
||||||
|
);
|
||||||
|
|
||||||
// These are illegal
|
// These are illegal
|
||||||
for (int packetID : result.getPackets())
|
for (int packetID : result.getPackets())
|
||||||
|
@ -32,6 +32,8 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.compiler.StructureCompiler.StructureKey;
|
import com.comphenix.protocol.reflect.compiler.StructureCompiler.StructureKey;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
@ -46,6 +48,8 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class BackgroundCompiler {
|
public class BackgroundCompiler {
|
||||||
|
public static final ReportType REPORT_CANNOT_COMPILE_STRUCTURE_MODIFIER = new ReportType("Cannot compile structure. Disabing compiler.");
|
||||||
|
public static final ReportType REPORT_CANNOT_SCHEDULE_COMPILATION = new ReportType("Unable to schedule compilation task.");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default format for the name of new worker threads.
|
* The default format for the name of new worker threads.
|
||||||
@ -224,7 +228,8 @@ public class BackgroundCompiler {
|
|||||||
// Inform about this error as best as we can
|
// Inform about this error as best as we can
|
||||||
if (reporter != null) {
|
if (reporter != null) {
|
||||||
reporter.reportDetailed(BackgroundCompiler.this,
|
reporter.reportDetailed(BackgroundCompiler.this,
|
||||||
"Cannot compile structure. Disabing compiler.", e, uncompiled);
|
Report.newBuilder(REPORT_CANNOT_COMPILE_STRUCTURE_MODIFIER).callerParam(uncompiled).error(e)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
System.err.println("Exception occured in structure compiler: ");
|
System.err.println("Exception occured in structure compiler: ");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -258,7 +263,7 @@ public class BackgroundCompiler {
|
|||||||
// Occures when the underlying queue is overflowing. Since the compilation
|
// Occures when the underlying queue is overflowing. Since the compilation
|
||||||
// is only an optmization and not really essential we'll just log this failure
|
// is only an optmization and not really essential we'll just log this failure
|
||||||
// and move on.
|
// and move on.
|
||||||
reporter.reportWarning(this, "Unable to schedule compilation task.", e);
|
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_SCHEDULE_COMPILATION).error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.error.Report;
|
||||||
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.primitives.Primitives;
|
import com.google.common.primitives.Primitives;
|
||||||
@ -92,6 +94,7 @@ import net.sf.cglib.asm.*;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public final class StructureCompiler {
|
public final class StructureCompiler {
|
||||||
|
public static final ReportType REPORT_TOO_MANY_GENERATED_CLASSES = new ReportType("Generated too many classes (count: %s)");
|
||||||
|
|
||||||
// Used to store generated classes of different types
|
// Used to store generated classes of different types
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@ -210,7 +213,8 @@ public final class StructureCompiler {
|
|||||||
} catch (OutOfMemoryError e) {
|
} catch (OutOfMemoryError e) {
|
||||||
// Print the number of generated classes by the current instances
|
// Print the number of generated classes by the current instances
|
||||||
ProtocolLibrary.getErrorReporter().reportWarning(
|
ProtocolLibrary.getErrorReporter().reportWarning(
|
||||||
this, "May have generated too many classes (count: " + compiledCache.size() + ")");
|
this, Report.newBuilder(REPORT_TOO_MANY_GENERATED_CLASSES).messageParam(compiledCache.size())
|
||||||
|
);
|
||||||
throw e;
|
throw e;
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new IllegalStateException("Used invalid parameters in instance creation", e);
|
throw new IllegalStateException("Used invalid parameters in instance creation", e);
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren