Tuesday, October 12, 2010

Small update

This is just a small update to let everyone know I'm still around. A lot of things conspired this summer to keep me from posting. The latest is a recent surgery from which I am still recovering.

Still, I haven't stopped work on the project. In fact I recently created a project at http://grue.codeplex.com/ to host the source code for my class library.
I haven't done a binary release yet as I want to make a few more changes first. I eventually want to add the code for some of my front end applications as well, although at the moment the library's public API is still changing enough that they become outdated fairly quickly.

If anyone has the desire to dig through the source, I'd be happy to answer any questions. If anyone is feeling particularly adventurous and wants to try their hand at writing a front end, the project files require Stylecop be installed in order to build. If you aren't using Stylecop yet...why?

The current status of the library is such that Version 1 through 3 games run great (with the notable exception of Seastalker versions which use the SonarScope display). Upper window support and color is currently broken, which means V4-5, V7-8 will run but display incorrectly. Version 6 support is unfinished. Your mileage may vary.

Tuesday, April 6, 2010

You learn something everyday...if you read the documentation

As I mentioned once, I have a static array of delegates in my Z-machine base class.

The delegate signature looks like this:
protected delegate void Operation(ZMachine machine);

The array is intialized with a series of statements like this:
op[0] = op[32] = op[64] = op[96] = op[192] = z => z.Op0();
op[1] = op[33] = op[65] = op[97] = op[193] = z => z.Op1();
...
op[254] = z => z.Op254();
op[255] = z => z.Op255();

I was forced to create a wrapper method which allows the delegate (which is static) to call an instance method specified at the time of invocation. This is because the actual operations are virtual to deal with the changing behavior of the various Z-machine versions. Using lambdas instead of named methods makes things look cleaner and involves a lot less typing, but always bugged me because of the extra method call needed for each instruction that is executed. I could find no better way though.

Today while reading through some documentation I discovered a way to do this without the wrapper represented by the lambda. About a third of the way down the page I found this:

"When a delegate represents an open instance method, it stores a reference to the method's entry point. The delegate signature must include the hidden this parameter in its formal parameter list; in this case, the delegate does not have a reference to a target object, and a target object must be supplied when the delegate is invoked."

I'd never heard of open instance delegates before. This was exactly what I was looking for!

Now I can write a method like:
private static Operation CreateOperation(string method)
{
return (Operation)Delegate.CreateDelegate(typeof(Operation), typeof(ZmachineV1).GetMethod(method, BindingFlags.NonPublic BindingFlags.Instance));
}


and my array initialization looks like:
op[0] = op[32] = op[64] = op[96] = op[192] = CreateOperation("Operation0");
op[1] = op[33] = op[65] = op[97] = op[193] = CreateOperation("Operation1");
...
op[254] = CreateOperation("Operation254");
op[255] = CreateOperation("Operation255");

This reduces the size of the binary and removes the extra method call when each instruction is executed. I only wish C# had some sort of native support for this type of delegate, as the CreateOperation method is ugly and can fail at runtime if the wrong name is passed whereas delegate creation using a method group name is checked at compile time.

I've nearly finished my refactoring and hope to make some code publicly available soon.

[Update: Thanks for the comments. They inspired me to keep trying.]

I'll admit I'm inexperienced with functional programming. It gives me headaches.
From what I see, expression trees reintroduce the code bloat I had with the lambdas. Honestly I didn't look into it deep enough to see if the extra method call gets reinserted at execution time.

Anyway, I played around with it some more and came up with this (sorry about the formatting):

namespace ConsoleApplication1
{
using System;

///
/// The program.
///

internal class Program
{
///
/// Program entry.
///

private static void Main()
{
var z = new ZmachineV2();
z.Run();
}

///
/// The zmachine V1.
///

private class ZmachineV1
{
///
/// The operations.
///

private static Operation[] operations;

///
/// A fake op (Needed to get the MethodInfo).
///

private delegate void FakeOp();

///
/// An operation.
///

///
/// The zmachine.
///
private delegate void Operation(ZmachineV1 zmachine);

///
/// Gets the operations.
///

///
/// The operations.
///

private Operation[] Operations
{
get
{
return operations ?? (operations = this.InitializeOperations());
}
}

///
/// Runs one cycle of the zmachine.
///

public void Run()
{
this.Operations[0](this);
}

///
/// Operation 0.
///

protected virtual void Operation0()
{
Console.WriteLine("Called ZmachineV1.Operation0.");
}

///
/// Creates an operation.
///

///
/// The fake operation.
///
///
/// An operation.
///

private static Operation CreateOperation(FakeOp fake)
{
return (Operation)Delegate.CreateDelegate(typeof(Operation), fake.Method.GetBaseDefinition());
}

///
/// Initializes the operations.
///

///
/// The operations.
///

private Operation[] InitializeOperations()
{
var ops = new Operation[1];
ops[0] = CreateOperation(this.Operation0);
return ops;
}
}

///
/// The zmachine V2.
///

private class ZmachineV2 : ZmachineV1
{
///
/// Operation 0.
///

protected override void Operation0()
{
Console.WriteLine("Called ZmachineV2.Operation0.");
}
}
}
}


The only downsides to this that I see are that I had to give up the readonly modifier on the delegate array, wrap it in a property, create another delegate type, and the initialization generates a bit of garbage for the FakeOp delegates. On the plus side, the CreateOperation method looks better and I no longer need to refer to anything in the Reflection namespace, so I can drop the using statement for that. I no longer need to pass strings and my method names are verified at compile time. I also don't need any wrapper methods. What do you think?

Tuesday, February 16, 2010

Design decisions

This post is long overdue and was originally going to feature my code for playing sounds in the Z-machine. That will have to wait however as I've recently been making some significant changes to my Z-machine library and the sound code faces some significant rewriting.

Supporting all eight Z-machine versions in one codebase is an interesting challenge. Back when I first started this project, I had one class which encompassed every version. It was filled with hundreds of if/else statements and switches which directed behavior based on the machine version. This worked well enough, but was a mess to look at and maintain. After some time I decided to use an inheritance model to separate the behavior of each version. This helped me clean up the code as well as fix a few bugs which were hidden before.

One thing that became clear to me as I refactored my code was that my original design, in the interest of typing less code, had actually created a sort of hybrid machine where capabilities of later versions are actually available to earlier ones. An interpreter can get away with this sort of design by relying on the fact that earlier games will not try to use these capabilities, as I mentioned during my last post. Indeed, I think this approach is fairly common among Z-machine interpreters. While this is fine from a practical point of view of running games. I've recently come to the conclusion that it is poor from a code-as-documentation standpoint. If we had to reverse engineer existing interpreters to reproduce the Z-machine standards document, a hybrid machine would give us a badly distorted picture. Theoretically, it could also encourage the development of games that use capabilities not properly belonging to a given version. Because of this I've decided to adopt a more strict interpretation of the specification and make the appropriate changes to my library.

Moving to an inheritance model has helped me improve my code a lot, but it hasn't all been a cure all. There are a few methods, namely converting between Z-characters and ZSCII which don't lend themselves easily to inheritance. Key pieces of the algorithms change between versions, which makes it difficult to implement them as virtual/override methods and leads to blocks of repeated code. This is the exception however, and the overall improvement in the code has been substantial.

I still have some refactoring to do to implement my latest design changes, but I hope to make my source code available soon.