diff --git a/.travis.yml b/.travis.yml
index 49ff419..f660a2b 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.7
+ - PARABOT_VERSION=2.8
cache:
directories:
diff --git a/README.md b/README.md
index dfb55fb..03897aa 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
# Parabot
-Parabot V2.7
+Parabot V2.8
#### Links
diff --git a/pom.xml b/pom.xml
index 04ea80a..0fcc6fb 100755
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
org.parabot
client
- 2.7
+ 2.8
jar
@@ -73,7 +73,7 @@
org.parabot
internal-api
- 1.52.1
+ 1.53.1
diff --git a/src/main/java/org/parabot/Landing.java b/src/main/java/org/parabot/Landing.java
index f3cb7f9..b5ff725 100644
--- a/src/main/java/org/parabot/Landing.java
+++ b/src/main/java/org/parabot/Landing.java
@@ -1,6 +1,7 @@
package org.parabot;
import org.parabot.api.translations.TranslationHelper;
+import org.parabot.core.Context;
import org.parabot.core.Core;
import org.parabot.core.Directories;
import org.parabot.core.forum.AccountManager;
@@ -9,6 +10,7 @@ import org.parabot.core.network.proxy.ProxySocket;
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 javax.swing.*;
import java.io.File;
@@ -27,6 +29,16 @@ public final class Landing {
public static void main(String... args) throws IOException {
+ 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.");
+ }
+
parseArgs(args);
Directories.validate();
@@ -139,6 +151,9 @@ public final class Landing {
case "-uuid":
Core.setQuickLaunchByUuid(Integer.parseInt(args[++i]));
break;
+ default:
+ System.err.println(String.format("Unknown argument given: %s", arg.toLowerCase()));
+ break;
}
}
}
diff --git a/src/main/java/org/parabot/core/Configuration.java b/src/main/java/org/parabot/core/Configuration.java
index 6217c67..08a8ca1 100644
--- a/src/main/java/org/parabot/core/Configuration.java
+++ b/src/main/java/org/parabot/core/Configuration.java
@@ -11,17 +11,21 @@ public class Configuration extends org.parabot.api.Configuration {
public static final String LOGIN_SERVER = "http://bdn.parabot.org/api/v2/users/login";
public static final String GET_SCRIPTS = "http://bdn.parabot.org/api/get.php?action=scripts_scripts&server=";
public static final String GET_SCRIPT = "http://bdn.parabot.org/api/get.php?action=scripts_script&id=";
+ public static final String GET_SERVER_PROVIDER_TYPE = "http://v3.bdn.parabot.org/api/bot/server/type?server=%s";
public static final String GET_SERVER_PROVIDERS = "http://bdn.parabot.org/api/get.php?action=server_providers";
public static final String GET_SERVER_PROVIDER = "http://v3.bdn.parabot.org/api/bot/download/provider?nightly=%s&server=%s";
+ public static final String SERVER_PROVIDER_INFO = "http://v3.bdn.parabot.org/api/bot/list/%s?latest=true";
public static final String GET_SERVER_PROVIDER_INFO = "http://bdn.parabot.org/api/get.php?action=server_information&name=";
public static final String GET_SERVER_SETTINGS = "http://bdn.parabot.org/api/get.php?action=get_settings";
public static final String GET_BOT_VERSION = "http://bdn.parabot.org/api/v2/bot/version";
public static final String API_DOWNLOAD_BOT = "http://v3.bdn.parabot.org/api/bot/download/client";
public static final String DOWNLOAD_BOT = "http://bdn.parabot.org/versions/";
- public static final String REGISTRATION_PAGE = "https://www.parabot.org/community/register/";
public static final String GET_RANDOMS = "http://v3.bdn.parabot.org/api/bot/download/randoms";
public static final String DATA_API = "http://bdn.parabot.org/api/v2/data/";
public static final String ITEM_API = DATA_API + "items/";
- public static final Version BOT_VERSION = ProjectProperties.getProjectVersion();
+ public static final Version BOT_VERSION = ProjectProperties.getProjectVersion();
+
+ public static final String COMMUNITY_PAGE = "https://www.parabot.org/community/";
+ public static final String REGISTRATION_PAGE = COMMUNITY_PAGE + "register/";
}
diff --git a/src/main/java/org/parabot/core/Context.java b/src/main/java/org/parabot/core/Context.java
index 0b2f0fa..cc0420d 100644
--- a/src/main/java/org/parabot/core/Context.java
+++ b/src/main/java/org/parabot/core/Context.java
@@ -70,6 +70,13 @@ public class Context {
this.defaultErr = System.err;
}
+ public static double getJavaVersion() {
+ String version = System.getProperty("java.version");
+ int pos = version.indexOf('.');
+ pos = version.indexOf('.', pos + 1);
+ return Double.parseDouble(version.substring(0, pos));
+ }
+
/**
* Returns the instance of this class, based on a given ServerProvider
*
diff --git a/src/main/java/org/parabot/core/asm/hooks/HookFile.java b/src/main/java/org/parabot/core/asm/hooks/HookFile.java
index 05fa6f6..5aabd19 100644
--- a/src/main/java/org/parabot/core/asm/hooks/HookFile.java
+++ b/src/main/java/org/parabot/core/asm/hooks/HookFile.java
@@ -1,24 +1,29 @@
package org.parabot.core.asm.hooks;
+import org.parabot.core.forum.AccountManager;
import org.parabot.core.parsers.hooks.HookParser;
import org.parabot.core.parsers.hooks.JSONHookParser;
import org.parabot.core.parsers.hooks.XMLHookParser;
import org.parabot.environment.api.utils.WebUtil;
import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
public class HookFile {
- public static final int TYPE_XML = 0;
+ public static final int TYPE_XML = 0;
public static final int TYPE_JSON = 1;
private URL url;
private int type;
+ private boolean isLocal;
+
public HookFile(File file, int type) throws MalformedURLException {
this(file.toURI().toURL(), type);
+ this.isLocal = true;
}
public HookFile(URL url, int type) {
@@ -26,17 +31,22 @@ public class HookFile {
this.url = url;
}
- private void setType(int type) {
- if (type < 0 || type > 1) {
- throw new IllegalArgumentException("This type does not exist");
- }
- this.type = type;
- }
-
public InputStream getInputStream() {
return WebUtil.getInputStream(url);
}
+ public InputStream getInputStream(AccountManager manager) {
+ if (isLocal) {
+ return this.getInputStream();
+ } else {
+ try {
+ return WebUtil.getConnection(url, "apikey=" + manager.getAccount().getApi()).getInputStream();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+ }
+
public HookParser getParser() {
switch (type) {
case TYPE_XML:
@@ -47,4 +57,11 @@ public class HookFile {
return null;
}
+ private void setType(int type) {
+ if (type < 0 || type > 1) {
+ throw new IllegalArgumentException("This type does not exist");
+ }
+ this.type = type;
+ }
+
}
diff --git a/src/main/java/org/parabot/core/asm/redirect/ClassRedirect.java b/src/main/java/org/parabot/core/asm/redirect/ClassRedirect.java
index 0925aeb..c16c903 100644
--- a/src/main/java/org/parabot/core/asm/redirect/ClassRedirect.java
+++ b/src/main/java/org/parabot/core/asm/redirect/ClassRedirect.java
@@ -7,6 +7,7 @@ import org.parabot.environment.scripts.Script;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
+import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
@@ -58,6 +59,15 @@ public class ClassRedirect {
return Class.forName(name);
}
+ public static URL getResource(Class> c, String path) {
+ if(validStack() || validRequest(c)) {
+ return c.getResource(path);
+ }
+
+ System.err.println(c.getName() + "#getResource(" + path + ") Blocked.");
+ throw RedirectClassAdapter.createSecurityException();
+ }
+
public static ClassLoader getClassLoader(Class> c) {
System.err.println(c.getName() + "#getClassLoader()" + " Blocked.");
throw RedirectClassAdapter.createSecurityException();
diff --git a/src/main/java/org/parabot/core/asm/redirect/RuntimeRedirect.java b/src/main/java/org/parabot/core/asm/redirect/RuntimeRedirect.java
index f5074c2..502ba88 100644
--- a/src/main/java/org/parabot/core/asm/redirect/RuntimeRedirect.java
+++ b/src/main/java/org/parabot/core/asm/redirect/RuntimeRedirect.java
@@ -31,7 +31,7 @@ public class RuntimeRedirect {
if (s.contains("ping")) {
System.out.println("Faked attempted command: " + s);
try {
- return r.exec("ping 127.0.0.1");
+ return r.exec("ping 8.8.8.8");
} catch (IOException e) {
throw RedirectClassAdapter.createSecurityException();
}
diff --git a/src/main/java/org/parabot/core/asm/redirect/ThreadRedirect.java b/src/main/java/org/parabot/core/asm/redirect/ThreadRedirect.java
index c40d4d2..a6a58a3 100644
--- a/src/main/java/org/parabot/core/asm/redirect/ThreadRedirect.java
+++ b/src/main/java/org/parabot/core/asm/redirect/ThreadRedirect.java
@@ -61,4 +61,12 @@ public class ThreadRedirect {
public static void setUncaughtExceptionHandler(Thread t, Thread.UncaughtExceptionHandler handler) {
t.setUncaughtExceptionHandler(handler);
}
+
+ public static boolean isInterrupted(Thread thread) {
+ return thread.isInterrupted();
+ }
+
+ public static long getId(Thread thread) {
+ return thread.getId();
+ }
}
diff --git a/src/main/java/org/parabot/core/asm/wrappers/Callback.java b/src/main/java/org/parabot/core/asm/wrappers/Callback.java
index 5917f0f..5673d28 100644
--- a/src/main/java/org/parabot/core/asm/wrappers/Callback.java
+++ b/src/main/java/org/parabot/core/asm/wrappers/Callback.java
@@ -49,4 +49,19 @@ public class Callback implements Injectable {
this.invokeMethod, this.desc, this.args, this.conditional);
}
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("Injectable type: Callback");
+
+ if(method != null) {
+ sb.append(", intercepts method: ").append(method.name);
+ }
+
+ sb.append(", calls class: ").append(invokeClass)
+ .append(", calls method: ").append(invokeMethod);
+
+ return sb.toString();
+ }
}
diff --git a/src/main/java/org/parabot/core/asm/wrappers/Getter.java b/src/main/java/org/parabot/core/asm/wrappers/Getter.java
index f11d12f..e7ef7a7 100644
--- a/src/main/java/org/parabot/core/asm/wrappers/Getter.java
+++ b/src/main/java/org/parabot/core/asm/wrappers/Getter.java
@@ -38,7 +38,7 @@ public class Getter implements Injectable {
this.fieldLocation = ASMUtils.getClass(fieldLocation);
this.fieldNode = ASMUtils.getField(ASMUtils.getClass(fieldLocation), fieldNode, fieldDesc);
this.methodName = methodName;
- this.returnDesc = returnDesc == null ? this.fieldNode.desc : returnDesc;
+ this.returnDesc = (returnDesc == null && this.fieldNode != null) ? this.fieldNode.desc : returnDesc;
this.staticMethod = staticMethod;
this.multiplier = multiplier;
Core.verbose(methodName + "[" + fieldLocation + "." + fieldNode + "]");
@@ -77,4 +77,21 @@ public class Getter implements Injectable {
return new AddGetterAdapter(into, fieldLocation, fieldNode, methodName, returnDesc, staticMethod, multiplier);
}
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Injectable type: Getter");
+
+ if(fieldLocation.interfaces.size() > 0) {
+ sb.append(", accessor type: ").append(fieldLocation.interfaces.get(0).toString().replace('/', '.'));
+ }
+
+ if(fieldNode != null) {
+ sb.append(", field: ").append(fieldNode.name);
+ }
+
+ sb.append(", method name: ").append(methodName);
+
+ return sb.toString();
+ }
}
diff --git a/src/main/java/org/parabot/core/asm/wrappers/Invoker.java b/src/main/java/org/parabot/core/asm/wrappers/Invoker.java
index 328e073..a8bc7d8 100644
--- a/src/main/java/org/parabot/core/asm/wrappers/Invoker.java
+++ b/src/main/java/org/parabot/core/asm/wrappers/Invoker.java
@@ -79,4 +79,8 @@ public class Invoker implements Injectable {
this.argsDesc, this.returnDesc, this.methodName, this.isInterface, this.instanceCast, this.argsCheckCastDesc);
}
+ @Override
+ public String toString() {
+ return String.format("Injectable type: Invoker, accessor: %s, method name: %s, invokes method: %s", methodLocation.name, methodName, mName);
+ }
}
diff --git a/src/main/java/org/parabot/core/asm/wrappers/Setter.java b/src/main/java/org/parabot/core/asm/wrappers/Setter.java
index 99b4074..94ce25d 100644
--- a/src/main/java/org/parabot/core/asm/wrappers/Setter.java
+++ b/src/main/java/org/parabot/core/asm/wrappers/Setter.java
@@ -25,7 +25,7 @@ public class Setter implements Injectable {
this.into = ASMUtils.getClass(into);
this.field = ASMUtils.getField(this.fieldLocation, fieldName, fieldDesc);
this.name = methodName;
- this.desc = (desc == null) ? this.field.desc : desc;
+ this.desc = (desc == null && this.field != null) ? this.field.desc : desc;
this.methodStatic = methodStatic;
}
@@ -52,4 +52,21 @@ public class Setter implements Injectable {
return new AddSetterAdapter(fieldLocation, into, field, name, desc, methodStatic);
}
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Injectable type: Setter");
+
+ if(fieldLocation.interfaces.size() > 0) {
+ sb.append(", accessor type: ").append(fieldLocation.interfaces.get(0).toString().replace('/', '.'));
+ }
+
+ if(field != null) {
+ sb.append(", field: ").append(field.name);
+ }
+
+ sb.append(", method name: ").append(name);
+
+ return sb.toString();
+ }
}
diff --git a/src/main/java/org/parabot/core/desc/ServerProviderInfo.java b/src/main/java/org/parabot/core/desc/ServerProviderInfo.java
index a4e8c98..b5e84ae 100644
--- a/src/main/java/org/parabot/core/desc/ServerProviderInfo.java
+++ b/src/main/java/org/parabot/core/desc/ServerProviderInfo.java
@@ -166,6 +166,7 @@ public class ServerProviderInfo {
/**
* Gets the URL to download the Randoms JAR from.
+ *
* @return The provided URL in the server config JSON (denoted by 'randoms:') or, fallback to the default BDN URL.
*/
public URL getRandoms() {
@@ -182,4 +183,19 @@ public class ServerProviderInfo {
// Will never return null, unless the BDN URL is changed. It shouldn't be.
return null;
}
+
+ /**
+ * Gets the current provider version
+ *
+ * @return provider version
+ */
+ public String getProviderVersion() {
+ String providerType = WebUtil.getJsonValue(String.format(Configuration.GET_SERVER_PROVIDER_TYPE , properties.getProperty("name")), "type");
+ if(providerType != null) {
+ String providerInfo = String.format(Configuration.SERVER_PROVIDER_INFO, providerType);
+ return WebUtil.getJsonValue(providerInfo, "version");
+ }
+
+ return null;
+ }
}
diff --git a/src/main/java/org/parabot/core/forum/AccountManager.java b/src/main/java/org/parabot/core/forum/AccountManager.java
index 6b729a5..bdd21f3 100644
--- a/src/main/java/org/parabot/core/forum/AccountManager.java
+++ b/src/main/java/org/parabot/core/forum/AccountManager.java
@@ -4,6 +4,7 @@ import org.json.simple.JSONObject;
import org.parabot.core.Configuration;
import org.parabot.core.Context;
import org.parabot.core.Core;
+import org.parabot.core.parsers.hooks.HookParser;
import org.parabot.core.parsers.scripts.BDNScripts;
import org.parabot.core.parsers.servers.PublicServers;
import org.parabot.core.ui.components.VerboseLoader;
@@ -48,6 +49,7 @@ public final class AccountManager {
accessors.add(PublicServers.MANAGER_FETCHER);
accessors.add(PublicServerExecuter.MANAGER_FETCHER);
accessors.add(PBPreferences.MANAGER_FETCHER);
+ accessors.add(HookParser.MANAGER_FETCHER);
for (final AccountManagerAccess accessor : accessors) {
accessor.setManager(instance);
diff --git a/src/main/java/org/parabot/core/network/proxy/ProxySocket.java b/src/main/java/org/parabot/core/network/proxy/ProxySocket.java
index 46b7454..105c329 100644
--- a/src/main/java/org/parabot/core/network/proxy/ProxySocket.java
+++ b/src/main/java/org/parabot/core/network/proxy/ProxySocket.java
@@ -1,5 +1,6 @@
package org.parabot.core.network.proxy;
+import org.parabot.core.Core;
import org.parabot.core.ui.utils.UILog;
import javax.swing.*;
@@ -44,7 +45,7 @@ public class ProxySocket extends Socket {
socket.close();
value++;
} catch (Exception e) {
-
+ Core.verbose("Error closing proxy connection: " + e.getMessage());
}
}
return value;
diff --git a/src/main/java/org/parabot/core/parsers/hooks/HookParser.java b/src/main/java/org/parabot/core/parsers/hooks/HookParser.java
index 03d8292..6a307f1 100644
--- a/src/main/java/org/parabot/core/parsers/hooks/HookParser.java
+++ b/src/main/java/org/parabot/core/parsers/hooks/HookParser.java
@@ -3,25 +3,39 @@ package org.parabot.core.parsers.hooks;
import org.parabot.core.asm.hooks.HookFile;
import org.parabot.core.asm.interfaces.Injectable;
import org.parabot.core.asm.wrappers.*;
+import org.parabot.core.forum.AccountManager;
+import org.parabot.core.forum.AccountManagerAccess;
+import org.parabot.environment.api.utils.PBPreferences;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Map;
/**
- * Parses an XML files which injects the hooks and other bytecode manipulation
+ * Parses a structured format file which injects the hooks and other bytecode manipulation
* methods
*
- * @author Everel
+ * @author Everel, JKetelaar
*/
public abstract class HookParser {
+ protected static AccountManager manager;
+ public static final AccountManagerAccess MANAGER_FETCHER = new AccountManagerAccess() {
+ @Override
+ public final void setManager(AccountManager manager) {
+ HookParser.manager = manager;
+ }
+ };
+
public HookParser(HookFile hookFile) {
}
public abstract Interface[] getInterfaces();
+ public abstract Map getInterfaceMap();
+
public abstract Super[] getSupers();
public abstract Getter[] getGetters();
diff --git a/src/main/java/org/parabot/core/parsers/hooks/JSONHookParser.java b/src/main/java/org/parabot/core/parsers/hooks/JSONHookParser.java
index 2a230a0..30852fd 100644
--- a/src/main/java/org/parabot/core/parsers/hooks/JSONHookParser.java
+++ b/src/main/java/org/parabot/core/parsers/hooks/JSONHookParser.java
@@ -12,7 +12,10 @@ import java.util.HashMap;
import java.util.Map;
/**
- * @author Dane
+ * Parses a JSON file which injects the hooks and other bytecode manipulation
+ * methods
+ *
+ * @author Dane, JKetelaar
*/
public class JSONHookParser extends HookParser {
private JSONObject root;
@@ -71,6 +74,11 @@ public class JSONHookParser extends HookParser {
return null;
}
+ @Override
+ public Map getInterfaceMap() {
+ return this.interfaces;
+ }
+
@Override
public Super[] getSupers() {
JSONArray a = (JSONArray) root.get("supers");
diff --git a/src/main/java/org/parabot/core/parsers/hooks/XMLHookParser.java b/src/main/java/org/parabot/core/parsers/hooks/XMLHookParser.java
index e7fa473..c793c78 100644
--- a/src/main/java/org/parabot/core/parsers/hooks/XMLHookParser.java
+++ b/src/main/java/org/parabot/core/parsers/hooks/XMLHookParser.java
@@ -13,22 +13,29 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Map;
+/**
+ * Parses an XML file which injects the hooks and other bytecode manipulation
+ * methods
+ *
+ * @author JKetelaar
+ */
public class XMLHookParser extends HookParser {
- private Document doc;
+ private Document doc;
private HashMap interfaceMap;
private HashMap constants;
- private boolean parsedInterfaces;
+ private boolean parsedInterfaces;
public XMLHookParser(HookFile hookFile) {
super(hookFile);
- interfaceMap = new HashMap();
- constants = new HashMap();
+ interfaceMap = new HashMap<>();
+ constants = new HashMap<>();
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
- doc = dBuilder.parse(hookFile.getInputStream());
+ doc = dBuilder.parse(hookFile.getInputStream(manager));
doc.getDocumentElement().normalize();
if (!doc.getDocumentElement().getNodeName().equals("injector")) {
throw new RuntimeException("Incorrect hook file.");
@@ -38,48 +45,6 @@ public class XMLHookParser extends HookParser {
}
}
- private static String resolveDesc(String returnDesc) {
- String array = "";
- if (returnDesc != null && returnDesc.contains("%s")) {
- StringBuilder str = new StringBuilder();
- if (returnDesc.startsWith("[")) {
- for (int i = 0; i < returnDesc.length(); i++) {
- if (returnDesc.charAt(i) == '[') {
- array += '[';
- }
- }
- returnDesc = returnDesc.replaceAll("\\[", "");
- }
- str.append(array)
- .append('L')
- .append(String.format(returnDesc,
- AddInterfaceAdapter.getAccessorPackage()))
- .append(";");
- returnDesc = str.toString();
- }
- return returnDesc;
- }
-
- private static final boolean isSet(String tag, Element element) {
- return element.getElementsByTagName(tag).getLength() > 0;
- }
-
- private static final String getValue(String tag, Element element) {
- if (element.getElementsByTagName(tag).item(0) == null) {
- throw new NullPointerException("MISSING HOOK TAG: The '" + tag + "' xml tag is missing from one of the hooks of type: " + element.getParentNode().getNodeName());
- }
- NodeList nodes = element.getElementsByTagName(tag).item(0)
- .getChildNodes();
- if (nodes.getLength() == 0 || nodes.item(0) == null) {
- if (Core.inVerboseMode()) {
- System.err.println("WARNING: Invalid Hook " + tag + " subnode. Tag is missing or empty?");
- }
- return "";
- }
- Node node = (Node) nodes.item(0);
- return node.getNodeValue();
- }
-
@Override
public Interface[] getInterfaces() {
parsedInterfaces = true;
@@ -98,8 +63,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
- final Element interfaceRoot = (Element) node;
- final NodeList interfaces = interfaceRoot.getElementsByTagName("add");
+ final Element interfaceRoot = (Element) node;
+ final NodeList interfaces = interfaceRoot.getElementsByTagName("add");
if (interfaces.getLength() == 0) {
return null;
}
@@ -109,9 +74,9 @@ public class XMLHookParser extends HookParser {
if (n.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
- final Element addInterface = (Element) n;
- final String className = getValue("classname", addInterface);
- final String interfaceClass = getValue("interface", addInterface);
+ final Element addInterface = (Element) n;
+ final String className = getValue("classname", addInterface);
+ final String interfaceClass = getValue("interface", addInterface);
interfaceMap.put(interfaceClass, className);
final Interface inf = new Interface(className, interfaceClass);
interfaceList.add(inf);
@@ -119,6 +84,11 @@ public class XMLHookParser extends HookParser {
return interfaceList.toArray(new Interface[interfaceList.size()]);
}
+ @Override
+ public Map getInterfaceMap() {
+ return this.interfaceMap;
+ }
+
@Override
public Super[] getSupers() {
final NodeList interfaceRootList = doc.getElementsByTagName("supers");
@@ -135,8 +105,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
- final Element superRoot = (Element) node;
- final NodeList supers = superRoot.getElementsByTagName("add");
+ final Element superRoot = (Element) node;
+ final NodeList supers = superRoot.getElementsByTagName("add");
if (supers.getLength() == 0) {
return null;
}
@@ -146,10 +116,10 @@ public class XMLHookParser extends HookParser {
if (n.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
- final Element addSuper = (Element) n;
- final String className = getValue("classname", addSuper);
- final String superClass = getValue("super", addSuper);
- final Super sup = new Super(className, superClass);
+ final Element addSuper = (Element) n;
+ final String className = getValue("classname", addSuper);
+ final String superClass = getValue("super", addSuper);
+ final Super sup = new Super(className, superClass);
superList.add(sup);
}
return superList.toArray(new Super[superList.size()]);
@@ -171,8 +141,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
- final Element getterRoot = (Element) node;
- final NodeList getters = getterRoot.getElementsByTagName("add");
+ final Element getterRoot = (Element) node;
+ final NodeList getters = getterRoot.getElementsByTagName("add");
if (getters.getLength() == 0) {
return null;
}
@@ -196,9 +166,9 @@ public class XMLHookParser extends HookParser {
"accessor", addGetter));
final String into = isSet("into", addGetter) ? getValue("into",
addGetter) : className;
- final long multiplier = isSet("multiplier", addGetter) ? Long.parseLong(getValue("multiplier", addGetter)) : 0L;
- final String fieldName = getValue("field", addGetter);
- final String fieldDesc = isSet("descfield", addGetter) ? getValue("descfield", addGetter) : null;
+ final long multiplier = isSet("multiplier", addGetter) ? Long.parseLong(getValue("multiplier", addGetter)) : 0L;
+ final String fieldName = getValue("field", addGetter);
+ final String fieldDesc = isSet("descfield", addGetter) ? getValue("descfield", addGetter) : null;
final String methodName = getValue("methodname", addGetter);
boolean staticMethod = isSet("methstatic", addGetter) ? (getValue(
"methstatic", addGetter).equals("true")) : false;
@@ -246,8 +216,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
- final Element setterRoot = (Element) node;
- final NodeList setters = setterRoot.getElementsByTagName("add");
+ final Element setterRoot = (Element) node;
+ final NodeList setters = setterRoot.getElementsByTagName("add");
if (setters.getLength() == 0) {
return null;
}
@@ -271,8 +241,8 @@ public class XMLHookParser extends HookParser {
"accessor", addSetter));
final String into = isSet("into", addSetter) ? getValue("into",
addSetter) : className;
- final String fieldName = getValue("field", addSetter);
- final String fieldDesc = isSet("descfield", addSetter) ? getValue("descfield", addSetter) : null;
+ final String fieldName = getValue("field", addSetter);
+ final String fieldDesc = isSet("descfield", addSetter) ? getValue("descfield", addSetter) : null;
final String methodName = getValue("methodname", addSetter);
boolean staticMethod = isSet("methstatic", addSetter) ? (getValue(
"methstatic", addSetter).equals("true")) : false;
@@ -319,8 +289,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
- final Element invokerRoot = (Element) node;
- final NodeList invokers = invokerRoot.getElementsByTagName("add");
+ final Element invokerRoot = (Element) node;
+ final NodeList invokers = invokerRoot.getElementsByTagName("add");
if (invokers.getLength() == 0) {
return null;
}
@@ -344,15 +314,15 @@ public class XMLHookParser extends HookParser {
"accessor", addInvoker));
final String into = isSet("into", addInvoker) ? getValue("into",
addInvoker) : className;
- final String methodName = getValue("methodname", addInvoker);
+ final String methodName = getValue("methodname", addInvoker);
final String invMethodName = getValue("invokemethod", addInvoker);
- final String argsDesc = getValue("argsdesc", addInvoker);
+ final String argsDesc = getValue("argsdesc", addInvoker);
String returnDesc = isSet("desc", addInvoker) ? resolveDesc(getValue(
"desc", addInvoker)) : null;
- final boolean isInterface = isSet("interface", addInvoker) ? Boolean.parseBoolean(getValue("interface", addInvoker)) : false;
- final String instanceCast = isSet("instancecast", addInvoker) ? getValue("instancecast", addInvoker) : null;
- final String checkCastArgsDesc = isSet("castargs", addInvoker) ? getValue("castargs", addInvoker) : null;
+ final boolean isInterface = isSet("interface", addInvoker) ? Boolean.parseBoolean(getValue("interface", addInvoker)) : false;
+ final String instanceCast = isSet("instancecast", addInvoker) ? getValue("instancecast", addInvoker) : null;
+ final String checkCastArgsDesc = isSet("castargs", addInvoker) ? getValue("castargs", addInvoker) : null;
final Invoker invoker = new Invoker(into, className, invMethodName,
argsDesc, returnDesc, methodName, isInterface, instanceCast, checkCastArgsDesc);
@@ -381,7 +351,7 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
- final Element constantRoot = (Element) node;
+ final Element constantRoot = (Element) node;
final NodeList constantsList = constantRoot.getElementsByTagName("add");
if (constantsList.getLength() == 0) {
// return empty hashmap
@@ -393,8 +363,8 @@ public class XMLHookParser extends HookParser {
continue;
}
final Element addConstant = (Element) n;
- final String key = getValue("key", addConstant);
- final String value = getValue("value", addConstant);
+ final String key = getValue("key", addConstant);
+ final String value = getValue("value", addConstant);
constants.put(key, value);
}
return constants;
@@ -416,8 +386,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
- final Element callbackRoot = (Element) node;
- final NodeList callbacks = callbackRoot.getElementsByTagName("add");
+ final Element callbackRoot = (Element) node;
+ final NodeList callbacks = callbackRoot.getElementsByTagName("add");
if (callbacks.getLength() == 0) {
return null;
}
@@ -441,12 +411,12 @@ public class XMLHookParser extends HookParser {
"classname", addCallback) : interfaceMap.get(getValue(
"accessor", addCallback));
- final String methodName = getValue("methodname", addCallback);
- final String callClass = getValue("callclass", addCallback);
- final String callMethod = getValue("callmethod", addCallback);
- final String callDesc = getValue("calldesc", addCallback);
- final String callArgs = getValue("callargs", addCallback);
- final String desc = getValue("desc", addCallback);
+ final String methodName = getValue("methodname", addCallback);
+ final String callClass = getValue("callclass", addCallback);
+ final String callMethod = getValue("callmethod", addCallback);
+ final String callDesc = getValue("calldesc", addCallback);
+ final String callArgs = getValue("callargs", addCallback);
+ final String desc = getValue("desc", addCallback);
final boolean conditional = isSet("conditional", addCallback);
final Callback callback = new Callback(className, methodName, desc,
@@ -456,4 +426,46 @@ public class XMLHookParser extends HookParser {
return callbackList.toArray(new Callback[callbackList.size()]);
}
+ private static String resolveDesc(String returnDesc) {
+ String array = "";
+ if (returnDesc != null && returnDesc.contains("%s")) {
+ StringBuilder str = new StringBuilder();
+ if (returnDesc.startsWith("[")) {
+ for (int i = 0; i < returnDesc.length(); i++) {
+ if (returnDesc.charAt(i) == '[') {
+ array += '[';
+ }
+ }
+ returnDesc = returnDesc.replaceAll("\\[", "");
+ }
+ str.append(array)
+ .append('L')
+ .append(String.format(returnDesc,
+ AddInterfaceAdapter.getAccessorPackage()))
+ .append(";");
+ returnDesc = str.toString();
+ }
+ return returnDesc;
+ }
+
+ private static final boolean isSet(String tag, Element element) {
+ return element.getElementsByTagName(tag).getLength() > 0;
+ }
+
+ private static final String getValue(String tag, Element element) {
+ if (element.getElementsByTagName(tag).item(0) == null) {
+ throw new NullPointerException("MISSING HOOK TAG: The '" + tag + "' xml tag is missing from one of the hooks of type: " + element.getParentNode().getNodeName());
+ }
+ NodeList nodes = element.getElementsByTagName(tag).item(0)
+ .getChildNodes();
+ if (nodes.getLength() == 0 || nodes.item(0) == null) {
+ if (Core.inVerboseMode()) {
+ System.err.println("WARNING: Invalid Hook " + tag + " subnode. Tag is missing or empty?");
+ }
+ return "";
+ }
+ Node node = (Node) nodes.item(0);
+ return node.getNodeValue();
+ }
+
}
diff --git a/src/main/java/org/parabot/core/ui/BotUI.java b/src/main/java/org/parabot/core/ui/BotUI.java
index 90b384f..4765394 100644
--- a/src/main/java/org/parabot/core/ui/BotUI.java
+++ b/src/main/java/org/parabot/core/ui/BotUI.java
@@ -1,6 +1,5 @@
package org.parabot.core.ui;
-import javafx.application.Application;
import org.parabot.core.Configuration;
import org.parabot.core.Context;
import org.parabot.core.Directories;
@@ -248,7 +247,7 @@ public class BotUI extends JFrame implements ActionListener, ComponentListener,
Directories.clearCache();
break;
case "Notifications":
- Application.launch(NotificationUI.class);
+ NotificationUI.create();
break;
default:
System.out.println("Invalid command: " + command);
diff --git a/src/main/java/org/parabot/core/ui/components/notifications/NotificationUI.java b/src/main/java/org/parabot/core/ui/components/notifications/NotificationUI.java
index bc55311..72b8a34 100644
--- a/src/main/java/org/parabot/core/ui/components/notifications/NotificationUI.java
+++ b/src/main/java/org/parabot/core/ui/components/notifications/NotificationUI.java
@@ -1,20 +1,56 @@
package org.parabot.core.ui.components.notifications;
-import javafx.application.Application;
-import javafx.fxml.FXMLLoader;
-import javafx.scene.Scene;
-import javafx.scene.layout.BorderPane;
-import javafx.stage.Stage;
-import org.parabot.core.Configuration;
+import org.parabot.api.Configuration;
+import org.parabot.api.output.Verboser;
+import org.parabot.api.ui.JavaFxUtil;
-public class NotificationUI extends Application {
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+/**
+ * A JavaFX Panel embedded into a Swing JFrame - handles notification settings
+ *
+ * @author Shadowrs
+ */
+public class NotificationUI extends JavaFxUtil {
+
+ final NotificationUI n;
+
+ private NotificationUI() throws URISyntaxException, MalformedURLException {
+ super(Configuration.class.getClass().getResource("/storage/ui/notifications.fxml").toURI().toURL(), NotificationUIController.class);
+ this.n = this;
+ }
+
+ public static void create() {
+ try {
+ new NotificationUI();
+ } catch (URISyntaxException | MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
@Override
- public void start(Stage stage) throws Exception {
- //noinspection RedundantCast
- BorderPane root = (BorderPane) FXMLLoader.load(this.getClass().getResource("/storage/ui/notifications.fxml"));
- stage.setTitle(Configuration.BOT_TITLE);
- stage.setScene(new Scene(root));
- stage.show();
+ public WindowAdapter getWindowAdapter() {
+ return new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent e) {
+ Verboser.verbose("NotificationUI closed " + e);
+ }
+
+ @Override
+ public void windowClosing(WindowEvent e) {
+ // Anything here. JFrame hides on exit.
+ Verboser.verbose("NotificationUI closing " + e);
+ n.getFrame().dispose();
+ }
+ };
+ }
+
+ @Override
+ protected void onLaunched() {
+ n.getFrame().setTitle("Notifications");
}
}
\ No newline at end of file
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 ff00260..d1261f6 100644
--- a/src/main/java/org/parabot/core/ui/utils/UILog.java
+++ b/src/main/java/org/parabot/core/ui/utils/UILog.java
@@ -30,4 +30,13 @@ public class UILog {
public static int alert(final String title, final String message, int optionType, int messageType) {
return JOptionPane.showConfirmDialog(null, message, title, optionType, messageType);
}
+
+ public static int alert(final String title, final String message, Object[] options) {
+ return alert(title, message, options, JOptionPane.INFORMATION_MESSAGE);
+ }
+
+ public static int alert(final String title, final String message, Object[] options, int messageType) {
+ return JOptionPane.showOptionDialog(null, message, title,
+ JOptionPane.YES_NO_CANCEL_OPTION, messageType, null, options, null);
+ }
}
diff --git a/src/main/java/org/parabot/environment/Environment.java b/src/main/java/org/parabot/environment/Environment.java
index 88cf093..0e05b0d 100644
--- a/src/main/java/org/parabot/environment/Environment.java
+++ b/src/main/java/org/parabot/environment/Environment.java
@@ -33,7 +33,7 @@ public class Environment extends org.parabot.api.io.libraries.Environment {
loadLibrary(lib, true);
}
- Core.verbose("Loading server: " + desc.toString() + "...");
+ Core.verbose("[Environment] Loading server: " + desc.toString() + "...");
ServerParser.SERVER_CACHE.get(desc).run();
}
diff --git a/src/main/java/org/parabot/environment/api/utils/FileUtil.java b/src/main/java/org/parabot/environment/api/utils/FileUtil.java
index ce954d3..a7e2fd5 100644
--- a/src/main/java/org/parabot/environment/api/utils/FileUtil.java
+++ b/src/main/java/org/parabot/environment/api/utils/FileUtil.java
@@ -1,10 +1,8 @@
package org.parabot.environment.api.utils;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import java.io.*;
import java.nio.channels.FileChannel;
+import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -88,4 +86,29 @@ public class FileUtil {
}
destination.close();
}
+
+ /**
+ * Reads the contents of a text file
+ *
+ * @param file file to get contents from
+ * @return file contents
+ * @throws IOException when anything goes wrong
+ */
+ public static String getFileContents(File file) throws IOException {
+ return new String(Files.readAllBytes(file.toPath()));
+ }
+
+ /**
+ * Writes a string to a file overwriting the existing contents if present
+ *
+ * @param file file to write to
+ * @param contents contents to write to given file
+ * @throws IOException when anything goes wrong
+ */
+ public static void writeFileContents(File file, String contents) throws IOException {
+ BufferedWriter writer = new BufferedWriter(new FileWriter(file.getAbsolutePath()));
+ writer.write(contents);
+
+ writer.close();
+ }
}
diff --git a/src/main/java/org/parabot/environment/api/utils/PBLocalPreferences.java b/src/main/java/org/parabot/environment/api/utils/PBLocalPreferences.java
new file mode 100644
index 0000000..74eb1d7
--- /dev/null
+++ b/src/main/java/org/parabot/environment/api/utils/PBLocalPreferences.java
@@ -0,0 +1,118 @@
+package org.parabot.environment.api.utils;
+
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.parabot.core.Directories;
+
+import java.io.File;
+import java.util.HashMap;
+
+/**
+ * Manages preferences in a local file in JSON format in the Parabot settings folder
+ *
+ * @author AlexanderBielen
+ */
+public class PBLocalPreferences {
+ private static JSONParser parser = new JSONParser();
+ private File settingsFile;
+
+ public PBLocalPreferences(String fileName) {
+ settingsFile = new File(Directories.getSettingsPath() + "/" + secureFileName(fileName));
+ }
+
+ /**
+ * Gets all settings inside the file
+ *
+ * @return JSONObject or null if anything went wrong
+ */
+ public JSONObject getSettings() {
+ try {
+ String stringContents = FileUtil.getFileContents(settingsFile);
+ return (JSONObject) parser.parse(stringContents);
+ } catch(Exception ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Convert a HashMap to json and writes it to the file
+ *
+ * @param settings HashMap
+ * @param append If true, append to existing settings in file
+ */
+ public void writeSettings(HashMap settings, boolean append) {
+ JSONObject existingSettings;
+ if(append && (existingSettings = getSettings()) != null) {
+ existingSettings.putAll(settings);
+ settings = existingSettings;
+ }
+
+ try {
+ if (!settingsFile.exists()) {
+ settingsFile.createNewFile();
+ }
+ FileUtil.writeFileContents(settingsFile, new JSONObject(settings).toJSONString());
+
+ } catch (Exception ignore) {
+ ignore.printStackTrace();
+ }
+
+ }
+
+ /**
+ * Adds a setting, or overwrites it if it exists
+ *
+ * @param key key of the setting
+ * @param value value of the setting
+ */
+ public void addSetting(String key, String value) {
+ HashMap pair = new HashMap<>();
+ pair.put(key, value);
+ writeSettings(pair, true);
+ }
+
+ /**
+ * Fetches a setting
+ *
+ * @param key key to get the value for
+ * @return value that belongs to given key or null if non-existent
+ */
+ public String getSetting(String key) {
+ if(getSettings() == null) {
+ return null;
+ }
+
+ return getSettings().get(key).toString();
+ }
+
+ /**
+ * Adjusts an existing setting
+ *
+ * @param key key to adjust the value for
+ * @param value value for the key
+ */
+ public void adjustSetting(String key, String value) {
+ addSetting(key, value);
+ }
+
+ /**
+ * Removes a setting
+ *
+ * @param key key to remove
+ */
+ public void removeSetting(String key) {
+ JSONObject json = getSettings();
+ json.remove(key);
+ writeSettings(json, false);
+ }
+
+ /**
+ * Replaces all double dots to make sure the link does not leave the settings folder
+ *
+ * @param filePath path to secure
+ * @return secured string
+ */
+ private static String secureFileName(String filePath) {
+ return filePath.replace("..", "");
+ }
+}
diff --git a/src/main/java/org/parabot/environment/api/utils/Time.java b/src/main/java/org/parabot/environment/api/utils/Time.java
index 5418f42..c790ed0 100644
--- a/src/main/java/org/parabot/environment/api/utils/Time.java
+++ b/src/main/java/org/parabot/environment/api/utils/Time.java
@@ -53,6 +53,30 @@ public final class Time {
return true;
}
+ /**
+ * Sleeps until SleepCondition is valid, but with a minimum timeout.
+ *
+ * @param conn the condition.
+ * @param timeout the time in milliseconds before it stops sleeping.
+ * @param minimumTimeout the minimum time to sleep.
+ *
+ * @return whether it ran successfully without timing out.
+ */
+ public static boolean sleep(SleepCondition conn, int timeout, int minimumTimeout) {
+ long start = System.currentTimeMillis();
+
+ if(!sleep(conn, timeout)) {
+ return false;
+ }
+
+ long t;
+ if((t = System.currentTimeMillis() - start) < minimumTimeout) {
+ Time.sleep((int)(minimumTimeout - t));
+ }
+
+ return true;
+ }
+
/**
* Gets current time in milliseconds
*
diff --git a/src/main/java/org/parabot/environment/api/utils/Timer.java b/src/main/java/org/parabot/environment/api/utils/Timer.java
index fa3c07e..5a457cf 100644
--- a/src/main/java/org/parabot/environment/api/utils/Timer.java
+++ b/src/main/java/org/parabot/environment/api/utils/Timer.java
@@ -105,7 +105,18 @@ public class Timer {
* @return hourly gains
*/
public int getPerHour(final int gained) {
- return (int) ((gained) * 3600000D / (System.currentTimeMillis() - start));
+ return getPerHour(gained, 0);
+ }
+
+ /**
+ * Calculates hourly gains based on given variable, with variable start amount
+ *
+ * @param gained total gained amount
+ * @param startAmount start amount
+ * @return hourly gains
+ */
+ public int getPerHour(final int gained, final int startAmount) {
+ return (int) (((gained - startAmount) * 3600000D) / (System.currentTimeMillis() - start));
}
/**
diff --git a/src/main/java/org/parabot/environment/api/utils/WebUtil.java b/src/main/java/org/parabot/environment/api/utils/WebUtil.java
index 14c175b..8f1532d 100644
--- a/src/main/java/org/parabot/environment/api/utils/WebUtil.java
+++ b/src/main/java/org/parabot/environment/api/utils/WebUtil.java
@@ -1,5 +1,7 @@
package org.parabot.environment.api.utils;
+import org.json.simple.JSONObject;
+
/**
* A WebUtil class fetches data from an URL
*
@@ -7,4 +9,27 @@ package org.parabot.environment.api.utils;
*/
public class WebUtil extends org.parabot.api.io.WebUtil {
+ /**
+ * Fetches a single value from a JSON string at the given url
+ *
+ * @param url url to get the JSON string from
+ * @param key key to search for in the JSON string
+ * @return value that belongs to given key
+ */
+ public static String getJsonValue(String url, String key) {
+ try {
+ String response = WebUtil.getContents(url);
+
+ if(response.length() > 0) {
+ JSONObject jsonObject = (JSONObject) WebUtil.getJsonParser().parse(response);
+ if (jsonObject.get(key) != null) {
+ return jsonObject.get(key).toString();
+ }
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ return null;
+ }
}
diff --git a/src/main/java/org/parabot/environment/servers/ServerProvider.java b/src/main/java/org/parabot/environment/servers/ServerProvider.java
index 6765781..ae9b5ba 100644
--- a/src/main/java/org/parabot/environment/servers/ServerProvider.java
+++ b/src/main/java/org/parabot/environment/servers/ServerProvider.java
@@ -1,10 +1,12 @@
package org.parabot.environment.servers;
import org.objectweb.asm.Opcodes;
+import org.parabot.core.Configuration;
import org.parabot.core.Context;
import org.parabot.core.asm.hooks.HookFile;
import org.parabot.core.asm.interfaces.Injectable;
import org.parabot.core.parsers.hooks.HookParser;
+import org.parabot.core.ui.utils.UILog;
import org.parabot.environment.input.Keyboard;
import org.parabot.environment.input.Mouse;
import org.parabot.environment.scripts.Script;
@@ -13,6 +15,8 @@ import javax.swing.*;
import java.applet.Applet;
import java.applet.AppletStub;
import java.awt.*;
+import java.io.IOException;
+import java.net.URI;
import java.net.URL;
/**
@@ -21,6 +25,7 @@ import java.net.URL;
* @author Everel
*/
public abstract class ServerProvider implements Opcodes {
+ private boolean crashed = false;
/**
* Get the game/applet dimensions
@@ -74,12 +79,36 @@ public abstract class ServerProvider implements Opcodes {
HookParser parser = hookFile.getParser();
Injectable[] injectables = parser.getInjectables();
+
if (injectables == null) {
return;
}
- for (Injectable inj : injectables) {
- inj.inject();
+
+ int index = 0;
+
+ try {
+ for (Injectable inj : injectables) {
+ inj.inject();
+ index++;
+ }
+ } catch (NullPointerException ex) {
+ 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);
+
+ if(resp == 1) {
+ URI uri = URI.create(Configuration.COMMUNITY_PAGE + "forum/135-reports/");
+ try {
+ Desktop.getDesktop().browse(uri);
+ } catch (IOException ignore) {}
+ }
+ }
+ crashed = true;
+ throw ex;
}
+
Context.getInstance().setHookParser(parser);
}
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 b98bd3c..a316586 100644
--- a/src/main/java/org/parabot/environment/servers/executers/PublicServerExecuter.java
+++ b/src/main/java/org/parabot/environment/servers/executers/PublicServerExecuter.java
@@ -11,6 +11,7 @@ import org.parabot.core.forum.AccountManager;
import org.parabot.core.forum.AccountManagerAccess;
import org.parabot.core.ui.components.VerboseLoader;
import org.parabot.core.ui.utils.UILog;
+import org.parabot.environment.api.utils.PBLocalPreferences;
import org.parabot.environment.api.utils.WebUtil;
import org.parabot.environment.servers.ServerProvider;
import org.parabot.environment.servers.loader.ServerLoader;
@@ -37,6 +38,9 @@ public class PublicServerExecuter extends ServerExecuter {
};
private String serverName;
+ private PBLocalPreferences settings;
+ private final String cacheVersionKey = "cachedProviderVersion";
+
public PublicServerExecuter(final String serverName) {
this.serverName = serverName;
}
@@ -53,6 +57,24 @@ public class PublicServerExecuter extends ServerExecuter {
Core.verbose("Downloading: " + jarUrl + " ...");
+ String providerVersion = serverProviderInfo.getProviderVersion();
+ if(providerVersion == null) {
+ providerVersion = "error";
+ }
+
+ 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)) {
+ Core.verbose("Local provider outdated, clearing cache.");
+ Directories.clearCache();
+ }
+ } else {
+ Core.verbose("No local provider version in settings, adding to settings file");
+ }
+
+ settings.addSetting(cacheVersionKey, providerVersion);
+
if (destination.exists()) {
Core.verbose("Found cached server provider [CRC32: " + serverProviderInfo.getCRC32() + "]");
} else {
diff --git a/src/main/resources/storage/ui/notifications.fxml b/src/main/resources/storage/ui/notifications.fxml
index 1e6ac7b..6577abd 100644
--- a/src/main/resources/storage/ui/notifications.fxml
+++ b/src/main/resources/storage/ui/notifications.fxml
@@ -4,8 +4,7 @@
+ prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1">