01 February 2010

XML Serialization, the XNA Content Pipeline and Wumpus World

When replying to this Stack Overflow question, I realized that the poster was needlessly storing and loading XML through XML serialization at game time instead of using XNA's Content Pipeline.  As many people wanting to make a decent game, he wanted to create an editor and he wanted that editor to use his in-game engine.  This is a great idea, as it will let those designing worlds for your game (and you) see what things will actually look like in the resulting output.  It also opens the door for build-and-play scenarios where you do all design work in one application without the burden of the design-save-build-save-get into proper mode in actual game-test loop.

Unfortunately, his mistake was that he fell into the trap of .NET's XmlSerializer.  It is an easy trap to fall into because it is so simple and convenient to use.  Besides, the XNA Custom Content Pipeline is not advertised well enough and is actually quite obnoxious to use correctly (and the documentation is rather dull).  Luckily for all of my two readers, I have read that documentation already!

In today's example, I'm going to be operating on the wonderful game of Wumpus World.  I'm going to be making visualization and editor for the game, the reader can tie in input controls or whatever to make it a full game.

Setting Up the Project
First things first, we need to set up the project.  Obviously, you'll want to start off with your XNA Game - mine is called "Wumpus."  To make a custom pipeline extension, right-click your solution, perform the clicks to add a new project, and in the "XNA Game Studio $version" section, find "Content Pipeline Extension Library."  The convention here is to append ".Pipeline" to the namespace of your project, so mine is named "Wumpus.Pipeline."  There is automatically a ContentProcessor which is so creatively titled ContentProcessor1.  I'm not sure who at Microsoft made the decision to put these useless default files in every project, but you can just delete it.

Anyway, to actually use the things in your pipeline extension, your content project in the XNA game needs to have a reference to the pipeline project.  To do this, right click the content project, click "Add Reference," then go to the "Projects" tab of the dialog that comes up and select "Wumpus.Pipeline" (or whatever you named your pipeline project).

So now your content project can build with the pipeline extensions, but how do we build the objects in the extension library?  You'll most likely want to use the objects you've already created in your library, so try to add a reference to your main game through the same method.  I say "try to add" because this will not work.  It will tell you that you have a circular dependency.  Why?  Right now, there are three projects in your solution:
  • Wumpus -- This implicitly references Wumpus (Content).
  • Wumpus (Content) -- This references Wumpus.Pipeline.
  • Wumpus.Pipeline -- This cannot reference Wumpus, because that would make a loop.
In reality, this should not be a problem, since the content build project only needs the pipeline project while building and does not even exist at run time, so there is no circular reference.  However, Visual Studio cannot figure this out, so we have to work around this.

The solution is to create another project containing the core components of your game and reference that from both the game engine and the pipeline extension.  This avoids any possibility of circular references.  So add a new Windows Game Library to your project.  The convention is to append ".Core" to the name of the library.  As you probably know, Visual Studio will assume that is the namespace you would like to use for all classes in the project.  However, you won't be putting classes in the Wumpus.Core namespace, so you can change that behavior by opening the properties window for the core library and changing the "Default Namespace" to Wumpus (or whatever you want).

So here is the solution structure as it stands:
  • Wumpus.Core -- This has it's own content project, but you don't need to put anything in it.
  • Wumpus -- References Wumpus (Content) and Wumpus.Core.
  • Wumpus (Content) -- References Wumpus.Pipeline.
  • Wumpus.Pipeline -- References Wumpus.Core.
Now we're shaping up!

Originally I had mentioned an editor which uses the in-game engine and all the objects, so let's do that.  Add another project to your solution, but this one is going to be a WPF Application (you could also do a Windows Forms application, but WPF makes GUI creation fun and easy).  I named mine "Wumpus.Editor."  Add a reference to Wumpus.Core (since you're going to be using objects from it) and Wumpus (since we want to use the engine components from that).

As clearly indicated from my wonderful drawing, Wumpus.Core is the center of the attention.

Code Architecture
In the interests of brevity, I'm going to leave out the parts of the code that are boring.  They're all part of the download package at the bottom of this post.  Basically, there are two classes: TileQuality, which is an enum with qualities such as breezy, gold, stinky and wumpus with bitwise flags and WumpusWorld, which contains a grid of TileQualitys.  They both reside in Wumpus.Core, since they are needed for all phases of design
 

Being able to compose a full application by integrating many small pieces and making them communicate is wonderful.  However, it requires strict adherence to the one object serves one purpose philosophy of object-oriented programming.  Unfortunately, the Microsoft.Xna.Framework.Game class is often a blatant violation of this philosophy, as it encourages putting all the drawing, user interaction, asset management and everything else into this one place.  Knowing this, it is important to put different parts of the application in different places.  For this demo, the only part that will be on its own will be the graphics engine.

So, create a new class in Wumpus (because that is where engine things go) called GraphicsEngine (creative, I know).  In a real project, you might want to make an interface like IEngineModule or something so that you can easily manage all the engine parts, but you can just implement IDisposable.  Since we're abstracting things, we question: What does a graphics engine need?  I'm thinking it needs a reference to the GraphicsDevice so that it can do its job and a ContentManager so that it can locate and load graphics resources.  This is my constructor signature:

public GraphicsEngine(GraphicsDevice device, ContentManager manager);

This gives us the freedom to use the graphics engine any time we have those two items, instead of relying on the engine to go out and discover those things itself (which is a very easy way to accidentally create class coupling).  This is the basis of dependency injection.  Of course, if we wanted to be real legit about this, we could plug in a real dependency injection framework and work out what needs what from some configuration, but that's overkill here.

The sole job of the graphics engine is, given a WumpusWorld, draw it to the display device:

public void Draw(WumpusWorld world);

We are going to call this from our game, so we will need to have an instance of GraphicsEngine in our WumpusGame class.  Following the XNA patterns, Initialize is probably the best place to create the graphics engine, since we should have a reference to a valid device (assuming you've made a GraphicsDeviceManager and initialized it, as per the default):

m_graphics = new GraphicsEngine(GraphicsDevice, Content);

So instead of performing the drawing ourselves in WumpusGame.Draw, we delegate this task to the GraphicsEngine and trust it to do everything right:

protected override void Draw(GameTime gameTime)
{
    m_graphics.Draw(m_world);
}

Pretty easy, huh?  Of course, m_world is null right now, so you will want to instantiate it somewhere (doing it in LoadContent makes the most semantic sense).  If you have the free time, you can edit the world by hand and play the game:
Wumpus World Game

I know, the artwork is amazing.

Saving and Loading
As much fun as it is to create these worlds in code, it would be nice if we could persist these things outside of code.  For many things, .NET's automatic XML serialization is a wonderful thing and can be used.  However, my WumpusWorld class has a two-dimensional indexed property (public TileQuality this[int row, int col] { get; set; }), which cannot be serialized, so I wrote my own methods for saving and loading:

public void Save(Stream stream);
public static WumpusWorld Load(Stream stream);

These methods will be called by anything that wants to save or load for the simple text format (hereby referred to as .wump).  Here is some example output:

4,4
None
Breeze
Breeze
Pit
Breeze
Pit
Breeze, Stench
Breeze, Gold
None
Breeze, Stench
Breeze, Wumpus
Stench
Dude
Breeze
Pit
Breeze

Originally, though, I had talked about extending XNA's content pipeline, so we're going to make a reader and writer to convert to and read from the XNB binary format.  This lets you do fun things like verify every single file at build time, take advantage of automatic compression and deployment and a slew of other features gained by drinking the XNA Kool-Aid.  OOOH YEAH!
  1. ContentImporter: Reads an object from disk into memory.  Input is a file name and the output is some .NET object.  In our case, we're reading a .wump text file and outputting a WumpusWorld.
  2. ContentProcessor: Takes a .NET object, runs some operations on it and outputs some other .NET object.  You can perform whatever arbitrary modification to the object you need to.  We are not using it here, but I'm mentioning it because these can be very helpful (Shawn Hargreave's Pre-Multiplied Alpha Processor is a good example).
  3. ContentTypeWriter: Takes the .NET object that has been imported and optionally processed and writes it to disk with a binary serializer.  The input is the processed .NET object and the output is a binary serialized file.  This is the last step that is taken by the pipeline project.
  4. ContentTypeReader: Reads from the binary serialized stream and outputs the .NET in-game object.  This is in your actual game engine code.
All of these classes are very simple -- here is the entire WumpusWorldImporter class:

[ContentImporter(".wump", DisplayName = "Wumpus World Importer")]
public class WumpusWorldImporter : ContentImporter<WumpusWorld>
{
    public override WumpusWorld Import(string filename, ContentImporterContext context)
    {
        //    use the built-in load function
        return WumpusWorld.Load(File.OpenRead(filename));
    }
}



Simple, eh?  The ContentImporter attribute lets Visual Studio know that when we add a .wump file to the content build project, we would like to automatically use this content importer and the text to display the name of the importer with.  Look in the code for all the other class, but there is not much that needs explanation.  Most of the ugly stuff is out of the way so that you are presented with this nice, clean interface.

Create a .wump file (might I suggest using the "example output" from a few paragraphs ago?) and adding it to the Wumpus's content build project.  If everything worked properly, Visual Studio will associate the importer, not attach a processor, locate the writer at build time and associate the correct reader when the ContentManager needs it.  In short, you will be able to load a WumpusWorld with a simple call like this:

m_world = Content.Load("World/wumpus");

Pretty slick stuff.

The Editor
So, we would really like people to be able to create new worlds not by editing some text file, but by using a GUI tool.  As great as the NeoForce Controls are, they just do not have the sheer amount of things in the .NET forms nor are they as easy to design with (unless someone has made a WYSIWYG editor).  Wouldn't it be great to somehow embed the GraphicsEngine that we have already made into a heavyweight GUI framework?  In this demo, I'll be using WPF, because it is shiny, new and fun to work with.

The classic way to work with WinForms is to use Microsoft's WinForms Graphics Device, which is quite helpful.  This allows you to make an XNA GraphicsDevice render to the surface of a regular control.  However, this relies on the control having a handle, which is not present WPF (at least in a way that you can see).  This is easily solved through use of WindowsFormsHost, which lets you host a WinForms control in a WPF environment.

"ctl_formsHost" />

On initialization, attach our world control as the child element of the host:

ctl_worldView = new WumpusWorldControl();
m_graphicsService = GraphicsDeviceService.AddRef(ctl_worldView.Handle,
                                                  ctl_worldView.Width,
                                                  ctl_worldView.Height);
ctl_formsHost.Child = ctl_worldView;

The final output of my editor looks like this:
Wumpus World Editor 
Stunning beauty.

Code Files
The code here is not at all a "finished product." It would be pretty easy to extend the editor by doing things like adding smell and breeze automatically when a Wumpus or pit is added or making a world larger than 4x4.

It is released under the Apache License, Version 2.0 and should be used for good, not evil.
Wumpus Source Code

01 November 2009

Visual Studio 2010: Property Sheets and C++ Directories

I love external libraries.  A good library (one that is well-tested and interoperable) literally saves years of development time.  Since this post revolves around C++, I'm going to mention Boost as one of the most helpful libraries ever made.  Visual Studio provides a fairly obtuse (but working) system for referencing libraries on a per-user, per-system basis, accessable from the Tools > Options menu:


It doesn't look the most user-friendly and it's a little bit painful to get to (especially the first time), but it got the job done.  Theoretically, you only go into this menu (or you write a script to do it for you) once per library and never touch it again.

Naturally, when I began testing Visual Studio 2010, the first thing I wanted to do was set up my include and library paths.  So, I opened the options dialog only to find that Microsoft saw fit to remove this feature.  My first reaction was: "WHAT? WHY?" and I went on a hunt to see where they had moved that option to (because it is basically impossible to live without).  It turns out they had moved -- to the property page of the project (just right-click the project and open properties):

This is basically an extension (duplicate?) to the Visual Studio 200x options for the C++ compiler settings, which let you specify more directories to search through when looking for header files (a similar option exists for the linker in "Additional Library Directories"):



But before you start adding references to "C:\Path\To\Library" in all of your projects, let me tell you about a feature of Visual C++ called "Property Pages."  Personally, I have not seen them used very much in various projects for a number of reasons, the number one being that they are quite difficult to find, number two being that their visibility is not enabled by default, number three being that you do not have to know about them to get compiling in VC++ and lastly because their functionality is a little odd.

How to Use Property Sheets
These instructions will work with Visual Studio 2005, 2008 and 2010 (and probably beyond).

Anyway, the first thing you need to do is turn on the Property Manager toolbox.  Do this by hitting "Property Manager" under the "View" menu.  The toolbox will probably attach to your Solution Explorer, but it could just appear in the middle of the screen.  In either case, you should see a tree list of your projects, which have a cross-joined list of all solution configurations and platforms as children, which have a collection of settings sheets:


Okay, let's add a property sheet that defines the symbol _DEBUG and add it to all the debug configurations.  Right-click on any debug configuration and select "Add New Project Property Sheet."

If you are planning on using this sheet in multiple projects, it is a good idea to put the file in a directory that is not project-specific.  I made a directory called "Properties" in the solution directory to store all my property sheets.  A special note: At the time of writing, Visual Studio will give you an exception if you try to make a new property sheet in a directory that does not exist (error reported to Microsoft Connect), so you have to make the folder in Explorer or something first.

Open the newly-created file by double clicking and you should see a window that looks almost identical to what you would see if you opened up the "Properties" dialog from the Solution Explorer, save that there are a million options to configure.  The reason there are so many options to configure is because property sheets are not tied to any project, so all configurable options show up in the GUI.

Go into C++ > Preprocessor settings, add "_DEBUG" to the definition list and click OK.  Now you can add this .vsprops file to multiple projects.  You can actually share the .vsprops files between Visual Studio 2005 and Visual Studio 2008, if you are planning on maintaining two solutions for two separate consumer groups.  Unfortunately, Visual Studio 2010 creates a .props file, which is completely different XML and cannot be shared with previous versions of the IDE (but it can convert them).  A fun quirk is that you have to right-click on the individual sheet to explicitly save them (do not worry if you forget to do this, you will be asked when you exit the IDE).

Okay, so making a whole file and screwing around with all this stuff just to define another preprocessor macro is pretty pointless.  However, you can see that you have complete control over all the properties of VC++ projects, which means you could make another one for release that defines specific optimization settings for every project or a general setting that tells all projects to output to some shared output and intermediate files (I use a variation of "$(SolutionDir)/bin/$(ConfigurationName)/$(PlatformName)/$(ProjectName)" and "$(SolutionDir)/obj/$(ConfigurationName)/$(PlatformName)/$(ProjectName)").  Property sheets let you consolidate shared settings to arbitrary levels of granularity.

So if you have two property sheets, one which sets the output directory to "$(SolutionDir)/bin/$(ConfigurationName)/$(PlatformName)" and one that sets it to "$(SolutionDir)/bin/$(ConfigurationName)-$(PlatformName)", what is the value of $(OutDir)?  The answer is whichever one was evaluated last.  You can tell the order of evaluation by the order the sheets are listed in the Property Manager toolbox.  Evaluation occurs in a bottom-up order, so those sheets on top are evaluated last.

Back to the origninal problem: How can we use property sheets to make up for the lack of global VC++ Directories?  Even if we make a property sheet that adds a reference for #includes to "F:\Applications\Dev\boost_1_40_0", what happens when another developer has their Boost library in "C:\SDKs\boost1.40.0"?  Project property pages have not solved this problem, since changes to the file would get propagated over source control and screw up the settings for everyone else.  Wouldn't it be nice if there was a user-specific property page that was defined outside of the project?

In Visual Studio 2010 there is such a file: Microsoft.Cpp.Win32.user, which exists somewhere in your user application settings.  The good part about this change is that settings now reside in an overridable format.  If your project uses a modified version of some library, the project property sheet can add a search path to "$(SolutionDir)/ModifiedLibrary", which will be searched before the user files.  Granted, the change significantly changes the configuration system (in a way that takes a while to explain), but I think it's for the best.  There are also still some quirks with how adding different configurations will propagate certain sheets, but its still in beta, so hopefully they will be smoothed out.

13 October 2009

Model-Context-Interface

I have long been an opponent of the Model-View-Controller (MVC) philosophy of user interface design. Okay, it is not a horrible thing and it is certainly a good philosophy to know: keep your programming model separate from the way your users interact with it. The idea is to represent the domain model with objects, present views of said objects and allow a controller to manipulate those objects.



The first question is: Should the "model" be the actual underlying structure of the model or the user's mental model of how the program works? The answer to this question is quite obvious: The model is the actual program model. A user's mental model is not only crude and most likely incorrect, but it most likely varies from user to user. However, since UI design should be user-centric, we must never forget that the user's mental model of the process is important.

On to the View, which provides the user with a representation of the model. The separation allows one to easily add multiple views to the same data model, like viewing data through a pie chart or a bar chart. When Trygve Reenskaug conceived of MVC in 1979, the ability to easily view data in different charts was impressive. Modern users expect so much more! They want the ability to control and manipulate or otherwise interact with the data model. And the view has to be consistent through a desktop GUI application, text interface, an iPhone and Twitter.

This is where the Controller comes in: It is an abstraction of a method to manipulate the model. Unfortunately, even the Pragmatic Programmer will admit that the Controller and View are tightly coupled. This makes a whole lot of intuitive sense, since the things users see should directly relate to the things users do, but I am not sure it ever entered the minds of Xerox employees (I do not blame them, they were pretty busy making copiers and printers).

So we are really stuck with two systems: a Model and a View-Controller. Okay, so there is also Model-View-Presenter, which does not solve any problems, because it is pretty much the same thing (okay, the arrows are pointed a little differently). There has to be a better way to write interface code!

I first considered a new system wherein all data in the system was considered part of the Model, including data for interfaces. A model forms the foundation of information and the processing of that data on a small-scale. From pragmatic philosophy and MVC, the idea is that the model should only interact with what it owns. Data processing and functions therein can only interact with data that they create. For example, a Vector may hold values for X, Y and Z and could have a function named Length, which would represent the length of the vector. However, it should not have an interaction function called DistanceFrom(Vector) : float, which tells the distance between this vector and another. Keep in mind that "interaction" means that objects should not work with things they do not own, but something like a line, which consists of (owns) two points, can validly find the distance between them.

So, that simple example does not really show anything useful, but imagine a more complex system like a bank account transfer. There are rules regarding what the various accounts can and cannot do. For this world, let us say that it is illegal for a BankAccount to have less than $0 or more than $1,000,000 and that all transactions should be logged. We could strap methods to BankAccount like GiveTo(BankAccount) and Recieve(Money), but this leaves unanswered questions, the most imporant of which is: Who is responsible for rolling back on error? Anyone familiar with databases already knows the answer is that this should obviously take place inside of a managed transaction, where the system is responsible for rolling back failures.

A generalization of this transaction system is a Context, which provides a management layer for the data objects to communicate. This answers the second question of our previous problem: the context is responsible for logging the account transfer. This provides a convenient security mechanism as well: since the context is responsible for all interactions, we can easily make a rule that does not allow transfers to occur unless they are logged (and this is especially trivial if the logging system in integrated into the database).

Context provides a layer of abstraction for your objects to communicate through and can be seen as the network of communicating objects in your model. While the model represents things, context represents a system of communication, which begs the question: Why is this layer not named "communication." Not only would it continue to provide the same 'C' letter for an acronym, but it seems to be a better definition. However, using the word "communication" would imply that this layer conveys information, which is not true. While the context-layer provides a means for communication and performs communication by sending messages between systems, it is a stateful management layer - much more than a means of communication.

The final layer is how the context communicates the model to the outside world - the Interface. It is not an interface in the C-family sense of the word; it encompasses all of what you present to the user. An easy mistake is to assume that this only means a graphical- or console-user interface systems, but an interface can be a SOAP or JSON web service, a shared object library, operating system service or whatever method you use to interface with the world outside of your program.

This fits well into a service-oriented architecture, where the model provides local representations of domain objects, the context provides a system for those objects to communicate and an interface to work with the outside world. It is also quite reasonable to expect a context to work with other interfaces aside from the public one your application is presenting. For example, the context of a database-backed system would interact with the interface of an SQL server to provide the data. If the context is properly designed for configuration (Pragmatic Programmer says "Configure, Don't Integrate"), the interface does not need to know where the context gets information from, nor should it matter, and the system will be easily testable and debugable. The next obvious step is to extend this system to realise that we can chain these systems together however we need, so long as we do not let an interface directly manipulate the model (perhaps a better name would be (MC)*M(CI)*CI or the more catchy M(CM)*(CI)+).

But this whole thing was started with talk of end-user interfaces in terms of graphics and consoles. It is a natural and correct assumption that these user interfaces fit into the "interface" component of MCI. The goal is that it should be incredibly simple to swap out a given interface, be it a "system interface" that other system components work with, a "programmer interface" that others are meant to work with or a "user interface" for those regular people. Since they share underlying context components, it should be easy for multiple interface systems to seamlessly interact - changes made through one interface should be automatically reflected in another. However, do not forget that these components are also software. A web application which needs to remember user states or any other packet of information probably needs a model and context to remember it with. Just keep in mind that this should be a different model and context from the data you are serving, since they are fundementally different systems. This is a good design decision, mostly due to the separation of conserns, and will lead to a more service-oriented architecture (which will help when you make the AJAX or mobile version of the site).

Other tips for building data and context? Fill them with as much structural and descriptive metadata as possible. Java annotations (@interfaces) and .NET custom attributes are wonderful for this. In languages that do not support assembly-attached metadata, this functionality can be duplicated with automatically-generated XML files (if you're using Make, MSBuild, Ant or Maven, it is pretty easy to plug in a custom build step) or you could come up with another cool way, so long as semantic information is preserved in a runtime-readable format. This way, it becomes possible to automatically generate user-interface elements based on the program's metadata. Sound to good to be true? In the .NET Windows Forms system, there is a PropertyGrid, which is a single-object editor which designs itself using run-time reflection of attributes from the System.ComponentModel namespace. Java does not have a component like this built-in, but people have made programs in the Java Platform such as L2FProd's JPropertySheet (Apache-lisenced), which duplicates the functionality of PropertyGrid and the Java-Bean-Examiner (GPL-liscenced), which is specialized for EJBs.

There is another architectural pattern which is very similar to the MCI system, which plays off the three-letter acronym (3LA) system of named architectural patterns. It is called Data-Context-Interaction (DCI) and there was a fairly large page dedicated to it in March of 2009. If you are interested, I would highly recommend reading the linked page. Another good read is "The Common Sense of Object-Oriented Programming." Keep in mind that both of these papers quite Squeak-centric (the second, much more so), to the point that it is very difficult to abstract the core concepts out of their papers (and you really have to continually bypass statements like: "Smalltalk does everything for everyone in a clean and efficient system"). If you really like Smalltalk/Squeak, try out BabyIDE, which is a perspective-based IDE for Squeak (those familiar with Eclipse will feel close enough to home).

What is the difference between MCI and DCI? Aside from the different names, not much (I almost prefer "data" over "model" since it more clearly distances it from MVC, but I claim that the first letter of the acronym is much more than simple data). In reality, neither of these patterns are what I would call "mind-blowing." Essentially, it is better-defining the "model" from the MVC pattern by splitting into two parts, the "model" (or "data") and the "context." Furthermore, it gives up on the idea that the "view" and "controller" were ever separate entities by compressing them into an "interface" (or "interaction"). While this is a fairly subtle distinction, but it's the context that makes all the difference in the world.