diff --git a/parabotv2/asm-debug-all-4.0.jar b/parabotv2/asm-debug-all-4.0.jar deleted file mode 100644 index 9562c99..0000000 Binary files a/parabotv2/asm-debug-all-4.0.jar and /dev/null differ diff --git a/parabotv2/src/org/parabot/Landing.java b/parabotv2/src/org/parabot/Landing.java index 7526089..a2d17cb 100644 --- a/parabotv2/src/org/parabot/Landing.java +++ b/parabotv2/src/org/parabot/Landing.java @@ -1,13 +1,15 @@ package org.parabot; +import javax.swing.JOptionPane; import javax.swing.UIManager; import org.parabot.core.Core; import org.parabot.core.Directories; import org.parabot.core.ui.ServerSelector; +import org.parabot.core.ui.utils.UILog; /** - * Parabot X - A revolution in bot clients + * Parabot v2 * * @author Clisprail (Parnassian) * @author Matt, Dane @@ -16,14 +18,38 @@ import org.parabot.core.ui.ServerSelector; public final class Landing { public static void main(String... args) { + parseArgs(args); try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Throwable t) { t.printStackTrace(); } Directories.validate(); - Core.setDebug(true); - ServerSelector.getInstance().setVisible(true); + if(!Core.inDebugMode()) { + UILog.log("Error", "You can only run parabot in debug mode.", JOptionPane.ERROR_MESSAGE); + return; + } + ServerSelector.getInstance(); + } + + private static void parseArgs(String... args) { + for(int i = 0; i < args.length; i++) { + final String arg = args[i]; + switch(arg) { + case "-createdirs": + Directories.validate(); + System.out.println("Directories created, you can now run parabot."); + System.exit(0); + break; + case "-debug": + Core.setDebug(true); + break; + case "-server": + ServerSelector.initServer = args[++i]; + break; + } + + } } } diff --git a/parabotv2/src/org/parabot/core/Context.java b/parabotv2/src/org/parabot/core/Context.java index 2c304c0..707e577 100644 --- a/parabotv2/src/org/parabot/core/Context.java +++ b/parabotv2/src/org/parabot/core/Context.java @@ -9,9 +9,13 @@ import org.parabot.core.asm.ASMClassLoader; import org.parabot.core.bot.loader.BotLoader; import org.parabot.core.classpath.ClassPath; import org.parabot.core.paint.PaintDebugger; +import org.parabot.core.parsers.HookParser; import org.parabot.core.ui.BotUI; import org.parabot.core.ui.components.GamePanel; import org.parabot.environment.api.interfaces.Paintable; +import org.parabot.environment.input.Keyboard; +import org.parabot.environment.input.Mouse; +import org.parabot.environment.scripts.Script; import org.parabot.environment.servers.ServerProvider; /** @@ -21,7 +25,7 @@ import org.parabot.environment.servers.ServerProvider; * */ public class Context { - private static HashMap threadGroups = new HashMap(); + public static HashMap threadGroups = new HashMap(); private static int id = 1; private ASMClassLoader classLoader = null; @@ -29,6 +33,8 @@ public class Context { private ServerProvider serverProvider = null; private int tab = 0; private Applet gameApplet = null; + private HookParser hookParser = null; + private Script runningScript = null; private Object clientInstance = null; @@ -37,6 +43,9 @@ public class Context { private PaintDebugger paintDebugger = new PaintDebugger(); public boolean added = false; + + private Mouse mouse = null; + private Keyboard keyboard = null; public Context(final ServerProvider serverProvider) { threadGroups.put(Thread.currentThread().getThreadGroup(), this); @@ -45,6 +54,20 @@ public class Context { id++; this.classPath = new ClassPath(); } + + /** + * Resolves the context from threadgroup + * + * @return context + */ + public static Context resolve() { + return threadGroups.get(Thread.currentThread().getThreadGroup()); + } + + public static Context currentTab() { + // TODO + return threadGroups.values().iterator().next(); + } /** * Sets the ServerProvider class loader @@ -61,6 +84,47 @@ public class Context { public void setClientInstance(Object object) { this.clientInstance = object; } + + /** + * Sets the hook parser + * @param hookParser + */ + public void setHookParser(final HookParser hookParser) { + this.hookParser = hookParser; + } + + /** + * Sets the mouse + * @param mouse + */ + public void setMouse(final Mouse mouse) { + this.mouse = mouse; + } + + /** + * Gets the mouse + * @return mouse + */ + public Mouse getMouse() { + return mouse; + } + + + /** + * Sets the keyboard + * @param keyboard + */ + public void setKeyboard(final Keyboard keyboard) { + this.keyboard = keyboard; + } + + /** + * Gets the keyboard + * @return keyboard + */ + public Keyboard getKeyboard() { + return keyboard; + } /** * ClassPath @@ -89,15 +153,6 @@ public class Context { return gameApplet; } - /** - * Resolves the context from threadgroup - * - * @return context - */ - public static Context resolve() { - return threadGroups.get(Thread.currentThread().getThreadGroup()); - } - /** * Loads the game */ @@ -121,6 +176,8 @@ public class Context { gameApplet.setBounds(0, 0, 765, 503); } }, 1000); + serverProvider.initMouse(); + serverProvider.initKeyboard(); } /** @@ -203,5 +260,29 @@ public class Context { public Object getClient() { return this.clientInstance; } + + /** + * Gets the hook parser, may be null if injection is not used or a custom hook parser is used for injecting + * @return hook parser + */ + public HookParser getHookParser() { + return hookParser; + } + + /** + * Sets the current running script, if a script stops it will call this method with a null argument + * @param script + */ + public void setRunningScript(final Script script) { + this.runningScript = script; + } + + /** + * Gets the current running script + * @return script + */ + public Script getRunningScript() { + return this.runningScript; + } } diff --git a/parabotv2/src/org/parabot/core/asm/adapters/AddSetterAdapter.java b/parabotv2/src/org/parabot/core/asm/adapters/AddSetterAdapter.java new file mode 100644 index 0000000..d5ab966 --- /dev/null +++ b/parabotv2/src/org/parabot/core/asm/adapters/AddSetterAdapter.java @@ -0,0 +1,63 @@ +package org.parabot.core.asm.adapters; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; +import org.parabot.core.asm.interfaces.Injectable; + +/** + * Injects methods which sets a field + * + * @author Clisprail + * + */ +public class AddSetterAdapter implements Opcodes, Injectable { + private ClassNode fieldLocation = null; + private ClassNode into = null; + private FieldNode field = null; + private String name = null; + private String desc = null; + private boolean methodStatic = false; + + public AddSetterAdapter(ClassNode fieldLocation, ClassNode into, FieldNode field, String name, String desc, boolean methodStatic) { + this.fieldLocation = fieldLocation; + this.into = into; + this.field = field; + this.name = name; + this.desc = desc; + this.methodStatic = methodStatic; + } + + public AddSetterAdapter(ClassNode fieldLocation, ClassNode into, FieldNode field, String name, String desc) { + this(fieldLocation, into, field, name, desc, false); + } + + private static void addSetter(ClassNode fieldLocation, ClassNode into, FieldNode field, String name, String desc, boolean methodStatic) { + if (desc.contains("L") && !desc.endsWith("Ljava/lang/String;")) + desc = "Ljava/lang/Object;"; + MethodNode method = new MethodNode(ACC_PUBLIC | (methodStatic ? ACC_STATIC : 0), name, "(" + desc + ")V", null, null); + boolean isStatic = (field.access & ACC_STATIC) > 0; + if (!isStatic) { + method.visitVarInsn(ALOAD, 0); + } + if (desc.equals("I")) + method.visitVarInsn(ILOAD, 1); + else + method.visitVarInsn(ALOAD, 1); + method.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, fieldLocation.name, field.name, field.desc); + method.visitInsn(RETURN); + method.visitMaxs(2, 2); + into.methods.add(method); + } + + /** + * Injects the setter + */ + @Override + public void inject() { + addSetter(fieldLocation, into, field, name, desc, methodStatic); + + } + +} diff --git a/parabotv2/src/org/parabot/core/asm/wrappers/Getter.java b/parabotv2/src/org/parabot/core/asm/wrappers/Getter.java index 3c5ccc6..9cf2f09 100644 --- a/parabotv2/src/org/parabot/core/asm/wrappers/Getter.java +++ b/parabotv2/src/org/parabot/core/asm/wrappers/Getter.java @@ -35,6 +35,7 @@ public class Getter implements Injectable { this.fieldLocation = ASMUtils.getClass(fieldLocation); this.fieldNode = ASMUtils.getField(ASMUtils.getClass(fieldLocation), fieldNode); this.methodName = methodName; + System.out.println(fieldNode); this.returnDesc = returnDesc == null ? this.fieldNode.desc : returnDesc; this.staticMethod = staticMethod; } @@ -63,6 +64,10 @@ public class Getter implements Injectable { getAdapter().inject(); } + /** + * Gets the AddGetterAdapter + * @return AddGetterAdapter + */ public AddGetterAdapter getAdapter() { return new AddGetterAdapter(into, fieldLocation, fieldNode, methodName, returnDesc, staticMethod); } diff --git a/parabotv2/src/org/parabot/core/asm/wrappers/Setter.java b/parabotv2/src/org/parabot/core/asm/wrappers/Setter.java new file mode 100644 index 0000000..d2a97a1 --- /dev/null +++ b/parabotv2/src/org/parabot/core/asm/wrappers/Setter.java @@ -0,0 +1,53 @@ +package org.parabot.core.asm.wrappers; + +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.parabot.core.asm.ASMUtils; +import org.parabot.core.asm.adapters.AddSetterAdapter; +import org.parabot.core.asm.interfaces.Injectable; + +/** + * + * @author Clisprail + * + */ +public class Setter implements Injectable { + private ClassNode fieldLocation = null; + private ClassNode into = null; + private FieldNode field = null; + private String name = null; + private String desc = null; + private boolean methodStatic = false; + + public Setter(final String fieldLocation, String into, final String fieldName, final String methodName, final String desc, final boolean methodStatic) { + this.fieldLocation = ASMUtils.getClass(fieldLocation); + into = (into == null) ? fieldLocation : into; + this.into = ASMUtils.getClass(into); + this.field = ASMUtils.getField(this.fieldLocation, fieldName); + this.name = methodName; + this.desc = (desc == null) ? this.field.desc : desc; + this.methodStatic = methodStatic; + } + + public Setter(final String fieldLocation, final String fieldName, final String methodName) { + this(fieldLocation, null, fieldName, methodName, null, false); + } + + /** + * Short route for getAdaptar().inject(); + * @see AddSetterAdapter#inject + */ + @Override + public void inject() { + getAdapter().inject(); + } + + /** + * Gets the AddGetterAdapter + * @return AddGetterAdapter + */ + public AddSetterAdapter getAdapter() { + return new AddSetterAdapter(fieldLocation, into, field, name, desc, methodStatic); + } + +} diff --git a/parabotv2/src/org/parabot/core/build/BuildPath.java b/parabotv2/src/org/parabot/core/build/BuildPath.java new file mode 100644 index 0000000..5b25051 --- /dev/null +++ b/parabotv2/src/org/parabot/core/build/BuildPath.java @@ -0,0 +1,24 @@ +package org.parabot.core.build; + +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * + * @author Clisprail + * + */ +public class BuildPath { + + public static void add(final URL url) { + try { + Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + method.setAccessible(true); + method.invoke((URLClassLoader) ClassLoader.getSystemClassLoader(), url); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/parabotv2/src/org/parabot/core/classpath/ClassPath.java b/parabotv2/src/org/parabot/core/classpath/ClassPath.java index bfe1ee4..337c0d7 100644 --- a/parabotv2/src/org/parabot/core/classpath/ClassPath.java +++ b/parabotv2/src/org/parabot/core/classpath/ClassPath.java @@ -5,6 +5,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.zip.ZipEntry; @@ -12,6 +13,7 @@ import java.util.zip.ZipInputStream; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; +import org.parabot.core.build.BuildPath; /** * @@ -21,6 +23,20 @@ import org.objectweb.asm.tree.ClassNode; public class ClassPath { public final HashMap classes = new HashMap(); public final Map resources = new HashMap(); + + private boolean isJar = false; + private boolean parseJar = true; + private ArrayList jarFiles = new ArrayList(); + + public URL lastParsed = null; + + public ClassPath() { + + } + + public ClassPath(final boolean isJar) { + this.isJar = isJar; + } /** * Adds jar to this classpath @@ -37,6 +53,10 @@ public class ClassPath { public void addJar(final URL jarLocation) { JarParser.parseJar(this, jarLocation.toString()); } + + public void parseJarFiles(final boolean enabled) { + this.parseJar = enabled; + } /** * Finds and loads all classes/jar files in folder @@ -63,7 +83,11 @@ public class ClassPath { if (f1.getName().endsWith(".class")) loadClass(fin); else if (f.equals(root) && f1.getName().endsWith(".jar")) { - loadClasses(f1.toURI().toURL()); + jarFiles.add(f1.toURI().toURL()); + if(this.parseJar) { + // if enabled, there may be problem with duplicate class names....... + loadClasses(f1.toURI().toURL()); + } } else { String path = f1.toURI().relativize(root.toURI()) .getPath(); @@ -81,7 +105,8 @@ public class ClassPath { * * @param url to file */ - private void loadClasses(URL u) { + public void loadClasses(URL u) { + this.lastParsed = u; try (ZipInputStream zin = new ZipInputStream(u.openStream())) { ZipEntry e; while ((e = zin.getNextEntry()) != null) { @@ -113,6 +138,7 @@ public class ClassPath { classes.put(cn.name, cn); } + /** * Dumps the classnodes into a jar * @@ -121,5 +147,24 @@ public class ClassPath { public void dump(final String jarName) { JarDumper.dump(this, jarName); } + + public boolean isJar() { + return isJar; + } + + public ClassPath[] getJarFiles() { + final ClassPath[] jars = new ClassPath[jarFiles.size()]; + for(int i = 0; i < jarFiles.size(); i++) { + final ClassPath classPath = new ClassPath(true); + classPath.loadClasses(jarFiles.get(i)); + jars[i] = classPath; + } + return jars; + } + + public void addToBuildPath() { + BuildPath.add(lastParsed); + } + } diff --git a/parabotv2/src/org/parabot/core/desc/ScriptDescription.java b/parabotv2/src/org/parabot/core/desc/ScriptDescription.java new file mode 100644 index 0000000..3fe9eae --- /dev/null +++ b/parabotv2/src/org/parabot/core/desc/ScriptDescription.java @@ -0,0 +1,25 @@ +package org.parabot.core.desc; + +public class ScriptDescription { + public String scriptName = null; + public String author = null; + public String category = null; + public double version = 0; + public String description = null; + public String[] servers = null; + public int scriptIndex = -1; + + public ScriptDescription(final String scriptName, final String author, + final String category, final double version, + final String description, final String[] servers, + final int scriptIndex) { + this.scriptName = scriptName; + this.author = author; + this.category = category; + this.version = version; + this.description = description; + this.servers = servers; + this.scriptIndex = scriptIndex; + } + +} diff --git a/parabotv2/src/org/parabot/core/paint/PaintDebugger.java b/parabotv2/src/org/parabot/core/paint/PaintDebugger.java index cfc1a4c..ba12815 100644 --- a/parabotv2/src/org/parabot/core/paint/PaintDebugger.java +++ b/parabotv2/src/org/parabot/core/paint/PaintDebugger.java @@ -28,7 +28,7 @@ public class PaintDebugger { } } g.setColor(Color.green); - int y = 20; + int y = 40; while(stringDebug.size() > 0) { g.drawString(stringDebug.poll(), 10, y); y += 15; @@ -39,7 +39,7 @@ public class PaintDebugger { return Context.resolve().getPaintDebugger(); } - public final void addString(final String debugLine) { + public final void addLine(final String debugLine) { stringDebug.add(debugLine); } diff --git a/parabotv2/src/org/parabot/core/parsers/HookParser.java b/parabotv2/src/org/parabot/core/parsers/HookParser.java index 155a52e..2332a45 100644 --- a/parabotv2/src/org/parabot/core/parsers/HookParser.java +++ b/parabotv2/src/org/parabot/core/parsers/HookParser.java @@ -11,6 +11,7 @@ import org.parabot.core.asm.adapters.AddInterfaceAdapter; import org.parabot.core.asm.interfaces.Injectable; import org.parabot.core.asm.wrappers.Getter; import org.parabot.core.asm.wrappers.Interface; +import org.parabot.core.asm.wrappers.Setter; import org.parabot.core.asm.wrappers.Super; import org.parabot.environment.api.utils.WebUtil; import org.w3c.dom.Document; @@ -30,6 +31,8 @@ public class HookParser { private boolean parsedInterfaces = false; private HashMap interfaceMap = new HashMap(); + private HashMap constants = new HashMap(); + public HookParser(URL url) { try { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); @@ -186,6 +189,12 @@ public class HookParser { injectables.add(get); } } + Setter[] setters = getSetters(); + if(setters != null) { + for(Setter set : setters) { + injectables.add(set); + } + } Super[] supers = getSupers(); if(supers != null) { for(Super sup : supers) { @@ -195,6 +204,64 @@ public class HookParser { return injectables.toArray(new Injectable[injectables.size()]); } + public final Setter[] getSetters() { + final NodeList setterRootList = doc.getElementsByTagName("setters"); + switch(setterRootList.getLength()) { + case 0: + return null; + case 1: + break; + default: + throw new RuntimeException("Hook file may not contains multiple tags "); + } + final Node node = setterRootList.item(0); + if(node.getNodeType() != Node.ELEMENT_NODE) { + return null; + } + final Element setterRoot = (Element) node; + final NodeList setters = setterRoot.getElementsByTagName("add"); + if(setters.getLength() == 0) { + return null; + } + final ArrayList setterList = new ArrayList(); + for(int x = 0; x < setters.getLength(); x++) { + final Node n = setters.item(x); + if(n.getNodeType() != Node.ELEMENT_NODE) { + continue; + } + final Element addSetter = (Element) n; + if(isSet("classname", addSetter) && isSet("accessor", addSetter)) { + throw new RuntimeException("Can't set classname and accessor tag together."); + } + if(isSet("accessor", addSetter) && !parsedInterfaces) { + throw new RuntimeException("You'll need to parse interfaces first."); + } + final String className = isSet("classname", addSetter) ? getValue("classname", addSetter) : interfaceMap.get(getValue("accessor", addSetter)); + final String into = isSet("into", addSetter) ? getValue("into", addSetter) : className; + final String fieldName = getValue("field", addSetter); + final String methodName = getValue("methodname", addSetter); + boolean staticMethod = isSet("methstatic", addSetter) ? (getValue("methstatic", addSetter).equals("true")) : false; + String returnDesc = isSet("desc", addSetter) ? getValue("desc", addSetter) : null; + String array = ""; + if(returnDesc != null && returnDesc.contains("%s")) { + StringBuilder str = new StringBuilder(); + if(returnDesc.startsWith("[")) { + for( int i=0; i 0; } @@ -205,6 +272,42 @@ public class HookParser { return node.getNodeValue(); } + public final HashMap getConstants() { + if(!constants.isEmpty()) { + return constants; + } + final NodeList constantsRootList = doc.getElementsByTagName("constants"); + switch(constantsRootList.getLength()) { + case 0: + return null; + case 1: + break; + default: + throw new RuntimeException("Hook file may not contains multiple tags "); + } + final Node node = constantsRootList.item(0); + if(node.getNodeType() != Node.ELEMENT_NODE) { + return null; + } + final Element constantRoot = (Element) node; + final NodeList constantsList = constantRoot.getElementsByTagName("add"); + if(constantsList.getLength() == 0) { + // return empty hashmap + return constants; + } + for(int x = 0; x < constantsList.getLength(); x++) { + final Node n = constantsList.item(x); + if(n.getNodeType() != Node.ELEMENT_NODE) { + continue; + } + final Element addConstant = (Element) n; + final String key = getValue("key", addConstant); + final String value = getValue("value", addConstant); + constants.put(key, value); + } + return constants; + } + } diff --git a/parabotv2/src/org/parabot/core/parsers/ScriptManifestParser.java b/parabotv2/src/org/parabot/core/parsers/ScriptManifestParser.java new file mode 100644 index 0000000..056afef --- /dev/null +++ b/parabotv2/src/org/parabot/core/parsers/ScriptManifestParser.java @@ -0,0 +1,90 @@ +package org.parabot.core.parsers; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.parabot.core.Core; +import org.parabot.core.Directories; +import org.parabot.core.classpath.ClassPath; +import org.parabot.core.desc.ScriptDescription; +import org.parabot.environment.scripts.Script; +import org.parabot.environment.scripts.ScriptManifest; +import org.parabot.environment.scripts.loader.ScriptLoader; + +/** + * + * @author Clisprail + * + */ +public class ScriptManifestParser { + + public static Map scriptCache = new HashMap(); + + /** + * Gets server descriptions + * + * @return list of descriptions + */ + public ScriptDescription[] getDescriptions() { + scriptCache.clear(); + if (Core.inDebugMode()) { + return localDesc(); + } + return publicDesc(); + } + + private ScriptDescription[] publicDesc() { + return null; + } + + private ScriptDescription[] localDesc() { + // parse classes in server directories + final ClassPath path = new ClassPath(); + path.loadClasses(Directories.getScriptCompiledPath(), null); + + // init the script loader + final ScriptLoader loader = new ScriptLoader(path); + + // list of scripts + final List