diff --git a/.travis.yml b/.travis.yml
index f660a2b..7e83694 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -34,7 +34,7 @@ env:
- secure: UG+b1tEgc8xv9x4r//2OAIK1RrYv6n209KTTFMMwcnAa7DI8HaP8nljRa5/VhDhuKHdlVrYH/tI90v7UVBs0GDVNwK5V17Io0fMm3FUGZekSthTCqqno5wAGa9r6a6mMLtSaSmIFeIKi0+0d2ZwplRuhj/dtEYjjBBj+kK8g4nE=
- secure: St/fecUDInFBCRriYqgp2F8PU9/SooorgxD9Mrs+b0EsC7AbtSsQXvdIv2Lp6xzdQ0VSXPcLIhULPOYrmBKnGQ/NjXTIZXxnroyQxxnI6xyEWIZwiHRY/bKRJDRbQTxD9NL32szKiDSwnw7pu6llF4D64UqQvziq4Gm6VohU75M=
- secure: bD15GVZWowiknbfLavh8CxSh0GsnF5kT4kZ6ggCuUDGyj0mzqf7dNRnchQIKkCG0WRYyTrFN4pEiygeywWsipEeAVv9Xhx3cuUZmzeQaR5KCWabSwJ8gK6jZd1YhcWmM9vrdPHobZr65MP0y/8mu/Fovgky9dY7KDf4G3SebNrM=
- - PARABOT_VERSION=2.8
+ - PARABOT_VERSION=2.8.1
cache:
directories:
diff --git a/README.md b/README.md
index 03897aa..cc2094d 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
# Parabot
-Parabot V2.8
+Parabot V2.8.1
#### Links
@@ -42,7 +42,7 @@ Then you'll need to add the dependency:
org.parabot
client
- 2.7
+ 2.8.1
```
diff --git a/pom.xml b/pom.xml
index 0fcc6fb..2a0c814 100755
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
org.parabot
client
- 2.8
+ 2.8.1
jar
@@ -17,7 +17,7 @@
Parabot client
- The only perfect open source (Runescape private server) bot!
+ The best open-source (Runescape Private Server) bot
http://www.parabot.org/
@@ -68,7 +68,7 @@
junit
junit
4.12
- provided
+ test
org.parabot
@@ -191,13 +191,13 @@
false
parabot-maven
Custom Maven Repository
- ftp://maven.parabot.org
+ ftp://maven.parabot.org/public_html
default
parabot-maven
Frontend Parabot Maven
- ftp://maven.parabot.org/docs/${artifactId}/
+ ftp://maven.parabot.org/public_html/docs/${artifactId}/
diff --git a/src/main/java/org/parabot/Landing.java b/src/main/java/org/parabot/Landing.java
index b5ff725..0e0c4b7 100644
--- a/src/main/java/org/parabot/Landing.java
+++ b/src/main/java/org/parabot/Landing.java
@@ -11,32 +11,31 @@ import org.parabot.core.network.proxy.ProxyType;
import org.parabot.core.ui.BotUI;
import org.parabot.core.ui.ServerSelector;
import org.parabot.core.ui.utils.UILog;
+import org.parabot.environment.handlers.exceptions.ExceptionHandler;
+import org.parabot.environment.handlers.exceptions.FileExceptionHandler;
import javax.swing.*;
import java.io.File;
-import java.io.IOException;
/**
- * Parabot v2.7
- *
* @author Everel, JKetelaar, Matt, Dane
- * @version 2.7
- * @see Homepage
+ * @version 2.8.1
+ * @see Homepage
*/
public final class Landing {
private static String username;
private static String password;
- public static void main(String... args) throws IOException {
+ public static void main(String... args) {
+// Thread.setDefaultUncaughtExceptionHandler(new FileExceptionHandler(ExceptionHandler.ExceptionType.CLIENT));
if (Context.getJavaVersion() >= 9) {
UILog.log("Parabot", "Parabot doesn't support Java 9+ currently. Please downgrade to Java 8 to ensure Parabot is working correctly.");
- System.exit(0);
}
if (!System.getProperty("os.arch").contains("64")) {
UILog.log("Parabot", "You are not running a 64-bit version of Java, this might cause the client to lag or crash unexpectedly.\r\n" +
- "It's recommended to upgrade to a 64-bit version.");
+ "It is recommended to upgrade to a 64-bit version.");
}
parseArgs(args);
@@ -80,11 +79,11 @@ public final class Landing {
switch (arg.toLowerCase()) {
case "-createdirs":
Directories.validate();
- System.out
- .println(TranslationHelper.translate(("DIRECTORIES_CREATED")));
+ System.out.println(TranslationHelper.translate(("DIRECTORIES_CREATED")));
System.exit(0);
break;
case "-debug":
+ Core.setDump(true);
case "-offlinemode":
Core.setDebug(true);
break;
@@ -130,14 +129,9 @@ public final class Landing {
break;
case "-proxy":
ProxyType type = ProxyType.valueOf(args[++i].toUpperCase());
- if (type == null) {
- System.err.println(TranslationHelper.translate("INVALID_PROXY_TYPE") + args[i]);
- System.exit(1);
- return;
- }
- ProxySocket.setProxy(type, args[++i],
- Integer.parseInt(args[++i]));
+ ProxySocket.setProxy(type, args[++i], Integer.parseInt(args[++i]));
break;
+ case "-proxy_auth":
case "-auth":
ProxySocket.auth = true;
ProxySocket.setLogin(args[++i], args[++i]);
@@ -146,6 +140,7 @@ public final class Landing {
Core.disableSec();
break;
case "-no_validation":
+ case "-ignore_updates":
Core.disableValidation();
break;
case "-uuid":
diff --git a/src/main/java/org/parabot/core/Core.java b/src/main/java/org/parabot/core/Core.java
index 0688108..c4cbef5 100644
--- a/src/main/java/org/parabot/core/Core.java
+++ b/src/main/java/org/parabot/core/Core.java
@@ -35,7 +35,7 @@ public class Core {
private static boolean loadLocal; //Loads both local and public scripts/servers
private static boolean validate = true;
- private static boolean secure = true;
+ private static boolean secure = true;
private static Version currentVersion = Configuration.BOT_VERSION;
@@ -140,46 +140,13 @@ public class Core {
}
/**
- * Checks the version of the bot using a checksum of the jar comparison against checksum given by the website
+ * Prints a debug line to the Logger and System PrintStream
+ * Meant for the debug adapter within hooks
*
- * @return true if no new version is found, otherwise false.
+ * @param line
*/
- private static boolean checksumValid() {
- File f = new File(Landing.class.getProtectionDomain().getCodeSource().getLocation().getFile());
- if (f.isFile()) {
- try {
- MessageDigest md = MessageDigest.getInstance("MD5");
- File location = new File(Landing.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
- if (location.exists()) {
- FileInputStream fis = new FileInputStream(location);
- byte[] dataBytes = new byte[1024];
-
- int nread;
-
- while ((nread = fis.read(dataBytes)) != -1) {
- md.update(dataBytes, 0, nread);
- }
-
- byte[] mdbytes = md.digest();
-
- StringBuilder sb = new StringBuilder("");
- for (byte mdbyte : mdbytes) {
- sb.append(Integer.toString((mdbyte & 0xff) + 0x100, 16).substring(1));
- }
-
- String result;
- if ((result = WebUtil.getContents(String.format(Configuration.COMPARE_CHECKSUM_URL, "client", currentVersion.get()), "checksum=" + URLEncoder.encode(sb.toString(), "UTF-8"))) != null) {
- JSONObject object = (JSONObject) WebUtil.getJsonParser().parse(result);
- boolean upToDate = (boolean) object.get("result");
- Core.verbose("Local checksum: " + URLEncoder.encode(sb.toString(), "UTF-8") + ". " + (upToDate ? "This matches BDN and is up to date." : "BDN mismatch, must be Out Of Date."));
- return upToDate;
- }
- }
- } catch (NoSuchAlgorithmException | ParseException | IOException | URISyntaxException e) {
- e.printStackTrace();
- }
- }
- return true;
+ public static void debug(final String line) {
+ System.out.println(line);
}
/**
@@ -194,7 +161,7 @@ public class Core {
try {
if (br != null) {
JSONObject object = (JSONObject) WebUtil.getJsonParser().parse(br);
- boolean latest = (Boolean) object.get("result");
+ boolean latest = (Boolean) object.get("result");
if (!latest) {
Directories.clearCache();
}
@@ -216,14 +183,6 @@ public class Core {
return true;
}
- /**
- * Method that removes the cache contents after 3 days
- */
- private static void validateCache() {
- // Already handled by Directories initiating
- // Method will be used once BDN V3 has a functionality for this
- }
-
public static void downloadNewVersion() {
UILog.log(TranslationHelper.translate("UPDATES"),
TranslationHelper.translate("DOWNLOAD_UPDATE_PARABOT_AT")
@@ -268,4 +227,55 @@ public class Core {
public static int newVersionAlert() {
return UILog.alert("Parabot Update", "There's a new version of Parabot! \nDo you wish to download it?\n\nThe current version could have some problems!", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
}
+
+ /**
+ * Checks the version of the bot using a checksum of the jar comparison against checksum given by the website
+ *
+ * @return true if no new version is found, otherwise false.
+ */
+ private static boolean checksumValid() {
+ File f = new File(Landing.class.getProtectionDomain().getCodeSource().getLocation().getFile());
+ if (f.isFile()) {
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ File location = new File(Landing.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
+ if (location.exists()) {
+ FileInputStream fis = new FileInputStream(location);
+ byte[] dataBytes = new byte[1024];
+
+ int nread;
+
+ while ((nread = fis.read(dataBytes)) != -1) {
+ md.update(dataBytes, 0, nread);
+ }
+
+ byte[] mdbytes = md.digest();
+
+ StringBuilder sb = new StringBuilder("");
+ for (byte mdbyte : mdbytes) {
+ sb.append(Integer.toString((mdbyte & 0xff) + 0x100, 16).substring(1));
+ }
+
+ String result;
+ if ((result = WebUtil.getContents(String.format(Configuration.COMPARE_CHECKSUM_URL, "client", currentVersion.get()), "checksum=" + URLEncoder.encode(sb.toString(), "UTF-8"))) != null) {
+ JSONObject object = (JSONObject) WebUtil.getJsonParser().parse(result);
+ boolean upToDate = (boolean) object.get("result");
+ Core.verbose("Local checksum: " + URLEncoder.encode(sb.toString(), "UTF-8") + ". " + (upToDate ? "This matches BDN and is up to date." : "BDN mismatch, must be Out Of Date."));
+ return upToDate;
+ }
+ }
+ } catch (NoSuchAlgorithmException | ParseException | IOException | URISyntaxException e) {
+ e.printStackTrace();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Method that removes the cache contents after 3 days
+ */
+ private static void validateCache() {
+ // Already handled by Directories initiating
+ // Method will be used once BDN V3 has a functionality for this
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/parabot/core/asm/adapters/AddCallbackAdapter.java b/src/main/java/org/parabot/core/asm/adapters/AddCallbackAdapter.java
index 8b26227..3cc10f8 100644
--- a/src/main/java/org/parabot/core/asm/adapters/AddCallbackAdapter.java
+++ b/src/main/java/org/parabot/core/asm/adapters/AddCallbackAdapter.java
@@ -57,7 +57,7 @@ public class AddCallbackAdapter implements Injectable, Opcodes {
}
inject.add(new MethodInsnNode(INVOKESTATIC,
this.invokeClass, this.invokeMethod,
- this.desc));
+ this.desc, false));
if (this.conditional) {
LabelNode ln = new LabelNode(new Label());
inject.add(new JumpInsnNode(IFEQ, ln));
diff --git a/src/main/java/org/parabot/core/asm/adapters/AddDebugAdapter.java b/src/main/java/org/parabot/core/asm/adapters/AddDebugAdapter.java
index e6c14f7..9fa7c17 100644
--- a/src/main/java/org/parabot/core/asm/adapters/AddDebugAdapter.java
+++ b/src/main/java/org/parabot/core/asm/adapters/AddDebugAdapter.java
@@ -5,7 +5,7 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
public class AddDebugAdapter {
- private ClassNode owner;
+ private ClassNode owner;
private MethodNode mn;
public AddDebugAdapter(ClassNode owner, MethodNode mn) {
@@ -19,14 +19,19 @@ public class AddDebugAdapter {
public void inject() {
InsnList inject = new InsnList();
- Label l0 = new Label();
+ Label l0 = new Label();
inject.add(new LabelNode(l0));
- String callString = owner.name + "." + mn.name + " " + mn.desc;
- LdcInsnNode ldc = new LdcInsnNode(callString);
+ String callString = owner.name + "." + mn.name + " " + mn.desc;
+ LdcInsnNode ldc = new LdcInsnNode(callString);
- MethodInsnNode methodNode = new MethodInsnNode(Opcodes.INVOKESTATIC, "org/parabot/core/Core", "debug",
- "(Ljava/lang/String;)V");
+ MethodInsnNode methodNode = new MethodInsnNode(
+ Opcodes.INVOKESTATIC,
+ "org/parabot/core/Core",
+ "debug",
+ "(Ljava/lang/String;)V",
+ false
+ );
inject.add(ldc);
inject.add(methodNode);
diff --git a/src/main/java/org/parabot/core/asm/adapters/AddInvokerAdapter.java b/src/main/java/org/parabot/core/asm/adapters/AddInvokerAdapter.java
index 74f5a54..d0fbf54 100644
--- a/src/main/java/org/parabot/core/asm/adapters/AddInvokerAdapter.java
+++ b/src/main/java/org/parabot/core/asm/adapters/AddInvokerAdapter.java
@@ -94,9 +94,9 @@ public class AddInvokerAdapter implements Opcodes, Injectable {
}
if (isInterface) {
- m.visitMethodInsn(INVOKEINTERFACE, instanceCast, mName, mDesc);
+ m.visitMethodInsn(INVOKEINTERFACE, instanceCast, mName, mDesc, true);
} else {
- m.visitMethodInsn(isStatic ? INVOKESTATIC : INVOKEVIRTUAL, methodLocation.name, mn.name, mn.desc);
+ m.visitMethodInsn(isStatic ? INVOKESTATIC : INVOKEVIRTUAL, methodLocation.name, mn.name, mn.desc, false);
}
if (this.returnDesc.contains("L")) {
if (!this.returnDesc.contains("[")) {
diff --git a/src/main/java/org/parabot/core/asm/redirect/SystemRedirect.java b/src/main/java/org/parabot/core/asm/redirect/SystemRedirect.java
index d00fc1f..5c28a6a 100644
--- a/src/main/java/org/parabot/core/asm/redirect/SystemRedirect.java
+++ b/src/main/java/org/parabot/core/asm/redirect/SystemRedirect.java
@@ -9,7 +9,7 @@ public class SystemRedirect {
public static PrintStream out = System.out;
public static PrintStream err = System.err;
- public static InputStream in = System.in;
+ public static InputStream in = System.in;
public static long currentTimeMillis() {
return System.currentTimeMillis();
@@ -23,11 +23,23 @@ public class SystemRedirect {
System.exit(i);
}
+ private static String getClassPath(){
+ String classPath = System.getProperty("java.class.path");
+ StringBuilder finalClassPath = new StringBuilder();
+ for (String path : classPath.split(":")) {
+ if (!path.toLowerCase().contains("parabot")) {
+ finalClassPath.append(path).append(":");
+ }
+ }
+
+ return finalClassPath.toString();
+ }
+
public static String getProperty(String s) {
String value;
switch (s) {
case "java.class.path":
- value = ".";
+ value = getClassPath();
break;
default:
value = System.getProperty(s);
@@ -42,14 +54,14 @@ public class SystemRedirect {
String value = null;
switch (s2) {
case "java.class.path":
- value = ".";
+ value = getClassPath();
break;
}
if (value == null) {
switch (s) {
case "java.class.path":
- value = ".";
+ value = getClassPath();
break;
default:
value = System.getProperty(s);
diff --git a/src/main/java/org/parabot/core/parsers/scripts/ScriptParser.java b/src/main/java/org/parabot/core/parsers/scripts/ScriptParser.java
index a7e5d1f..cbb4ad2 100644
--- a/src/main/java/org/parabot/core/parsers/scripts/ScriptParser.java
+++ b/src/main/java/org/parabot/core/parsers/scripts/ScriptParser.java
@@ -18,9 +18,10 @@ public abstract class ScriptParser {
public static final Map SCRIPT_CACHE = new HashMap<>();
+ private static final ArrayList parsers = new ArrayList<>();
+
public static ScriptDescription[] getDescriptions() {
SCRIPT_CACHE.clear();
- final ArrayList parsers = new ArrayList<>();
if (Core.inLoadLocal()) {
parsers.add(new LocalJavaScripts());
parsers.add(new BDNScripts());
@@ -47,6 +48,9 @@ public abstract class ScriptParser {
return SORTED_SCRIPT_CACHE.keySet().toArray(new ScriptDescription[SORTED_SCRIPT_CACHE.size()]);
}
- public abstract void execute();
+ public static final void addParser(ScriptParser parser) {
+ parsers.add(parser);
+ }
+ public abstract void execute();
}
\ No newline at end of file
diff --git a/src/main/java/org/parabot/core/ui/ReflectUI.java b/src/main/java/org/parabot/core/ui/ReflectUI.java
index a35ba39..9475ce0 100644
--- a/src/main/java/org/parabot/core/ui/ReflectUI.java
+++ b/src/main/java/org/parabot/core/ui/ReflectUI.java
@@ -27,11 +27,11 @@ import java.util.HashMap;
*/
public class ReflectUI extends JFrame {
private static final long serialVersionUID = 98565034137367257L;
- private JTree tree;
+ private JTree tree;
private DefaultMutableTreeNode root;
- private DefaultTreeModel model;
- private JEditorPane basicInfoPane;
- private JEditorPane selectionInfoPane;
+ private DefaultTreeModel model;
+ private JEditorPane basicInfoPane;
+ private JEditorPane selectionInfoPane;
private Object instance;
@@ -82,7 +82,7 @@ public class ReflectUI extends JFrame {
@Override
public void actionPerformed(ActionEvent e) {
RefField result = null;
- String search = searchFunction.getText();
+ String search = searchFunction.getText();
for (RefField f : fields.values()) {
if (f != null && (f.asObject()) != null) {
String value;
@@ -137,9 +137,9 @@ public class ReflectUI extends JFrame {
@Override
public void valueChanged(TreeSelectionEvent event) {
- TreePath path = event.getPath();
+ TreePath path = event.getPath();
Object[] pathElements = path.getPath();
- Object element = pathElements[pathElements.length - 1];
+ Object element = pathElements[pathElements.length - 1];
if (pathElements.length == 2) {
setClassInfo(classes.get(element));
} else if (pathElements.length == 3) {
@@ -179,7 +179,7 @@ public class ReflectUI extends JFrame {
content.add(searchContent);
JScrollPane contentPane = new JScrollPane(content);
- Dimension prefSize = content.getPreferredSize();
+ Dimension prefSize = content.getPreferredSize();
contentPane.setPreferredSize(new Dimension(prefSize.width + contentPane.getVerticalScrollBar().getPreferredSize().width, prefSize.height + contentPane.getHorizontalScrollBar().getPreferredSize().height));
setContentPane(contentPane);
pack();
@@ -188,8 +188,8 @@ public class ReflectUI extends JFrame {
}
private void fillModel() {
- Context context = Context.getInstance();
- ClassPath classPath = context.getClassPath();
+ Context context = Context.getInstance();
+ ClassPath classPath = context.getClassPath();
ASMClassLoader classLoader = context.getASMClassLoader();
for (String className : classPath.classNames) {
try {
@@ -219,7 +219,7 @@ public class ReflectUI extends JFrame {
}
private void fillBasicInfoPane() {
- Context context = Context.getInstance();
+ Context context = Context.getInstance();
ClassPath classPath = context.getClassPath();
StringBuilder builder = new StringBuilder();
@@ -231,8 +231,8 @@ public class ReflectUI extends JFrame {
}
private void setFieldInfo(RefField refField) {
- StringBuilder builder = new StringBuilder();
- RefClass refClass = refField.getOwner();
+ StringBuilder builder = new StringBuilder();
+ RefClass refClass = refField.getOwner();
builder.append("").append(refClass.getClassName()).append(".").append(refField.getName()).append("
");
builder.append("Class: ").append(refClass.getClassName()).append("
");
builder.append("Value: ").append(refField.asObject()).append("
");
@@ -240,11 +240,23 @@ public class ReflectUI extends JFrame {
builder.append("Static: ").append(refField.isStatic() ? "yes" : "no").append("
");
builder.append("Array: ").append(refField.isArray() ? refField.getArrayDimensions() + " dimension(s)" : "no").append("
");
- if (refField.isArray() && refField.getASMType().getClassName().contains("String") && refField.getArrayDimensions() == 1) {
- String[] strings = (String[]) refField.asObject();
- String values = StringUtils.implode(", ", strings);
+ if (refField.isArray()) {
+ if (refField.getArrayDimensions() == 1) {
+ if (refField.getASMType().getClassName().contains("int")) {
+ int[] ints = (int[]) refField.asObject();
+ String values = "";
+ for (int i = 0; i < ints.length; i++) {
+ values += (ints[i] + (i < ints.length - 1 ? ", " : ""));
+ }
- builder.append("Values: ").append(values).append("
");
+ builder.append("Values: ").append(values).append("
");
+ } else if (refField.getASMType().getClassName().contains("String")) {
+ String[] strings = (String[]) refField.asObject();
+ String values = StringUtils.implode(", ", strings);
+
+ builder.append("Values: ").append(values).append("
");
+ }
+ }
}
selectionInfoPane.setText(builder.toString());
diff --git a/src/main/java/org/parabot/core/ui/ScriptSelector.java b/src/main/java/org/parabot/core/ui/ScriptSelector.java
index 9890420..97081db 100644
--- a/src/main/java/org/parabot/core/ui/ScriptSelector.java
+++ b/src/main/java/org/parabot/core/ui/ScriptSelector.java
@@ -163,14 +163,7 @@ public final class ScriptSelector extends JFrame {
@Override
public void actionPerformed(ActionEvent e) {
String s = getScriptName(tree.getSelectionPath().toString());
- if (s != null) {
- try {
- WebUtil.getContents("http://bdn.parabot.org/api/v2/scripts/local", "script=" + URLEncoder.encode(s, "UTF-8") + "&username=" + URLEncoder.encode(Context.getUsername(), "UTF-8"));
- } catch (MalformedURLException | UnsupportedEncodingException e1) {
- e1.printStackTrace();
- }
- runScript(format.get(s));
- }
+ runScript(format.get(s));
}
});
diff --git a/src/main/java/org/parabot/core/ui/utils/UILog.java b/src/main/java/org/parabot/core/ui/utils/UILog.java
index d1261f6..ffa4552 100644
--- a/src/main/java/org/parabot/core/ui/utils/UILog.java
+++ b/src/main/java/org/parabot/core/ui/utils/UILog.java
@@ -39,4 +39,9 @@ public class UILog {
return JOptionPane.showOptionDialog(null, message, title,
JOptionPane.YES_NO_CANCEL_OPTION, messageType, null, options, null);
}
+
+ public static int alert(final String title, final String message, Object[] options, int initialValue, int messageType) {
+ return JOptionPane.showOptionDialog(null, message, title,
+ JOptionPane.YES_NO_CANCEL_OPTION, messageType, null, options, initialValue);
+ }
}
diff --git a/src/main/java/org/parabot/environment/handlers/exceptions/ExceptionHandler.java b/src/main/java/org/parabot/environment/handlers/exceptions/ExceptionHandler.java
new file mode 100644
index 0000000..198a55a
--- /dev/null
+++ b/src/main/java/org/parabot/environment/handlers/exceptions/ExceptionHandler.java
@@ -0,0 +1,88 @@
+package org.parabot.environment.handlers.exceptions;
+
+/**
+ * Class to be implemented that allows multiple types of exception handlers
+ */
+public abstract class ExceptionHandler implements Thread.UncaughtExceptionHandler {
+ /**
+ * The name of the exception handler
+ */
+ private final String name;
+
+ /**
+ * The status of the exception handler; Defines if the exception handler is enabled or disabled
+ */
+ private boolean enabled = true;
+
+ /**
+ * The type the handler is meant for
+ */
+ private ExceptionType exceptionType;
+
+ public ExceptionHandler(String name, ExceptionType exceptionType) {
+ this.name = name;
+ this.exceptionType = exceptionType;
+ }
+
+ @Override
+ public void uncaughtException(Thread t, Throwable e) {
+ this.handle(e);
+ }
+
+ /**
+ * Writes the exception to class extending this abstract class
+ *
+ * @param e
+ */
+ public abstract void handle(Throwable e);
+
+ /**
+ * Returns if the exception handler is enabled or disabled
+ *
+ * @return
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Sets the enabled status of the exception handler
+ *
+ * @param enabled
+ *
+ * @return
+ */
+ public ExceptionHandler setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ public ExceptionType getExceptionType() {
+ return exceptionType;
+ }
+
+ public ExceptionHandler setExceptionType(ExceptionType exceptionType) {
+ this.exceptionType = exceptionType;
+ return this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public enum ExceptionType {
+ SERVER("Server"),
+ SCRIPT("Script"),
+ CLIENT("Client");
+
+ private String name;
+
+ ExceptionType(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+}
diff --git a/src/main/java/org/parabot/environment/handlers/exceptions/FileExceptionHandler.java b/src/main/java/org/parabot/environment/handlers/exceptions/FileExceptionHandler.java
new file mode 100644
index 0000000..e72c355
--- /dev/null
+++ b/src/main/java/org/parabot/environment/handlers/exceptions/FileExceptionHandler.java
@@ -0,0 +1,139 @@
+package org.parabot.environment.handlers.exceptions;
+
+import org.parabot.core.Directories;
+import org.parabot.core.ui.utils.UILog;
+import org.parabot.environment.api.utils.FileUtil;
+
+import javax.swing.*;
+import java.awt.*;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Writes exceptions to a file and reports the file location back to the user
+ */
+public class FileExceptionHandler extends ExceptionHandler {
+ /**
+ * The default index of all options to be selected when the popup appears
+ */
+ private static final int defaultOptionIndex = 1;
+
+ /**
+ * Directory where the reports get written to
+ */
+ private final File reportsDirectory;
+
+ /**
+ * All possible options to select when the popup appears
+ */
+ private final Object[] options = new Object[]{
+ "Close",
+ "Open report",
+ "Ignore " + this.getExceptionType().getName().toLowerCase() + " errors" };
+
+ /**
+ * Defines if the alert should popup during this client instance again
+ */
+ private boolean ignored = false;
+
+ /**
+ * Initializes the exception handler and ensures the reports directory is created and writable
+ */
+ public FileExceptionHandler(ExceptionType exceptionType) {
+ super("File exception handler", exceptionType);
+
+ this.reportsDirectory = new File(Directories.getWorkspace(), "reports");
+ if (!this.reportsDirectory.exists() || !this.reportsDirectory.isDirectory()) {
+ this.reportsDirectory.mkdir();
+ }
+
+ this.cleanOldErrors();
+ }
+
+ @Override
+ public void handle(Throwable e) {
+ File report = new File(this.reportsDirectory, "report-" + this.getExceptionType().getName().toLowerCase() + "-" + (System.currentTimeMillis() / 1000) + ".txt");
+ try {
+ report.createNewFile();
+
+ StringBuilder reportContent = new StringBuilder();
+ reportContent.append("Message: ").append(e.getMessage()).append("\n\n");
+ reportContent.append(e.toString()).append("\n\n");
+
+ for (int i = 0; i < e.getStackTrace().length; i++) {
+ if (i > 0) {
+ reportContent.append("\t");
+ }
+ reportContent.append(e.getStackTrace()[i]).append("\n");
+ }
+
+ FileUtil.writeFileContents(report, reportContent.toString());
+
+ if (!ignored) {
+ displayAlert(report);
+ }
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public boolean isIgnored() {
+ return ignored;
+ }
+
+ public FileExceptionHandler setIgnored(boolean ignored) {
+ this.ignored = ignored;
+ return this;
+ }
+
+ public File getReportsDirectory() {
+ return reportsDirectory;
+ }
+
+ /**
+ * Displays the dialog of the alert
+ *
+ * @param report
+ */
+ private void displayAlert(File report) {
+ int response = UILog.alert(
+ "Error occurred",
+ "We are sorry to inform you that an error occurred within Parabot.\n\n" +
+ "The error has been written to a report file.\n" +
+ "Please report the error to the Parabot staff with as much information as possible.",
+ this.options,
+ defaultOptionIndex,
+ JOptionPane.WARNING_MESSAGE
+ );
+
+ switch (response) {
+ case 1:
+ try {
+ Desktop.getDesktop().open(report);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ break;
+ case 2:
+ ignored = true;
+ break;
+
+ }
+ }
+
+ /**
+ * Remove errors older than 24 hours
+ */
+ private void cleanOldErrors() {
+ File[] reports = this.reportsDirectory.listFiles();
+ if (reports != null) {
+ for (File report : reports) {
+ if (report.isFile()) {
+ if ((System.currentTimeMillis() - report.lastModified()) / 1000 > 60 * 60 * 24) {
+ report.delete();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/parabot/environment/servers/ServerProvider.java b/src/main/java/org/parabot/environment/servers/ServerProvider.java
index ae9b5ba..78ca006 100644
--- a/src/main/java/org/parabot/environment/servers/ServerProvider.java
+++ b/src/main/java/org/parabot/environment/servers/ServerProvider.java
@@ -77,7 +77,7 @@ public abstract class ServerProvider implements Opcodes {
return;
}
- HookParser parser = hookFile.getParser();
+ HookParser parser = hookFile.getParser();
Injectable[] injectables = parser.getInjectables();
if (injectables == null) {
@@ -92,17 +92,18 @@ public abstract class ServerProvider implements Opcodes {
index++;
}
} catch (NullPointerException ex) {
- if(!crashed) {
+ if (!crashed) {
Injectable inj = injectables[index];
- int resp = UILog.alert("Outdated client", "This server currently has outdated hooks, please report it to a member of the Parabot staff.\r\n\r\n" +
- "Broken hook:\r\n"+inj, new Object[]{"Close", "Report here..."}, JOptionPane.ERROR_MESSAGE);
+ int resp = UILog.alert("Outdated client", "This server currently has outdated hooks, please report it to the Parabot staff.\r\n\r\n" +
+ "Broken hook:\r\n" + inj, new Object[]{ "Close", "Report here..." }, JOptionPane.ERROR_MESSAGE);
- if(resp == 1) {
+ if (resp == 1) {
URI uri = URI.create(Configuration.COMMUNITY_PAGE + "forum/135-reports/");
try {
Desktop.getDesktop().browse(uri);
- } catch (IOException ignore) {}
+ } catch (IOException ignore) {
+ }
}
}
crashed = true;
@@ -112,20 +113,6 @@ public abstract class ServerProvider implements Opcodes {
Context.getInstance().setHookParser(parser);
}
- private HookFile fetchHookFile() {
- HookFile hookFile = getHookFile();
- if (hookFile != null) {
- return hookFile;
- }
-
- URL hookLocation = getHooks();
- if (hookLocation == null) {
- return null;
- }
-
- return new HookFile(hookLocation, HookFile.TYPE_XML);
- }
-
/**
* Add custom items to the bot menu bar
*
@@ -156,16 +143,16 @@ public abstract class ServerProvider implements Opcodes {
public void initMouse() {
final Context context = Context.getInstance();
- final Applet applet = context.getApplet();
- final Mouse mouse = new Mouse(applet);
+ final Applet applet = context.getApplet();
+ final Mouse mouse = new Mouse(applet);
applet.addMouseListener(mouse);
applet.addMouseMotionListener(mouse);
context.setMouse(mouse);
}
public void initKeyboard() {
- final Context context = Context.getInstance();
- final Applet applet = context.getApplet();
+ final Context context = Context.getInstance();
+ final Applet applet = context.getApplet();
final Keyboard keyboard = new Keyboard(applet);
applet.addKeyListener(keyboard);
context.setKeyboard(keyboard);
@@ -191,4 +178,18 @@ public abstract class ServerProvider implements Opcodes {
}
+ private HookFile fetchHookFile() {
+ HookFile hookFile = getHookFile();
+ if (hookFile != null) {
+ return hookFile;
+ }
+
+ URL hookLocation = getHooks();
+ if (hookLocation == null) {
+ return null;
+ }
+
+ return new HookFile(hookLocation, HookFile.TYPE_XML);
+ }
+
}
diff --git a/src/main/java/org/parabot/environment/servers/executers/LocalPublicServerExecuter.java b/src/main/java/org/parabot/environment/servers/executers/LocalPublicServerExecuter.java
index 3f06b14..b52574c 100644
--- a/src/main/java/org/parabot/environment/servers/executers/LocalPublicServerExecuter.java
+++ b/src/main/java/org/parabot/environment/servers/executers/LocalPublicServerExecuter.java
@@ -24,9 +24,9 @@ import java.net.URL;
* @author JKetelaar
*/
public class LocalPublicServerExecuter extends ServerExecuter {
- private String serverName;
- private String serverUrl;
- private String providerUrl;
+ private String serverName;
+ private String serverUrl;
+ private String providerUrl;
private ServerProviderInfo serverProviderInfo;
public LocalPublicServerExecuter(final String serverName, final ServerProviderInfo serverProviderInfo, String serverUrl, String providerUrl) {
@@ -80,8 +80,8 @@ public class LocalPublicServerExecuter extends ServerExecuter {
BuildPath.add(destination.toURI().toURL());
- ServerLoader serverLoader = new ServerLoader(classPath);
- final String[] classNames = serverLoader.getServerClassNames();
+ ServerLoader serverLoader = new ServerLoader(classPath);
+ final String[] classNames = serverLoader.getServerClassNames();
if (classNames.length == 0) {
UILog.log(
"Error",
diff --git a/src/main/java/org/parabot/environment/servers/executers/LocalServerExecuter.java b/src/main/java/org/parabot/environment/servers/executers/LocalServerExecuter.java
index 1ff3a40..f509ecc 100644
--- a/src/main/java/org/parabot/environment/servers/executers/LocalServerExecuter.java
+++ b/src/main/java/org/parabot/environment/servers/executers/LocalServerExecuter.java
@@ -16,8 +16,8 @@ import java.net.MalformedURLException;
*/
public class LocalServerExecuter extends ServerExecuter {
private final Constructor> serverProviderConstructor;
- private ClassPath classPath;
- private String serverName;
+ private ClassPath classPath;
+ private String serverName;
public LocalServerExecuter(Constructor> serverProviderConstructor,
ClassPath classPath, final String serverName) {
diff --git a/src/main/java/org/parabot/environment/servers/executers/PublicServerExecuter.java b/src/main/java/org/parabot/environment/servers/executers/PublicServerExecuter.java
index a316586..b8d2f77 100644
--- a/src/main/java/org/parabot/environment/servers/executers/PublicServerExecuter.java
+++ b/src/main/java/org/parabot/environment/servers/executers/PublicServerExecuter.java
@@ -36,10 +36,9 @@ public class PublicServerExecuter extends ServerExecuter {
}
};
- private String serverName;
-
- private PBLocalPreferences settings;
private final String cacheVersionKey = "cachedProviderVersion";
+ private String serverName;
+ private PBLocalPreferences settings;
public PublicServerExecuter(final String serverName) {
this.serverName = serverName;
@@ -58,14 +57,14 @@ public class PublicServerExecuter extends ServerExecuter {
Core.verbose("Downloading: " + jarUrl + " ...");
String providerVersion = serverProviderInfo.getProviderVersion();
- if(providerVersion == null) {
+ if (providerVersion == null) {
providerVersion = "error";
}
- settings = new PBLocalPreferences(serverProviderInfo.getClientCRC32()+".json");
- if(settings.getSetting(cacheVersionKey) != null) {
+ settings = new PBLocalPreferences(serverProviderInfo.getClientCRC32() + ".json");
+ if (settings.getSetting(cacheVersionKey) != null) {
Core.verbose(String.format("Latest provider version: %s, local provider version: %s", settings.getSetting(cacheVersionKey), providerVersion));
- if(!settings.getSetting(cacheVersionKey).equals(providerVersion)) {
+ if (!settings.getSetting(cacheVersionKey).equals(providerVersion)) {
Core.verbose("Local provider outdated, clearing cache.");
Directories.clearCache();
}
@@ -88,8 +87,8 @@ public class PublicServerExecuter extends ServerExecuter {
BuildPath.add(destination.toURI().toURL());
- ServerLoader serverLoader = new ServerLoader(classPath);
- final String[] classNames = serverLoader.getServerClassNames();
+ ServerLoader serverLoader = new ServerLoader(classPath);
+ final String[] classNames = serverLoader.getServerClassNames();
if (classNames == null || classNames.length == 0) {
UILog.log(
"Error",
diff --git a/src/main/java/org/parabot/environment/servers/executers/ServerExecuter.java b/src/main/java/org/parabot/environment/servers/executers/ServerExecuter.java
index cae7c5f..1fd6df9 100644
--- a/src/main/java/org/parabot/environment/servers/executers/ServerExecuter.java
+++ b/src/main/java/org/parabot/environment/servers/executers/ServerExecuter.java
@@ -3,6 +3,8 @@ package org.parabot.environment.servers.executers;
import org.parabot.core.Context;
import org.parabot.core.ui.BotUI;
import org.parabot.core.ui.components.PaintComponent;
+import org.parabot.environment.handlers.exceptions.ExceptionHandler;
+import org.parabot.environment.handlers.exceptions.FileExceptionHandler;
import org.parabot.environment.servers.ServerProvider;
/**
@@ -15,7 +17,7 @@ public abstract class ServerExecuter {
public abstract void run();
public void finalize(final ServerProvider provider, final String serverName) {
- new Thread(new Runnable() {
+ Thread serverThread = new Thread(new Runnable() {
@Override
public void run() {
try {
@@ -30,7 +32,11 @@ public abstract class ServerExecuter {
t.printStackTrace();
}
}
- }).start();
+ });
+
+ serverThread.setUncaughtExceptionHandler(new FileExceptionHandler(ExceptionHandler.ExceptionType.SERVER));
+
+ serverThread.start();
}
}
diff --git a/src/main/java/org/parabot/environment/servers/loader/ServerLoader.java b/src/main/java/org/parabot/environment/servers/loader/ServerLoader.java
index 4ed965b..7f214a6 100644
--- a/src/main/java/org/parabot/environment/servers/loader/ServerLoader.java
+++ b/src/main/java/org/parabot/environment/servers/loader/ServerLoader.java
@@ -29,8 +29,9 @@ public class ServerLoader extends ASMClassLoader {
public final String[] getServerClassNames() {
final List classNames = new ArrayList();
for (ClassNode c : classPath.classes.values()) {
- if (c.superName.replace('/', '.').equals(
- ServerProvider.class.getName())) {
+ if (c.superName
+ .replace('/', '.')
+ .equals(ServerProvider.class.getName())) {
classNames.add(c.name.replace('/', '.'));
}
}
diff --git a/src/test/java/org/parabot/FileExceptionHandlerTest.java b/src/test/java/org/parabot/FileExceptionHandlerTest.java
new file mode 100644
index 0000000..7066c7f
--- /dev/null
+++ b/src/test/java/org/parabot/FileExceptionHandlerTest.java
@@ -0,0 +1,39 @@
+package org.parabot;
+
+import org.junit.Test;
+import org.parabot.environment.handlers.exceptions.ExceptionHandler;
+import org.parabot.environment.handlers.exceptions.FileExceptionHandler;
+
+public class FileExceptionHandlerTest {
+
+ @Test
+ public void manualTest() {
+ FileExceptionHandler handler = new FileExceptionHandler(ExceptionHandler.ExceptionType.CLIENT);
+ handler.setIgnored(true);
+
+ Exception exception = new NullPointerException("Manual test");
+ handler.handle(exception);
+ }
+
+ @Test
+ public void threadHandlerTest() {
+ FileExceptionHandler handler = new FileExceptionHandler(ExceptionHandler.ExceptionType.CLIENT);
+ handler.setIgnored(true);
+
+ Thread thread = new Thread() {
+ @Override
+ public void run() throws NullPointerException {
+ throw new NullPointerException("Thread test");
+ }
+ };
+
+ thread.setUncaughtExceptionHandler(handler);
+ thread.start();
+
+ try {
+ Thread.sleep(1500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+}