First commit
@@ -0,0 +1,5 @@
|
|||||||
|
bin
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.metadata
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.parabot;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
|
import org.parabot.core.ui.ServerSelector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parabot X - A revolution in bot clients
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
* @author Matt, Dane, Queue, Parameter
|
||||||
|
* @version 2.0
|
||||||
|
*/
|
||||||
|
public class Landing {
|
||||||
|
|
||||||
|
public static void main(String... args) {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
ServerSelector.getInstance().setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package org.parabot.core;
|
||||||
|
|
||||||
|
import java.applet.Applet;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import org.parabot.core.asm.ASMClassLoader;
|
||||||
|
import org.parabot.core.bot.loader.BotLoader;
|
||||||
|
import org.parabot.core.classpath.ClassPath;
|
||||||
|
import org.parabot.core.ui.components.GamePanel;
|
||||||
|
import org.parabot.environment.servers.ServerProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Game context
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Context {
|
||||||
|
private static HashMap<ThreadGroup, Context> threadGroups = new HashMap<ThreadGroup, Context>();
|
||||||
|
private static int id = 1;
|
||||||
|
|
||||||
|
private ASMClassLoader classLoader = null;
|
||||||
|
private ClassPath classPath = null;
|
||||||
|
private ServerProvider serverProvider = null;
|
||||||
|
private int tab = 0;
|
||||||
|
private Applet gameApplet = null;
|
||||||
|
|
||||||
|
public boolean added = false;
|
||||||
|
|
||||||
|
public Context(final ServerProvider serverProvider) {
|
||||||
|
threadGroups.put(Thread.currentThread().getThreadGroup(), this);
|
||||||
|
tab = id;
|
||||||
|
this.serverProvider = serverProvider;
|
||||||
|
id++;
|
||||||
|
this.classPath = new ClassPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ServerProvider class loader
|
||||||
|
* @param serverEnvironment
|
||||||
|
*/
|
||||||
|
public void setEnvironment(ASMClassLoader serverEnvironment) {
|
||||||
|
classLoader = new BotLoader(classPath, serverEnvironment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassPath
|
||||||
|
* @return classpath
|
||||||
|
*/
|
||||||
|
public ClassPath getClassPath() {
|
||||||
|
return classPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if applet has been set
|
||||||
|
* @return <b>true</b> if set
|
||||||
|
*/
|
||||||
|
public boolean appletSet() {
|
||||||
|
return gameApplet != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets game applet
|
||||||
|
* @return applet
|
||||||
|
*/
|
||||||
|
public Applet getApplet() {
|
||||||
|
return gameApplet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the context from threadgroup
|
||||||
|
* @return context
|
||||||
|
*/
|
||||||
|
public static Context resolve() {
|
||||||
|
return threadGroups.get(Thread.currentThread().getThreadGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the game
|
||||||
|
*/
|
||||||
|
public void load() {
|
||||||
|
serverProvider.parseJar();
|
||||||
|
gameApplet = serverProvider.fetchApplet();
|
||||||
|
final GamePanel panel = GamePanel.getInstance();
|
||||||
|
panel.removeLoader();
|
||||||
|
panel.setContext(this);
|
||||||
|
gameApplet.setSize(765, 503);
|
||||||
|
java.util.Timer t = new java.util.Timer();
|
||||||
|
t.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
gameApplet.setBounds(0, 0, 765, 503);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the server prodiver belonging to this context
|
||||||
|
* @return server provider
|
||||||
|
*/
|
||||||
|
public ServerProvider getServerProvider() {
|
||||||
|
return serverProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets class loader from this context
|
||||||
|
* @return class loader
|
||||||
|
*/
|
||||||
|
public ASMClassLoader getASMClassLoader() {
|
||||||
|
return classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getID() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTab() {
|
||||||
|
return tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.parabot.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Core {
|
||||||
|
private static boolean devMode = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the developers mode
|
||||||
|
*/
|
||||||
|
public static void enableDevMode() {
|
||||||
|
devMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if bot is in developers mode
|
||||||
|
* @return <b>true</b> if bot is in developers mode
|
||||||
|
*/
|
||||||
|
public static boolean isDevMode() {
|
||||||
|
return devMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package org.parabot.core.asm;
|
||||||
|
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.AllPermission;
|
||||||
|
import java.security.CodeSource;
|
||||||
|
import java.security.Permissions;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.parabot.core.classpath.ClassPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
* @author Matt
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ASMClassLoader extends ClassLoader {
|
||||||
|
|
||||||
|
public Map<String,Class<?>>classCache = new HashMap<String,Class<?>>();
|
||||||
|
public ClassPath classPath = null;
|
||||||
|
|
||||||
|
public ASMClassLoader(final ClassPath classPath) {
|
||||||
|
this.classPath = classPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected URL findResource(String name) {
|
||||||
|
if (getSystemResource(name) == null) {
|
||||||
|
if (classPath.resources.containsKey(name))
|
||||||
|
return classPath.resources.get(name);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
} else
|
||||||
|
return getSystemResource(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addClassToCache(final Class<?> clazz) {
|
||||||
|
String clazzName = clazz.getName().replace('.', '/');
|
||||||
|
classCache.put(clazzName, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
|
return findClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
|
String key = name.replace('.', '/');
|
||||||
|
if(classCache.containsKey(key)) {
|
||||||
|
return classCache.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassNode node = classPath.classes.get(key);
|
||||||
|
if (node != null) {
|
||||||
|
classPath.classes.remove(key);
|
||||||
|
Class<?>c = nodeToClass(node);
|
||||||
|
classCache.put(key, c);
|
||||||
|
return c;
|
||||||
|
} else
|
||||||
|
return super.getSystemClassLoader().loadClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Class<?> nodeToClass(ClassNode node) {
|
||||||
|
if (super.findLoadedClass(node.name) != null)
|
||||||
|
return findLoadedClass(node.name);
|
||||||
|
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||||
|
node.accept(cw);
|
||||||
|
byte[] b = cw.toByteArray();
|
||||||
|
return defineClass(node.name.replace('/', '.'), b, 0, b.length,
|
||||||
|
getDomain());
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ProtectionDomain getDomain() {
|
||||||
|
CodeSource code = new CodeSource(null, (Certificate[]) null);
|
||||||
|
return new ProtectionDomain(code, getPermissions());
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Permissions getPermissions() {
|
||||||
|
Permissions permissions = new Permissions();
|
||||||
|
permissions.add(new AllPermission());
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.parabot.core.asm;
|
||||||
|
|
||||||
|
public class Injector {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
package org.parabot.core.asm.adapters;
|
||||||
|
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.FieldNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a method into a Classnode which returns a field
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AddGetterAdapter implements Opcodes {
|
||||||
|
private ClassNode into = null;
|
||||||
|
private ClassNode fieldLocation = null;
|
||||||
|
private FieldNode fieldNode = null;
|
||||||
|
private String methodName = null;
|
||||||
|
private String returnDesc = null;
|
||||||
|
private boolean staticField = false;
|
||||||
|
private boolean staticMethod = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param into - classnode to inject getter method in
|
||||||
|
* @param fieldLocation - classnode where field is located
|
||||||
|
* @param fieldName - field name to get
|
||||||
|
* @param methodName - method name of getter
|
||||||
|
* @param returnDesc - return type of method, can be null for default return
|
||||||
|
* @param staticMethod - pass true if you want the method to be static
|
||||||
|
*/
|
||||||
|
public AddGetterAdapter(final ClassNode into, final ClassNode fieldLocation, final FieldNode fieldNode,
|
||||||
|
final String methodName, final String returnDesc, final boolean staticMethod) {
|
||||||
|
this.into = into;
|
||||||
|
this.fieldLocation = fieldLocation;
|
||||||
|
this.fieldNode = fieldNode;
|
||||||
|
this.methodName = methodName;
|
||||||
|
this.returnDesc = returnDesc == null ? fieldNode.desc : returnDesc;
|
||||||
|
this.staticField = Modifier.isStatic(fieldNode.access);
|
||||||
|
this.staticMethod = staticMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param fieldLocation
|
||||||
|
* @param fieldNode
|
||||||
|
* @param methodName
|
||||||
|
*/
|
||||||
|
public AddGetterAdapter(final ClassNode fieldLocation, final FieldNode fieldNode, final String methodName) {
|
||||||
|
this.into = fieldLocation;
|
||||||
|
this.fieldLocation = fieldLocation;
|
||||||
|
this.fieldNode = fieldNode;
|
||||||
|
this.methodName = methodName;
|
||||||
|
this.returnDesc = fieldNode.desc;
|
||||||
|
this.staticField = Modifier.isStatic(fieldNode.access);
|
||||||
|
this.staticMethod = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if this getter can be injected, if not a runtime exception is thrown
|
||||||
|
*/
|
||||||
|
public void validate() {
|
||||||
|
if(methodName == null) {
|
||||||
|
throw new RuntimeException("Null method name");
|
||||||
|
}
|
||||||
|
if(into == null) {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Into ClassNode is null, at : ").append(methodName).append("()");
|
||||||
|
throw new RuntimeException(sb.toString());
|
||||||
|
}
|
||||||
|
if(fieldNode == null) {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("FieldLocation ClassNode is null, at : ").append(methodName).append("()");
|
||||||
|
throw new RuntimeException(sb.toString());
|
||||||
|
}
|
||||||
|
if(fieldNode == null) {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("FieldNode is null, at : ").append(methodName).append("()");
|
||||||
|
throw new RuntimeException(sb.toString());
|
||||||
|
}
|
||||||
|
for(final MethodNode methodNode : into.methods) {
|
||||||
|
if(methodNode.name.equals(methodName)) {
|
||||||
|
final Type[] args = Type.getArgumentTypes(methodNode.desc);
|
||||||
|
if(args != null && args.length != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Duplicated method detected. ").append(methodName).append("() in ").append(into.name);
|
||||||
|
throw new RuntimeException(sb.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injects this the method getter
|
||||||
|
*/
|
||||||
|
public void inject() {
|
||||||
|
MethodNode method = new MethodNode(ACC_PUBLIC | (staticMethod ? ACC_STATIC : 0), methodName, "()" + returnDesc, null, null);
|
||||||
|
if (staticField) {
|
||||||
|
method.visitVarInsn(ALOAD, 0);
|
||||||
|
}
|
||||||
|
method.visitFieldInsn(staticField ? GETSTATIC : GETFIELD, fieldLocation.name, fieldNode.name, fieldNode.desc);
|
||||||
|
if (!fieldNode.desc.equals(returnDesc)) {
|
||||||
|
if (returnDesc.contains("L")) {
|
||||||
|
if (!returnDesc.contains("[")) {
|
||||||
|
method.visitTypeInsn(CHECKCAST,returnDesc.replaceFirst("L", "").replaceAll(";", ""));
|
||||||
|
} else {
|
||||||
|
method.visitTypeInsn(CHECKCAST, returnDesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldNode.desc.equals("J") && returnDesc.equals("I"))
|
||||||
|
method.visitInsn(L2I);
|
||||||
|
|
||||||
|
method.visitInsn(getReturnOpcode(returnDesc));
|
||||||
|
method.visitMaxs(0, 0);
|
||||||
|
into.methods.add(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return right opcode for desc
|
||||||
|
* @param desc
|
||||||
|
* @return return opcode
|
||||||
|
*/
|
||||||
|
private static int getReturnOpcode(String desc) {
|
||||||
|
desc = desc.substring(desc.indexOf("L") + 1);
|
||||||
|
if (desc.length() > 1) {
|
||||||
|
return ARETURN;
|
||||||
|
}
|
||||||
|
final char c = desc.charAt(0);
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'I':
|
||||||
|
case 'Z':
|
||||||
|
case 'B':
|
||||||
|
case 'S':
|
||||||
|
case 'C':
|
||||||
|
return IRETURN;
|
||||||
|
case 'J':
|
||||||
|
return LRETURN;
|
||||||
|
case 'F':
|
||||||
|
return FRETURN;
|
||||||
|
case 'D':
|
||||||
|
return DRETURN;
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Wrong desc type: " + c);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package org.parabot.core.bot.loader;
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.parabot.core.asm.ASMClassLoader;
|
||||||
|
import org.parabot.core.classpath.ClassPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles client class calls
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BotLoader extends ASMClassLoader {
|
||||||
|
private ASMClassLoader serverProvider = null;
|
||||||
|
|
||||||
|
public BotLoader(ClassPath classPath, ASMClassLoader serverProvider) {
|
||||||
|
super(classPath);
|
||||||
|
this.serverProvider = serverProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
|
return findClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
|
String key = name.replace('.', '/');
|
||||||
|
if(serverProvider.classCache.containsKey(key)) {
|
||||||
|
return serverProvider.classCache.get(key);
|
||||||
|
}
|
||||||
|
ClassNode node = serverProvider.classPath.classes.get(key);
|
||||||
|
if (node != null) {
|
||||||
|
serverProvider.classPath.classes.remove(key);
|
||||||
|
Class<?>c = serverProvider.nodeToClass(node);
|
||||||
|
serverProvider.classCache.put(key, c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return super.findClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package org.parabot.core.classpath;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
* @author Matt
|
||||||
|
*/
|
||||||
|
public class ClassPath {
|
||||||
|
public final HashMap<String, ClassNode> classes = new HashMap<String, ClassNode>();
|
||||||
|
public final Map<String, URL> resources = new HashMap<String, URL>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds jar to this classpath
|
||||||
|
* @param jarLocation
|
||||||
|
*/
|
||||||
|
public void addJar(final String jarLocation) {
|
||||||
|
JarParser.parseJar(this, jarLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and loads all classes/jar files in folder
|
||||||
|
*
|
||||||
|
* @param file to find class / jar files
|
||||||
|
* @param root
|
||||||
|
*/
|
||||||
|
public void loadClasses(final File f, File root) {
|
||||||
|
if (f == null)
|
||||||
|
return;
|
||||||
|
if (!f.exists()) {
|
||||||
|
f.mkdirs();
|
||||||
|
}
|
||||||
|
if (root == null) {
|
||||||
|
root = f;
|
||||||
|
}
|
||||||
|
for (File f1 : f.listFiles()) {
|
||||||
|
if (f1 == null) {
|
||||||
|
continue;
|
||||||
|
} else if (f1.isDirectory()) {
|
||||||
|
loadClasses(f1, root);
|
||||||
|
} else {
|
||||||
|
try (FileInputStream fin = new FileInputStream(f1)) {
|
||||||
|
if (f1.getName().endsWith(".class"))
|
||||||
|
loadClass(fin);
|
||||||
|
else if (f.equals(root) && f1.getName().endsWith(".jar")) {
|
||||||
|
loadClasses(f1.toURI().toURL());
|
||||||
|
} else {
|
||||||
|
String path = f1.toURI().relativize(root.toURI())
|
||||||
|
.getPath();
|
||||||
|
Resources.loadResource(this, path, fin);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads classes from zip/jar files
|
||||||
|
*
|
||||||
|
* @param url to file
|
||||||
|
*/
|
||||||
|
private void loadClasses(URL u) {
|
||||||
|
try (ZipInputStream zin = new ZipInputStream(u.openStream())) {
|
||||||
|
ZipEntry e;
|
||||||
|
while ((e = zin.getNextEntry()) != null) {
|
||||||
|
if (e.isDirectory())
|
||||||
|
continue;
|
||||||
|
if (e.getName().endsWith(".class")) {
|
||||||
|
loadClass(zin);
|
||||||
|
} else {
|
||||||
|
Resources.loadResource(this, e.getName(), zin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads class from input stream
|
||||||
|
*
|
||||||
|
* @param inputstream
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void loadClass(InputStream in) throws IOException {
|
||||||
|
ClassReader cr = new ClassReader(in);
|
||||||
|
ClassNode cn = new ClassNode();
|
||||||
|
cr.accept(cn, 0);
|
||||||
|
classes.put(cn.name, cn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps the classnodes into a jar
|
||||||
|
*
|
||||||
|
* @param jarName
|
||||||
|
*/
|
||||||
|
public void dump(final String jarName) {
|
||||||
|
JarDumper.dump(this, jarName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package org.parabot.core.classpath;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarOutputStream;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JarDumper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps classnodes to a jar file
|
||||||
|
* @param classPath
|
||||||
|
* @param fileName
|
||||||
|
*/
|
||||||
|
public static void dump(final ClassPath classPath, final String fileName) {
|
||||||
|
try {
|
||||||
|
FileOutputStream stream = new FileOutputStream(new File(fileName));
|
||||||
|
JarOutputStream out = new JarOutputStream(stream);
|
||||||
|
for (ClassNode cn : classPath.classes.values()) {
|
||||||
|
JarEntry je = new JarEntry(cn.name + ".class");
|
||||||
|
out.putNextEntry(je);
|
||||||
|
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||||
|
cn.accept(cw);
|
||||||
|
out.write(cw.toByteArray());
|
||||||
|
}
|
||||||
|
out.close();
|
||||||
|
stream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package org.parabot.core.classpath;
|
||||||
|
|
||||||
|
import java.net.JarURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A class for parsing a jar file
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JarParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a jar from an URL
|
||||||
|
* @param classPath
|
||||||
|
* @param jarLocation
|
||||||
|
*/
|
||||||
|
public static void parseJar(final ClassPath classPath, final String jarLocation) {
|
||||||
|
try {
|
||||||
|
URL jarURL = new URL("jar:" + jarLocation + "!/");
|
||||||
|
JarURLConnection jarConnection = (JarURLConnection) jarURL
|
||||||
|
.openConnection();
|
||||||
|
JarFile theJar = jarConnection.getJarFile();
|
||||||
|
Enumeration<?> en = theJar.entries();
|
||||||
|
while (en.hasMoreElements()) {
|
||||||
|
JarEntry entry = (JarEntry) en.nextElement();
|
||||||
|
if (entry.getName().endsWith(".class")) {
|
||||||
|
ClassReader cr = new ClassReader(
|
||||||
|
theJar.getInputStream(entry));
|
||||||
|
ClassNode cn = new ClassNode();
|
||||||
|
//cr.accept(cn, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||||
|
cr.accept(cn, 0);
|
||||||
|
classPath.classes.put(cn.name, cn);
|
||||||
|
} else if (!entry.isDirectory()
|
||||||
|
&& !entry.getName().startsWith("META-INF")) {
|
||||||
|
Resources.loadResource(classPath, entry.getName(), theJar.getInputStream(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.parabot.core.classpath;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
* @author Matt
|
||||||
|
*/
|
||||||
|
public class Resources {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps a resource from a input stream
|
||||||
|
* @param classPath
|
||||||
|
* @param name
|
||||||
|
* @param inputstream
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void loadResource(final ClassPath classPath, final String name, final InputStream in)
|
||||||
|
throws IOException {
|
||||||
|
File f = File.createTempFile("bot", ".tmp", new File("./"));
|
||||||
|
f.deleteOnExit();
|
||||||
|
try (OutputStream out = new FileOutputStream(f)) {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int len;
|
||||||
|
while ((len = in.read(buffer)) != -1)
|
||||||
|
out.write(buffer, 0, len);
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
classPath.resources.put(name, f.toURI().toURL());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package org.parabot.core.logging;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.logging.Handler;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
|
||||||
|
public class LabelLogHandler extends Handler
|
||||||
|
{
|
||||||
|
public final JLabel label = new JLabel();
|
||||||
|
private final Color defaultColor;
|
||||||
|
|
||||||
|
public LabelLogHandler()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
defaultColor = label.getForeground();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws SecurityException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(final LogRecord record) {
|
||||||
|
StringBuilder b = new StringBuilder(record.getMessage());
|
||||||
|
|
||||||
|
if (record.getLevel().intValue() > Level.WARNING.intValue()) {
|
||||||
|
label.setForeground(new Color(0xcc0000));
|
||||||
|
} else {
|
||||||
|
label.setForeground(defaultColor);
|
||||||
|
b.append(" ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
label.setText(new String(b));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package org.parabot.core.logging;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.logging.Formatter;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
|
public class LogFormatter extends Formatter
|
||||||
|
{
|
||||||
|
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
private final boolean appendNewLine;
|
||||||
|
|
||||||
|
public LogFormatter()
|
||||||
|
{
|
||||||
|
this(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogFormatter(final boolean appendNewLine)
|
||||||
|
{
|
||||||
|
this.appendNewLine = appendNewLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format(final LogRecord record) {
|
||||||
|
final StringBuilder result = new StringBuilder().append("[").append(record.getLevel().getName()).append("] ").append(new Date(record.getMillis())).append(": ").append(record.getLoggerName()).append(": ").append(record.getMessage()).append(throwableToString(record.getThrown()));
|
||||||
|
if (appendNewLine) {
|
||||||
|
result.append(LogFormatter.LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String formatMessage(final LogRecord record) {
|
||||||
|
return String.format(record.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String throwableToString(final Throwable t) {
|
||||||
|
if (t != null) {
|
||||||
|
final Writer exception = new StringWriter();
|
||||||
|
final PrintWriter printWriter = new PrintWriter(exception);
|
||||||
|
t.printStackTrace(printWriter);
|
||||||
|
return exception.toString();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package org.parabot.core.logging;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Paris
|
||||||
|
*/
|
||||||
|
public class LogOutputStream extends OutputStream {
|
||||||
|
protected boolean hasBeenClosed = false;
|
||||||
|
protected Logger category;
|
||||||
|
protected Level priority;
|
||||||
|
protected StringBuilder buffer;
|
||||||
|
|
||||||
|
public LogOutputStream(final Logger category, final Level priority) {
|
||||||
|
this.priority = priority;
|
||||||
|
this.category = category;
|
||||||
|
buffer = new StringBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
flush();
|
||||||
|
hasBeenClosed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
final String txt = buffer.toString().replace("\\s+$", "");
|
||||||
|
if (txt.trim().length() != 0) {
|
||||||
|
category.log(priority, txt);
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reset() {
|
||||||
|
buffer.setLength(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(final int b) throws IOException {
|
||||||
|
if (hasBeenClosed) {
|
||||||
|
throw new IOException("The stream has been closed.");
|
||||||
|
} else if (b != 0) {
|
||||||
|
buffer.append((char) (b & 0xff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
package org.parabot.core.logging;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Formatter;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
|
import javax.swing.AbstractListModel;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JTextPane;
|
||||||
|
import javax.swing.ListCellRenderer;
|
||||||
|
import javax.swing.ListSelectionModel;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.border.Border;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non swing methods are thread safe.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public class LogTextArea extends JList
|
||||||
|
{
|
||||||
|
private static final int MAX_ENTRIES = 100;
|
||||||
|
private static final Rectangle BOTTOM_OF_WINDOW = new Rectangle(0, Integer.MAX_VALUE, 0, 0);
|
||||||
|
private static final long serialVersionUID = 0;
|
||||||
|
private final LogQueue logQueue = new LogQueue();
|
||||||
|
private final LogAreaListModel model = new LogAreaListModel();
|
||||||
|
private final Runnable scrollToBottom = new Runnable()
|
||||||
|
{
|
||||||
|
public void run() {
|
||||||
|
scrollRectToVisible(LogTextArea.BOTTOM_OF_WINDOW);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final Formatter formatter = new Formatter()
|
||||||
|
{
|
||||||
|
private final SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm:ss");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format(final LogRecord record) {
|
||||||
|
final String[] className = record.getLoggerName().split("\\.");
|
||||||
|
final String name = className[className.length - 1];
|
||||||
|
final int maxLen = 16;
|
||||||
|
final String append = "...";
|
||||||
|
|
||||||
|
return String.format("[%s] %-" + maxLen + "s %s %s", dateFormat.format(record.getMillis()), name.length() > maxLen ? name.substring(0, maxLen - append.length()) + append : name, record.getMessage(), throwableToString(record.getThrown()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static String throwableToString(final Throwable t) {
|
||||||
|
if (t != null) {
|
||||||
|
final Writer exception = new StringWriter();
|
||||||
|
final PrintWriter printWriter = new PrintWriter(exception);
|
||||||
|
t.printStackTrace(printWriter);
|
||||||
|
return exception.toString();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Formatter copyPasteFormatter = new LogFormatter(false);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public LogTextArea()
|
||||||
|
{
|
||||||
|
setModel(model);
|
||||||
|
setCellRenderer(new Renderer());
|
||||||
|
setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||||
|
String fontName = Font.MONOSPACED;
|
||||||
|
for (final Font font : GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()) {
|
||||||
|
final String name = font.getName();
|
||||||
|
if (name.matches("Monaco|Consolas")) {
|
||||||
|
fontName = name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setFont(new Font(fontName, Font.PLAIN, 12));
|
||||||
|
|
||||||
|
new Thread(logQueue, "LogGuiQueue").start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a new entry to be shown in the list. Thread safe.
|
||||||
|
*
|
||||||
|
* @param logRecord
|
||||||
|
* The entry.
|
||||||
|
*/
|
||||||
|
public void log(final LogRecord logRecord) {
|
||||||
|
logQueue.queue(new WrappedLogRecord(logRecord));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LogAreaListModel extends AbstractListModel
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 0;
|
||||||
|
|
||||||
|
private List<WrappedLogRecord> records = new ArrayList<WrappedLogRecord>(LogTextArea.MAX_ENTRIES);
|
||||||
|
|
||||||
|
public void addAllElements(final List<WrappedLogRecord> obj) {
|
||||||
|
records.addAll(obj);
|
||||||
|
if (getSize() > LogTextArea.MAX_ENTRIES) {
|
||||||
|
records.subList(0, (getSize() - LogTextArea.MAX_ENTRIES)).clear();
|
||||||
|
|
||||||
|
fireContentsChanged(this, 0, (getSize() - 1));
|
||||||
|
} else {
|
||||||
|
fireIntervalAdded(this, (getSize() - 1), (getSize() - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getElementAt(final int index) {
|
||||||
|
return records.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return records.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes every #FLUSH_RATE (milliseconds)
|
||||||
|
*/
|
||||||
|
private class LogQueue implements Runnable
|
||||||
|
{
|
||||||
|
public static final int FLUSH_RATE = 1000;
|
||||||
|
private final Object lock = new Object();
|
||||||
|
private List<WrappedLogRecord> queue = new ArrayList<WrappedLogRecord>(100);
|
||||||
|
|
||||||
|
public void queue(final WrappedLogRecord record) {
|
||||||
|
synchronized (lock) {
|
||||||
|
queue.add(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
List<WrappedLogRecord> toFlush = null;
|
||||||
|
|
||||||
|
synchronized (lock) {
|
||||||
|
if (queue.size() != 0) {
|
||||||
|
toFlush = new ArrayList<WrappedLogRecord>(queue);
|
||||||
|
queue = queue.subList(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toFlush != null) { // Hold the lock for as little time as
|
||||||
|
// possible
|
||||||
|
model.addAllElements(toFlush);
|
||||||
|
SwingUtilities.invokeLater(scrollToBottom);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(LogQueue.FLUSH_RATE);
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Renderer implements ListCellRenderer
|
||||||
|
{
|
||||||
|
private final Border EMPTY_BORDER = new EmptyBorder(1, 1, 1, 1);
|
||||||
|
private final Border SELECTED_BORDER = UIManager.getBorder("List.focusCellHighlightBorder");
|
||||||
|
private final Color DARK_GREEN = new Color(0, 0xcc, 0), DARK_RED = new Color(0xcc, 0, 0), DARK_PINK = new Color(0xff, 0, 0x66);
|
||||||
|
|
||||||
|
public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) {
|
||||||
|
if (!(value instanceof WrappedLogRecord)) {
|
||||||
|
return new JLabel();
|
||||||
|
}
|
||||||
|
final WrappedLogRecord wlr = (WrappedLogRecord) value;
|
||||||
|
|
||||||
|
final JTextPane result = new JTextPane();
|
||||||
|
result.setDragEnabled(true);
|
||||||
|
result.setText(wlr.formatted);
|
||||||
|
result.setComponentOrientation(list.getComponentOrientation());
|
||||||
|
result.setFont(list.getFont());
|
||||||
|
result.setBorder(cellHasFocus || isSelected ? SELECTED_BORDER : EMPTY_BORDER);
|
||||||
|
|
||||||
|
result.setForeground(Color.BLACK);
|
||||||
|
|
||||||
|
if (wlr.record.getLevel() == Level.SEVERE) {
|
||||||
|
result.setBackground(DARK_RED);
|
||||||
|
result.setForeground(Color.BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wlr.record.getLevel() == Level.WARNING) {
|
||||||
|
result.setForeground(DARK_PINK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wlr.record.getLevel() == Level.FINE || wlr.record.getLevel() == Level.FINER || wlr.record.getLevel() == Level.FINEST) {
|
||||||
|
result.setForeground(DARK_GREEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object[] parameters = wlr.record.getParameters();
|
||||||
|
if (parameters != null) {
|
||||||
|
for (final Object parameter : parameters) {
|
||||||
|
if (parameter == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameter instanceof Color) {
|
||||||
|
result.setForeground((Color) parameter);
|
||||||
|
} else if (parameter instanceof Font) {
|
||||||
|
result.setFont((Font) parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap the log records so we can control the copy paste text (via #toString)
|
||||||
|
*/
|
||||||
|
private class WrappedLogRecord
|
||||||
|
{
|
||||||
|
public final LogRecord record;
|
||||||
|
public final String formatted;
|
||||||
|
|
||||||
|
public WrappedLogRecord(final LogRecord record)
|
||||||
|
{
|
||||||
|
this.record = record;
|
||||||
|
formatted = LogTextArea.formatter.format(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return LogTextArea.copyPasteFormatter.format(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package org.parabot.core.logging;
|
||||||
|
|
||||||
|
import java.util.logging.ConsoleHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs to System.out
|
||||||
|
*/
|
||||||
|
public class SystemConsoleHandler extends ConsoleHandler {
|
||||||
|
public SystemConsoleHandler() {
|
||||||
|
super();
|
||||||
|
setOutputStream(System.out);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.parabot.core.logging;
|
||||||
|
|
||||||
|
import java.util.logging.Handler;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
|
|
||||||
|
public class TextAreaLogHandler extends Handler {
|
||||||
|
public static final LogTextArea TEXT_AREA = new LogTextArea();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws SecurityException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(final LogRecord record) {
|
||||||
|
TextAreaLogHandler.TEXT_AREA.log(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.parabot.core.parsers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ServerManifestParser {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package org.parabot.core.ui;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JMenuBar;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JToolBar;
|
||||||
|
import javax.swing.WindowConstants;
|
||||||
|
|
||||||
|
import org.parabot.core.Context;
|
||||||
|
import org.parabot.core.ui.components.BotToolbar;
|
||||||
|
import org.parabot.core.ui.components.GamePanel;
|
||||||
|
import org.parabot.core.ui.components.LogArea;
|
||||||
|
import org.parabot.core.ui.images.Images;
|
||||||
|
import org.parabot.core.ui.utils.Center;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bot frame
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BotUI extends JFrame {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static BotUI instance = null;
|
||||||
|
|
||||||
|
public static BotUI getInstance() {
|
||||||
|
return instance == null ? instance = new BotUI() : instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BotUI() {
|
||||||
|
JMenuBar bar = new JMenuBar();
|
||||||
|
JMenu file = new JMenu("File");
|
||||||
|
JMenuItem screenshot = new JMenuItem("Screenshot");
|
||||||
|
screenshot.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final Context c = GamePanel.getInstance().context;
|
||||||
|
GamePanel.getInstance().setContext(null);
|
||||||
|
try {
|
||||||
|
Thread.sleep(10000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
GamePanel.getInstance().setContext(c);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
file.add(screenshot);
|
||||||
|
bar.add(file);
|
||||||
|
|
||||||
|
JScrollPane textPane = LogArea.getInstance();
|
||||||
|
GroupLayout layout = new GroupLayout(getContentPane());
|
||||||
|
JToolBar tool = BotToolbar.getInstance();
|
||||||
|
GamePanel pane = GamePanel.getInstance();
|
||||||
|
pane.addLoader();
|
||||||
|
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
|
||||||
|
getContentPane().setLayout(layout);
|
||||||
|
setJMenuBar(bar);
|
||||||
|
setDefaultLookAndFeelDecorated(true);
|
||||||
|
setTitle("parabot v2");
|
||||||
|
setIconImage(Images.getResource("/org/parabot/core/ui/images/icon.png"));
|
||||||
|
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||||
|
setResizable(false);
|
||||||
|
Center.centerFramea(this, 775, 683);
|
||||||
|
layout.setHorizontalGroup(layout
|
||||||
|
.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout
|
||||||
|
.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(layout
|
||||||
|
.createParallelGroup(GroupLayout.Alignment.LEADING)))
|
||||||
|
.addComponent(tool, 768, 768, 768)
|
||||||
|
.addComponent(pane, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addComponent(textPane, 768, 768, 768));
|
||||||
|
layout.setVerticalGroup(layout
|
||||||
|
.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout
|
||||||
|
.createSequentialGroup()
|
||||||
|
.addComponent(tool, 30, 30, 30)
|
||||||
|
.addComponent(pane, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addComponent(textPane, 100, 100, 100)
|
||||||
|
.addContainerGap(58, Short.MAX_VALUE)));
|
||||||
|
LogArea.log("Welcome to Parabot v2");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.parabot.core.ui;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
|
||||||
|
import org.parabot.core.ui.utils.Center;
|
||||||
|
import org.parabot.core.ui.widgets.ServerWidget;
|
||||||
|
|
||||||
|
|
||||||
|
public class ServerSelector extends JFrame
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static ServerSelector instance = null;
|
||||||
|
|
||||||
|
public static ServerSelector getInstance() {
|
||||||
|
if(instance != null) {
|
||||||
|
instance.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
return instance = new ServerSelector();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ServerSelector() {
|
||||||
|
setLayout(null);
|
||||||
|
ServerWidget[] widgets = getServers();
|
||||||
|
JPanel p = new JPanel();
|
||||||
|
p.setBounds(0, 0, 400, 800);
|
||||||
|
p.setLayout(null);
|
||||||
|
p.setPreferredSize(new Dimension(400, widgets.length * 100));
|
||||||
|
JScrollPane pane = new JScrollPane(p);
|
||||||
|
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
for (int i = 0; i < widgets.length; i++) {
|
||||||
|
widgets[i].setBounds(0, i * 100, 400, 100);
|
||||||
|
p.add(widgets[i]);
|
||||||
|
}
|
||||||
|
pane.setBounds(0, 0, 400, 200);
|
||||||
|
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||||
|
getContentPane().add(pane);
|
||||||
|
setResizable(false);
|
||||||
|
setTitle("Servers");
|
||||||
|
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
Center.centerFramea(this, 406, 228);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerWidget[] getServers() {
|
||||||
|
ArrayList<ServerWidget> widgets = new ArrayList<ServerWidget>();
|
||||||
|
widgets.add(new ServerWidget("RecklessPk", "Clisprail", "317"));
|
||||||
|
widgets.add(new ServerWidget("Soulsplit", "Clisprail", "317"));
|
||||||
|
widgets.add(new ServerWidget("RS2007", "Clisprail", "10"));
|
||||||
|
return widgets.toArray(new ServerWidget[widgets.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package org.parabot.core.ui.applet;
|
||||||
|
|
||||||
|
import java.applet.Applet;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import org.parabot.core.ui.images.Images;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An informative applet which tells the user what bot is doing
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LoadApplet extends Applet {
|
||||||
|
private static final long serialVersionUID = 7412412644921803896L;
|
||||||
|
private static LoadApplet current = null;
|
||||||
|
private static String state = "Initializing loader...";
|
||||||
|
private FontMetrics fontMetrics = null;
|
||||||
|
private BufferedImage bot_image = null;
|
||||||
|
|
||||||
|
public LoadApplet() {
|
||||||
|
bot_image = Images.getResource("/org/parabot/core/ui/images/para.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
setSize(775, 510);
|
||||||
|
setBackground(Color.black);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paints on this applet
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void paint(Graphics g) {
|
||||||
|
g.setFont(new Font("Calibri", Font.PLAIN, 18));
|
||||||
|
if (fontMetrics == null) {
|
||||||
|
fontMetrics = g.getFontMetrics();
|
||||||
|
}
|
||||||
|
g.setColor(Color.white);
|
||||||
|
int x = (getWidth() / 2) - (fontMetrics.stringWidth(state) / 2);
|
||||||
|
g.drawString(state, x, 200);
|
||||||
|
g.setFont(new Font("Calibri", Font.PLAIN, 12));
|
||||||
|
final String version = "v2.0";
|
||||||
|
g.drawString(version,
|
||||||
|
getWidth() - g.getFontMetrics().stringWidth(version) - 10,
|
||||||
|
getHeight() - 12);
|
||||||
|
x = (getWidth() / 2) - (bot_image.getWidth() / 2);
|
||||||
|
g.drawImage(bot_image, x, 80, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets instance of this applet
|
||||||
|
* @return instance of this applet
|
||||||
|
*/
|
||||||
|
public static LoadApplet get() {
|
||||||
|
if (current != null) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
final LoadApplet splash = new LoadApplet();
|
||||||
|
splash.init();
|
||||||
|
current = splash;
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the status message and repaints the applet
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
public static void setState(final String message) {
|
||||||
|
state = message;
|
||||||
|
current.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package org.parabot.core.ui.components;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.MouseAdapter;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseMotionAdapter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JToolBar;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
|
import org.parabot.core.Context;
|
||||||
|
import org.parabot.core.ui.ServerSelector;
|
||||||
|
import org.parabot.core.ui.images.Images;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bot toolbar
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BotToolbar extends JToolBar {
|
||||||
|
private static final long serialVersionUID = 5373484845104212180L;
|
||||||
|
private static BotToolbar instance = null;
|
||||||
|
private JButton tab = null;
|
||||||
|
private static Map<TabButton, Context> environments = new HashMap<TabButton, Context>();
|
||||||
|
|
||||||
|
public BotToolbar() {
|
||||||
|
setFloatable(false);
|
||||||
|
final JButton run = new JButton();
|
||||||
|
final JButton pause = new JButton();
|
||||||
|
tab = new JButton();
|
||||||
|
tab.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
ServerSelector.getInstance().setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
run.setFocusable(false);
|
||||||
|
pause.setFocusable(false);
|
||||||
|
tab.setFocusable(false);
|
||||||
|
try {
|
||||||
|
run.setIcon(new ImageIcon(Images.getResource("/org/parabot/core/ui/images/run.png")));
|
||||||
|
pause.setIcon(new ImageIcon(Images.getResource("/org/parabot/core/ui/images/pause.png")));
|
||||||
|
tab.setIcon(new ImageIcon(Images.getResource("/org/parabot/core/ui/images/add.png")));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
//add(tab);
|
||||||
|
add(Box.createHorizontalGlue());
|
||||||
|
add(run);
|
||||||
|
add(pause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BotToolbar getInstance() {
|
||||||
|
return instance == null ? instance = new BotToolbar() : instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTab(final Context context, final String name) {
|
||||||
|
TabButton b = new TabButton(name);
|
||||||
|
b.setActive(true);
|
||||||
|
b.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
final TabButton tabButton = (TabButton) e.getSource();
|
||||||
|
final Context context = environments.get(tabButton);
|
||||||
|
for(final TabButton button : environments.keySet()) {
|
||||||
|
button.setActive(false);
|
||||||
|
}
|
||||||
|
tabButton.setActive(true);
|
||||||
|
if(!context.appletSet()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GamePanel.getInstance().setContext(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
//add(b, getComponentIndex(tab));
|
||||||
|
add(b, 0);
|
||||||
|
environments.put(b, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tab button
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private final class TabButton extends JButton {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public TabButton(final String name) {
|
||||||
|
super(name);
|
||||||
|
setFocusable(false);
|
||||||
|
setHorizontalTextPosition(SwingConstants.LEFT);
|
||||||
|
setIcon(getBlackClose());
|
||||||
|
final Component c = this;
|
||||||
|
addMouseMotionListener(new MouseMotionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseMoved(final MouseEvent e) {
|
||||||
|
if (e.getX() > getWidth() - getIcon().getIconWidth()
|
||||||
|
&& e.getX() < getWidth() - getIconTextGap()) {
|
||||||
|
setIcon(getRedClose());
|
||||||
|
} else {
|
||||||
|
setIcon(getBlackClose());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
addMouseListener(new MouseAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(final MouseEvent e) {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
final int n = getComponentIndex(c);
|
||||||
|
if (e.getX() > getWidth() - getIcon().getIconWidth()
|
||||||
|
&& e.getX() < getWidth() - getIconTextGap()) {
|
||||||
|
// close
|
||||||
|
} else {
|
||||||
|
// enable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseExited(final MouseEvent e) {
|
||||||
|
setIcon(getBlackClose());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ImageIcon getBlackClose() {
|
||||||
|
try {
|
||||||
|
return new ImageIcon(Images.getResource("/org/parabot/core/ui/images/close.png"));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw new RuntimeException("Unable to load icon image: " + t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ImageIcon getRedClose() {
|
||||||
|
try {
|
||||||
|
return new ImageIcon(Images.getResource("/org/parabot/core/ui/images/close_red.png"));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw new RuntimeException("Unable to load icon image: " + t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActive(final boolean active) {
|
||||||
|
setFont(getFont().deriveFont(active ? Font.BOLD : Font.PLAIN));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package org.parabot.core.ui.components;
|
||||||
|
|
||||||
|
import java.applet.Applet;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import org.parabot.core.Context;
|
||||||
|
import org.parabot.core.ui.applet.LoadApplet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Main panel where applets are added.
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class GamePanel extends JPanel {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static GamePanel instance = null;
|
||||||
|
private static LoadApplet loader = LoadApplet.get();
|
||||||
|
public Context context = null;
|
||||||
|
|
||||||
|
private GamePanel() {
|
||||||
|
setFocusable(true);
|
||||||
|
setFocusTraversalKeysEnabled(false);
|
||||||
|
setOpaque(true);
|
||||||
|
setBackground(Color.black);
|
||||||
|
setPreferredSize(new Dimension(770, 503));
|
||||||
|
GroupLayout panelLayout = new GroupLayout(this);
|
||||||
|
setLayout(panelLayout);
|
||||||
|
panelLayout.setHorizontalGroup(panelLayout.createParallelGroup(
|
||||||
|
GroupLayout.Alignment.LEADING).addGap(0, 770, Short.MAX_VALUE));
|
||||||
|
panelLayout.setVerticalGroup(panelLayout.createParallelGroup(
|
||||||
|
GroupLayout.Alignment.LEADING).addGap(0, 418, Short.MAX_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates context of this panel and adds a different Applet to the panel
|
||||||
|
* @param context
|
||||||
|
*/
|
||||||
|
public void setContext(final Context c) {
|
||||||
|
if(context != null) {
|
||||||
|
context.getApplet().setVisible(false);
|
||||||
|
}
|
||||||
|
context = c;
|
||||||
|
if(c == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Applet gameApplet = context.getApplet();
|
||||||
|
if(!c.added) {
|
||||||
|
add(gameApplet);
|
||||||
|
c.added = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gameApplet.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets instance of this panel
|
||||||
|
* @return instance of this panel
|
||||||
|
*/
|
||||||
|
public static GamePanel getInstance() {
|
||||||
|
return instance == null ? instance = new GamePanel() : instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the loader applet
|
||||||
|
*/
|
||||||
|
public void addLoader() {
|
||||||
|
add(loader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the loader applet
|
||||||
|
*/
|
||||||
|
public void removeLoader() {
|
||||||
|
remove(loader);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package org.parabot.core.ui.components;
|
||||||
|
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.logging.FileHandler;
|
||||||
|
import java.util.logging.LogManager;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.ScrollPaneConstants;
|
||||||
|
|
||||||
|
import org.parabot.core.logging.LogFormatter;
|
||||||
|
import org.parabot.core.logging.LogTextArea;
|
||||||
|
import org.parabot.core.logging.SystemConsoleHandler;
|
||||||
|
import org.parabot.core.logging.TextAreaLogHandler;
|
||||||
|
|
||||||
|
public class LogArea extends JScrollPane {
|
||||||
|
private static final long serialVersionUID = 6571141103751675714L;
|
||||||
|
private static LogArea instance = null;
|
||||||
|
private static LogTextArea logArea = new LogTextArea();
|
||||||
|
|
||||||
|
private LogArea() {
|
||||||
|
super(TextAreaLogHandler.TEXT_AREA,
|
||||||
|
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
|
||||||
|
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||||
|
logArea.setPreferredSize(new Dimension(775, 80));
|
||||||
|
setPreferredSize(new Dimension(776, 100));
|
||||||
|
setSize(775, 100);
|
||||||
|
setVisible(true);
|
||||||
|
registerLogging();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LogArea getInstance() {
|
||||||
|
return instance == null ? instance = new LogArea() : instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger("Bot");
|
||||||
|
|
||||||
|
public static void log(String s) {
|
||||||
|
log.info(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void error(String s) {
|
||||||
|
log.severe(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearLog() {
|
||||||
|
logArea.clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void hideLog() {
|
||||||
|
logArea.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showLog() {
|
||||||
|
logArea.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerLogging() {
|
||||||
|
final Properties logging = new Properties();
|
||||||
|
final String logFormatter = LogFormatter.class.getCanonicalName();
|
||||||
|
final String fileHandler = FileHandler.class.getCanonicalName();
|
||||||
|
logging.setProperty("handlers",
|
||||||
|
TextAreaLogHandler.class.getCanonicalName() + "," + fileHandler);
|
||||||
|
logging.setProperty(".level", "INFO");
|
||||||
|
logging.setProperty(SystemConsoleHandler.class.getCanonicalName()
|
||||||
|
+ ".formatter", logFormatter);
|
||||||
|
logging.setProperty(fileHandler + ".formatter", logFormatter);
|
||||||
|
logging.setProperty(TextAreaLogHandler.class.getCanonicalName()
|
||||||
|
+ ".formatter", logFormatter);
|
||||||
|
final ByteArrayOutputStream logout = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
logging.store(logout, "");
|
||||||
|
LogManager.getLogManager().readConfiguration(
|
||||||
|
new ByteArrayInputStream(logout.toByteArray()));
|
||||||
|
} catch (final Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package org.parabot.core.ui.components;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ServerPanel extends JPanel {
|
||||||
|
private static final long serialVersionUID = 6034139911394898295L;
|
||||||
|
|
||||||
|
|
||||||
|
public ServerPanel() {
|
||||||
|
setBorder(null);
|
||||||
|
setOpaque(false);
|
||||||
|
setPreferredSize(new Dimension(765, 503));
|
||||||
|
GroupLayout layout = new GroupLayout(this);
|
||||||
|
setLayout(layout);
|
||||||
|
layout.setHorizontalGroup(layout.createParallelGroup(
|
||||||
|
GroupLayout.Alignment.LEADING).addGap(0, 706, Short.MAX_VALUE));
|
||||||
|
layout.setVerticalGroup(layout.createParallelGroup(
|
||||||
|
GroupLayout.Alignment.LEADING).addGap(0, 418, Short.MAX_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
g.setColor(Color.LIGHT_GRAY);
|
||||||
|
g.fillRect(0, 0, getWidth(), getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.parabot.core.ui.images;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
public class Images {
|
||||||
|
private static final HashMap<String, BufferedImage> imageCache = new HashMap<String, BufferedImage>();
|
||||||
|
|
||||||
|
public static BufferedImage getResource(final String resource) {
|
||||||
|
if(imageCache.containsKey(resource)) {
|
||||||
|
return imageCache.get(resource);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final BufferedImage img = ImageIO.read(Images.class.getResourceAsStream(resource));
|
||||||
|
imageCache.put(resource, img);
|
||||||
|
return img;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw new RuntimeException("Failed to load image from resource. " + t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 152 B |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 125 B |
|
After Width: | Height: | Size: 155 B |
|
After Width: | Height: | Size: 110 B |
@@ -0,0 +1,30 @@
|
|||||||
|
package org.parabot.core.ui.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class Center {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centers a JFrame
|
||||||
|
* @param frame
|
||||||
|
* @param width
|
||||||
|
* @param height
|
||||||
|
*/
|
||||||
|
public static final void centerFramea(final JFrame f, final int width, final int height) {
|
||||||
|
final Dimension fscreen = Toolkit.getDefaultToolkit().getScreenSize();
|
||||||
|
final int x = (fscreen.width - width) / 2;
|
||||||
|
final int y = (fscreen.height - height) / 2;
|
||||||
|
f.setBounds(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package org.parabot.core.ui.widgets;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.GradientPaint;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import org.parabot.environment.Environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A colorful server widget
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ServerWidget extends JPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private String name = null;
|
||||||
|
|
||||||
|
final ActionListener play = new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
try {
|
||||||
|
load(new URL("http://parnassian.host56.com/" + name
|
||||||
|
+ ".jar"), name);
|
||||||
|
} catch (MalformedURLException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public ServerWidget(final String serverName, final String author,
|
||||||
|
final String revision) {
|
||||||
|
setLayout(null);
|
||||||
|
this.name = serverName.replaceAll(" ", "");
|
||||||
|
JLabel l = new JLabel();
|
||||||
|
l.setFont(new Font("Arial", Font.BOLD, 16));
|
||||||
|
l.setForeground(Color.white);
|
||||||
|
l.setText(serverName);
|
||||||
|
l.setBounds(10, 10, 100, 20);
|
||||||
|
add(l);
|
||||||
|
final Font f = new Font("Arial", Font.PLAIN, 12);
|
||||||
|
add(l);
|
||||||
|
l = new JLabel();
|
||||||
|
l.setFont(f);
|
||||||
|
l.setForeground(Color.white);
|
||||||
|
l.setBounds(10, 45, 100, 20);
|
||||||
|
l.setText("Author: " + author);
|
||||||
|
add(l);
|
||||||
|
l = new JLabel();
|
||||||
|
l.setFont(f);
|
||||||
|
l.setForeground(Color.white);
|
||||||
|
l.setBounds(10, 60, 100, 20);
|
||||||
|
l.setText("Revision: " + revision);
|
||||||
|
add(l);
|
||||||
|
final JButton b = new JButton("Start");
|
||||||
|
b.setFocusable(false);
|
||||||
|
b.setBounds(300, 70, 70, 20);
|
||||||
|
b.setOpaque(false);
|
||||||
|
b.addActionListener(play);
|
||||||
|
add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintComponent(Graphics g) {
|
||||||
|
Graphics2D g2d = (Graphics2D) g;
|
||||||
|
setOpaque(false);
|
||||||
|
super.paintComponent(g);
|
||||||
|
setOpaque(true);
|
||||||
|
int w = getWidth();
|
||||||
|
int h = getHeight();
|
||||||
|
Color color1 = new Color(160, 0, 0);
|
||||||
|
Color color2 = color1.darker();
|
||||||
|
GradientPaint gp = new GradientPaint(0, 0, color1, 0, h, color2);
|
||||||
|
g2d.setPaint(gp);
|
||||||
|
g2d.fillRect(0, 0, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load(final URL url, final String serverName) {
|
||||||
|
Environment.load(url, serverName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.parabot.environment;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.parabot.core.Context;
|
||||||
|
import org.parabot.core.classpath.ClassPath;
|
||||||
|
import org.parabot.core.ui.BotUI;
|
||||||
|
import org.parabot.core.ui.ServerSelector;
|
||||||
|
import org.parabot.core.ui.components.BotToolbar;
|
||||||
|
import org.parabot.environment.servers.ServerProvider;
|
||||||
|
import org.parabot.environment.servers.loader.ServerLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Environment {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a new environment
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
public static void load(final URL url, final String serverName) {
|
||||||
|
ServerSelector.getInstance().dispose();
|
||||||
|
if(!BotUI.getInstance().isVisible()) {
|
||||||
|
BotUI.getInstance().setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ClassPath classPath = new ClassPath();
|
||||||
|
classPath.addJar(url.toString());
|
||||||
|
|
||||||
|
final ServerLoader serverLoader = new ServerLoader(classPath);
|
||||||
|
final String[] serverProviders = serverLoader.getServerClassNames();
|
||||||
|
if (serverProviders == null) {
|
||||||
|
throw new RuntimeException("No server provided.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String id = "tab" + Context.getID();
|
||||||
|
final ThreadGroup bot = new ThreadGroup(id);
|
||||||
|
new Thread(bot, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
final Class<?> serverProviderClass = serverLoader.loadClass(serverProviders[0]);
|
||||||
|
final Constructor<?> con = serverProviderClass.getConstructor();
|
||||||
|
ServerProvider server = (ServerProvider) con.newInstance();
|
||||||
|
server.context.setEnvironment(serverLoader);
|
||||||
|
BotToolbar.getInstance().addTab(server.context, serverName);
|
||||||
|
server.context.load();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw new RuntimeException("Error while loading server. " + t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package org.parabot.environment.api.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple class to filter things
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
* @param <F>
|
||||||
|
*/
|
||||||
|
public interface Filter<F>
|
||||||
|
{
|
||||||
|
public boolean accept(F f);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.parabot.environment.servers;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A server manifest
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface ServerManifest {
|
||||||
|
|
||||||
|
String author();
|
||||||
|
|
||||||
|
String name();
|
||||||
|
|
||||||
|
double version();
|
||||||
|
|
||||||
|
Type type();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package org.parabot.environment.servers;
|
||||||
|
|
||||||
|
import java.applet.Applet;
|
||||||
|
import java.applet.AppletStub;
|
||||||
|
import java.net.URL;
|
||||||
|
import javax.swing.JMenuBar;
|
||||||
|
|
||||||
|
import org.parabot.core.Context;
|
||||||
|
/**
|
||||||
|
* Provides a server to the bot
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class ServerProvider {
|
||||||
|
public Context context = new Context(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hooks to parse
|
||||||
|
* @return URL to hooks file
|
||||||
|
*/
|
||||||
|
public URL getHooks() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jar to parse
|
||||||
|
* @return URL to client jar
|
||||||
|
*/
|
||||||
|
public abstract String getJar();
|
||||||
|
|
||||||
|
public abstract Applet fetchApplet();
|
||||||
|
|
||||||
|
public String getAccessorsPackage() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add custom items to the bot menu bar
|
||||||
|
* @param menu bar to add items on
|
||||||
|
*/
|
||||||
|
public void addMenuItems(JMenuBar bar) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppletStub getStub() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parseJar() {
|
||||||
|
context.getClassPath().addJar(getJar());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package org.parabot.environment.servers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Bot type
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum Type {
|
||||||
|
|
||||||
|
INJECTION, REFLECTION, COLOR, OTHER
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package org.parabot.environment.servers.loader;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.parabot.core.asm.ASMClassLoader;
|
||||||
|
import org.parabot.core.classpath.ClassPath;
|
||||||
|
import org.parabot.environment.servers.ServerProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Clisprail
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ServerLoader extends ASMClassLoader {
|
||||||
|
private ClassPath classPath = null;
|
||||||
|
|
||||||
|
public ServerLoader(ClassPath classPath) {
|
||||||
|
super(classPath);
|
||||||
|
this.classPath = classPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all classes that extends ServerProvider
|
||||||
|
* @return string array of class names that extends ServerProvider
|
||||||
|
*/
|
||||||
|
public final String[] getServerClassNames() {
|
||||||
|
final List<String> classNames = new ArrayList<String>();
|
||||||
|
for (ClassNode c : classPath.classes.values())
|
||||||
|
if (c.superName.replace('/', '.').equals(
|
||||||
|
ServerProvider.class.getName())) {
|
||||||
|
classNames.add(c.name.replace('/', '.'));
|
||||||
|
}
|
||||||
|
return classNames.toArray(new String[classNames.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||