Games

Oldschool Runescape downloadable client world list mod

Sunday, March 10th, 2013

This mod allows you to never have a “Full” world on the worldlist. setup is simple and does not Modify anything in the gameclient so should be safe to use.

All you have to do is Follow the offical client setup tutorial:

However when it says to use: http://oldschool.runescape.com/jav_config.ws

Replace with: http://silabsoft.org/jav_config.ws

Then enjoy never having to deal with the “Full” message on the worldlist again.

ZRlO1jv Oldschool Runescape downloadable client world list mod

Simple Oldschool Runescape worldlist grabber

Wednesday, March 6th, 2013

This is a simple Java application that grabs the Runescape wordlist data the same way the client does.

HoustCountry.java:

/**
 *
 * @author Silabsoft
 */
public enum HostCountry {
 
    USA,
    UK,
    GERMANY,
    UNKNOWN;
 
    public static HostCountry getHostCountry(int countryId) {
        switch (countryId) {
            case 0:
                return HostCountry.USA;
            case 1:
                return HostCountry.UK;
            case 7:
                return HostCountry.GERMANY;
            default:
                return HostCountry.UNKNOWN;
        }
    }
}

ByteStream.java:

/**
 *
 * @author Silabsoft
 */
public class ByteStream {
 
    private ByteStream() {
    }
 
    public ByteStream(byte abyte0[]) {
        data = abyte0;
        caret = 0;
    }
 
    public int g1() {
        return data[caret++] & 0xff;
    }
 
    public byte g1b() {
        return data[caret++];
    }
 
    public int g2() {
        caret += 2;
        return ((data[caret - 2] & 0xff) << 8) + (data[caret - 1] & 0xff);
    }
 
    public int g2b() {
        caret += 2;
        int i = ((data[caret - 2] & 0xff) << 8) + (data[caret - 1] & 0xff);
        if (i > 32767) {
            i -= 0x10000;
        }
        return i;
    }
 
    public int g3() {
        caret += 3;
        return ((data[caret - 3] & 0xff) << 16) + ((data[caret - 2] & 0xff) << 8) + (data[caret - 1] & 0xff);
    }
 
    public int g4() {
        caret += 4;
        return ((data[caret - 4] & 0xff) << 24) + ((data[caret - 3] & 0xff) << 16) + ((data[caret - 2] & 0xff) << 8) + (data[caret - 1] & 0xff);
    }
 
    public String gstr() {
        int i = caret;
        while (data[caret++] != 0) ;
        return new String(data, i, caret - i - 1);
    }
    public byte data[];
    public int caret;
}

World.java:

 
/**
 *
 * @author Silabsoft
 */
public class World {
 
    private final int worldId;
    private final boolean members;
    private final HostCountry hostCountry;
    private final String host;
    private int players;
 
    World(int worldId, String host, boolean members, HostCountry hostCountry, int numberOfPlayers) {
        this.worldId = worldId;
        this.host = host;
        this.members = members;
        this.hostCountry = hostCountry;
        this.players = numberOfPlayers;
    }
 
    public String getHost() {
        return host;
    }
 
    public HostCountry getHostCountry() {
        return hostCountry;
    }
 
    public boolean isMembers() {
        return members;
    }
 
    public int getPlayers() {
        return players;
    }
 
    public int getWorldId() {
        return worldId;
    }
 
    public void setPlayers(int players) {
        this.players = players;
    }
 
    @Override
    public String toString() {
        return "World{" + "worldId=" + worldId + ", members=" + members + ", hostCountry=" + hostCountry + ", host=" + host + ", players=" + players + '}';
    }
}

WorldList.java:

 
/**
 *
 * @author Silabsoft
 */
import java.io.DataInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
 
public class WorldList {
 
    private final HashMap<Integer, World> worlds;
    private int worldCount;
    private final String worldListAddress;
    private int numberOfPlayers;
 
    public WorldList(String worldListAddress) {
        this.worldListAddress = worldListAddress;
        this.worlds = new HashMap<Integer, World>();
    }
 
    public void updateWorldList() throws IOException {
        numberOfPlayers = 0;
        HttpURLConnection url = (HttpURLConnection) new URL(worldListAddress).openConnection();
        DataInputStream in = new DataInputStream(url.getInputStream());
        byte data[] = new byte[url.getContentLength()];
        in.readFully(data);
        ByteStream p = new ByteStream(data);
        p.caret = 4; //skip first 4, might be a session id or timestamp
        int count = p.g2(); //   aq = dl1.ag(0x804d807d) * 0x54db551e;
 
 
        for (int i = 0; i < count; i++) {
            int j1 = p.g2();  // int j1 = dl1.ag(0x83d47af5);
            int worldId = (j1 & 0x7fff); // n1.c = 0xbe183a66 * (j1 & 0x7fff);
            boolean isMembers = j1 != 0;// n1.e = 0 != (j1 & 0xc5af3c81);
            String host = p.gstr(); // n1.f = dl1.ai(0x3bd62f26);
            int countryId = p.g1();// n1.y = dl1.az(0xdb8be48a) * 0x5932670f;
            int numberOfPlayers = p.g2b(); // n1.j = dl1.am((byte)-30) * 0xa5d501b;
            // n1.x = i1 * 0x53f5e1ef; 
            World w = new World(worldId, host, isMembers, HostCountry.getHostCountry(countryId), numberOfPlayers);
            this.worlds.put(worldId, w);
            this.numberOfPlayers += numberOfPlayers;
 
        }
    }
 
    public int getNumberOfPlayers() {
        return numberOfPlayers;
    }
 
    public int getWorldCount() {
        return worldCount;
    }
 
    public String getWorldListAddress() {
        return worldListAddress;
    }
 
    public HashMap<Integer, World> getWorlds() {
        return worlds;
    }
}

Test Run:

 
/**
 *
 * @author Silabsoft
 */
public class Main {
 
    public static void main(String[] args) throws Exception {
 
        WorldList l = new WorldList("http://www.runescape.com/slr.ws?order=LPWM");
        l.updateWorldList();
        System.out.println("total number of players: " + l.getNumberOfPlayers());
        l.updateWorldList();
        System.out.println("total number of players: " + l.getNumberOfPlayers());
 
        System.out.println(l.getWorlds().get(318));
    }
}

Java Runescape Bestiary Viewer

Friday, March 1st, 2013

Runescape recently released a new Bestiary displaying part of the all new Runetek 7 engine, Although It’s fun to look at it currently only supports google chrome. (inb4 google fanboys comment after my next statement) Myself I really don’t like using chrome and can’t really see myself just using 1 browser to view a bestiary for a game I don’t play. Due to the technical limitations of my firefox not being support by the bestiary I decided I would write a viewer in Java. Currently it only grabs the npc details but I hope to have it also be able to view the models and animations in the future. Google GSON made easy work of the json parsing and everything else is just standard swing using netbeans form builder.

rsbv 1024x619 Java Runescape Bestiary Viewer

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.silabsoft.runescape.bestiary;
 
import com.google.gson.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import org.silabsoft.runescape.bestiary.model.BestiaryName;
 
/**
 *
 * @author Silabsoft
 */
public class RunescapeBestiary extends javax.swing.JFrame {
 
    public static final String TITLE = "Silabsoft's Runescape Bestiary Viewer";
    private final DefaultMutableTreeNode bestiaryRootNode;
    public static final String alphabet[] = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
 
    /**
     * Creates new form RunescapeBestiary
     */
    public RunescapeBestiary() {
        bestiaryRootNode = new DefaultMutableTreeNode("Bestiary List");
 
        for (String s : alphabet) {
            bestiaryRootNode.add(new DefaultMutableTreeNode(s));
        }
        initComponents();
 
    }
 
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    //                          
    private void initComponents() {
 
        jScrollPane1 = new javax.swing.JScrollPane();
        jTree1 = new javax.swing.JTree();
        jProgressBar1 = new javax.swing.JProgressBar();
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        updateMenuItem = new javax.swing.JMenuItem();
 
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle(TITLE);
 
        jTree1.setModel(new javax.swing.tree.DefaultTreeModel(bestiaryRootNode));
        jScrollPane1.setViewportView(jTree1);
 
        jMenu1.setText("File");
 
        updateMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_U, java.awt.event.InputEvent.CTRL_MASK));
        updateMenuItem.setText("Update");
        updateMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateMenuItemActionPerformed(evt);
            }
        });
        jMenu1.add(updateMenuItem);
 
        jMenuBar1.add(jMenu1);
 
        setJMenuBar(jMenuBar1);
 
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jProgressBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 529, Short.MAX_VALUE)
            .addComponent(jScrollPane1)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 254, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
 
        pack();
    }//                        
    int index = 0;
    private void updateMenuItemActionPerformed(java.awt.event.ActionEvent evt) {                                               
        UpdateTask updateTask = new UpdateTask();
        updateTask.addPropertyChangeListener(
                new PropertyChangeListener() {
 
                    public void propertyChange(PropertyChangeEvent evt) {
                        if ("progress".equals(evt.getPropertyName())) {
                            jProgressBar1.setValue((Integer) evt.getNewValue());
                        }
                    }
                });
        updateTask.execute();
    }                                              
 
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /*
         * Set the Nimbus look and feel
         */
        //
        /*
         * If Nimbus (introduced in Java SE 6) is not available, stay with the
         * default look and feel. For details see
         * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(RunescapeBestiary.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(RunescapeBestiary.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(RunescapeBestiary.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(RunescapeBestiary.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //
 
        /*
         * Create and display the form
         */
        java.awt.EventQueue.invokeLater(new Runnable() {
 
            public void run() {
                new RunescapeBestiary().setVisible(true);
            }
        });
    }
 
    private static String readUrl(String urlString) throws Exception {
        BufferedReader reader = null;
        try {
            URL url = new URL(urlString);
            reader = new BufferedReader(new InputStreamReader(url.openStream()));
            StringBuilder buffer = new StringBuilder();
            int read;
            char[] chars = new char[1024];
            while ((read = reader.read(chars)) != -1) {
                buffer.append(chars, 0, read);
            }
 
            return buffer.toString();
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
    }
    // Variables declaration - do not modify                     
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JProgressBar jProgressBar1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTree jTree1;
    private javax.swing.JMenuItem updateMenuItem;
    // End of variables declaration                   
 
    class UpdateTask extends SwingWorker&lt;Integer, Object&gt; {
 
        int count;
 
        @Override
        public Integer doInBackground() {
            updateMenuItem.setEnabled(false);
            setTitle(TITLE + " UPDATING LIST");
            for (int i = 0; i &lt; 26; i++) {
 
                updateNode((DefaultMutableTreeNode) ((DefaultTreeModel) jTree1.getModel()).getChild(bestiaryRootNode, i), i);
                this.setProgress(100 * i / 25);
            }
 
            setTitle(TITLE + " UPDATING Bestiary Data");
            for (int i = 0; i &lt; 26; i++) {
                updateBeastData((DefaultMutableTreeNode) ((DefaultTreeModel) jTree1.getModel()).getChild(bestiaryRootNode, i));
                this.setProgress(100 * i / 25);
            }
            return count;
        }
 
        @Override
        protected void done() {
 
            try {
                setTitle(TITLE + " Mob Count: " + get());
            } catch (InterruptedException ex) {
            } catch (ExecutionException ex) {
            }
            updateMenuItem.setEnabled(true);
        }
 
        private void updateNode(DefaultMutableTreeNode child, int index) {
            Gson gson = new Gson();
            JsonParser jp = new JsonParser();
 
            JsonArray ja = null;
            try {
                ja = jp.parse(readUrl("http://services.runescape.com/m=itemdb_rs/bestiary/bestiaryNames.json?letter=" + alphabet[index])).getAsJsonArray();
            } catch (Exception ex) {
 
                return;
            }
            int size = ja.size();
            int idx = 0;
            for (int i = 0; i &lt; size; i++) {
                JsonObject jo = ja.get(i).getAsJsonObject();
 
                if (jo.has("npcs")) {
                    JsonArray npcArray = jo.getAsJsonArray("npcs");
                    DefaultMutableTreeNode groupNode = new DefaultMutableTreeNode(jo.get("dupe").getAsString());
                    ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(groupNode, child, idx++);
                    for (int x = 0; x &lt; npcArray.size(); x++) {
                        BestiaryName bn = gson.fromJson(npcArray.get(x), BestiaryName.class);
                        ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(new DefaultMutableTreeNode(bn), groupNode, x);
                        count++;
                    }
                } else {
 
                    BestiaryName bn = gson.fromJson(jo, BestiaryName.class);
 
                    ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(new DefaultMutableTreeNode(bn), child, idx++);
 
                    count++;
                }
 
            }
 
        }
 
        private void updateBeastData(DefaultMutableTreeNode child) {
            int size = child.getChildCount();
            for (int i = 0; i &lt; size; i++) {                 Object o = child.getChildAt(i);                 if (((DefaultMutableTreeNode) o).getChildCount() &gt; 0) {
                    updateBeastData((DefaultMutableTreeNode) o);
                } else {
 
                    parseBeastData((DefaultMutableTreeNode) o);
                }
            }
        }
 
        private void parseBeastData(DefaultMutableTreeNode node) {
            JsonParser jp = new JsonParser();
 
            JsonObject jo = null;
            try {
                jo = jp.parse(readUrl("http://services.runescape.com/m=itemdb_rs/bestiary/beastData.json?beastid=" + ((BestiaryName) node.getUserObject()).getValue())).getAsJsonObject();
 
            } catch (Exception ex) {
 
                return;
            }
            int idx = 0;
            for (Entry&lt;String, JsonElement&gt; e : jo.entrySet()) {
                insertBeastDataNode(node, e.getKey(), e.getValue());
 
            }
        }
 
        private void insertBeastDataNode(DefaultMutableTreeNode parent, String key, JsonElement value) {
            if (value.isJsonObject()) {
                DefaultMutableTreeNode dataCat = new DefaultMutableTreeNode(key);
                ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(dataCat, parent, parent.getChildCount());
                for (Entry&lt;String, JsonElement&gt; e : value.getAsJsonObject().entrySet()) {
 
                    insertBeastDataNode(dataCat, e.getKey(), e.getValue());
                }
            }
            else if(value.isJsonArray()){
                DefaultMutableTreeNode dataCat = new DefaultMutableTreeNode(key);
                ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(dataCat, parent, parent.getChildCount());
                JsonArray a = value.getAsJsonArray();
                int size = a.size();
                for(int i = 0; i &lt; size; i++){
 
                     ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(new DefaultMutableTreeNode(a.get(i)), dataCat,i);
                }
            }
            else {
                ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(new DefaultMutableTreeNode(key + ":" + value), parent, parent.getChildCount());
            }
        }
    }
}
package org.silabsoft.runescape.bestiary;
 
import com.google.gson.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import org.silabsoft.runescape.bestiary.model.BestiaryName;
 
/**
 *
 * @author Silabsoft
 */
public class RunescapeBestiary extends javax.swing.JFrame {
 
    public static final String TITLE = "Silabsoft's Runescape Bestiary Viewer";
    private final DefaultMutableTreeNode bestiaryRootNode;
    public static final String alphabet[] = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
 
    /**
     * Creates new form RunescapeBestiary
     */
    public RunescapeBestiary() {
        bestiaryRootNode = new DefaultMutableTreeNode("Bestiary List");
 
        for (String s : alphabet) {
            bestiaryRootNode.add(new DefaultMutableTreeNode(s));
        }
        initComponents();
 
    }
 
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    //                           
    private void initComponents() {
 
        jScrollPane1 = new javax.swing.JScrollPane();
        jTree1 = new javax.swing.JTree();
        jProgressBar1 = new javax.swing.JProgressBar();
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        updateMenuItem = new javax.swing.JMenuItem();
 
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle(TITLE);
 
        jTree1.setModel(new javax.swing.tree.DefaultTreeModel(bestiaryRootNode));
        jScrollPane1.setViewportView(jTree1);
 
        jMenu1.setText("File");
 
        updateMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_U, java.awt.event.InputEvent.CTRL_MASK));
        updateMenuItem.setText("Update");
        updateMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateMenuItemActionPerformed(evt);
            }
        });
        jMenu1.add(updateMenuItem);
 
        jMenuBar1.add(jMenu1);
 
        setJMenuBar(jMenuBar1);
 
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jProgressBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 529, Short.MAX_VALUE)
            .addComponent(jScrollPane1)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 254, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
 
        pack();
    }//                         
    int index = 0;
    private void updateMenuItemActionPerformed(java.awt.event.ActionEvent evt) {                                               
        UpdateTask updateTask = new UpdateTask();
        updateTask.addPropertyChangeListener(
                new PropertyChangeListener() {
 
                    public void propertyChange(PropertyChangeEvent evt) {
                        if ("progress".equals(evt.getPropertyName())) {
                            jProgressBar1.setValue((Integer) evt.getNewValue());
                        }
                    }
                });
        updateTask.execute();
    }                                              
 
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /*
         * Set the Nimbus look and feel
         */
        //
        /*
         * If Nimbus (introduced in Java SE 6) is not available, stay with the
         * default look and feel. For details see
         * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(RunescapeBestiary.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(RunescapeBestiary.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(RunescapeBestiary.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(RunescapeBestiary.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //
 
        /*
         * Create and display the form
         */
        java.awt.EventQueue.invokeLater(new Runnable() {
 
            public void run() {
                new RunescapeBestiary().setVisible(true);
            }
        });
    }
 
    private static String readUrl(String urlString) throws Exception {
        BufferedReader reader = null;
        try {
            URL url = new URL(urlString);
            reader = new BufferedReader(new InputStreamReader(url.openStream()));
            StringBuilder buffer = new StringBuilder();
            int read;
            char[] chars = new char[1024];
            while ((read = reader.read(chars)) != -1) {
                buffer.append(chars, 0, read);
            }
 
            return buffer.toString();
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
    }
    // Variables declaration - do not modify                     
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JProgressBar jProgressBar1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTree jTree1;
    private javax.swing.JMenuItem updateMenuItem;
    // End of variables declaration                   
 
    class UpdateTask extends SwingWorker&lt;Integer, Object&gt; {
 
        int count;
 
        @Override
        public Integer doInBackground() {
            updateMenuItem.setEnabled(false);
            setTitle(TITLE + " UPDATING LIST");
            for (int i = 0; i &lt; 26; i++) {
 
                updateNode((DefaultMutableTreeNode) ((DefaultTreeModel) jTree1.getModel()).getChild(bestiaryRootNode, i), i);
                this.setProgress(100 * i / 25);
            }
 
            setTitle(TITLE + " UPDATING Bestiary Data");
            for (int i = 0; i &lt; 26; i++) {
                updateBeastData((DefaultMutableTreeNode) ((DefaultTreeModel) jTree1.getModel()).getChild(bestiaryRootNode, i));
                this.setProgress(100 * i / 25);
            }
            return count;
        }
 
        @Override
        protected void done() {
 
            try {
                setTitle(TITLE + " Mob Count: " + get());
            } catch (InterruptedException ex) {
            } catch (ExecutionException ex) {
            }
            updateMenuItem.setEnabled(true);
        }
 
        private void updateNode(DefaultMutableTreeNode child, int index) {
            Gson gson = new Gson();
            JsonParser jp = new JsonParser();
 
            JsonArray ja = null;
            try {
                ja = jp.parse(readUrl("http://services.runescape.com/m=itemdb_rs/bestiary/bestiaryNames.json?letter=" + alphabet[index])).getAsJsonArray();
            } catch (Exception ex) {
 
                return;
            }
            int size = ja.size();
            int idx = 0;
            for (int i = 0; i &lt; size; i++) {
                JsonObject jo = ja.get(i).getAsJsonObject();
 
                if (jo.has("npcs")) {
                    JsonArray npcArray = jo.getAsJsonArray("npcs");
                    DefaultMutableTreeNode groupNode = new DefaultMutableTreeNode(jo.get("dupe").getAsString());
                    ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(groupNode, child, idx++);
                    for (int x = 0; x &lt; npcArray.size(); x++) {
                        BestiaryName bn = gson.fromJson(npcArray.get(x), BestiaryName.class);
                        ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(new DefaultMutableTreeNode(bn), groupNode, x);
                        count++;
                    }
                } else {
 
                    BestiaryName bn = gson.fromJson(jo, BestiaryName.class);
 
                    ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(new DefaultMutableTreeNode(bn), child, idx++);
 
                    count++;
                }
 
            }
 
        }
 
        private void updateBeastData(DefaultMutableTreeNode child) {
            int size = child.getChildCount();
            for (int i = 0; i &lt; size; i++) {                 Object o = child.getChildAt(i);                 if (((DefaultMutableTreeNode) o).getChildCount() &gt; 0) {
                    updateBeastData((DefaultMutableTreeNode) o);
                } else {
 
                    parseBeastData((DefaultMutableTreeNode) o);
                }
            }
        }
 
        private void parseBeastData(DefaultMutableTreeNode node) {
            JsonParser jp = new JsonParser();
 
            JsonObject jo = null;
            try {
                jo = jp.parse(readUrl("http://services.runescape.com/m=itemdb_rs/bestiary/beastData.json?beastid=" + ((BestiaryName) node.getUserObject()).getValue())).getAsJsonObject();
 
            } catch (Exception ex) {
 
                return;
            }
            int idx = 0;
            for (Entry&lt;String, JsonElement&gt; e : jo.entrySet()) {
                insertBeastDataNode(node, e.getKey(), e.getValue());
 
            }
        }
 
        private void insertBeastDataNode(DefaultMutableTreeNode parent, String key, JsonElement value) {
            if (value.isJsonObject()) {
                DefaultMutableTreeNode dataCat = new DefaultMutableTreeNode(key);
                ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(dataCat, parent, parent.getChildCount());
                for (Entry&lt;String, JsonElement&gt; e : value.getAsJsonObject().entrySet()) {
 
                    insertBeastDataNode(dataCat, e.getKey(), e.getValue());
                }
            }
            else if(value.isJsonArray()){
                DefaultMutableTreeNode dataCat = new DefaultMutableTreeNode(key);
                ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(dataCat, parent, parent.getChildCount());
                JsonArray a = value.getAsJsonArray();
                int size = a.size();
                for(int i = 0; i &lt; size; i++){
 
                     ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(new DefaultMutableTreeNode(a.get(i)), dataCat,i);
                }
            }
            else {
                ((DefaultTreeModel) jTree1.getModel()).insertNodeInto(new DefaultMutableTreeNode(key + ":" + value), parent, parent.getChildCount());
            }
        }
    }
}

Torchlight 2 Beta Review

Wednesday, May 23rd, 2012

For those of you that didn’t know torchlight II recently had an open beta for those that signed up. I had a chance to play for a little bit and so now that I feel that I am an expert in the content I will give a review to be taken and flamed by others.

Firstly let me say that I have never played torchlight 1 so I will not base my review on what I was expecting from the first game nor will I compare it to Diablo as I always find that comparing one game to another is unjustified to both games.

Firstly lets get the bashing out of the way. The game is is a hack and slash dungeon crawler but to me I did not have the feel of a dungeon. Maybe I am taking the word too literal I don’t expect the game to be entirely based in a dank dungeon but I do expect the game to have a dark and gritty feel. Sadly however the only dark feel I got from the game was from the music the art and models just seemed out of place. Also character design is a bit over the top imagine taking one of those final fantasy hero’s (you know the ones that wear an outfit consisting of only belts an zippers) and placing it into resident evil 2. It seemed all the character designs I could choose felt childish.

On the positive I found the game very easy to pick up and the controls had been very clean I choose an Embermage as my character and found the questing to be enjoyable. I also liked the fact that the terrain could be both your friend or your enemy. At times I found myself blasting a small hill with a fireball rather than the rat creature that I wanted to be killing. other times I was able to channel the enemys between tree’s so they didn’t gang me.

Overall the game was fun and probably will be picking it up to play when its released.