604 lines
		
	
	
	
		
			26 KiB
			
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			604 lines
		
	
	
	
		
			26 KiB
			
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 | 
						|
From: Zach Brown <1254957+zachbr@users.noreply.github.com>
 | 
						|
Date: Mon, 29 Feb 2016 20:24:35 -0600
 | 
						|
Subject: [PATCH] Add exception reporting event
 | 
						|
 | 
						|
 | 
						|
diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java
 | 
						|
new file mode 100644
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 | 
						|
--- /dev/null
 | 
						|
+++ b/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java
 | 
						|
@@ -0,0 +0,0 @@
 | 
						|
+package com.destroystokyo.paper.event.server;
 | 
						|
+
 | 
						|
+import com.google.common.base.Preconditions;
 | 
						|
+import org.apache.commons.lang.Validate;
 | 
						|
+import org.bukkit.Bukkit;
 | 
						|
+import org.bukkit.event.Event;
 | 
						|
+import org.bukkit.event.HandlerList;
 | 
						|
+import com.destroystokyo.paper.exception.ServerException;
 | 
						|
+import org.jetbrains.annotations.NotNull;
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * Called whenever an exception is thrown in a recoverable section of the server.
 | 
						|
+ */
 | 
						|
+public class ServerExceptionEvent extends Event {
 | 
						|
+    private static final HandlerList handlers = new HandlerList();
 | 
						|
+    @NotNull private ServerException exception;
 | 
						|
+
 | 
						|
+    public ServerExceptionEvent(@NotNull ServerException exception) {
 | 
						|
+        super(!Bukkit.isPrimaryThread());
 | 
						|
+        this.exception = Preconditions.checkNotNull(exception, "exception");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the wrapped exception that was thrown.
 | 
						|
+     *
 | 
						|
+     * @return Exception thrown
 | 
						|
+     */
 | 
						|
+    @NotNull
 | 
						|
+    public ServerException getException() {
 | 
						|
+        return exception;
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    @NotNull
 | 
						|
+    @Override
 | 
						|
+    public HandlerList getHandlers() {
 | 
						|
+        return handlers;
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    @NotNull
 | 
						|
+    public static HandlerList getHandlerList() {
 | 
						|
+        return handlers;
 | 
						|
+    }
 | 
						|
+}
 | 
						|
diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerCommandException.java b/src/main/java/com/destroystokyo/paper/exception/ServerCommandException.java
 | 
						|
new file mode 100644
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 | 
						|
--- /dev/null
 | 
						|
+++ b/src/main/java/com/destroystokyo/paper/exception/ServerCommandException.java
 | 
						|
@@ -0,0 +0,0 @@
 | 
						|
+package com.destroystokyo.paper.exception;
 | 
						|
+
 | 
						|
+import org.bukkit.command.Command;
 | 
						|
+import org.bukkit.command.CommandSender;
 | 
						|
+
 | 
						|
+import static com.google.common.base.Preconditions.checkNotNull;
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * Thrown when a command throws an exception
 | 
						|
+ */
 | 
						|
+public class ServerCommandException extends ServerException {
 | 
						|
+
 | 
						|
+    private final Command command;
 | 
						|
+    private final CommandSender commandSender;
 | 
						|
+    private final String[] arguments;
 | 
						|
+
 | 
						|
+    public ServerCommandException(String message, Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
 | 
						|
+        super(message, cause);
 | 
						|
+        this.commandSender = checkNotNull(commandSender, "commandSender");
 | 
						|
+        this.arguments = checkNotNull(arguments, "arguments");
 | 
						|
+        this.command = checkNotNull(command, "command");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerCommandException(Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
 | 
						|
+        super(cause);
 | 
						|
+        this.commandSender = checkNotNull(commandSender, "commandSender");
 | 
						|
+        this.arguments = checkNotNull(arguments, "arguments");
 | 
						|
+        this.command = checkNotNull(command, "command");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    protected ServerCommandException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Command command, CommandSender commandSender, String[] arguments) {
 | 
						|
+        super(message, cause, enableSuppression, writableStackTrace);
 | 
						|
+        this.commandSender = checkNotNull(commandSender, "commandSender");
 | 
						|
+        this.arguments = checkNotNull(arguments, "arguments");
 | 
						|
+        this.command = checkNotNull(command, "command");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the command which threw the exception
 | 
						|
+     *
 | 
						|
+     * @return exception throwing command
 | 
						|
+     */
 | 
						|
+    public Command getCommand() {
 | 
						|
+        return command;
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the command sender which executed the command request
 | 
						|
+     *
 | 
						|
+     * @return command sender of exception thrown command request
 | 
						|
+     */
 | 
						|
+    public CommandSender getCommandSender() {
 | 
						|
+        return commandSender;
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the arguments which threw the exception for the command
 | 
						|
+     *
 | 
						|
+     * @return arguments of exception thrown command request
 | 
						|
+     */
 | 
						|
+    public String[] getArguments() {
 | 
						|
+        return arguments;
 | 
						|
+    }
 | 
						|
+}
 | 
						|
diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerEventException.java b/src/main/java/com/destroystokyo/paper/exception/ServerEventException.java
 | 
						|
new file mode 100644
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 | 
						|
--- /dev/null
 | 
						|
+++ b/src/main/java/com/destroystokyo/paper/exception/ServerEventException.java
 | 
						|
@@ -0,0 +0,0 @@
 | 
						|
+package com.destroystokyo.paper.exception;
 | 
						|
+
 | 
						|
+import org.bukkit.event.Event;
 | 
						|
+import org.bukkit.event.Listener;
 | 
						|
+import org.bukkit.plugin.Plugin;
 | 
						|
+
 | 
						|
+import static com.google.common.base.Preconditions.*;
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * Exception thrown when a server event listener throws an exception
 | 
						|
+ */
 | 
						|
+public class ServerEventException extends ServerPluginException {
 | 
						|
+
 | 
						|
+    private final Listener listener;
 | 
						|
+    private final Event event;
 | 
						|
+
 | 
						|
+    public ServerEventException(String message, Throwable cause, Plugin responsiblePlugin, Listener listener, Event event) {
 | 
						|
+        super(message, cause, responsiblePlugin);
 | 
						|
+        this.listener = checkNotNull(listener, "listener");
 | 
						|
+        this.event = checkNotNull(event, "event");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerEventException(Throwable cause, Plugin responsiblePlugin, Listener listener, Event event) {
 | 
						|
+        super(cause, responsiblePlugin);
 | 
						|
+        this.listener = checkNotNull(listener, "listener");
 | 
						|
+        this.event = checkNotNull(event, "event");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    protected ServerEventException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin, Listener listener, Event event) {
 | 
						|
+        super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin);
 | 
						|
+        this.listener = checkNotNull(listener, "listener");
 | 
						|
+        this.event = checkNotNull(event, "event");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the listener which threw the exception
 | 
						|
+     *
 | 
						|
+     * @return event listener
 | 
						|
+     */
 | 
						|
+    public Listener getListener() {
 | 
						|
+        return listener;
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the event which caused the exception
 | 
						|
+     *
 | 
						|
+     * @return event
 | 
						|
+     */
 | 
						|
+    public Event getEvent() {
 | 
						|
+        return event;
 | 
						|
+    }
 | 
						|
+}
 | 
						|
diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerException.java b/src/main/java/com/destroystokyo/paper/exception/ServerException.java
 | 
						|
new file mode 100644
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 | 
						|
--- /dev/null
 | 
						|
+++ b/src/main/java/com/destroystokyo/paper/exception/ServerException.java
 | 
						|
@@ -0,0 +0,0 @@
 | 
						|
+package com.destroystokyo.paper.exception;
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * Wrapper exception for all exceptions that are thrown by the server.
 | 
						|
+ */
 | 
						|
+public class ServerException extends Exception {
 | 
						|
+
 | 
						|
+    public ServerException(String message) {
 | 
						|
+        super(message);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerException(String message, Throwable cause) {
 | 
						|
+        super(message, cause);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerException(Throwable cause) {
 | 
						|
+        super(cause);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    protected ServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
 | 
						|
+        super(message, cause, enableSuppression, writableStackTrace);
 | 
						|
+    }
 | 
						|
+}
 | 
						|
diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerInternalException.java b/src/main/java/com/destroystokyo/paper/exception/ServerInternalException.java
 | 
						|
new file mode 100644
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 | 
						|
--- /dev/null
 | 
						|
+++ b/src/main/java/com/destroystokyo/paper/exception/ServerInternalException.java
 | 
						|
@@ -0,0 +0,0 @@
 | 
						|
+package com.destroystokyo.paper.exception;
 | 
						|
+
 | 
						|
+import org.bukkit.Bukkit;
 | 
						|
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * Thrown when the internal server throws a recoverable exception.
 | 
						|
+ */
 | 
						|
+public class ServerInternalException extends ServerException {
 | 
						|
+
 | 
						|
+    public ServerInternalException(String message) {
 | 
						|
+        super(message);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerInternalException(String message, Throwable cause) {
 | 
						|
+        super(message, cause);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerInternalException(Throwable cause) {
 | 
						|
+        super(cause);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    protected ServerInternalException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
 | 
						|
+        super(message, cause, enableSuppression, writableStackTrace);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public static void reportInternalException(Throwable cause) {
 | 
						|
+        try {
 | 
						|
+            Bukkit.getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(cause)));
 | 
						|
+            ;
 | 
						|
+        } catch (Throwable t) {
 | 
						|
+            t.printStackTrace(); // Don't want to rethrow!
 | 
						|
+        }
 | 
						|
+    }
 | 
						|
+}
 | 
						|
diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerPluginEnableDisableException.java b/src/main/java/com/destroystokyo/paper/exception/ServerPluginEnableDisableException.java
 | 
						|
new file mode 100644
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 | 
						|
--- /dev/null
 | 
						|
+++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginEnableDisableException.java
 | 
						|
@@ -0,0 +0,0 @@
 | 
						|
+package com.destroystokyo.paper.exception;
 | 
						|
+
 | 
						|
+import org.bukkit.plugin.Plugin;
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * Thrown whenever there is an exception with any enabling or disabling of plugins.
 | 
						|
+ */
 | 
						|
+public class ServerPluginEnableDisableException extends ServerPluginException {
 | 
						|
+    public ServerPluginEnableDisableException(String message, Throwable cause, Plugin responsiblePlugin) {
 | 
						|
+        super(message, cause, responsiblePlugin);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerPluginEnableDisableException(Throwable cause, Plugin responsiblePlugin) {
 | 
						|
+        super(cause, responsiblePlugin);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    protected ServerPluginEnableDisableException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin) {
 | 
						|
+        super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin);
 | 
						|
+    }
 | 
						|
+}
 | 
						|
\ No newline at end of file
 | 
						|
diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerPluginException.java b/src/main/java/com/destroystokyo/paper/exception/ServerPluginException.java
 | 
						|
new file mode 100644
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 | 
						|
--- /dev/null
 | 
						|
+++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginException.java
 | 
						|
@@ -0,0 +0,0 @@
 | 
						|
+package com.destroystokyo.paper.exception;
 | 
						|
+
 | 
						|
+import com.google.common.base.Preconditions;
 | 
						|
+import org.apache.commons.lang.Validate;
 | 
						|
+import org.bukkit.plugin.Plugin;
 | 
						|
+
 | 
						|
+import static com.google.common.base.Preconditions.*;
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * Wrapper exception for all cases to which a plugin can be immediately blamed for
 | 
						|
+ */
 | 
						|
+public class ServerPluginException extends ServerException {
 | 
						|
+    public ServerPluginException(String message, Throwable cause, Plugin responsiblePlugin) {
 | 
						|
+        super(message, cause);
 | 
						|
+        this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerPluginException(Throwable cause, Plugin responsiblePlugin) {
 | 
						|
+        super(cause);
 | 
						|
+        this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    protected ServerPluginException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin) {
 | 
						|
+        super(message, cause, enableSuppression, writableStackTrace);
 | 
						|
+        this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    private final Plugin responsiblePlugin;
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the plugin which is directly responsible for the exception being thrown
 | 
						|
+     *
 | 
						|
+     * @return plugin which is responsible for the exception throw
 | 
						|
+     */
 | 
						|
+    public Plugin getResponsiblePlugin() {
 | 
						|
+        return responsiblePlugin;
 | 
						|
+    }
 | 
						|
+}
 | 
						|
diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java b/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java
 | 
						|
new file mode 100644
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 | 
						|
--- /dev/null
 | 
						|
+++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java
 | 
						|
@@ -0,0 +0,0 @@
 | 
						|
+package com.destroystokyo.paper.exception;
 | 
						|
+
 | 
						|
+import org.bukkit.entity.Player;
 | 
						|
+import org.bukkit.plugin.Plugin;
 | 
						|
+
 | 
						|
+import static com.google.common.base.Preconditions.*;
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * Thrown when an incoming plugin message channel throws an exception
 | 
						|
+ */
 | 
						|
+public class ServerPluginMessageException extends ServerPluginException {
 | 
						|
+
 | 
						|
+    private final Player player;
 | 
						|
+    private final String channel;
 | 
						|
+    private final byte[] data;
 | 
						|
+
 | 
						|
+    public ServerPluginMessageException(String message, Throwable cause, Plugin responsiblePlugin, Player player, String channel, byte[] data) {
 | 
						|
+        super(message, cause, responsiblePlugin);
 | 
						|
+        this.player = checkNotNull(player, "player");
 | 
						|
+        this.channel = checkNotNull(channel, "channel");
 | 
						|
+        this.data = checkNotNull(data, "data");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerPluginMessageException(Throwable cause, Plugin responsiblePlugin, Player player, String channel, byte[] data) {
 | 
						|
+        super(cause, responsiblePlugin);
 | 
						|
+        this.player = checkNotNull(player, "player");
 | 
						|
+        this.channel = checkNotNull(channel, "channel");
 | 
						|
+        this.data = checkNotNull(data, "data");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    protected ServerPluginMessageException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin, Player player, String channel, byte[] data) {
 | 
						|
+        super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin);
 | 
						|
+        this.player = checkNotNull(player, "player");
 | 
						|
+        this.channel = checkNotNull(channel, "channel");
 | 
						|
+        this.data = checkNotNull(data, "data");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the channel to which the error occurred from recieving data from
 | 
						|
+     *
 | 
						|
+     * @return exception channel
 | 
						|
+     */
 | 
						|
+    public String getChannel() {
 | 
						|
+        return channel;
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the data to which the error occurred from
 | 
						|
+     *
 | 
						|
+     * @return exception data
 | 
						|
+     */
 | 
						|
+    public byte[] getData() {
 | 
						|
+        return data;
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the player which the plugin message causing the exception originated from
 | 
						|
+     *
 | 
						|
+     * @return exception player
 | 
						|
+     */
 | 
						|
+    public Player getPlayer() {
 | 
						|
+        return player;
 | 
						|
+    }
 | 
						|
+}
 | 
						|
diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerSchedulerException.java b/src/main/java/com/destroystokyo/paper/exception/ServerSchedulerException.java
 | 
						|
new file mode 100644
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 | 
						|
--- /dev/null
 | 
						|
+++ b/src/main/java/com/destroystokyo/paper/exception/ServerSchedulerException.java
 | 
						|
@@ -0,0 +0,0 @@
 | 
						|
+package com.destroystokyo.paper.exception;
 | 
						|
+
 | 
						|
+import org.bukkit.scheduler.BukkitTask;
 | 
						|
+
 | 
						|
+import static com.google.common.base.Preconditions.checkNotNull;
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * Thrown when a plugin's scheduler fails with an exception
 | 
						|
+ */
 | 
						|
+public class ServerSchedulerException extends ServerPluginException {
 | 
						|
+
 | 
						|
+    private final BukkitTask task;
 | 
						|
+
 | 
						|
+    public ServerSchedulerException(String message, Throwable cause, BukkitTask task) {
 | 
						|
+        super(message, cause, task.getOwner());
 | 
						|
+        this.task = checkNotNull(task, "task");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerSchedulerException(Throwable cause, BukkitTask task) {
 | 
						|
+        super(cause, task.getOwner());
 | 
						|
+        this.task = checkNotNull(task, "task");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    protected ServerSchedulerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, BukkitTask task) {
 | 
						|
+        super(message, cause, enableSuppression, writableStackTrace, task.getOwner());
 | 
						|
+        this.task = checkNotNull(task, "task");
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    /**
 | 
						|
+     * Gets the task which threw the exception
 | 
						|
+     *
 | 
						|
+     * @return exception throwing task
 | 
						|
+     */
 | 
						|
+    public BukkitTask getTask() {
 | 
						|
+        return task;
 | 
						|
+    }
 | 
						|
+}
 | 
						|
diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerTabCompleteException.java b/src/main/java/com/destroystokyo/paper/exception/ServerTabCompleteException.java
 | 
						|
new file mode 100644
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 | 
						|
--- /dev/null
 | 
						|
+++ b/src/main/java/com/destroystokyo/paper/exception/ServerTabCompleteException.java
 | 
						|
@@ -0,0 +0,0 @@
 | 
						|
+package com.destroystokyo.paper.exception;
 | 
						|
+
 | 
						|
+import org.bukkit.command.Command;
 | 
						|
+import org.bukkit.command.CommandSender;
 | 
						|
+
 | 
						|
+/**
 | 
						|
+ * Called when a tab-complete request throws an exception
 | 
						|
+ */
 | 
						|
+public class ServerTabCompleteException extends ServerCommandException {
 | 
						|
+
 | 
						|
+    public ServerTabCompleteException(String message, Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
 | 
						|
+        super(message, cause, command, commandSender, arguments);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public ServerTabCompleteException(Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
 | 
						|
+        super(cause, command, commandSender, arguments);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    protected ServerTabCompleteException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Command command, CommandSender commandSender, String[] arguments) {
 | 
						|
+        super(message, cause, enableSuppression, writableStackTrace, command, commandSender, arguments);
 | 
						|
+    }
 | 
						|
+}
 | 
						|
diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java
 | 
						|
+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java
 | 
						|
@@ -0,0 +0,0 @@ import java.util.HashMap;
 | 
						|
 import java.util.Iterator;
 | 
						|
 import java.util.List;
 | 
						|
 import java.util.Map;
 | 
						|
+
 | 
						|
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
 | 
						|
+import com.destroystokyo.paper.exception.ServerCommandException;
 | 
						|
+import com.destroystokyo.paper.exception.ServerTabCompleteException;
 | 
						|
 import org.apache.commons.lang.Validate;
 | 
						|
 import org.bukkit.Location;
 | 
						|
 import org.bukkit.Server;
 | 
						|
@@ -0,0 +0,0 @@ public class SimpleCommandMap implements CommandMap {
 | 
						|
             target.execute(sender, sentCommandLabel, Arrays.copyOfRange(args, 1, args.length));
 | 
						|
             } // target.timings.stopTiming(); // Spigot // Paper
 | 
						|
         } catch (CommandException ex) {
 | 
						|
+            server.getPluginManager().callEvent(new ServerExceptionEvent(new ServerCommandException(ex, target, sender, args))); // Paper
 | 
						|
             //target.timings.stopTiming(); // Spigot // Paper
 | 
						|
             throw ex;
 | 
						|
         } catch (Throwable ex) {
 | 
						|
             //target.timings.stopTiming(); // Spigot // Paper
 | 
						|
-            throw new CommandException("Unhandled exception executing '" + commandLine + "' in " + target, ex);
 | 
						|
+            String msg = "Unhandled exception executing '" + commandLine + "' in " + target;
 | 
						|
+            server.getPluginManager().callEvent(new ServerExceptionEvent(new ServerCommandException(ex, target, sender, args))); // Paper
 | 
						|
+            throw new CommandException(msg, ex);
 | 
						|
         }
 | 
						|
 
 | 
						|
         // return true as command was handled
 | 
						|
@@ -0,0 +0,0 @@ public class SimpleCommandMap implements CommandMap {
 | 
						|
         } catch (CommandException ex) {
 | 
						|
             throw ex;
 | 
						|
         } catch (Throwable ex) {
 | 
						|
-            throw new CommandException("Unhandled exception executing tab-completer for '" + cmdLine + "' in " + target, ex);
 | 
						|
+            String msg = "Unhandled exception executing tab-completer for '" + cmdLine + "' in " + target;
 | 
						|
+            server.getPluginManager().callEvent(new ServerExceptionEvent(new ServerTabCompleteException(msg, ex, target, sender, args))); // Paper
 | 
						|
+            throw new CommandException(msg, ex);
 | 
						|
         }
 | 
						|
     }
 | 
						|
 
 | 
						|
diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java
 | 
						|
+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
 | 
						|
@@ -0,0 +0,0 @@ import java.util.WeakHashMap;
 | 
						|
 import java.util.logging.Level;
 | 
						|
 import java.util.regex.Matcher;
 | 
						|
 import java.util.regex.Pattern;
 | 
						|
+
 | 
						|
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
 | 
						|
+import com.destroystokyo.paper.exception.ServerEventException;
 | 
						|
+import com.destroystokyo.paper.exception.ServerPluginEnableDisableException;
 | 
						|
 import org.apache.commons.lang.Validate;
 | 
						|
 import org.bukkit.Server;
 | 
						|
 import org.bukkit.World;
 | 
						|
@@ -0,0 +0,0 @@ public final class SimplePluginManager implements PluginManager {
 | 
						|
             try {
 | 
						|
                 plugin.getPluginLoader().enablePlugin(plugin);
 | 
						|
             } catch (Throwable ex) {
 | 
						|
-                server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
 | 
						|
+                handlePluginException("Error occurred (in the plugin loader) while enabling "
 | 
						|
+                        + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin);
 | 
						|
             }
 | 
						|
 
 | 
						|
             HandlerList.bakeAll();
 | 
						|
@@ -0,0 +0,0 @@ public final class SimplePluginManager implements PluginManager {
 | 
						|
             try {
 | 
						|
                 plugin.getPluginLoader().disablePlugin(plugin);
 | 
						|
             } catch (Throwable ex) {
 | 
						|
-                server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
 | 
						|
+                handlePluginException("Error occurred (in the plugin loader) while disabling "
 | 
						|
+                        + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper
 | 
						|
             }
 | 
						|
 
 | 
						|
             try {
 | 
						|
                 server.getScheduler().cancelTasks(plugin);
 | 
						|
             } catch (Throwable ex) {
 | 
						|
-                server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while cancelling tasks for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
 | 
						|
+                handlePluginException("Error occurred (in the plugin loader) while cancelling tasks for "
 | 
						|
+                        + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper
 | 
						|
             }
 | 
						|
 
 | 
						|
             try {
 | 
						|
                 server.getServicesManager().unregisterAll(plugin);
 | 
						|
             } catch (Throwable ex) {
 | 
						|
-                server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering services for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
 | 
						|
+                handlePluginException("Error occurred (in the plugin loader) while unregistering services for "
 | 
						|
+                        + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper
 | 
						|
             }
 | 
						|
 
 | 
						|
             try {
 | 
						|
                 HandlerList.unregisterAll(plugin);
 | 
						|
             } catch (Throwable ex) {
 | 
						|
-                server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering events for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
 | 
						|
+                handlePluginException("Error occurred (in the plugin loader) while unregistering events for "
 | 
						|
+                        + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper
 | 
						|
             }
 | 
						|
 
 | 
						|
             try {
 | 
						|
                 server.getMessenger().unregisterIncomingPluginChannel(plugin);
 | 
						|
                 server.getMessenger().unregisterOutgoingPluginChannel(plugin);
 | 
						|
             } catch (Throwable ex) {
 | 
						|
-                server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering plugin channels for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
 | 
						|
+                handlePluginException("Error occurred (in the plugin loader) while unregistering plugin channels for "
 | 
						|
+                        + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper
 | 
						|
             }
 | 
						|
 
 | 
						|
             try {
 | 
						|
@@ -0,0 +0,0 @@ public final class SimplePluginManager implements PluginManager {
 | 
						|
         }
 | 
						|
     }
 | 
						|
 
 | 
						|
+    // Paper start
 | 
						|
+    private void handlePluginException(String msg, Throwable ex, Plugin plugin) {
 | 
						|
+        server.getLogger().log(Level.SEVERE, msg, ex);
 | 
						|
+        callEvent(new ServerExceptionEvent(new ServerPluginEnableDisableException(msg, ex, plugin)));
 | 
						|
+    }
 | 
						|
+    // Paper end
 | 
						|
+
 | 
						|
     @Override
 | 
						|
     public void clearPlugins() {
 | 
						|
         synchronized (this) {
 | 
						|
@@ -0,0 +0,0 @@ public final class SimplePluginManager implements PluginManager {
 | 
						|
                             ));
 | 
						|
                 }
 | 
						|
             } catch (Throwable ex) {
 | 
						|
-                server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName(), ex);
 | 
						|
+                // Paper start - error reporting
 | 
						|
+                String msg = "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName();
 | 
						|
+                server.getLogger().log(Level.SEVERE, msg, ex);
 | 
						|
+                if (!(event instanceof ServerExceptionEvent)) { // We don't want to cause an endless event loop
 | 
						|
+                    callEvent(new ServerExceptionEvent(new ServerEventException(msg, ex, registration.getPlugin(), registration.getListener(), event)));
 | 
						|
+                }
 | 
						|
+                // Paper end
 | 
						|
             }
 | 
						|
         }
 | 
						|
     }
 |