Sunday, March 29, 2009

Let's do something C++ can't

Recently I was writing some code to load levels. This is a common task but I think I ended up with some pretty neat code that can be used in a variety of ways.

My levels are rather unusual. A level can be generated totally by my code. So I can be as a vague as 'make a level' or I can say 'I want a monster here and here and walls here' and describe everything down to the last detail. I'm still somewhat in the early stages of development, so the layout of the level file is likely to change a lot as I add new things.

My first thought was XML. I'd write something like:

 
<level>
<name>Level One</name>

<simpleDescription>
<setting>
<stone/>
<wood/>
<setting>

<enemies>
<orc/>
<dragon/>
<enemies>
</simpleDescription>

</level>
 


Obviously this is code that's going to change quite a bit as I develop the game. Writing an XML parser would mean everytime there's a code change - the data files and the parser must change. Not only that but I'd be editing these files by hand. XML isn't the most pleasant medium to write in.

XML Alternatives

So what can be used instead of XML? Dimly, ever so dimly I recalled an XML alternative. The way I remember this alternative was that it used whitespace in a novel way. The above xml code would be rendered:


Level
Name : LevelOne
SimpleDescription
Setting
Wood
Stone
Enemies
Orc
Dragon


This seemed great - unfortunately I couldn't find any reference to it, perhaps my google-foo is weak. All I could find was JSON, which is a subset of Javascript laid out to look like XML. I toyed with JSON for a while but in the end it was just as unpleasant as XML for me.

After failing to find the whitespace xml alternative my mind wandered to kjAPI a C++ game programming library (it's wonderful though the public release is somewhat tricky to compile.) kjAPI has this great reflection system, you mark a number of fields to be 'metaclassed'. Once the field's are metaclassed they can be directly manipulated by it's GUI editor - and they can be serialized to XML. This is done automatically no parser needs writing just automatic load and save functionality. Excellent.

Of course C# has this in the form of the serialize attribute - but this generates computer XML. I'm going to be writing these level descriptions - I have a hard enough time with human xml! Never mind writing my XML so that the serialize methods of C# will correctly map it to my class data.

Next I considered going the C# serialize route but doing all my editing in a GUI. Then I started to think about how such a GUI would need to appear, and I started to look at datagrid controls and things ... soon my initial enthusiasm waned. Also if I'm going the GUI route - why bother with the XML? I could just use a binary file. Deciding the GUI option would be a unreasonable time sink I came upon my current solution.

I'd do what all programmers love to do - roll my own!

A general solution that fits my needs

First here's the data file.


+Level
{
_name = "Level One"
_simpleDescription = +SimpleDescription
{
@AddSetting("Wood")
@AddSetting("Stone")
@AddMonster("Orc")
@AddMonster("Dragon")
}
}


Ok - it looks a lot like the others, but it's got a clever trick. I have some general code that searches the current C# assembly and creates an object the type 'Level' then it assigns it's fields _name and _simpleDescription. The code can do this for any class in the C# assembly provided the data files names match up correctly.

So if I have a class item.


class Item
{
string _name;
string _description;
}


I can write


+Item
{
_name = "Some toast."
_description = "A piece of toast, it's cold and slightly burnt."
}


Then in C# code I can write something like (I've called my generic object loader 'dresser'):


Dresser dresser = new Dresser("the text of the data file goes here.");
Item item = dresser.GetNextObject<Item>();


And that's it. That item is now filled up, it's name is set to 'Some toast' and the description is set too.

How it works

The '+' sign means create a new object. The object type is whatever follows the +[that is what goes here]. I use C#'s reflection system to find the class with the name, then using various trickery I create an instance of that class at runtime. The name in the data file and the name in the C# file must be the same. Then I go through the fields and set them in the same way, I search the class using reflection for a field's name and then set it directly (using reflection private fields can be set).

The @ symbol is something I've added only for this example (my level's aren't of the orc, dragon kind). It merely means calls a function of this name. So once again I search for the method and call it with the appropriate arguments. Neat right?

This means I can change and extend the code as I like and I only need change the data where the two don't match. There's no parsing code to rewrite.

Saturday, March 28, 2009

system.badimageformatexception

The errors are slowly trickling in. This time Nunit. I tried to load some of my assemblies to unit test and recieved this exception: "system.badimageformatexception". So I ensured all the projects in my solution where compiling using the same CPU. Still I got the same error.

It turns out this is another symptom of developing on 64bit Vista system. The assemblies I was testing were x86. The nunit was 64bit, and that's were the problem was. This can be resolved by using nunit-x86.exe in the bin directory.

Another problem down.

Friday, March 27, 2009

An attempt was made to load a program with an incorrect format.

I'm updating here until I resolve what I'm going to do withgodpatterns.

Recently I setup a new dev machine, while I'm back in the UK searching for a new job (I'm hoping to get something to do with C# if possible). Anyway I moved my SVN repository over along with my most recent code check outs.

As I mentioned in my last post I'm developing using C# and Tao (which, among other things, is an OpenGL wrapper).

On running my code I got a runtime crash. An exception


public SoundManager()
{
Alut.alutInit();


When the program tries to start up OpenAL I get the error message "An attempt was made to load a program with an incorrect format."

It's worth noting I'm now developing on Vista (this machine had it preinstalled) and the machine is 64 bit. Using this post, I found out the problem is that the Tao dlls are x86 (32 bit) and I was trying to compile my code as 64 bit. This seemed to be default in visual studio.

If you want to fix this, then for each project in your solution go to Project > Properties. This will bring up a dialog. Select BUILD, then find the combo box next to the label 'Platform Target'. Change this from any to x86.

That should fix any problems.

(One other issue I seem to be having is a number of dlls are missing in Vista. So for now I'm just including copies with my executable)

Happy hacking.

Note: If you're still having problems and want some more voodoo. I also remove all my Tao references and readded them