Month: January 2010

Thank you Wizards of the Coast

I have a group that is about ready to start a new Dungeons and Dragons campaign. The last time we played was somewhere between 2 and 4 years ago. Since then, Wizards of the Coast has release the 4th edition of the system. In addition to that, they have released a character creator, which has made creating and leveling up characters super easy.

I downloaded the demo of the character creator and created a sample character. I then had a look at the file that was saved. I was amazed to see that it was saved in xml format. Nice plain text. Thank you wizards of the coast for making it accessible. Even better than that, within the xml, they provide links to their online compendium of rules. For instance, here is an xml node from the saved character file, which is of the new Dragonborn class.

         <ruleselement name="Dragon Breath" type="Power" internal-id="ID_FMP_POWER_1448" url="" charelem="60bad78" legality="rules-legal"></ruleselement>

Using that URL, you can visit the compendium site and read about the power. That said, the compendium requires authentication of a paid account. I see the compendium as a great value. Wizards makes all the rules, feats, powers, etc. available in the compendium site and character creator even if you haven’t purchased the book. They have a lot of intellectual property in the compendium, and it makes sense to me that they get paid for the service.

When you view your character sheet in the character creator, there is a page or two of “power cards” at the end. I thought it would be interesting to print those on 4×6 cards, laminate them, and make them available to the players to make playing easier, especially since we have a few new players in our group for this session. The format of the cards from the character creator wasn’t quite right for me. First, because it contained character specific information, like bonuses at the current state of the character. I wanted the generic power cards that could be reused by different characters. With them laminated, they players could write the appropriate bonuses right on the cards in dry-erase marker, and update as we go.

My solution was to use the nice, open, dnd4e xml files saved by the character creator. I wrote a little jython script that uses the httpunit framework in java to login to the compendium and download the power pages. that way they don’t have any character specific information in them, and I can just open them in firefox and format them for my 4×6 cards that I can feed right through the printer.

the script took considerably longer than I hoped, partly because I haven’t done any jython/python in a few years, partly because of the compendium login session management. So, without further ado, here is the source.

from import FileInputStream
from import StreamSource
from import StreamResult
from javax.xml.parsers import DocumentBuilderFactory
from com.meterware.httpunit import *
from com.meterware.httpunit.cookies import CookieProperties
import subprocess
import codecs
import os.path
import sys


inputList = sys.argv;
del inputList[0];

nameList = []
CookieProperties.setDomainMatchingStrict( 0 );
CookieProperties.setPathMatchingStrict( 0 );
wc = WebConversation();

def getPower( url, name ):
    if name not in nameList:
        print name+"...";
        if not os.path.exists( name ):
                nameList.append( name );
                request = GetMethodWebRequest( url );
                response = wc.getResponse( request );
                form = response.getFormWithID( "form1" );
                if form is not None and "email" in form.getParameterNames():
                    print "logging in";
                    form.setParameter( "email", email );
                    form.setParameter( "password", pwd );
                    subButton = form.getSubmitButton( "InsiderSignin" );
                    response = form.submit(subButton);
                    request = GetMethodWebRequest( url );
                    response = wc.getResponse( request );
                    print "not required to login";
                outFile = name, "w", "utf-8" );
                outFile.write( response.getText());
                nameList.remove( name );
                print "ERROR: Unable to get "+name+" at "+url;

for charname in inputList:
    print "Processing "+charname
    fname = "characters/%s.dnd4e" % charname
    powerdir = "./characters/"+charname+"/powers"
        input=FileInputStream( fname )
        print "unable to load %s" % fname

        print "making directory %s" %powerdir
        os.makedirs( powerdir )
        print "uanble to make directory %s" % powerdir

    factory = DocumentBuilderFactory.newInstance()
    builder = factory.newDocumentBuilder()
    document = builder.parse(input)
    nodes = document.getElementsByTagName( "RulesElement" )
    for i in range( nodes.getLength()):
        node = nodes.item(i)
        if node.getAttributes() is not None:
            typeattr = node.getAttributes().getNamedItem( "type" )
            urlattr = node.getAttributes().getNamedItem( "url" )
            nameattr = node.getAttributes().getNamedItem( "name" )
            if typeattr.getNodeValue() ==  "Power" :
                if urlattr is not None and urlattr.getNodeValue() is not None:
                    outName = powerdir+"/"+nameattr.getNodeValue()+".html";
                    getPower( urlattr.getNodeValue(), outName );
            print "no attributes"

Ok, so this is not pretty jython code. I’m sure there are a hundred improvements that could be made to this code by someone that actually knows what they are doing in python. Here’s the batch script I use to launch the script

@echo off
set LIBPATH=.\lib

set JAR_PATH=%LIBPATH%\httpunit.jar;%LIBPATH%\js-1.6R5.jar;%LIBPATH%\nekohtml-0.9.5.jar;%LIBPATH%\xercesimpl-2.6.1.jar

..\jython2.5.1\bin\jython.bat -Dpython.path=%JAR_PATH% %*

Obviously, to run the script, you must have the above jar files, which are used to support httpunit. Also, you must have jython. Once you have that, you can modify the .bat script for your environment.

The script is expecting to have a directory named “characters” adjacent to it. Within that directory should be the dnd4e files for the characters. It would be awesome if the script would just grab all the .dnd4e files within the characters directory, but it doesn’t yet. That’s just the way it is. Part of the reason was so that I would be able to update only a single character at a time if I wanted to. In any case, I run it as follows:

jython.bat Fezzik Orlissa

where Fezzik and Orlissa are the names of the characters, and have corresponding Fezzik.dnd4e and Orlissa.dnd4e files in the characters directory.

The script will load the dnd4e file, find all the powers that have URLs, and download them. Fortunately, it will not download them if they already exist on the hard drive (we don’t want to abuse wizards’ servers) for that character.

I’ve debated whether to have it dump all the powers into the same directory or do it on a character by character basis. Right now I’ve got it on a character basis so that I know what I need to print for each character before we get started. I’ll probably modify it and just use the timestamp on the power file to know which ones to print once we get started.

Finally, to get the power file to display correctly, you must have the stylesheets within the appropriate directory so they can be read by your browser when you load the power html file. Wizards used different stylesheets for the view, and the print. The print stylesheet removes all the colors and whatnot. That’s easy enough to get around by simply saving the display stylesheet as both display and print.

I may be blogging about this earlier than I should. The script isn’t really great yet, but it’s functional for my needs, and I thought it might be a good start for anyone else looking to do the same thing.

Here’s a picture of the cards I printed.
DnD Power Cards

JSF 2 Custom Converter

I ran into a very strange problem in my little Google App Engine application. I’m using JSF 2 as the presentation layer. I’m using Google’s low level api for accessing the data store and have written some little utilities to convert from my objects to Google’s Entity objects.

I thought I had the mapping working OK, but had only tried setting simple String properties on my data objects. I finally tried to map a simple association, where one object would have a list of keys of other objects. In my case I have Tables. Each table can be associated with zero or more Genres. So, my Table data object has a List of Keys for the genres that it is a part of, like this:

public class Table
        extends DataObjectAbstract
        implements Serializable
    private List<Key> genres;

    // other private attributes here

    public List<Key> getGenres()
        return genres;

    public void setGenres( List<Key> genres )
        this.genres = genres;

    // other public getters and setters and other methods here

You can safely ignore DataObjectAbstract and the @Persistent annotation. They aren’t part of this blog post.

The strange behavior I was seeing was that when I would get the genre list from the data store, it would be a List<String> instead of the List<Key> I was expecting. After some debugging, I finally discovered that I was setting it as a List<String> because Strings are what I was getting from my JSF page, and thanks to Java’s type erasure with generics, my code didn’t know any better. So, the solution is a custom converter, which will allow me to pass the Keys to and from the browser.

Fortunately, in JSF 2, custom converters are even easier than they are in JSF 1.x. Here’s my simple converter class for the class. Making this even more simple is the fact that Google offers a KeyFactory that takes care of giving a URL safe representation of their Key object.

package jota.soc.ui.converter;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

 * Converter for Google Key.
 * @author Joel.Weight
@FacesConverter( value="keyConverter" )
public class KeyConverter implements Converter {

     * converts the String representation of the key back to the Object
    public Object getAsObject( FacesContext context, UIComponent component,
                               String value )
        // will throw new IllegalArgumentException if it can't parse.
        return KeyFactory.stringToKey( value );

     * converts the Key object into its String representation.
    public String getAsString( FacesContext context, UIComponent component,
                               Object value )
        if ( value instanceof Key )
            return KeyFactory.keyToString( (Key)value );
            throw new IllegalArgumentException( "Cannot convert non-key object in KeyConverter" );

With the @FacesConverter annotation, you don’t have to register the converter in faces-config or anything. You can simply reference it using the id.

Here’s the code that uses the converter.

<h:selectManyListbox id="genresBox" value="#{createTable.table.genres}">
    <f:converter converterId="keyConverter" />
    <f:selectItems value="#{createTable.genres}"
        itemLabel="#{}" />

And just like that, I’m storing Keys in the data store instead of Strings.